[Mlir-commits] [mlir] [MLIR][Doc] Remove LLVM dialect typed pointer documentation (PR #71246)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Nov 3 15:40:17 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-llvm
Author: Christian Ulmann (Dinistro)
<details>
<summary>Changes</summary>
This commit removes all references to typed pointers. Typed pointers have been deprecated for a while now and they will be removed in a followup.
Related PSA: https://discourse.llvm.org/t/psa-removal-of-typed-pointers-from-the-llvm-dialect/74502
---
Patch is 38.76 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71246.diff
12 Files Affected:
- (modified) mlir/docs/Dialects/LLVM.md (+17-39)
- (modified) mlir/docs/SPIRVToLLVMDialectConversion.md (+9-9)
- (modified) mlir/docs/TargetLLVMIR.md (+58-75)
- (modified) mlir/include/mlir/Conversion/LLVMCommon/Pattern.h (+3-3)
- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td (+5-5)
- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td (+15-15)
- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td (+2-4)
- (modified) mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td (+4-4)
- (modified) mlir/include/mlir/Dialect/MemRef/IR/MemRefOps.td (+2-2)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+15-15)
- (modified) mlir/include/mlir/Dialect/SparseTensor/Transforms/Passes.td (+2-2)
- (modified) mlir/unittests/Dialect/LLVMIR/LLVMTypeTest.cpp (+2-2)
``````````diff
diff --git a/mlir/docs/Dialects/LLVM.md b/mlir/docs/Dialects/LLVM.md
index 796c3a7b768443b..5bbccda7cf6bd22 100644
--- a/mlir/docs/Dialects/LLVM.md
+++ b/mlir/docs/Dialects/LLVM.md
@@ -210,9 +210,9 @@ style for types with nested angle brackets and keyword specifiers rather than
using different bracket styles to differentiate types. Types inside the angle
brackets may omit the `!llvm.` prefix for brevity: the parser first attempts to
find a type (starting with `!` or a built-in type) and falls back to accepting a
-keyword. For example, `!llvm.ptr<!llvm.ptr<i32>>` and `!llvm.ptr<ptr<i32>>` are
-equivalent, with the latter being the canonical form, and denote a pointer to a
-pointer to a 32-bit integer.
+keyword. For example, `!llvm.struct<(!llvm.ptr, f32)>` and
+`!llvm.struct<(ptr, f32)>` are equivalent, with the latter being the canonical
+form, and denote a struct containing a pointer and a float.
### Built-in Type Compatibility
@@ -232,8 +232,8 @@ compatibility check.
Each LLVM IR type corresponds to *exactly one* MLIR type, either built-in or
LLVM dialect type. For example, because `i32` is LLVM-compatible, there is no
-`!llvm.i32` type. However, `!llvm.ptr<T>` is defined in the LLVM dialect as
-there is no corresponding built-in type.
+`!llvm.i32` type. However, `!llvm.struct<(T, ...)>` is defined in the LLVM
+dialect as there is no corresponding built-in type.
### Additional Simple Types
@@ -263,24 +263,19 @@ the element type, which can be either compatible built-in or LLVM dialect types.
Pointer types specify an address in memory.
-Both opaque and type-parameterized pointer types are supported.
-[Opaque pointers](https://llvm.org/docs/OpaquePointers.html) do not indicate the
-type of the data pointed to, and are intended to simplify LLVM IR by encoding
-behavior relevant to the pointee type into operations rather than into types.
-Non-opaque pointer types carry the pointee type as a type parameter. Both kinds
-of pointers may be additionally parameterized by an address space. The address
-space is an integer, but this choice may be reconsidered if MLIR implements
-named address spaces. The syntax of pointer types is as follows:
+Pointers are [opaque](https://llvm.org/docs/OpaquePointers.html), i.e., do not
+indicate the type of the data pointed to, and are intended to simplify LLVM IR
+by encoding behavior relevant to the pointee type into operations rather than
+into types. Pointers can optionally be parametrized with an address space. The
+address space is an integer, but this choice may be reconsidered if MLIR
+implements named address spaces. The syntax of pointer types is as follows:
```
llvm-ptr-type ::= `!llvm.ptr` (`<` integer-literal `>`)?
- | `!llvm.ptr<` type (`,` integer-literal)? `>`
```
-where the former case is the opaque pointer type and the latter case is the
-non-opaque pointer type; the optional group containing the integer literal
-corresponds to the memory space. All cases are represented by `LLVMPointerType`
-internally.
+where the optional group containing the integer literal corresponds to the
+address space. All cases are represented by `LLVMPointerType` internally.
#### Array Types
@@ -346,7 +341,7 @@ syntax:
Note that the sets of element types supported by built-in and LLVM dialect
vector types are mutually exclusive, e.g., the built-in vector type does not
-accept `!llvm.ptr<i32>` and the LLVM dialect fixed-width vector type does not
+accept `!llvm.ptr` and the LLVM dialect fixed-width vector type does not
accept `i32`.
The following functions are provided to operate on any kind of the vector types
@@ -367,12 +362,11 @@ compatible with the LLVM dialect:
```mlir
vector<42 x i32> // Vector of 42 32-bit integers.
-!llvm.vec<42 x ptr<i32>> // Vector of 42 pointers to 32-bit integers.
+!llvm.vec<42 x ptr> // Vector of 42 pointers.
!llvm.vec<? x 4 x i32> // Scalable vector of 32-bit integers with
// size divisible by 4.
!llvm.array<2 x vector<2 x i32>> // Array of 2 vectors of 2 32-bit integers.
-!llvm.array<2 x vec<2 x ptr<i32>>> // Array of 2 vectors of 2 pointers to 32-bit
- // integers.
+!llvm.array<2 x vec<2 x ptr>> // Array of 2 vectors of 2 pointers.
```
### Structure Types
@@ -421,21 +415,6 @@ type-or-ref ::= <any compatible type with optional !llvm.>
| `!llvm.`? `struct<` string-literal `>`
```
-The body of the identified struct is printed in full unless the it is
-transitively contained in the same struct. In the latter case, only the
-identifier is printed. For example, the structure containing the pointer to
-itself is represented as `!llvm.struct<"A", (ptr<"A">)>`, and the structure `A`
-containing two pointers to the structure `B` containing a pointer to the
-structure `A` is represented as `!llvm.struct<"A", (ptr<"B", (ptr<"A">)>,
-ptr<"B", (ptr<"A">))>`. Note that the structure `B` is "unrolled" for both
-elements. _A structure with the same name but different body is a syntax error._
-**The user must ensure structure name uniqueness across all modules processed in
-a given MLIR context.** Structure names are arbitrary string literals and may
-include, e.g., spaces and keywords.
-
-Identified structs may be _opaque_. In this case, the body is unknown but the
-structure type is considered _initialized_ and is valid in the IR.
-
#### Literal Structure Types
Literal structures are uniqued according to the list of elements they contain,
@@ -460,11 +439,10 @@ elements provided.
!llvm.struct<packed (i8, i32)> // packed struct
!llvm.struct<"a"> // recursive reference, only allowed within
// another struct, NOT allowed at top level
-!llvm.struct<"a", ptr<struct<"a">>> // supported example of recursive reference
!llvm.struct<"a", ()> // empty, named (necessary to differentiate from
// recursive reference)
!llvm.struct<"a", opaque> // opaque, named
-!llvm.struct<"a", (i32)> // named
+!llvm.struct<"a", (i32, ptr)> // named
!llvm.struct<"a", packed (i8, i32)> // named, packed
```
diff --git a/mlir/docs/SPIRVToLLVMDialectConversion.md b/mlir/docs/SPIRVToLLVMDialectConversion.md
index 7a3bc7c62bd9a2c..0aae02cff26be1b 100644
--- a/mlir/docs/SPIRVToLLVMDialectConversion.md
+++ b/mlir/docs/SPIRVToLLVMDialectConversion.md
@@ -45,7 +45,7 @@ A SPIR-V pointer also takes a Storage Class. At the moment, conversion does
SPIR-V Dialect | LLVM Dialect
:-------------------------------------------: | :-------------------------:
-`!spirv.ptr< <element-type>, <storage-class> >` | `!llvm.ptr<<element-type>>`
+`!spirv.ptr< <element-type>, <storage-class> >` | `!llvm.ptr`
### Array types
@@ -443,7 +443,7 @@ order to go through the pointer.
%i = ...
%var = ...
%0 = llvm.mlir.constant(0 : i32) : i32
-%el = llvm.getelementptr %var[%0, %i, %i] : (!llvm.ptr<struct<packed (f32, array<4 x f32>)>>, i32, i32, i32)
+%el = llvm.getelementptr %var[%0, %i, %i] : (!llvm.ptr, i32, i32, i32), !llvm.struct<packed (f32, array<4 x f32>)>
```
#### `spirv.Load` and `spirv.Store`
@@ -453,16 +453,16 @@ These ops are converted to their LLVM counterparts: `llvm.load` and
following cases, based on the value of the attribute:
* **Aligned**: alignment is passed on to LLVM op builder, for example: `mlir
- // llvm.store %ptr, %val {alignment = 4 : i64} : !llvm.ptr<f32> spirv.Store
+ // llvm.store %ptr, %val {alignment = 4 : i64} : !llvm.ptr spirv.Store
"Function" %ptr, %val ["Aligned", 4] : f32`
* **None**: same case as if there is no memory access attribute.
* **Nontemporal**: set `nontemporal` flag, for example: `mlir // %res =
- llvm.load %ptr {nontemporal} : !llvm.ptr<f32> %res = spirv.Load "Function"
+ llvm.load %ptr {nontemporal} : !llvm.ptr %res = spirv.Load "Function"
%ptr ["Nontemporal"] : f32`
* **Volatile**: mark the op as `volatile`, for example: `mlir // %res =
- llvm.load volatile %ptr : !llvm.ptr<f32> %res = spirv.Load "Function" %ptr
+ llvm.load volatile %ptr : !llvm.ptr f32> %res = spirv.Load "Function" %ptr
["Volatile"] : f32` Otherwise the conversion fails as other cases
(`MakePointerAvailable`, `MakePointerVisible`, `NonPrivatePointer`) are not
supported yet.
@@ -491,7 +491,7 @@ spirv.module Logical GLSL450 {
module {
llvm.mlir.global private @struct() : !llvm.struct<packed (f32, [10 x f32])>
llvm.func @func() {
- %0 = llvm.mlir.addressof @struct : !llvm.ptr<struct<packed (f32, [10 x f32])>>
+ %0 = llvm.mlir.addressof @struct : !llvm.ptr
llvm.return
}
}
@@ -535,13 +535,13 @@ Also, at the moment initialization is only possible via `spirv.Constant`.
```mlir
// Conversion of VariableOp without initialization
%size = llvm.mlir.constant(1 : i32) : i32
-%res = spirv.Variable : !spirv.ptr<vector<3xf32>, Function> => %res = llvm.alloca %size x vector<3xf32> : (i32) -> !llvm.ptr<vec<3 x f32>>
+%res = spirv.Variable : !spirv.ptr<vector<3xf32>, Function> => %res = llvm.alloca %size x vector<3xf32> : (i32) -> !llvm.ptr
// Conversion of VariableOp with initialization
%c = llvm.mlir.constant(0 : i64) : i64
%c = spirv.Constant 0 : i64 %size = llvm.mlir.constant(1 : i32) : i32
-%res = spirv.Variable init(%c) : !spirv.ptr<i64, Function> => %res = llvm.alloca %[[SIZE]] x i64 : (i32) -> !llvm.ptr<i64>
- llvm.store %c, %res : !llvm.ptr<i64>
+%res = spirv.Variable init(%c) : !spirv.ptr<i64, Function> => %res = llvm.alloca %[[SIZE]] x i64 : (i32) -> !llvm.ptr
+ llvm.store %c, %res : i64, !llvm.ptr
```
Note that simple conversion to `alloca` may not be sufficient if the code has
diff --git a/mlir/docs/TargetLLVMIR.md b/mlir/docs/TargetLLVMIR.md
index 4553accc5b9ae2b..73a74c394f2af79 100644
--- a/mlir/docs/TargetLLVMIR.md
+++ b/mlir/docs/TargetLLVMIR.md
@@ -135,20 +135,19 @@ Examples:
```mlir
// Assuming index is converted to i64.
-memref<f32> -> !llvm.struct<(ptr<f32> , ptr<f32>, i64)>
-memref<1 x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64,
+memref<f32> -> !llvm.struct<(ptr , ptr, i64)>
+memref<1 x f32> -> !llvm.struct<(ptr, ptr, i64,
array<1 x i64>, array<1 x i64>)>
-memref<? x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64
+memref<? x f32> -> !llvm.struct<(ptr, ptr, i64
array<1 x i64>, array<1 x i64>)>
-memref<10x42x42x43x123 x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64
+memref<10x42x42x43x123 x f32> -> !llvm.struct<(ptr, ptr, i64
array<5 x i64>, array<5 x i64>)>
-memref<10x?x42x?x123 x f32> -> !llvm.struct<(ptr<f32>, ptr<f32>, i64
+memref<10x?x42x?x123 x f32> -> !llvm.struct<(ptr, ptr, i64
array<5 x i64>, array<5 x i64>)>
// Memref types can have vectors as element types
-memref<1x? x vector<4xf32>> -> !llvm.struct<(ptr<vector<4 x f32>>,
- ptr<vector<4 x f32>>, i64,
- array<2 x i64>, array<2 x i64>)>
+memref<1x? x vector<4xf32>> -> !llvm.struct<(ptr, ptr, i64, array<2 x i64>,
+ array<2 x i64>)>
```
#### Unranked MemRef Types
@@ -159,7 +158,7 @@ as *unranked descriptor*. It contains:
1. a converted `index`-typed integer representing the dynamic rank of the
memref;
-2. a type-erased pointer (`!llvm.ptr<i8>`) to a ranked memref descriptor with
+2. a type-erased pointer (`!llvm.ptr`) to a ranked memref descriptor with
the contents listed above.
This descriptor is primarily intended for interfacing with rank-polymorphic
@@ -219,49 +218,42 @@ Examples:
// Function-typed arguments or results in higher-order functions:
(() -> ()) -> (() -> ())
-// are converted into pointers to functions.
-!llvm.func<ptr<func<void ()>> (ptr<func<void ()>>)>
-
-// These rules apply recursively: a function type taking a function that takes
-// another function
-( ( (i32) -> (i64) ) -> () ) -> ()
-// is converted into a function type taking a pointer-to-function that takes
-// another point-to-function.
-!llvm.func<void (ptr<func<void (ptr<func<i64 (i32)>>)>>)>
+// are converted into opaque pointers.
+!llvm.func<ptr (ptr)>
// A memref descriptor appearing as function argument:
(memref<f32>) -> ()
// gets converted into a list of individual scalar components of a descriptor.
-!llvm.func<void (ptr<f32>, ptr<f32>, i64)>
+!llvm.func<void (ptr, ptr, i64)>
// The list of arguments is linearized and one can freely mix memref and other
// types in this list:
(memref<f32>, f32) -> ()
// which gets converted into a flat list.
-!llvm.func<void (ptr<f32>, ptr<f32>, i64, f32)>
+!llvm.func<void (ptr, ptr, i64, f32)>
// For nD ranked memref descriptors:
(memref<?x?xf32>) -> ()
// the converted signature will contain 2n+1 `index`-typed integer arguments,
// offset, n sizes and n strides, per memref argument type.
-!llvm.func<void (ptr<f32>, ptr<f32>, i64, i64, i64, i64, i64)>
+!llvm.func<void (ptr, ptr, i64, i64, i64, i64, i64)>
// Same rules apply to unranked descriptors:
(memref<*xf32>) -> ()
// which get converted into their components.
-!llvm.func<void (i64, ptr<i8>)>
+!llvm.func<void (i64, ptr)>
// However, returning a memref from a function is not affected:
() -> (memref<?xf32>)
// gets converted to a function returning a descriptor structure.
-!llvm.func<struct<(ptr<f32>, ptr<f32>, i64, array<1xi64>, array<1xi64>)> ()>
+!llvm.func<struct<(ptr, ptr, i64, array<1xi64>, array<1xi64>)> ()>
// If multiple memref-typed results are returned:
() -> (memref<f32>, memref<f64>)
// their descriptor structures are additionally packed into another structure,
// potentially with other non-memref typed results.
-!llvm.func<struct<(struct<(ptr<f32>, ptr<f32>, i64)>,
- struct<(ptr<double>, ptr<double>, i64)>)> ()>
+!llvm.func<struct<(struct<(ptr, ptr, i64)>,
+ struct<(ptr, ptr, i64)>)> ()>
// If "func.varargs" attribute is set:
(i32) -> () attributes { "func.varargs" = true }
@@ -290,8 +282,7 @@ vector<4x8 x f32>
memref<2 x vector<4x8 x f32>
// ->
-!llvm.struct<(ptr<array<4 x vector<8xf32>>>, ptr<array<4 x vector<8xf32>>>
- i64, array<1 x i64>, array<1 x i64>)>
+!llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
```
#### Tensor Types
@@ -382,10 +373,10 @@ func.func @foo(%arg0: memref<?xf32>) -> () {
// Gets converted to the following
// (using type alias for brevity):
-!llvm.memref_1d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1xi64>, array<1xi64>)>
+!llvm.memref_1d = !llvm.struct<(ptr, ptr, i64, array<1xi64>, array<1xi64>)>
-llvm.func @foo(%arg0: !llvm.ptr<f32>, // Allocated pointer.
- %arg1: !llvm.ptr<f32>, // Aligned pointer.
+llvm.func @foo(%arg0: !llvm.ptr, // Allocated pointer.
+ %arg1: !llvm.ptr, // Aligned pointer.
%arg2: i64, // Offset.
%arg3: i64, // Size in dim 0.
%arg4: i64) { // Stride in dim 0.
@@ -412,7 +403,7 @@ func.func @bar() {
// Gets converted to the following
// (using type alias for brevity):
-!llvm.memref_1d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<1xi64>, array<1xi64>)>
+!llvm.memref_1d = !llvm.struct<(ptr, ptr, i64, array<1xi64>, array<1xi64>)>
llvm.func @bar() {
%0 = "get"() : () -> !llvm.memref_1d
@@ -434,7 +425,7 @@ llvm.func @bar() {
For unranked memrefs, the list of function arguments always contains two
elements, same as the unranked memref descriptor: an integer rank, and a
-type-erased (`!llvm<"i8*">`) pointer to the ranked memref descriptor. Note that
+type-erased (`!llvm.ptr`) pointer to the ranked memref descriptor. Note that
while the *calling convention* does not require allocation, *casting* to
unranked memref does since one cannot take an address of an SSA value containing
the ranked memref, which must be stored in some memory instead. The caller is in
@@ -452,13 +443,13 @@ llvm.func @foo(%arg0: memref<*xf32>) -> () {
// Gets converted to the following.
llvm.func @foo(%arg0: i64 // Rank.
- %arg1: !llvm.ptr<i8>) { // Type-erased pointer to descriptor.
+ %arg1: !llvm.ptr) { // Type-erased pointer to descriptor.
// Pack the unranked memref descriptor.
- %0 = llvm.mlir.undef : !llvm.struct<(i64, ptr<i8>)>
- %1 = llvm.insertvalue %arg0, %0[0] : !llvm.struct<(i64, ptr<i8>)>
- %2 = llvm.insertvalue %arg1, %1[1] : !llvm.struct<(i64, ptr<i8>)>
+ %0 = llvm.mlir.undef : !llvm.struct<(i64, ptr)>
+ %1 = llvm.insertvalue %arg0, %0[0] : !llvm.struct<(i64, ptr)>
+ %2 = llvm.insertvalue %arg1, %1[1] : !llvm.struct<(i64, ptr)>
- "use"(%2) : (!llvm.struct<(i64, ptr<i8>)>) -> ()
+ "use"(%2) : (!llvm.struct<(i64, ptr)>) -> ()
llvm.return
}
```
@@ -473,14 +464,14 @@ llvm.func @bar() {
// Gets converted to the following.
llvm.func @bar() {
- %0 = "get"() : () -> (!llvm.struct<(i64, ptr<i8>)>)
+ %0 = "get"() : () -> (!llvm.struct<(i64, ptr)>)
// Unpack the memref descriptor.
- %1 = llvm.extractvalue %0[0] : !llvm.struct<(i64, ptr<i8>)>
- %2 = llvm.extractvalue %0[1] : !llvm.struct<(i64, ptr<i8>)>
+ %1 = llvm.extractvalue %0[0] : !llvm.struct<(i64, ptr)>
+ %2 = llvm.extractvalue %0[1] : !llvm.struct<(i64, ptr)>
// Pass individual values to the callee.
- llvm.call @foo(%1, %2) : (i64, !llvm.ptr<i8>)
+ llvm.call @foo(%1, %2) : (i64, !llvm.ptr)
llvm.return
}
```
@@ -524,12 +515,12 @@ func.func @caller(%0 : memref<2x4xf32>) {
// ->
-!descriptor = !llvm.struct<(ptr<f32>, ptr<f32>, i64,
+!descriptor = !llvm.struct<(ptr, ptr, i64,
array<2xi64>, array<2xi64>)>
-llvm.func @callee(!llvm.ptr<f32>)
+llvm.func @callee(!llvm.ptr)
-llvm.func @caller(%arg0: !llvm.ptr<f32>) {
+llvm.func @caller(%arg0: !llvm.ptr) {
// A descriptor value is defined at the function entry point.
%0 = llvm.mlir.undef : !descriptor
@@ -552,7 +543,7 @@ llvm.func @caller(%arg0: !llvm.ptr<f32>) {
// The function call corresponds to extracting the aligned data pointer.
%12 = llvm.extractelement %11[1] : !descriptor
- llvm.call @callee(%12) : (!llvm.ptr<f32>) -> ()
+ llvm.call @callee(%12) : (!llvm.ptr) -> ()
}
```
@@ -644,10 +635,10 @@ func.func @qux(%arg0: memref<?x?xf32>)
// Gets converted into the following
// (using type alias for brevity):
-!llvm.memref_2d = !llvm.struct<(ptr<f32>, ptr<f32>, i64, array<2xi64>, array<2xi64>)>
+!llvm.memref_2d = !llvm.struct<(ptr, ptr, i64, array<2xi64>, array<2xi64>)>
// Function with unpacked arguments.
-llvm.func @qux(%arg0: !llvm.ptr<f32>, %arg1: !llvm.ptr<f32>,
+llvm.func @qux(%arg0: !llvm.ptr, %arg1: !llvm.ptr,
%arg2: i64, %arg3: i64, %arg4: i64,
%arg5: i64, %arg6: i64) {
// Populate memref descriptor (as per calling convention).
@@ -663,23 +654,18 @@ llvm.func @qux(%arg0: !llvm.ptr<f32>, %arg1: !llvm.ptr<f32>,
// Store the descriptor in a stack-allocated space.
%8 = llvm.mlir.constant(1 : index) : i64
%9 = llvm.alloca %8 x !llvm.memref_2d
- : (i64) -> !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64,
- array<2xi64>, array<2xi64>)>>
- llvm.store %7, %9 : !llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64,
- array<2xi64>, array<2xi64>)>>
+ : (i64) -> !llvm.ptr
+ llvm.store %7, %9 : !llvm.memref_2d, !llvm.ptr
// Call the interface function.
- llvm.call @_mlir_ciface_qux(%9)
- : (!llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64,
- array<2xi64>, array<2xi64>)>>) -> ()
+ llvm.call @_mlir_ciface_qux(%9) : (!llvm.ptr) -> ()
// The stored descriptor will be freed on return.
llvm.return
}
// Interface function.
-llvm.func @_mlir_ciface_qux(!llvm.ptr<struct<(ptr<f32>, ptr<f32>, i64,
- array<2xi64>, array<2xi64>)>>)
+llvm.func @_...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/71246
More information about the Mlir-commits
mailing list