diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index 7ceec72144eb5..7c03e0bd4451a 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -1506,6 +1506,30 @@ def LLVM_PoisonOp : LLVM_Op<"mlir.poison", [Pure]>, let assemblyFormat = "attr-dict `:` type($res)"; } +def LLVM_ZeroOp + : LLVM_Op<"mlir.zero", [Pure]>, + LLVM_Builder<"$res = llvm::Constant::getNullValue($_resultType);"> +{ + let summary = "Creates a zero-initialized value of LLVM dialect type."; + let description = [{ + Unlike LLVM IR, MLIR does not have first-class zero-initialized values. + Such values must be created as SSA values using `llvm.mlir.zero`. This + operation has no operands or attributes. It creates a zero-initialized + value of the specified LLVM IR dialect type. + + Example: + + ```mlir + // Create a zero-initialized value for a structure with a 32-bit integer + // followed by a float. + %0 = llvm.mlir.zero : !llvm.struct<(i32, f32)> + ``` + }]; + let results = (outs LLVM_Type:$res); + let builders = [LLVM_OneResultOpBuilder]; + let assemblyFormat = "attr-dict `:` type($res)"; +} + def LLVM_ConstantOp : LLVM_Op<"mlir.constant", [Pure, ConstantLike]>, LLVM_Builder<[{$res = getLLVMConstant($_resultType, $value, $_location, diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir index b9ce6933a9eb5..558ed3058fe75 100644 --- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -334,6 +334,13 @@ func.func @null() { llvm.return } +// CHECK-LABEL: @zero +func.func @zero() { + // CHECK: llvm.mlir.zero : i8 + %0 = llvm.mlir.zero : i8 + llvm.return +} + // CHECK-LABEL: @atomic_load func.func @atomic_load(%ptr : !llvm.ptr) { // CHECK: llvm.load %{{.*}} atomic monotonic {alignment = 4 : i64} : !llvm.ptr -> f32 diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 82e8d451da055..d08f5b2776ee1 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2292,3 +2292,29 @@ llvm.func @locally_streaming_func() attributes {arm_locally_streaming} { } // CHECK: attributes #[[ATTR]] = { "aarch64_pstate_sm_body" } + +// ----- + +// +// Zero-initialize operation. +// + +// CHECK: @partially_zeroinit_aggregate = linkonce global { i32, i64, [3 x i8] } { i32 0, i64 1, [3 x i8] zeroinitializer } +llvm.mlir.global linkonce @partially_zeroinit_aggregate() : !llvm.struct<(i32, i64, !llvm.array<3 x i8>)> { + %0 = llvm.mlir.zero : !llvm.struct<(i32, i64, !llvm.array<3 x i8>)> + %1 = llvm.mlir.constant(1 : i64) : i64 + %2 = llvm.insertvalue %1, %0[1] : !llvm.struct<(i32, i64, !llvm.array<3 x i8>)> + llvm.return %2 : !llvm.struct<(i32, i64, !llvm.array<3 x i8>)> +} + +llvm.func @zeroinit_complex_local_aggregate() { + // CHECK: %[[#VAR:]] = alloca [1000 x { i32, [3 x { double, <4 x ptr>, [2 x ptr] }], [6 x ptr] }], i64 1, align 32 + %0 = llvm.mlir.constant(1 : i64) : i64 + %1 = llvm.alloca %0 x !llvm.array<1000 x !llvm.struct<(i32, !llvm.array<3 x !llvm.struct<(f64, !llvm.vec<4 x ptr>, !llvm.array<2 x ptr>)>>, !llvm.array<6 x ptr>)>> : (i64) -> !llvm.ptr + + // CHECK: store [1000 x { i32, [3 x { double, <4 x ptr>, [2 x ptr] }], [6 x ptr] }] zeroinitializer, ptr %[[#VAR]], align 32 + %2 = llvm.mlir.zero : !llvm.array<1000 x !llvm.struct<(i32, !llvm.array<3 x !llvm.struct<(f64, !llvm.vec<4 x ptr>, !llvm.array<2 x ptr>)>>, !llvm.array<6 x ptr>)>> + llvm.store %2, %1 : !llvm.array<1000 x !llvm.struct<(i32, !llvm.array<3 x !llvm.struct<(f64, !llvm.vec<4 x ptr>, !llvm.array<2 x ptr>)>>, !llvm.array<6 x ptr>)>>, !llvm.ptr + + llvm.return +}