Skip to content

Commit 8c97ddf

Browse files
fabianmcgDinistro
andauthored
[mlir][DataLayout] Add a default memory space entry to the data layout. (#127416)
This patch adds a default memory space attribute to the DL and adds methods to query the attribute. This is required as MLIR has no well defined default memory space unlike LLVM which has 0. While `nullptr` is a candidate for default memory space, the `ptr` dialect will remove the possibility for `nullptr` memory spaces to avoid undefined semantics. This patch also modifies the `DataLayoutTypeInterface::areCompatible` to include the new DL spec and merged entries, as it is needed to query the default memory space. --------- Co-authored-by: Christian Ulmann <[email protected]>
1 parent dad0a4e commit 8c97ddf

File tree

13 files changed

+210
-56
lines changed

13 files changed

+210
-56
lines changed

mlir/include/mlir/Dialect/DLTI/DLTIAttrs.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ def DLTI_DataLayoutSpecAttr :
7474
/// Returns the endiannes identifier.
7575
StringAttr getEndiannessIdentifier(MLIRContext *context) const;
7676

77+
/// Returns the default memory space identifier.
78+
StringAttr getDefaultMemorySpaceIdentifier(MLIRContext *context) const;
79+
7780
/// Returns the alloca memory space identifier.
7881
StringAttr getAllocaMemorySpaceIdentifier(MLIRContext *context) const;
7982

mlir/include/mlir/Dialect/DLTI/DLTIBase.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ def DLTI_Dialect : Dialect {
5353
constexpr const static ::llvm::StringLiteral
5454
kDataLayoutManglingModeKey = "dlti.mangling_mode";
5555

56+
constexpr const static ::llvm::StringLiteral
57+
kDataLayoutDefaultMemorySpaceKey = "dlti.default_memory_space";
58+
5659
constexpr const static ::llvm::StringLiteral
5760
kDataLayoutAllocaMemorySpaceKey = "dlti.alloca_memory_space";
5861

mlir/include/mlir/Interfaces/DataLayoutInterfaces.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ using DataLayoutEntryList = llvm::SmallVector<DataLayoutEntryInterface, 4>;
3434
using DataLayoutEntryListRef = llvm::ArrayRef<DataLayoutEntryInterface>;
3535
using TargetDeviceSpecListRef = llvm::ArrayRef<TargetDeviceSpecInterface>;
3636
using TargetDeviceSpecEntry = std::pair<StringAttr, TargetDeviceSpecInterface>;
37+
using DataLayoutIdentifiedEntryMap =
38+
::llvm::DenseMap<::mlir::StringAttr, ::mlir::DataLayoutEntryInterface>;
3739
class DataLayoutOpInterface;
3840
class DataLayoutSpecInterface;
3941
class ModuleOp;
@@ -74,6 +76,10 @@ getDefaultIndexBitwidth(Type type, const DataLayout &dataLayout,
7476
/// DataLayoutInterface if specified, otherwise returns the default.
7577
Attribute getDefaultEndianness(DataLayoutEntryInterface entry);
7678

79+
/// Default handler for the default memory space request. Dispatches to the
80+
/// DataLayoutInterface if specified, otherwise returns the default.
81+
Attribute getDefaultMemorySpace(DataLayoutEntryInterface entry);
82+
7783
/// Default handler for alloca memory space request. Dispatches to the
7884
/// DataLayoutInterface if specified, otherwise returns the default.
7985
Attribute getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry);
@@ -231,6 +237,9 @@ class DataLayout {
231237
/// Returns the specified endianness.
232238
Attribute getEndianness() const;
233239

240+
/// Returns the default memory space used for memory operations.
241+
Attribute getDefaultMemorySpace() const;
242+
234243
/// Returns the memory space used for AllocaOps.
235244
Attribute getAllocaMemorySpace() const;
236245

@@ -285,7 +294,8 @@ class DataLayout {
285294
mutable std::optional<Attribute> endianness;
286295
/// Cache for the mangling mode.
287296
mutable std::optional<Attribute> manglingMode;
288-
/// Cache for alloca, global, and program memory spaces.
297+
/// Cache for default, alloca, global, and program memory spaces.
298+
mutable std::optional<Attribute> defaultMemorySpace;
289299
mutable std::optional<Attribute> allocaMemorySpace;
290300
mutable std::optional<Attribute> programMemorySpace;
291301
mutable std::optional<Attribute> globalMemorySpace;

mlir/include/mlir/Interfaces/DataLayoutInterfaces.td

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface", [DLTIQuer
135135
/*methodName=*/"getEndiannessIdentifier",
136136
/*args=*/(ins "::mlir::MLIRContext *":$context)
137137
>,
138+
InterfaceMethod<
139+
/*description=*/"Returns the default memory space identifier.",
140+
/*retTy=*/"::mlir::StringAttr",
141+
/*methodName=*/"getDefaultMemorySpaceIdentifier",
142+
/*args=*/(ins "::mlir::MLIRContext *":$context)
143+
>,
138144
InterfaceMethod<
139145
/*description=*/"Returns the alloca memory space identifier.",
140146
/*retTy=*/"::mlir::StringAttr",
@@ -475,6 +481,18 @@ def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
475481
return ::mlir::detail::getDefaultEndianness(entry);
476482
}]
477483
>,
484+
StaticInterfaceMethod<
485+
/*description=*/"Returns the memory space used by the ABI computed "
486+
"using the relevant entries. The data layout object "
487+
"can be used for recursive queries.",
488+
/*retTy=*/"::mlir::Attribute",
489+
/*methodName=*/"getDefaultMemorySpace",
490+
/*args=*/(ins "::mlir::DataLayoutEntryInterface":$entry),
491+
/*methodBody=*/"",
492+
/*defaultImplementation=*/[{
493+
return ::mlir::detail::getDefaultMemorySpace(entry);
494+
}]
495+
>,
478496
StaticInterfaceMethod<
479497
/*description=*/"Returns the memory space used by the ABI computed "
480498
"using the relevant entries. The data layout object "
@@ -637,11 +655,16 @@ def DataLayoutTypeInterface : TypeInterface<"DataLayoutTypeInterface"> {
637655
InterfaceMethod<
638656
/*desc=*/"Returns true if the two lists of entries are compatible, that "
639657
"is, that `newLayout` spec entries can be nested in an op with "
640-
"`oldLayout` spec entries.",
658+
"`oldLayout` spec entries. `newSpec` and `identified` are"
659+
"provided to further query data from the combined spec, e.g.,"
660+
"the default address space. TODO: Revisit this method once"
661+
"https://github.com/llvm/llvm-project/issues/130321 gets solved",
641662
/*retTy=*/"bool",
642663
/*methodName=*/"areCompatible",
643664
/*args=*/(ins "::mlir::DataLayoutEntryListRef":$oldLayout,
644-
"::mlir::DataLayoutEntryListRef":$newLayout),
665+
"::mlir::DataLayoutEntryListRef":$newLayout,
666+
"::mlir::DataLayoutSpecInterface":$newSpec,
667+
"const ::mlir::DataLayoutIdentifiedEntryMap&":$identified),
645668
/*methodBody=*/"",
646669
/*defaultImplementation=*/[{ return true; }]
647670
>,

mlir/lib/Dialect/DLTI/DLTI.cpp

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -305,25 +305,8 @@ combineOneSpec(DataLayoutSpecInterface spec,
305305
DenseMap<StringAttr, DataLayoutEntryInterface> newEntriesForID;
306306
spec.bucketEntriesByType(newEntriesForType, newEntriesForID);
307307

308-
// Try overwriting the old entries with the new ones.
309-
for (auto &kvp : newEntriesForType) {
310-
if (!entriesForType.count(kvp.first)) {
311-
entriesForType[kvp.first] = std::move(kvp.second);
312-
continue;
313-
}
314-
315-
Type typeSample = cast<Type>(kvp.second.front().getKey());
316-
assert(&typeSample.getDialect() !=
317-
typeSample.getContext()->getLoadedDialect<BuiltinDialect>() &&
318-
"unexpected data layout entry for built-in type");
319-
320-
auto interface = cast<DataLayoutTypeInterface>(typeSample);
321-
if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second))
322-
return failure();
323-
324-
overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second);
325-
}
326-
308+
// Combine non-Type DL entries first so they are visible to the
309+
// `type.areCompatible` method, allowing to query global properties.
327310
for (const auto &kvp : newEntriesForID) {
328311
StringAttr id = cast<StringAttr>(kvp.second.getKey());
329312
Dialect *dialect = id.getReferencedDialect();
@@ -332,7 +315,7 @@ combineOneSpec(DataLayoutSpecInterface spec,
332315
continue;
333316
}
334317

335-
// Attempt to combine the enties using the dialect interface. If the
318+
// Attempt to combine the entries using the dialect interface. If the
336319
// dialect is not loaded for some reason, use the default combinator
337320
// that conservatively accepts identical entries only.
338321
entriesForID[id] =
@@ -344,6 +327,28 @@ combineOneSpec(DataLayoutSpecInterface spec,
344327
return failure();
345328
}
346329

330+
// Try overwriting the old entries with the new ones.
331+
for (auto &kvp : newEntriesForType) {
332+
if (!entriesForType.count(kvp.first)) {
333+
entriesForType[kvp.first] = std::move(kvp.second);
334+
continue;
335+
}
336+
337+
Type typeSample = cast<Type>(kvp.second.front().getKey());
338+
assert(&typeSample.getDialect() !=
339+
typeSample.getContext()->getLoadedDialect<BuiltinDialect>() &&
340+
"unexpected data layout entry for built-in type");
341+
342+
auto interface = cast<DataLayoutTypeInterface>(typeSample);
343+
// TODO: Revisit this method and call once
344+
// https://github.com/llvm/llvm-project/issues/130321 gets resolved.
345+
if (!interface.areCompatible(entriesForType.lookup(kvp.first), kvp.second,
346+
spec, entriesForID))
347+
return failure();
348+
349+
overwriteDuplicateEntries(entriesForType[kvp.first], kvp.second);
350+
}
351+
347352
return success();
348353
}
349354

@@ -379,6 +384,12 @@ DataLayoutSpecAttr::getEndiannessIdentifier(MLIRContext *context) const {
379384
return Builder(context).getStringAttr(DLTIDialect::kDataLayoutEndiannessKey);
380385
}
381386

387+
StringAttr DataLayoutSpecAttr::getDefaultMemorySpaceIdentifier(
388+
MLIRContext *context) const {
389+
return Builder(context).getStringAttr(
390+
DLTIDialect::kDataLayoutDefaultMemorySpaceKey);
391+
}
392+
382393
StringAttr
383394
DataLayoutSpecAttr::getAllocaMemorySpaceIdentifier(MLIRContext *context) const {
384395
return Builder(context).getStringAttr(
@@ -609,7 +620,8 @@ class TargetDataLayoutInterface : public DataLayoutDialectInterface {
609620
<< DLTIDialect::kDataLayoutEndiannessBig << "' or '"
610621
<< DLTIDialect::kDataLayoutEndiannessLittle << "'";
611622
}
612-
if (entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
623+
if (entryName == DLTIDialect::kDataLayoutDefaultMemorySpaceKey ||
624+
entryName == DLTIDialect::kDataLayoutAllocaMemorySpaceKey ||
613625
entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
614626
entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
615627
entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,8 +349,10 @@ LLVMPointerType::getIndexBitwidth(const DataLayout &dataLayout,
349349
return dataLayout.getTypeIndexBitwidth(get(getContext()));
350350
}
351351

352-
bool LLVMPointerType::areCompatible(DataLayoutEntryListRef oldLayout,
353-
DataLayoutEntryListRef newLayout) const {
352+
bool LLVMPointerType::areCompatible(
353+
DataLayoutEntryListRef oldLayout, DataLayoutEntryListRef newLayout,
354+
DataLayoutSpecInterface newSpec,
355+
const DataLayoutIdentifiedEntryMap &map) const {
354356
for (DataLayoutEntryInterface newEntry : newLayout) {
355357
if (!newEntry.isTypeEntry())
356358
continue;
@@ -597,8 +599,10 @@ static uint64_t extractStructSpecValue(Attribute attr, StructDLEntryPos pos) {
597599
.getValues<uint64_t>()[static_cast<size_t>(pos)];
598600
}
599601

600-
bool LLVMStructType::areCompatible(DataLayoutEntryListRef oldLayout,
601-
DataLayoutEntryListRef newLayout) const {
602+
bool LLVMStructType::areCompatible(
603+
DataLayoutEntryListRef oldLayout, DataLayoutEntryListRef newLayout,
604+
DataLayoutSpecInterface newSpec,
605+
const DataLayoutIdentifiedEntryMap &map) const {
602606
for (DataLayoutEntryInterface newEntry : newLayout) {
603607
if (!newEntry.isTypeEntry())
604608
continue;

mlir/lib/Dialect/Ptr/IR/PtrTypes.cpp

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,12 @@ using namespace mlir::ptr;
2323

2424
constexpr const static unsigned kDefaultPointerSizeBits = 64;
2525
constexpr const static unsigned kBitsInByte = 8;
26-
constexpr const static unsigned kDefaultPointerAlignment = 8;
27-
28-
static Attribute getDefaultMemorySpace(PtrType ptr) { return nullptr; }
26+
constexpr const static unsigned kDefaultPointerAlignmentBits = 8;
2927

3028
/// Searches the data layout for the pointer spec, returns nullptr if it is not
3129
/// found.
32-
static SpecAttr getPointerSpec(DataLayoutEntryListRef params, PtrType type) {
30+
static SpecAttr getPointerSpec(DataLayoutEntryListRef params, PtrType type,
31+
Attribute defaultMemorySpace) {
3332
for (DataLayoutEntryInterface entry : params) {
3433
if (!entry.isTypeEntry())
3534
continue;
@@ -41,20 +40,22 @@ static SpecAttr getPointerSpec(DataLayoutEntryListRef params, PtrType type) {
4140
}
4241
// If not found, and this is the pointer to the default memory space, assume
4342
// 64-bit pointers.
44-
if (type.getMemorySpace() == getDefaultMemorySpace(type))
43+
if (type.getMemorySpace() == defaultMemorySpace)
4544
return SpecAttr::get(type.getContext(), kDefaultPointerSizeBits,
46-
kDefaultPointerAlignment, kDefaultPointerAlignment,
47-
kDefaultPointerSizeBits);
45+
kDefaultPointerAlignmentBits,
46+
kDefaultPointerAlignmentBits, kDefaultPointerSizeBits);
4847
return nullptr;
4948
}
5049

5150
bool PtrType::areCompatible(DataLayoutEntryListRef oldLayout,
52-
DataLayoutEntryListRef newLayout) const {
51+
DataLayoutEntryListRef newLayout,
52+
DataLayoutSpecInterface newSpec,
53+
const DataLayoutIdentifiedEntryMap &map) const {
5354
for (DataLayoutEntryInterface newEntry : newLayout) {
5455
if (!newEntry.isTypeEntry())
5556
continue;
5657
uint32_t size = kDefaultPointerSizeBits;
57-
uint32_t abi = kDefaultPointerAlignment;
58+
uint32_t abi = kDefaultPointerAlignmentBits;
5859
auto newType = llvm::cast<PtrType>(llvm::cast<Type>(newEntry.getKey()));
5960
const auto *it =
6061
llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
@@ -65,10 +66,12 @@ bool PtrType::areCompatible(DataLayoutEntryListRef oldLayout,
6566
return false;
6667
});
6768
if (it == oldLayout.end()) {
69+
Attribute defaultMemorySpace = mlir::detail::getDefaultMemorySpace(
70+
map.lookup(newSpec.getDefaultMemorySpaceIdentifier(getContext())));
6871
it = llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
6972
if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
7073
auto ptrTy = llvm::cast<PtrType>(type);
71-
return ptrTy.getMemorySpace() == getDefaultMemorySpace(ptrTy);
74+
return ptrTy.getMemorySpace() == defaultMemorySpace;
7275
}
7376
return false;
7477
});
@@ -90,43 +93,44 @@ bool PtrType::areCompatible(DataLayoutEntryListRef oldLayout,
9093

9194
uint64_t PtrType::getABIAlignment(const DataLayout &dataLayout,
9295
DataLayoutEntryListRef params) const {
93-
if (SpecAttr spec = getPointerSpec(params, *this))
96+
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
97+
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace))
9498
return spec.getAbi() / kBitsInByte;
9599

96-
return dataLayout.getTypeABIAlignment(
97-
get(getContext(), getDefaultMemorySpace(*this)));
100+
return dataLayout.getTypeABIAlignment(get(getContext(), defaultMemorySpace));
98101
}
99102

100103
std::optional<uint64_t>
101104
PtrType::getIndexBitwidth(const DataLayout &dataLayout,
102105
DataLayoutEntryListRef params) const {
103-
if (SpecAttr spec = getPointerSpec(params, *this)) {
106+
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
107+
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace)) {
104108
return spec.getIndex() == SpecAttr::kOptionalSpecValue ? spec.getSize()
105109
: spec.getIndex();
106110
}
107111

108-
return dataLayout.getTypeIndexBitwidth(
109-
get(getContext(), getDefaultMemorySpace(*this)));
112+
return dataLayout.getTypeIndexBitwidth(get(getContext(), defaultMemorySpace));
110113
}
111114

112115
llvm::TypeSize PtrType::getTypeSizeInBits(const DataLayout &dataLayout,
113116
DataLayoutEntryListRef params) const {
114-
if (SpecAttr spec = getPointerSpec(params, *this))
117+
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
118+
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace))
115119
return llvm::TypeSize::getFixed(spec.getSize());
116120

117121
// For other memory spaces, use the size of the pointer to the default memory
118122
// space.
119-
return dataLayout.getTypeSizeInBits(
120-
get(getContext(), getDefaultMemorySpace(*this)));
123+
return dataLayout.getTypeSizeInBits(get(getContext(), defaultMemorySpace));
121124
}
122125

123126
uint64_t PtrType::getPreferredAlignment(const DataLayout &dataLayout,
124127
DataLayoutEntryListRef params) const {
125-
if (SpecAttr spec = getPointerSpec(params, *this))
128+
Attribute defaultMemorySpace = dataLayout.getDefaultMemorySpace();
129+
if (SpecAttr spec = getPointerSpec(params, *this, defaultMemorySpace))
126130
return spec.getPreferred() / kBitsInByte;
127131

128132
return dataLayout.getTypePreferredAlignment(
129-
get(getContext(), getDefaultMemorySpace(*this)));
133+
get(getContext(), defaultMemorySpace));
130134
}
131135

132136
LogicalResult PtrType::verifyEntries(DataLayoutEntryListRef entries,

mlir/lib/Interfaces/DataLayoutInterfaces.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,16 @@ Attribute mlir::detail::getDefaultEndianness(DataLayoutEntryInterface entry) {
246246
return entry.getValue();
247247
}
248248

249+
// Returns the default memory space if specified in the given entry. If the
250+
// entry is empty the default memory space represented by an empty attribute is
251+
// returned.
252+
Attribute mlir::detail::getDefaultMemorySpace(DataLayoutEntryInterface entry) {
253+
if (!entry)
254+
return Attribute();
255+
256+
return entry.getValue();
257+
}
258+
249259
// Returns the memory space used for alloca operations if specified in the
250260
// given entry. If the entry is empty the default memory space represented by
251261
// an empty attribute is returned.
@@ -605,6 +615,22 @@ mlir::Attribute mlir::DataLayout::getEndianness() const {
605615
return *endianness;
606616
}
607617

618+
mlir::Attribute mlir::DataLayout::getDefaultMemorySpace() const {
619+
checkValid();
620+
if (defaultMemorySpace)
621+
return *defaultMemorySpace;
622+
DataLayoutEntryInterface entry;
623+
if (originalLayout)
624+
entry = originalLayout.getSpecForIdentifier(
625+
originalLayout.getDefaultMemorySpaceIdentifier(
626+
originalLayout.getContext()));
627+
if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
628+
defaultMemorySpace = iface.getDefaultMemorySpace(entry);
629+
else
630+
defaultMemorySpace = detail::getDefaultMemorySpace(entry);
631+
return *defaultMemorySpace;
632+
}
633+
608634
mlir::Attribute mlir::DataLayout::getAllocaMemorySpace() const {
609635
checkValid();
610636
if (allocaMemorySpace)

0 commit comments

Comments
 (0)