-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[MLIR][Doc] Remove LLVM dialect typed pointer documentation #71246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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
@llvm/pr-subscribers-mlir-memref @llvm/pr-subscribers-openacc Author: Christian Ulmann (Dinistro) ChangesThis 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:
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]
|
@llvm/pr-subscribers-mlir-llvm Author: Christian Ulmann (Dinistro) ChangesThis 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:
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]
|
@llvm/pr-subscribers-mlir-openacc Author: Christian Ulmann (Dinistro) ChangesThis 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:
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]
|
@llvm/pr-subscribers-mlir-sparse Author: Christian Ulmann (Dinistro) ChangesThis 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:
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]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM % two comments
Thanks for the review 😄 |
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