Skip to content

Commit adda597

Browse files
authored
[MLIR] Add index bitwidth to the DataLayout (llvm#85927)
When importing from LLVM IR the data layout of all pointer types contains an index bitwidth that should be used for index computations. This revision adds a getter to the DataLayout that provides access to the already stored bitwidth. The function returns an optional since only pointer-like types have an index bitwidth. Querying the bitwidth of a non-pointer type returns std::nullopt. The new function works for the built-in Index type and, using a type interface, for the LLVMPointerType.
1 parent 8fb2160 commit adda597

File tree

16 files changed

+193
-38
lines changed

16 files changed

+193
-38
lines changed

mlir/docs/DataLayout.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public:
7777
llvm::TypeSize getTypeSizeInBits(Type type) const;
7878
uint64_t getTypeABIAlignment(Type type) const;
7979
uint64_t getTypePreferredAlignment(Type type) const;
80+
std::optional<uint64_t> getTypeIndexBitwidth(Type type) const;
8081
};
8182
```
8283
@@ -267,7 +268,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
267268
>} {}
268269
```
269270

270-
specifies that `index` has 32 bits. All other layout properties of `index` match
271+
specifies that `index` has 32 bits and index computations should be performed
272+
using 32-bit precision as well. All other layout properties of `index` match
271273
those of the integer type with the same bitwidth defined above.
272274

273275
In absence of the corresponding entry, `index` is assumed to be a 64-bit

mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ def LLVMFunctionType : LLVMType<"LLVMFunction", "func"> {
123123

124124
def LLVMPointerType : LLVMType<"LLVMPointer", "ptr", [
125125
DeclareTypeInterfaceMethods<DataLayoutTypeInterface, [
126-
"areCompatible", "verifyEntries"]>]> {
126+
"getIndexBitwidth", "areCompatible", "verifyEntries"]>]> {
127127
let summary = "LLVM pointer type";
128128
let description = [{
129129
The `!llvm.ptr` type is an LLVM pointer type. This type typically represents

mlir/include/mlir/Interfaces/DataLayoutInterfaces.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,13 @@ uint64_t
5757
getDefaultPreferredAlignment(Type type, const DataLayout &dataLayout,
5858
ArrayRef<DataLayoutEntryInterface> params);
5959

60+
/// Default handler for the index bitwidth request. Computes the result for
61+
/// the built-in index type and dispatches to the DataLayoutTypeInterface for
62+
/// other types.
63+
std::optional<uint64_t>
64+
getDefaultIndexBitwidth(Type type, const DataLayout &dataLayout,
65+
ArrayRef<DataLayoutEntryInterface> params);
66+
6067
/// Default handler for alloca memory space request. Dispatches to the
6168
/// DataLayoutInterface if specified, otherwise returns the default.
6269
Attribute getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry);
@@ -180,6 +187,11 @@ class DataLayout {
180187
/// Returns the preferred of the given type in the current scope.
181188
uint64_t getTypePreferredAlignment(Type t) const;
182189

190+
/// Returns the bitwidth that should be used when performing index
191+
/// computations for the given pointer-like type in the current scope. If the
192+
/// type is not a pointer-like type, it returns std::nullopt.
193+
std::optional<uint64_t> getTypeIndexBitwidth(Type t) const;
194+
183195
/// Returns the memory space used for AllocaOps.
184196
Attribute getAllocaMemorySpace() const;
185197

@@ -216,6 +228,7 @@ class DataLayout {
216228
mutable DenseMap<Type, llvm::TypeSize> bitsizes;
217229
mutable DenseMap<Type, uint64_t> abiAlignments;
218230
mutable DenseMap<Type, uint64_t> preferredAlignments;
231+
mutable DenseMap<Type, std::optional<uint64_t>> indexBitwidths;
219232

220233
/// Cache for alloca, global, and program memory spaces.
221234
mutable std::optional<Attribute> allocaMemorySpace;

mlir/include/mlir/Interfaces/DataLayoutInterfaces.td

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,22 @@ def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
280280
params);
281281
}]
282282
>,
283+
StaticInterfaceMethod<
284+
/*description=*/"Returns the bitwidth that should be used when "
285+
"performing index computations for the type computed "
286+
"using the relevant entries. The data layout object can "
287+
"be used for recursive queries.",
288+
/*retTy=*/"std::optional<uint64_t>",
289+
/*methodName=*/"getIndexBitwidth",
290+
/*args=*/(ins "::mlir::Type":$type,
291+
"const ::mlir::DataLayout &":$dataLayout,
292+
"::mlir::DataLayoutEntryListRef":$params),
293+
/*methodBody=*/"",
294+
/*defaultImplementation=*/[{
295+
return ::mlir::detail::getDefaultIndexBitwidth(type, dataLayout,
296+
params);
297+
}]
298+
>,
283299
StaticInterfaceMethod<
284300
/*description=*/"Returns the memory space used by the ABI computed "
285301
"using the relevant entries. The data layout object "
@@ -400,6 +416,18 @@ def DataLayoutTypeInterface : TypeInterface<"DataLayoutTypeInterface"> {
400416
/*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
401417
"::mlir::DataLayoutEntryListRef":$params)
402418
>,
419+
InterfaceMethod<
420+
/*description=*/"Returns the bitwidth that should be used when "
421+
"performing index computations for the given "
422+
"pointer-like type. If the type is not a pointer-like "
423+
"type, returns std::nullopt.",
424+
/*retTy=*/"std::optional<uint64_t>",
425+
/*methodName=*/"getIndexBitwidth",
426+
/*args=*/(ins "const ::mlir::DataLayout &":$dataLayout,
427+
"::mlir::DataLayoutEntryListRef":$params),
428+
/*methodBody=*/"",
429+
/*defaultImplementation=*/[{ return std::nullopt; }]
430+
>,
403431
InterfaceMethod<
404432
/*desc=*/"Returns true if the two lists of entries are compatible, that "
405433
"is, that `newLayout` spec entries can be nested in an op with "

mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -287,15 +287,22 @@ getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type,
287287
}
288288
}
289289
if (currentEntry) {
290-
return *extractPointerSpecValue(currentEntry, pos) /
291-
(pos == PtrDLEntryPos::Size ? 1 : kBitsInByte);
290+
std::optional<uint64_t> value = extractPointerSpecValue(currentEntry, pos);
291+
// If the optional `PtrDLEntryPos::Index` entry is not available, use the
292+
// pointer size as the index bitwidth.
293+
if (!value && pos == PtrDLEntryPos::Index)
294+
value = extractPointerSpecValue(currentEntry, PtrDLEntryPos::Size);
295+
bool isSizeOrIndex =
296+
pos == PtrDLEntryPos::Size || pos == PtrDLEntryPos::Index;
297+
return *value / (isSizeOrIndex ? 1 : kBitsInByte);
292298
}
293299

294300
// If not found, and this is the pointer to the default memory space, assume
295301
// 64-bit pointers.
296302
if (type.getAddressSpace() == 0) {
297-
return pos == PtrDLEntryPos::Size ? kDefaultPointerSizeBits
298-
: kDefaultPointerAlignment;
303+
bool isSizeOrIndex =
304+
pos == PtrDLEntryPos::Size || pos == PtrDLEntryPos::Index;
305+
return isSizeOrIndex ? kDefaultPointerSizeBits : kDefaultPointerAlignment;
299306
}
300307

301308
return std::nullopt;
@@ -332,6 +339,16 @@ LLVMPointerType::getPreferredAlignment(const DataLayout &dataLayout,
332339
return dataLayout.getTypePreferredAlignment(get(getContext()));
333340
}
334341

342+
std::optional<uint64_t>
343+
LLVMPointerType::getIndexBitwidth(const DataLayout &dataLayout,
344+
DataLayoutEntryListRef params) const {
345+
if (std::optional<uint64_t> indexBitwidth =
346+
getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Index))
347+
return *indexBitwidth;
348+
349+
return dataLayout.getTypeIndexBitwidth(get(getContext()));
350+
}
351+
335352
bool LLVMPointerType::areCompatible(DataLayoutEntryListRef oldLayout,
336353
DataLayoutEntryListRef newLayout) const {
337354
for (DataLayoutEntryInterface newEntry : newLayout) {

mlir/lib/Interfaces/DataLayoutInterfaces.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,23 @@ uint64_t mlir::detail::getDefaultPreferredAlignment(
218218
reportMissingDataLayout(type);
219219
}
220220

221-
// Returns the memory space used for allocal operations if specified in the
221+
std::optional<uint64_t> mlir::detail::getDefaultIndexBitwidth(
222+
Type type, const DataLayout &dataLayout,
223+
ArrayRef<DataLayoutEntryInterface> params) {
224+
if (isa<IndexType>(type))
225+
return getIndexBitwidth(params);
226+
227+
if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
228+
if (std::optional<uint64_t> indexBitwidth =
229+
typeInterface.getIndexBitwidth(dataLayout, params))
230+
return *indexBitwidth;
231+
232+
// Return std::nullopt for all other types, which are assumed to be non
233+
// pointer-like types.
234+
return std::nullopt;
235+
}
236+
237+
// Returns the memory space used for alloca operations if specified in the
222238
// given entry. If the entry is empty the default memory space represented by
223239
// an empty attribute is returned.
224240
Attribute
@@ -520,6 +536,18 @@ uint64_t mlir::DataLayout::getTypePreferredAlignment(Type t) const {
520536
});
521537
}
522538

539+
std::optional<uint64_t> mlir::DataLayout::getTypeIndexBitwidth(Type t) const {
540+
checkValid();
541+
return cachedLookup<std::optional<uint64_t>>(t, indexBitwidths, [&](Type ty) {
542+
DataLayoutEntryList list;
543+
if (originalLayout)
544+
list = originalLayout.getSpecForType(ty.getTypeID());
545+
if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
546+
return iface.getIndexBitwidth(ty, *this, list);
547+
return detail::getDefaultIndexBitwidth(ty, *this, list);
548+
});
549+
}
550+
523551
mlir::Attribute mlir::DataLayout::getAllocaMemorySpace() const {
524552
checkValid();
525553
if (allocaMemorySpace)

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,15 @@ translateDataLayout(DataLayoutSpecInterface attribute,
274274
layoutStream << ":" << preferred;
275275
return success();
276276
})
277-
.Case([&](LLVMPointerType ptrType) {
278-
layoutStream << "p" << ptrType.getAddressSpace() << ":";
277+
.Case([&](LLVMPointerType type) {
278+
layoutStream << "p" << type.getAddressSpace() << ":";
279279
uint64_t size = dataLayout.getTypeSizeInBits(type);
280280
uint64_t abi = dataLayout.getTypeABIAlignment(type) * 8u;
281281
uint64_t preferred =
282282
dataLayout.getTypePreferredAlignment(type) * 8u;
283-
layoutStream << size << ":" << abi << ":" << preferred;
284-
if (std::optional<uint64_t> index = extractPointerSpecValue(
285-
entry.getValue(), PtrDLEntryPos::Index))
286-
layoutStream << ":" << *index;
283+
uint64_t index = *dataLayout.getTypeIndexBitwidth(type);
284+
layoutStream << size << ":" << abi << ":" << preferred << ":"
285+
<< index;
287286
return success();
288287
})
289288
.Default([loc](Type type) {

mlir/test/Dialect/LLVMIR/layout.mlir

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module {
77
// CHECK: alloca_memory_space = 0
88
// CHECK: bitsize = 64
99
// CHECK: global_memory_space = 0
10+
// CHECK: index = 64
1011
// CHECK: preferred = 8
1112
// CHECK: program_memory_space = 0
1213
// CHECK: size = 8
@@ -16,6 +17,7 @@ module {
1617
// CHECK: alloca_memory_space = 0
1718
// CHECK: bitsize = 64
1819
// CHECK: global_memory_space = 0
20+
// CHECK: index = 64
1921
// CHECK: preferred = 8
2022
// CHECK: program_memory_space = 0
2123
// CHECK: size = 8
@@ -25,6 +27,7 @@ module {
2527
// CHECK: alloca_memory_space = 0
2628
// CHECK: bitsize = 64
2729
// CHECK: global_memory_space = 0
30+
// CHECK: index = 64
2831
// CHECK: preferred = 8
2932
// CHECK: program_memory_space = 0
3033
// CHECK: size = 8
@@ -39,7 +42,7 @@ module {
3942
module attributes { dlti.dl_spec = #dlti.dl_spec<
4043
#dlti.dl_entry<!llvm.ptr, dense<[32, 32, 64]> : vector<3xi64>>,
4144
#dlti.dl_entry<!llvm.ptr<5>, dense<[64, 64, 64]> : vector<3xi64>>,
42-
#dlti.dl_entry<!llvm.ptr<4>, dense<[32, 64, 64]> : vector<3xi64>>,
45+
#dlti.dl_entry<!llvm.ptr<4>, dense<[32, 64, 64, 24]> : vector<4xi64>>,
4346
#dlti.dl_entry<"dlti.alloca_memory_space", 5 : ui64>,
4447
#dlti.dl_entry<"dlti.global_memory_space", 2 : ui64>,
4548
#dlti.dl_entry<"dlti.program_memory_space", 3 : ui64>,
@@ -51,6 +54,7 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
5154
// CHECK: alloca_memory_space = 5
5255
// CHECK: bitsize = 32
5356
// CHECK: global_memory_space = 2
57+
// CHECK: index = 32
5458
// CHECK: preferred = 8
5559
// CHECK: program_memory_space = 3
5660
// CHECK: size = 4
@@ -60,6 +64,7 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
6064
// CHECK: alloca_memory_space = 5
6165
// CHECK: bitsize = 32
6266
// CHECK: global_memory_space = 2
67+
// CHECK: index = 32
6368
// CHECK: preferred = 8
6469
// CHECK: program_memory_space = 3
6570
// CHECK: size = 4
@@ -69,24 +74,17 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
6974
// CHECK: alloca_memory_space = 5
7075
// CHECK: bitsize = 64
7176
// CHECK: global_memory_space = 2
77+
// CHECK: index = 64
7278
// CHECK: preferred = 8
7379
// CHECK: program_memory_space = 3
7480
// CHECK: size = 8
7581
// CHECK: stack_alignment = 128
7682
"test.data_layout_query"() : () -> !llvm.ptr<5>
77-
// CHECK: alignment = 4
78-
// CHECK: alloca_memory_space = 5
79-
// CHECK: bitsize = 32
80-
// CHECK: global_memory_space = 2
81-
// CHECK: preferred = 8
82-
// CHECK: program_memory_space = 3
83-
// CHECK: size = 4
84-
// CHECK: stack_alignment = 128
85-
"test.data_layout_query"() : () -> !llvm.ptr<3>
8683
// CHECK: alignment = 8
8784
// CHECK: alloca_memory_space = 5
8885
// CHECK: bitsize = 32
8986
// CHECK: global_memory_space = 2
87+
// CHECK: index = 24
9088
// CHECK: preferred = 8
9189
// CHECK: program_memory_space = 3
9290
// CHECK: size = 4
@@ -134,34 +132,39 @@ module {
134132
// simple case
135133
// CHECK: alignment = 4
136134
// CHECK: bitsize = 32
135+
// CHECK: index = 0
137136
// CHECK: preferred = 4
138137
// CHECK: size = 4
139138
"test.data_layout_query"() : () -> !llvm.struct<(i32)>
140139

141140
// padding inbetween
142141
// CHECK: alignment = 8
143142
// CHECK: bitsize = 128
143+
// CHECK: index = 0
144144
// CHECK: preferred = 8
145145
// CHECK: size = 16
146146
"test.data_layout_query"() : () -> !llvm.struct<(i32, f64)>
147147

148148
// padding at end of struct
149149
// CHECK: alignment = 8
150150
// CHECK: bitsize = 128
151+
// CHECK: index = 0
151152
// CHECK: preferred = 8
152153
// CHECK: size = 16
153154
"test.data_layout_query"() : () -> !llvm.struct<(f64, i32)>
154155

155156
// packed
156157
// CHECK: alignment = 1
157158
// CHECK: bitsize = 96
159+
// CHECK: index = 0
158160
// CHECK: preferred = 8
159161
// CHECK: size = 12
160162
"test.data_layout_query"() : () -> !llvm.struct<packed (f64, i32)>
161163

162164
// empty
163165
// CHECK: alignment = 1
164166
// CHECK: bitsize = 0
167+
// CHECK: index = 0
165168
// CHECK: preferred = 1
166169
// CHECK: size = 0
167170
"test.data_layout_query"() : () -> !llvm.struct<()>
@@ -179,27 +182,31 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
179182
// Strict alignment is applied
180183
// CHECK: alignment = 4
181184
// CHECK: bitsize = 16
185+
// CHECK: index = 0
182186
// CHECK: preferred = 4
183187
// CHECK: size = 2
184188
"test.data_layout_query"() : () -> !llvm.struct<(i16)>
185189

186190
// No impact on structs that have stricter requirements
187191
// CHECK: alignment = 8
188192
// CHECK: bitsize = 128
193+
// CHECK: index = 0
189194
// CHECK: preferred = 8
190195
// CHECK: size = 16
191196
"test.data_layout_query"() : () -> !llvm.struct<(i32, f64)>
192197

193198
// Only the preferred alignment of structs is affected
194199
// CHECK: alignment = 1
195200
// CHECK: bitsize = 32
201+
// CHECK: index = 0
196202
// CHECK: preferred = 4
197203
// CHECK: size = 4
198204
"test.data_layout_query"() : () -> !llvm.struct<packed (i16, i16)>
199205

200206
// empty
201207
// CHECK: alignment = 4
202208
// CHECK: bitsize = 0
209+
// CHECK: index = 0
203210
// CHECK: preferred = 4
204211
// CHECK: size = 0
205212
"test.data_layout_query"() : () -> !llvm.struct<()>
@@ -265,20 +272,23 @@ module {
265272
// simple case
266273
// CHECK: alignment = 4
267274
// CHECK: bitsize = 64
275+
// CHECK: index = 0
268276
// CHECK: preferred = 4
269277
// CHECK: size = 8
270278
"test.data_layout_query"() : () -> !llvm.array<2 x i32>
271279

272280
// size 0
273281
// CHECK: alignment = 8
274282
// CHECK: bitsize = 0
283+
// CHECK: index = 0
275284
// CHECK: preferred = 8
276285
// CHECK: size = 0
277286
"test.data_layout_query"() : () -> !llvm.array<0 x f64>
278287

279288
// alignment info matches element type
280289
// CHECK: alignment = 4
281290
// CHECK: bitsize = 64
291+
// CHECK: index = 0
282292
// CHECK: preferred = 8
283293
// CHECK: size = 8
284294
"test.data_layout_query"() : () -> !llvm.array<1 x i64>

mlir/test/Interfaces/DataLayoutInterfaces/module.mlir

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
module attributes { dlti.dl_spec = #dlti.dl_spec<
44
#dlti.dl_entry<!test.test_type_with_layout<10>, ["size", 12]>,
5-
#dlti.dl_entry<!test.test_type_with_layout<20>, ["alignment", 32]>>} {
5+
#dlti.dl_entry<!test.test_type_with_layout<20>, ["alignment", 32]>,
6+
#dlti.dl_entry<!test.test_type_with_layout<30>, ["index", 7]>>} {
67
// CHECK-LABEL: @module_level_layout
78
func.func @module_level_layout() {
89
// CHECK: alignment = 32
910
// CHECK: bitsize = 12
11+
// CHECK: index = 7
1012
// CHECK: preferred = 1
1113
// CHECK: size = 2
1214
"test.data_layout_query"() : () -> !test.test_type_with_layout<10>

0 commit comments

Comments
 (0)