From 89cf3f821e56aff12062c6003e857591d01b9a6b Mon Sep 17 00:00:00 2001 From: Vinicius Couto Espindola Date: Tue, 29 Aug 2023 07:54:35 -0300 Subject: [PATCH 1/3] [mlir][llvm] Add zeroinitializer constant This patch adds support for the zeroinitializer constant to LLVM dialect. It's meant to simplify zero-initialization of aggregate types in MLIR, although it can also be used with non-aggregate types. --- mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 24 ++++ mlir/test/Target/LLVMIR/llvmir.mlir | 129 ++++++++++++++++++++ 2 files changed, 153 insertions(+) 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/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 82e8d451da055..a795dbf76fab8 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2292,3 +2292,132 @@ llvm.func @locally_streaming_func() attributes {arm_locally_streaming} { } // CHECK: attributes #[[ATTR]] = { "aarch64_pstate_sm_body" } + +// ----- + +// +// Zero-initialize operation. +// + +llvm.mlir.global linkonce @zero_integer() : i32 { + %0 = llvm.mlir.zero : i32 + llvm.return %0 : i32 +} +// CHECK: @zero_integer = linkonce global i32 0 + +llvm.mlir.global linkonce @zero_float() : f32 { + %0 = llvm.mlir.zero : f32 + llvm.return %0 : f32 +} +// CHECK: @zero_float = linkonce global float 0.000000e+00 + +llvm.mlir.global linkonce @zero_array() : !llvm.array<5 x i32> { + %0 = llvm.mlir.zero : !llvm.array<5 x i32> + llvm.return %0 : !llvm.array<5 x i32> +} +// CHECK: @zero_array = linkonce global [5 x i32] zeroinitializer + +llvm.mlir.global linkonce @zero_struct() : !llvm.struct<(i32, f64, i8)> { + %0 = llvm.mlir.zero : !llvm.struct<(i32, f64, i8)> + llvm.return %0 : !llvm.struct<(i32, f64, i8)> +} +// CHECK: @zero_struct = linkonce global { i32, double, i8 } zeroinitializer + +llvm.mlir.global linkonce @zero_ptr() : !llvm.ptr { + %0 = llvm.mlir.zero : !llvm.ptr + llvm.return %0 : !llvm.ptr +} +// CHECK: @zero_ptr = linkonce global ptr null + +llvm.mlir.global linkonce @zero_vector() : !llvm.vec<42 x ptr> { + %0 = llvm.mlir.zero : !llvm.vec<42 x ptr> + llvm.return %0 : !llvm.vec<42 x ptr> +} +// CHECK: @zero_vector = linkonce global <42 x ptr> zeroinitializer + +llvm.mlir.global linkonce @zero_nested() : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> { + %0 = llvm.mlir.zero : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> + llvm.return %0 : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> +} +// CHECK: @zero_nested = linkonce global { i32, { i32, i32 }, double } zeroinitializer + +llvm.mlir.global linkonce @zero_func_ptr() : !llvm.ptr> { + %0 = llvm.mlir.zero : !llvm.ptr> + llvm.return %0 : !llvm.ptr> +} +// CHECK: @zero_func_ptr = linkonce global ptr null + +llvm.mlir.global linkonce @zero_complex_type() : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> { + %0 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> + llvm.return %0 : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> +} +// CHECK: @zero_complex_type = linkonce global [5 x { i32, [3 x ptr] }] zeroinitializer + +llvm.func @local_zero_initialize() { + %0 = llvm.mlir.constant(1 : i64) : i64 + + // Integer type + %local_integer = llvm.alloca %0 x i32 : (i64) -> !llvm.ptr + %1 = llvm.mlir.zero : i32 + llvm.store %1, %local_integer : !llvm.ptr + // CHECK: %[[#V1:]] = alloca i32, i64 1, align 4 + // CHECK: store i32 0, ptr %[[#V1]], align 4 + + // Float type + %local_float = llvm.alloca %0 x f32 : (i64) -> !llvm.ptr + %2 = llvm.mlir.zero : f32 + llvm.store %2, %local_float : !llvm.ptr + // CHECK: %[[#V2:]] = alloca float, i64 1, align 4 + // CHECK: store float 0.000000e+00, ptr %[[#V2]], align 4 + + // Array type + %local_array = llvm.alloca %0 x !llvm.array<5 x i32> : (i64) -> !llvm.ptr> + %3 = llvm.mlir.zero : !llvm.array<5 x i32> + llvm.store %3, %local_array : !llvm.ptr> + // CHECK: %[[#V3:]] = alloca [5 x i32], i64 1, align 4 + // CHECK: store [5 x i32] zeroinitializer, ptr %[[#V3]], align 4 + + // Struct type + %local_struct = llvm.alloca %0 x !llvm.struct<(i32, f64, i8)> : (i64) -> !llvm.ptr> + %4 = llvm.mlir.zero : !llvm.struct<(i32, f64, i8)> + llvm.store %4, %local_struct : !llvm.ptr> + // CHECK: %[[#V4:]] = alloca { i32, double, i8 }, i64 1, align 8 + // CHECK: store { i32, double, i8 } zeroinitializer, ptr %[[#V4]], align 8 + + // Pointer type + %local_ptr = llvm.alloca %0 x !llvm.ptr : (i64) -> !llvm.ptr> + %5 = llvm.mlir.zero : !llvm.ptr + llvm.store %5, %local_ptr : !llvm.ptr> + // CHECK: %[[#V5:]] = alloca ptr, i64 1, align 8 + // CHECK: store ptr null, ptr %[[#V5]], align 8 + + // Vector type + %local_vector = llvm.alloca %0 x !llvm.vec<42 x ptr> : (i64) -> !llvm.ptr>> + %6 = llvm.mlir.zero : !llvm.vec<42 x ptr> + llvm.store %6, %local_vector : !llvm.ptr>> + // CHECK: %[[#V6:]] = alloca <42 x ptr>, i64 1, align 512 + // CHECK: store <42 x ptr> zeroinitializer, ptr %[[#V6]], align 512 + + // Nested type + %local_nested = llvm.alloca %0 x !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> : (i64) -> !llvm.ptr, f64)>> + %7 = llvm.mlir.zero : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> + llvm.store %7, %local_nested : !llvm.ptr, f64)>> + // CHECK: %[[#V7:]] = alloca { i32, { i32, i32 }, double }, i64 1, align 8 + // CHECK: store { i32, { i32, i32 }, double } zeroinitializer, ptr %[[#V7]], align 8 + + // Function Pointer type + %local_func_ptr = llvm.alloca %0 x !llvm.ptr> : (i64) -> !llvm.ptr>> + %8 = llvm.mlir.zero : !llvm.ptr> + llvm.store %8, %local_func_ptr : !llvm.ptr>> + // CHECK: %[[#V8:]] = alloca ptr, i64 1, align 8 + // CHECK: store ptr null, ptr %[[#V8]], align 8 + + // Complex type + %local_complex = llvm.alloca %0 x !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> : (i64) -> !llvm.ptr>) >>> + %9 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> + llvm.store %9, %local_complex : !llvm.ptr>) >>> + // CHECK: %[[#V9:]] = alloca [5 x { i32, [3 x ptr] }], i64 1, align 8 + // CHECK: store [5 x { i32, [3 x ptr] }] zeroinitializer, ptr %[[#V9]], align 8 + + llvm.return +} From a82a4168dd0f1f2a59432384f7cacc9ea2e2ae53 Mon Sep 17 00:00:00 2001 From: Vinicius Couto Espindola Date: Wed, 6 Sep 2023 19:01:08 -0300 Subject: [PATCH 2/3] Apply first round of reviews --- mlir/test/Dialect/LLVMIR/roundtrip.mlir | 7 ++ mlir/test/Target/LLVMIR/llvmir.mlir | 127 +++--------------------- 2 files changed, 19 insertions(+), 115 deletions(-) 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 a795dbf76fab8..96b231a5375cb 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2299,125 +2299,22 @@ llvm.func @locally_streaming_func() attributes {arm_locally_streaming} { // Zero-initialize operation. // -llvm.mlir.global linkonce @zero_integer() : i32 { - %0 = llvm.mlir.zero : i32 - llvm.return %0 : i32 -} -// CHECK: @zero_integer = linkonce global i32 0 - -llvm.mlir.global linkonce @zero_float() : f32 { - %0 = llvm.mlir.zero : f32 - llvm.return %0 : f32 -} -// CHECK: @zero_float = linkonce global float 0.000000e+00 - -llvm.mlir.global linkonce @zero_array() : !llvm.array<5 x i32> { - %0 = llvm.mlir.zero : !llvm.array<5 x i32> - llvm.return %0 : !llvm.array<5 x i32> -} -// CHECK: @zero_array = linkonce global [5 x i32] zeroinitializer - -llvm.mlir.global linkonce @zero_struct() : !llvm.struct<(i32, f64, i8)> { - %0 = llvm.mlir.zero : !llvm.struct<(i32, f64, i8)> - llvm.return %0 : !llvm.struct<(i32, f64, i8)> -} -// CHECK: @zero_struct = linkonce global { i32, double, i8 } zeroinitializer - -llvm.mlir.global linkonce @zero_ptr() : !llvm.ptr { - %0 = llvm.mlir.zero : !llvm.ptr - llvm.return %0 : !llvm.ptr -} -// CHECK: @zero_ptr = linkonce global ptr null - -llvm.mlir.global linkonce @zero_vector() : !llvm.vec<42 x ptr> { - %0 = llvm.mlir.zero : !llvm.vec<42 x ptr> - llvm.return %0 : !llvm.vec<42 x ptr> -} -// CHECK: @zero_vector = linkonce global <42 x ptr> zeroinitializer - -llvm.mlir.global linkonce @zero_nested() : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> { - %0 = llvm.mlir.zero : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> - llvm.return %0 : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> -} -// CHECK: @zero_nested = linkonce global { i32, { i32, i32 }, double } zeroinitializer - -llvm.mlir.global linkonce @zero_func_ptr() : !llvm.ptr> { - %0 = llvm.mlir.zero : !llvm.ptr> - llvm.return %0 : !llvm.ptr> -} -// CHECK: @zero_func_ptr = linkonce global ptr null - -llvm.mlir.global linkonce @zero_complex_type() : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> { - %0 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> - llvm.return %0 : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> +// 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>)> } -// CHECK: @zero_complex_type = linkonce global [5 x { i32, [3 x ptr] }] zeroinitializer -llvm.func @local_zero_initialize() { +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 - // Integer type - %local_integer = llvm.alloca %0 x i32 : (i64) -> !llvm.ptr - %1 = llvm.mlir.zero : i32 - llvm.store %1, %local_integer : !llvm.ptr - // CHECK: %[[#V1:]] = alloca i32, i64 1, align 4 - // CHECK: store i32 0, ptr %[[#V1]], align 4 - - // Float type - %local_float = llvm.alloca %0 x f32 : (i64) -> !llvm.ptr - %2 = llvm.mlir.zero : f32 - llvm.store %2, %local_float : !llvm.ptr - // CHECK: %[[#V2:]] = alloca float, i64 1, align 4 - // CHECK: store float 0.000000e+00, ptr %[[#V2]], align 4 - - // Array type - %local_array = llvm.alloca %0 x !llvm.array<5 x i32> : (i64) -> !llvm.ptr> - %3 = llvm.mlir.zero : !llvm.array<5 x i32> - llvm.store %3, %local_array : !llvm.ptr> - // CHECK: %[[#V3:]] = alloca [5 x i32], i64 1, align 4 - // CHECK: store [5 x i32] zeroinitializer, ptr %[[#V3]], align 4 - - // Struct type - %local_struct = llvm.alloca %0 x !llvm.struct<(i32, f64, i8)> : (i64) -> !llvm.ptr> - %4 = llvm.mlir.zero : !llvm.struct<(i32, f64, i8)> - llvm.store %4, %local_struct : !llvm.ptr> - // CHECK: %[[#V4:]] = alloca { i32, double, i8 }, i64 1, align 8 - // CHECK: store { i32, double, i8 } zeroinitializer, ptr %[[#V4]], align 8 - - // Pointer type - %local_ptr = llvm.alloca %0 x !llvm.ptr : (i64) -> !llvm.ptr> - %5 = llvm.mlir.zero : !llvm.ptr - llvm.store %5, %local_ptr : !llvm.ptr> - // CHECK: %[[#V5:]] = alloca ptr, i64 1, align 8 - // CHECK: store ptr null, ptr %[[#V5]], align 8 - - // Vector type - %local_vector = llvm.alloca %0 x !llvm.vec<42 x ptr> : (i64) -> !llvm.ptr>> - %6 = llvm.mlir.zero : !llvm.vec<42 x ptr> - llvm.store %6, %local_vector : !llvm.ptr>> - // CHECK: %[[#V6:]] = alloca <42 x ptr>, i64 1, align 512 - // CHECK: store <42 x ptr> zeroinitializer, ptr %[[#V6]], align 512 - - // Nested type - %local_nested = llvm.alloca %0 x !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> : (i64) -> !llvm.ptr, f64)>> - %7 = llvm.mlir.zero : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)> - llvm.store %7, %local_nested : !llvm.ptr, f64)>> - // CHECK: %[[#V7:]] = alloca { i32, { i32, i32 }, double }, i64 1, align 8 - // CHECK: store { i32, { i32, i32 }, double } zeroinitializer, ptr %[[#V7]], align 8 - - // Function Pointer type - %local_func_ptr = llvm.alloca %0 x !llvm.ptr> : (i64) -> !llvm.ptr>> - %8 = llvm.mlir.zero : !llvm.ptr> - llvm.store %8, %local_func_ptr : !llvm.ptr>> - // CHECK: %[[#V8:]] = alloca ptr, i64 1, align 8 - // CHECK: store ptr null, ptr %[[#V8]], align 8 - - // Complex type - %local_complex = llvm.alloca %0 x !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> : (i64) -> !llvm.ptr>) >>> - %9 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr>) >> - llvm.store %9, %local_complex : !llvm.ptr>) >>> - // CHECK: %[[#V9:]] = alloca [5 x { i32, [3 x ptr] }], i64 1, align 8 - // CHECK: store [5 x { i32, [3 x ptr] }] zeroinitializer, ptr %[[#V9]], align 8 + // CHECK: store [1000 x { i32, [3 x { double, <4 x ptr>, [2 x ptr] }], [6 x ptr] }] zeroinitializer, ptr %1, 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 } From ecedd7bc76d874dd688f96738fb4a8de45031f79 Mon Sep 17 00:00:00 2001 From: Vinicius Couto Espindola Date: Wed, 6 Sep 2023 19:19:00 -0300 Subject: [PATCH 3/3] Fix test FileCheck variable usage --- mlir/test/Target/LLVMIR/llvmir.mlir | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index 96b231a5375cb..d08f5b2776ee1 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2312,7 +2312,7 @@ llvm.func @zeroinit_complex_local_aggregate() { %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 %1, align 32 + // 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