Skip to content

Commit faa4505

Browse files
[MLIR][LLVM][DLTI] Handle data layout token 'Fn32' (#141167)
1 parent 77a3f81 commit faa4505

File tree

14 files changed

+201
-6
lines changed

14 files changed

+201
-6
lines changed

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ def DLTI_DataLayoutSpecAttr :
9292
/// Returns the stack alignment identifier.
9393
StringAttr getStackAlignmentIdentifier(MLIRContext *context) const;
9494

95+
/// Returns the function pointer alignment identifier.
96+
StringAttr getFunctionPointerAlignmentIdentifier(MLIRContext *context) const;
97+
9598
/// Returns the attribute associated with the key.
9699
FailureOr<Attribute> query(DataLayoutEntryKey key) {
97100
return ::llvm::cast<mlir::DataLayoutSpecInterface>(*this).queryHelper(key);
@@ -249,4 +252,35 @@ def DLTI_TargetDeviceSpecAttr :
249252
}];
250253
}
251254

255+
//===----------------------------------------------------------------------===//
256+
// FunctionPointerAlignmentAttr
257+
//===----------------------------------------------------------------------===//
258+
259+
def DLTI_FunctionPointerAlignmentAttr :
260+
DLTIAttr<"FunctionPointerAlignment", []> {
261+
let summary = "An attribute to represent function pointer alignment.";
262+
let description = [{
263+
Function pointer alignment specifies the minimum alignment of function
264+
pointers, it's a multiple of `alignment`. This alignment can also depend
265+
on the target function, indicated by `function_dependent`.
266+
Example:
267+
```
268+
#dlti.dl_entry<"dlti.function_pointer_alignment",
269+
#dlti.function_pointer_alignment<64, function_dependent = false>>
270+
```
271+
}];
272+
let parameters = (ins
273+
"uint64_t":$alignment,
274+
"bool":$function_dependent
275+
);
276+
let assemblyFormat = [{
277+
`<`
278+
$alignment `,`
279+
`function_dependent` `=` $function_dependent
280+
`>`
281+
}];
282+
let mnemonic = "function_pointer_alignment";
283+
}
284+
285+
252286
#endif // MLIR_DIALECT_DLTI_DLTIATTRS_TD

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def DLTI_Dialect : Dialect {
5858

5959
constexpr const static ::llvm::StringLiteral
6060
kDataLayoutAllocaMemorySpaceKey = "dlti.alloca_memory_space";
61-
61+
6262
constexpr const static ::llvm::StringLiteral
6363
kDataLayoutProgramMemorySpaceKey = "dlti.program_memory_space";
6464

@@ -67,6 +67,9 @@ def DLTI_Dialect : Dialect {
6767

6868
constexpr const static ::llvm::StringLiteral
6969
kDataLayoutStackAlignmentKey = "dlti.stack_alignment";
70+
71+
constexpr const static ::llvm::StringLiteral
72+
kDataLayoutFunctionPointerAlignmentKey = "dlti.function_pointer_alignment";
7073
}];
7174

7275
let useDefaultAttributePrinterParser = 1;

mlir/include/mlir/Interfaces/DataLayoutInterfaces.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ Attribute getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry);
101101
/// DataLayoutInterface if specified, otherwise returns the default.
102102
uint64_t getDefaultStackAlignment(DataLayoutEntryInterface entry);
103103

104+
/// Default handler for the function pointer alignment request. Dispatches to
105+
/// the DataLayoutInterface if specified, otherwise returns the default.
106+
Attribute getDefaultFunctionPointerAlignment(DataLayoutEntryInterface entry);
107+
104108
/// Returns the value of the property from the specified DataLayoutEntry. If the
105109
/// property is missing from the entry, returns std::nullopt.
106110
std::optional<Attribute> getDevicePropertyValue(DataLayoutEntryInterface entry);
@@ -259,6 +263,9 @@ class DataLayout {
259263
/// unspecified.
260264
uint64_t getStackAlignment() const;
261265

266+
/// Returns function pointer alignment.
267+
Attribute getFunctionPointerAlignment() const;
268+
262269
/// Returns the value of the specified property if the property is defined for
263270
/// the given device ID, otherwise returns std::nullopt.
264271
std::optional<Attribute>
@@ -303,6 +310,8 @@ class DataLayout {
303310

304311
/// Cache for stack alignment.
305312
mutable std::optional<uint64_t> stackAlignment;
313+
/// Cache for function pointer alignment.
314+
mutable std::optional<Attribute> functionPointerAlignment;
306315
};
307316

308317
} // namespace mlir

mlir/include/mlir/Interfaces/DataLayoutInterfaces.td

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,12 @@ def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface", [DLTIQuer
171171
/*methodName=*/"getStackAlignmentIdentifier",
172172
/*args=*/(ins "::mlir::MLIRContext *":$context)
173173
>,
174+
InterfaceMethod<
175+
/*description=*/"Returns the function pointer alignment identifier.",
176+
/*retTy=*/"::mlir::StringAttr",
177+
/*methodName=*/"getFunctionPointerAlignmentIdentifier",
178+
/*args=*/(ins "::mlir::MLIRContext *":$context)
179+
>,
174180
// Implementations may override this if they have an efficient lookup
175181
// mechanism.
176182
InterfaceMethod<
@@ -553,6 +559,18 @@ def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> {
553559
return ::mlir::detail::getDefaultStackAlignment(entry);
554560
}]
555561
>,
562+
StaticInterfaceMethod<
563+
/*description=*/"Returns the function pointer alignment in bits computed "
564+
"using the relevant entries. The data layout object "
565+
"can be used for recursive queries.",
566+
/*retTy=*/"Attribute",
567+
/*methodName=*/"getFunctionPointerAlignment",
568+
/*args=*/(ins "::mlir::DataLayoutEntryInterface":$entry),
569+
/*methodBody=*/"",
570+
/*defaultImplementation=*/[{
571+
return ::mlir::detail::getDefaultFunctionPointerAlignment(entry);
572+
}]
573+
>,
556574
StaticInterfaceMethod<
557575
/*description=*/"Returns the value of the property, if the property is "
558576
"defined. Otherwise, it returns std::nullopt.",

mlir/lib/Dialect/DLTI/DLTI.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,12 @@ DataLayoutSpecAttr::getStackAlignmentIdentifier(MLIRContext *context) const {
420420
DLTIDialect::kDataLayoutStackAlignmentKey);
421421
}
422422

423+
StringAttr DataLayoutSpecAttr::getFunctionPointerAlignmentIdentifier(
424+
MLIRContext *context) const {
425+
return Builder(context).getStringAttr(
426+
DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
427+
}
428+
423429
/// Parses an attribute with syntax:
424430
/// dl-spec-attr ::= `#dlti.` `dl_spec` `<` entry-list `>`
425431
/// entry-list ::= | entry | entry `,` entry-list
@@ -625,6 +631,7 @@ class TargetDataLayoutInterface : public DataLayoutDialectInterface {
625631
entryName == DLTIDialect::kDataLayoutProgramMemorySpaceKey ||
626632
entryName == DLTIDialect::kDataLayoutGlobalMemorySpaceKey ||
627633
entryName == DLTIDialect::kDataLayoutStackAlignmentKey ||
634+
entryName == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey ||
628635
entryName == DLTIDialect::kDataLayoutManglingModeKey)
629636
return success();
630637
return emitError(loc) << "unknown data layout entry name: " << entryName;

mlir/lib/Interfaces/DataLayoutInterfaces.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,15 @@ mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry) {
312312
return value.getValue().getZExtValue();
313313
}
314314

315+
// Returns the function pointer alignment if specified in the given entry. If
316+
// the entry is empty the default alignment zero is returned.
317+
Attribute mlir::detail::getDefaultFunctionPointerAlignment(
318+
DataLayoutEntryInterface entry) {
319+
if (entry == DataLayoutEntryInterface())
320+
return Attribute();
321+
return entry.getValue();
322+
}
323+
315324
std::optional<Attribute>
316325
mlir::detail::getDevicePropertyValue(DataLayoutEntryInterface entry) {
317326
if (entry == DataLayoutEntryInterface())
@@ -710,6 +719,23 @@ uint64_t mlir::DataLayout::getStackAlignment() const {
710719
return *stackAlignment;
711720
}
712721

722+
Attribute mlir::DataLayout::getFunctionPointerAlignment() const {
723+
checkValid();
724+
if (functionPointerAlignment)
725+
return *functionPointerAlignment;
726+
DataLayoutEntryInterface entry;
727+
if (originalLayout)
728+
entry = originalLayout.getSpecForIdentifier(
729+
originalLayout.getFunctionPointerAlignmentIdentifier(
730+
originalLayout.getContext()));
731+
if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
732+
functionPointerAlignment = iface.getFunctionPointerAlignment(entry);
733+
else
734+
functionPointerAlignment =
735+
detail::getDefaultFunctionPointerAlignment(entry);
736+
return *functionPointerAlignment;
737+
}
738+
713739
std::optional<Attribute> mlir::DataLayout::getDevicePropertyValue(
714740
TargetSystemSpecInterface::DeviceID deviceID,
715741
StringAttr propertyName) const {

mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,36 @@ DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) {
221221
return success();
222222
}
223223

224+
LogicalResult DataLayoutImporter::tryToEmplaceFunctionPointerAlignmentEntry(
225+
StringRef fnPtrString, StringRef token) {
226+
auto key = StringAttr::get(
227+
context, DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
228+
if (keyEntries.count(key))
229+
return success();
230+
231+
// The data layout entry for "F<type><abi>". <abi> is the aligment value,
232+
// preceded by one of the two possible <types>:
233+
// "i": The alignment of function pointers is independent of the alignment of
234+
// functions, and is a multiple of <abi>.
235+
// "n": The alignment of function pointers is a multiple of the explicit
236+
// alignment specified on the function, and is a multiple of <abi>.
237+
bool functionDependent = false;
238+
if (fnPtrString == "n")
239+
functionDependent = true;
240+
else if (fnPtrString != "i")
241+
return failure();
242+
243+
FailureOr<uint64_t> alignment = tryToParseInt(token);
244+
if (failed(alignment))
245+
return failure();
246+
247+
keyEntries.try_emplace(
248+
key, DataLayoutEntryAttr::get(
249+
key, FunctionPointerAlignmentAttr::get(
250+
key.getContext(), *alignment, functionDependent)));
251+
return success();
252+
}
253+
224254
void DataLayoutImporter::translateDataLayout(
225255
const llvm::DataLayout &llvmDataLayout) {
226256
dataLayout = {};
@@ -330,6 +360,14 @@ void DataLayoutImporter::translateDataLayout(
330360
return;
331361
continue;
332362
}
363+
// Parse function pointer alignment specifications.
364+
// Note that prefix here is "Fn" or "Fi", not a single character.
365+
if (prefix->starts_with("F")) {
366+
StringRef nextPrefix = prefix->drop_front(1);
367+
if (failed(tryToEmplaceFunctionPointerAlignmentEntry(nextPrefix, token)))
368+
return;
369+
continue;
370+
}
333371

334372
// Store all tokens that have not been handled.
335373
unhandledTokens.push_back(lastToken);

mlir/lib/Target/LLVMIR/DataLayoutImporter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ class DataLayoutImporter {
108108
/// Adds a stack alignment entry if there is none yet.
109109
LogicalResult tryToEmplaceStackAlignmentEntry(StringRef token);
110110

111+
/// Adds a function pointer alignment entry if there is none yet.
112+
LogicalResult
113+
tryToEmplaceFunctionPointerAlignmentEntry(StringRef fnPtrAlignEntry,
114+
StringRef token);
115+
111116
std::string layoutStr = {};
112117
StringRef lastToken = {};
113118
SmallVector<StringRef> unhandledTokens;

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,16 @@ translateDataLayout(DataLayoutSpecInterface attribute,
240240
layoutStream << "-S" << alignment;
241241
continue;
242242
}
243+
if (key.getValue() == DLTIDialect::kDataLayoutFunctionPointerAlignmentKey) {
244+
auto value = cast<FunctionPointerAlignmentAttr>(entry.getValue());
245+
uint64_t alignment = value.getAlignment();
246+
// Skip the default function pointer alignment.
247+
if (alignment == 0)
248+
continue;
249+
layoutStream << "-F" << (value.getFunctionDependent() ? "n" : "i")
250+
<< alignment;
251+
continue;
252+
}
243253
emitError(*loc) << "unsupported data layout key " << key;
244254
return failure();
245255
}

mlir/test/Dialect/LLVMIR/layout.mlir

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module {
88
// CHECK: bitsize = 64
99
// CHECK: default_memory_space = 0
1010
// CHECK: endianness = ""
11+
// CHECK: function_pointer_alignment =
12+
// CHECK-SAME: #dlti.function_pointer_alignment<0, function_dependent = false>,
1113
// CHECK: global_memory_space = 0
1214
// CHECK: index = 64
1315
// CHECK: mangling_mode = ""
@@ -21,6 +23,8 @@ module {
2123
// CHECK: bitsize = 64
2224
// CHECK: default_memory_space = 0
2325
// CHECK: endianness = ""
26+
// CHECK: function_pointer_alignment =
27+
// CHECK-SAME: #dlti.function_pointer_alignment<0, function_dependent = false>,
2428
// CHECK: global_memory_space = 0
2529
// CHECK: index = 64
2630
// CHECK: mangling_mode = ""
@@ -34,6 +38,8 @@ module {
3438
// CHECK: bitsize = 64
3539
// CHECK: default_memory_space = 0
3640
// CHECK: endianness = ""
41+
// CHECK: function_pointer_alignment =
42+
// CHECK-SAME: #dlti.function_pointer_alignment<0, function_dependent = false>,
3743
// CHECK: global_memory_space = 0
3844
// CHECK: index = 64
3945
// CHECK: mangling_mode = ""
@@ -58,7 +64,9 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
5864
#dlti.dl_entry<"dlti.global_memory_space", 2 : ui64>,
5965
#dlti.dl_entry<"dlti.program_memory_space", 3 : ui64>,
6066
#dlti.dl_entry<"dlti.stack_alignment", 128 : i64>,
61-
#dlti.dl_entry<"dlti.mangling_mode", "e">
67+
#dlti.dl_entry<"dlti.mangling_mode", "e">,
68+
#dlti.dl_entry<"dlti.function_pointer_alignment",
69+
"#dlti.function_pointer_alignment<32, function_dependent = true>">
6270
>} {
6371
// CHECK: @spec
6472
func.func @spec() {
@@ -67,6 +75,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
6775
// CHECK: bitsize = 32
6876
// CHECK: default_memory_space = 7
6977
// CHECK: endianness = "little"
78+
// CHECK: function_pointer_alignment =
79+
// CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
7080
// CHECK: global_memory_space = 2
7181
// CHECK: index = 32
7282
// CHECK: mangling_mode = "e"
@@ -80,6 +90,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
8090
// CHECK: bitsize = 32
8191
// CHECK: default_memory_space = 7
8292
// CHECK: endianness = "little"
93+
// CHECK: function_pointer_alignment =
94+
// CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
8395
// CHECK: global_memory_space = 2
8496
// CHECK: index = 32
8597
// CHECK: preferred = 8
@@ -92,6 +104,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
92104
// CHECK: bitsize = 64
93105
// CHECK: default_memory_space = 7
94106
// CHECK: endianness = "little"
107+
// CHECK: function_pointer_alignment =
108+
// CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
95109
// CHECK: global_memory_space = 2
96110
// CHECK: index = 64
97111
// CHECK: mangling_mode = "e"
@@ -105,6 +119,8 @@ module attributes { dlti.dl_spec = #dlti.dl_spec<
105119
// CHECK: bitsize = 32
106120
// CHECK: default_memory_space = 7
107121
// CHECK: endianness = "little"
122+
// CHECK: function_pointer_alignment =
123+
// CHECK-SAME: "#dlti.function_pointer_alignment<32, function_dependent = true>",
108124
// CHECK: global_memory_space = 2
109125
// CHECK: index = 24
110126
// CHECK: mangling_mode = "e"

0 commit comments

Comments
 (0)