[Mlir-commits] [mlir] [mlir][llvm] Add zeroinitializer constant (PR #65508)

Vinicius Couto Espindola llvmlistbot at llvm.org
Wed Sep 6 15:05:55 PDT 2023


https://github.com/sitio-couto updated https://github.com/llvm/llvm-project/pull/65508:

>From 89cf3f821e56aff12062c6003e857591d01b9a6b Mon Sep 17 00:00:00 2001
From: Vinicius Couto Espindola <vini.couto.e at gmail.com>
Date: Tue, 29 Aug 2023 07:54:35 -0300
Subject: [PATCH 1/2] [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 7ceec72144eb52c..7c03e0bd4451aed 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 82e8d451da05576..a795dbf76fab8e3 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<i32> {
+  %0 = llvm.mlir.zero : !llvm.ptr<i32>
+  llvm.return %0 : !llvm.ptr<i32>
+}
+// CHECK: @zero_ptr = linkonce global ptr null
+
+llvm.mlir.global linkonce @zero_vector() : !llvm.vec<42 x ptr<i32>> {
+  %0 = llvm.mlir.zero : !llvm.vec<42 x ptr<i32>>
+  llvm.return %0 : !llvm.vec<42 x ptr<i32>>
+}
+// 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<func<i32 (i32)>> {
+  %0 = llvm.mlir.zero : !llvm.ptr<func<i32 (i32)>>
+  llvm.return %0 : !llvm.ptr<func<i32 (i32)>>
+}
+// 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<i32>>) >> {
+  %0 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>
+  llvm.return %0 : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>
+}
+// 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<i32>
+  %1 = llvm.mlir.zero : i32
+  llvm.store %1, %local_integer : !llvm.ptr<i32>
+  // 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<f32>
+  %2 = llvm.mlir.zero : f32
+  llvm.store %2, %local_float : !llvm.ptr<f32>
+  // 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<!llvm.array<5 x i32>>
+  %3 = llvm.mlir.zero : !llvm.array<5 x i32>
+  llvm.store %3, %local_array : !llvm.ptr<!llvm.array<5 x i32>>
+  // 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<!llvm.struct<(i32, f64, i8)>>
+  %4 = llvm.mlir.zero : !llvm.struct<(i32, f64, i8)>
+  llvm.store %4, %local_struct : !llvm.ptr<!llvm.struct<(i32, f64, i8)>>
+  // 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<i32> : (i64) -> !llvm.ptr<!llvm.ptr<i32>>
+  %5 = llvm.mlir.zero : !llvm.ptr<i32>
+  llvm.store %5, %local_ptr : !llvm.ptr<!llvm.ptr<i32>>
+  // 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<i32>> : (i64) -> !llvm.ptr<!llvm.vec<42 x ptr<i32>>>
+  %6 = llvm.mlir.zero : !llvm.vec<42 x ptr<i32>>
+  llvm.store %6, %local_vector : !llvm.ptr<!llvm.vec<42 x ptr<i32>>>
+  // 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<!llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)>>
+  %7 = llvm.mlir.zero : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)>
+  llvm.store %7, %local_nested : !llvm.ptr<!llvm.struct<(i32, !llvm.struct<(i32, i32)>, 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<func<i32 (i32)>> : (i64) -> !llvm.ptr<!llvm.ptr<func<i32 (i32)>>>
+  %8 = llvm.mlir.zero : !llvm.ptr<func<i32 (i32)>>
+  llvm.store %8, %local_func_ptr : !llvm.ptr<!llvm.ptr<func<i32 (i32)>>>
+  // 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<i32>>) >> : (i64) -> !llvm.ptr<!llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>>
+  %9 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>
+  llvm.store %9, %local_complex : !llvm.ptr<!llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>>
+  // 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 <vini.couto.e at gmail.com>
Date: Wed, 6 Sep 2023 19:01:08 -0300
Subject: [PATCH 2/2] 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 b9ce6933a9eb524..558ed3058fe7585 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 a795dbf76fab8e3..96b231a5375cb3c 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<i32> {
-  %0 = llvm.mlir.zero : !llvm.ptr<i32>
-  llvm.return %0 : !llvm.ptr<i32>
-}
-// CHECK: @zero_ptr = linkonce global ptr null
-
-llvm.mlir.global linkonce @zero_vector() : !llvm.vec<42 x ptr<i32>> {
-  %0 = llvm.mlir.zero : !llvm.vec<42 x ptr<i32>>
-  llvm.return %0 : !llvm.vec<42 x ptr<i32>>
-}
-// 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<func<i32 (i32)>> {
-  %0 = llvm.mlir.zero : !llvm.ptr<func<i32 (i32)>>
-  llvm.return %0 : !llvm.ptr<func<i32 (i32)>>
-}
-// 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<i32>>) >> {
-  %0 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>
-  llvm.return %0 : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>
+// 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<i32>
-  %1 = llvm.mlir.zero : i32
-  llvm.store %1, %local_integer : !llvm.ptr<i32>
-  // 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<f32>
-  %2 = llvm.mlir.zero : f32
-  llvm.store %2, %local_float : !llvm.ptr<f32>
-  // 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<!llvm.array<5 x i32>>
-  %3 = llvm.mlir.zero : !llvm.array<5 x i32>
-  llvm.store %3, %local_array : !llvm.ptr<!llvm.array<5 x i32>>
-  // 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<!llvm.struct<(i32, f64, i8)>>
-  %4 = llvm.mlir.zero : !llvm.struct<(i32, f64, i8)>
-  llvm.store %4, %local_struct : !llvm.ptr<!llvm.struct<(i32, f64, i8)>>
-  // 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<i32> : (i64) -> !llvm.ptr<!llvm.ptr<i32>>
-  %5 = llvm.mlir.zero : !llvm.ptr<i32>
-  llvm.store %5, %local_ptr : !llvm.ptr<!llvm.ptr<i32>>
-  // 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<i32>> : (i64) -> !llvm.ptr<!llvm.vec<42 x ptr<i32>>>
-  %6 = llvm.mlir.zero : !llvm.vec<42 x ptr<i32>>
-  llvm.store %6, %local_vector : !llvm.ptr<!llvm.vec<42 x ptr<i32>>>
-  // 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<!llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)>>
-  %7 = llvm.mlir.zero : !llvm.struct<(i32, !llvm.struct<(i32, i32)>, f64)>
-  llvm.store %7, %local_nested : !llvm.ptr<!llvm.struct<(i32, !llvm.struct<(i32, i32)>, 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<func<i32 (i32)>> : (i64) -> !llvm.ptr<!llvm.ptr<func<i32 (i32)>>>
-  %8 = llvm.mlir.zero : !llvm.ptr<func<i32 (i32)>>
-  llvm.store %8, %local_func_ptr : !llvm.ptr<!llvm.ptr<func<i32 (i32)>>>
-  // 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<i32>>) >> : (i64) -> !llvm.ptr<!llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>>
-  %9 = llvm.mlir.zero : !llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>
-  llvm.store %9, %local_complex : !llvm.ptr<!llvm.array<5 x !llvm.struct<(i32, !llvm.array<3 x !llvm.ptr<i32>>) >>>
-  // 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
 }



More information about the Mlir-commits mailing list