-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[MLIR][LLVMIR][DLTI] Add LLVM::TargetAttrInterface and #llvm.target attr
#145899
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
Changes from 12 commits
6523e51
0a1903b
eb1cbb5
b6a07f9
ef55a79
9b67848
91560a5
c7b3be3
fa84e7f
53d4d16
33d70a8
5c1d985
046733d
68c2e06
80c1f37
86aa3c4
6f32979
2a50fee
60f1324
a73b061
0377eff
f094eeb
4e247da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,8 +11,8 @@ | |
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_ | ||
| #define MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_ | ||
| #ifndef MLIR_DIALECT_LLVMIR_DATALAYOUTIMPORTER_H | ||
| #define MLIR_DIALECT_LLVMIR_DATALAYOUTIMPORTER_H | ||
|
|
||
| #include "mlir/Dialect/LLVMIR/LLVMTypes.h" | ||
| #include "mlir/IR/BuiltinAttributes.h" | ||
|
|
@@ -38,23 +38,30 @@ namespace detail { | |
| /// null if the bit width is not supported. | ||
| FloatType getFloatType(MLIRContext *context, unsigned width); | ||
|
|
||
| /// Helper class that translates an LLVM data layout to an MLIR data layout | ||
| /// specification. Only integer, float, pointer, alloca memory space, stack | ||
| /// alignment, and endianness entries are translated. The class also returns all | ||
| /// entries from the default data layout specification found in the language | ||
| /// reference (https://llvm.org/docs/LangRef.html#data-layout) if they are not | ||
| /// overwritten by the provided data layout. | ||
| /// Helper class that translates an LLVM data layout string to an MLIR data | ||
| /// layout specification. Only integer, float, pointer, alloca memory space, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's MLIR data layout specification? Is there any reference akin to https://llvm.org/docs/LangRef.html#data-layout?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's this page: https://mlir.llvm.org/docs/DataLayout/#data-layout-specifications It doesn't do a good job of specifying all the properties that are supported. Nor does it clearly explain how those properties are encoded in Is there any consensus on whether tracking issues on Github are worth the effort? |
||
| /// stack alignment, and endianness entries are translated. The class also | ||
| /// returns all entries from the default data layout specification found in the | ||
| /// language reference (https://llvm.org/docs/LangRef.html#data-layout) if they | ||
| /// are not overwritten by the provided data layout. | ||
| class DataLayoutImporter { | ||
| public: | ||
| DataLayoutImporter(MLIRContext *context, | ||
| const llvm::DataLayout &llvmDataLayout) | ||
| : context(context) { | ||
| translateDataLayout(llvmDataLayout); | ||
| DataLayoutImporter(MLIRContext *context, StringRef dataLayoutStr) | ||
| : dataLayoutStr(dataLayoutStr), context(context) { | ||
| // Append the default data layout string specified in the language reference | ||
rolfmorel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // (https://llvm.org/docs/LangRef.html#data-layout) to the supplied data | ||
| // layout string. The translation then parses the string and ignores the | ||
| // default value if a specific kind occurs in both strings. Additionally, | ||
| // the following default values exist: | ||
| // - non-default address space pointer specifications default to the default | ||
| // address space pointer specification | ||
| // - the alloca address space defaults to the default address space. | ||
| dataLayoutSpec = dataLayoutSpecFromDataLayoutStr(); | ||
| } | ||
|
|
||
| /// Returns the MLIR data layout specification translated from the LLVM | ||
| /// data layout. | ||
| DataLayoutSpecInterface getDataLayout() const { return dataLayout; } | ||
| DataLayoutSpecInterface getDataLayoutSpec() const { return dataLayoutSpec; } | ||
|
|
||
| /// Returns the last data layout token that has been processed before | ||
| /// the data layout translation failed. | ||
|
|
@@ -66,7 +73,7 @@ class DataLayoutImporter { | |
|
|
||
| private: | ||
| /// Translates the LLVM `dataLayout` to an MLIR data layout specification. | ||
| void translateDataLayout(const llvm::DataLayout &llvmDataLayout); | ||
| DataLayoutSpecInterface dataLayoutSpecFromDataLayoutStr(); | ||
rolfmorel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// Tries to parse the letter only prefix that identifies the specification | ||
| /// and removes the consumed characters from the beginning of the string. | ||
|
|
@@ -116,17 +123,18 @@ class DataLayoutImporter { | |
| /// Adds legal int widths entry if there is none yet. | ||
| LogicalResult tryToEmplaceLegalIntWidthsEntry(StringRef token); | ||
|
|
||
| std::string layoutStr = {}; | ||
| std::string dataLayoutStr = {}; | ||
| DataLayoutSpecInterface dataLayoutSpec; | ||
|
|
||
| StringRef lastToken = {}; | ||
| SmallVector<StringRef> unhandledTokens; | ||
| llvm::MapVector<StringAttr, DataLayoutEntryInterface> keyEntries; | ||
| llvm::MapVector<TypeAttr, DataLayoutEntryInterface> typeEntries; | ||
| MLIRContext *context; | ||
| DataLayoutSpecInterface dataLayout; | ||
| }; | ||
|
|
||
| } // namespace detail | ||
| } // namespace LLVM | ||
| } // namespace mlir | ||
|
|
||
| #endif // MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_ | ||
| #endif // MLIR_DIALECT_LLVMIR_DATALAYOUTIMPORTER_H | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,7 @@ include "mlir/Dialect/LLVMIR/LLVMDialect.td" | |
| include "mlir/Dialect/LLVMIR/LLVMInterfaces.td" | ||
| include "mlir/IR/AttrTypeBase.td" | ||
| include "mlir/IR/CommonAttrConstraints.td" | ||
| include "mlir/Interfaces/DataLayoutInterfaces.td" | ||
|
|
||
| // All of the attributes will extend this class. | ||
| class LLVM_Attr<string name, string attrMnemonic, | ||
|
|
@@ -1304,6 +1305,128 @@ def LLVM_TargetFeaturesAttr : LLVM_Attr<"TargetFeatures", "target_features"> | |
| let genVerifyDecl = 1; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // LLVM_TargetAttr | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def LLVM_TargetAttr : LLVM_Attr<"Target", "target", | ||
| [DLTIQueryInterface]> { | ||
| let summary = "LLVM target info: triple, chip, features"; | ||
| let description = [{ | ||
| An attribute to hold LLVM target information, specifying LLVM's target | ||
| `triple` string, the target `chip` string (i.e. the `cpu` string), and | ||
| target `features` string as an attribute. The latter two are optional. | ||
rolfmorel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Has facilities to obtain the corresponding `llvm::TargetMachine` and | ||
| `llvm::DataLayout`, given the relevant LLVM backend is loaded. | ||
|
|
||
| --- | ||
|
|
||
| Responds to DLTI-queries on the keys: | ||
| * A query for `"triple"` returns the `StringAttr` for the `triple`. | ||
| * A query for `"chip"` returns the `StringAttr` for the `chip`/`cpu`. | ||
| * A query for `"features"` returns the `StringAttr`, if provided. | ||
| }]; | ||
| let parameters = (ins "StringAttr":$triple, | ||
| "StringAttr":$chip, | ||
| OptionalParameter<"StringAttr", "">:$features); | ||
rolfmorel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| let assemblyFormat = [{`<` struct($triple, $chip, $features) `>`}]; | ||
|
|
||
| let extraClassDeclaration = [{ | ||
| FailureOr<Attribute> query(DataLayoutEntryKey key); | ||
| }]; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // LLVM_DataLayoutAttr | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| def LLVM_DataLayoutAttr | ||
|
||
| : LLVM_Attr<"DataLayout", "data_layout", [DataLayoutSpecInterface]> { | ||
| let summary = "LLVM data layout string, exposed through DLTI"; | ||
| let description = [{ | ||
| An attribute to hold a LLVM data layout string. | ||
|
|
||
| The LLVM data layout string is parsed and mapped to the corresponding MLIR | ||
| data layout specification. The `#llvm.data_layout` attribute then serves as | ||
| a proxy, forwarding all DLTI queries to the underlying MLIR data layout | ||
| specification. | ||
|
|
||
| The default data layout string specified in the language reference | ||
| (https://llvm.org/docs/LangRef.html#data-layout) is used to derive | ||
| unspecified elements of the data layout string. | ||
| }]; | ||
| let parameters = (ins OptionalParameter<"StringAttr", "\"\"">:$data_layout_str, | ||
| OptionalParameter<"DataLayoutSpecInterface", "{}">:$data_layout_spec); | ||
| let builders = [ | ||
| AttrBuilder<(ins "llvm::StringRef":$data_layout_str), [{ | ||
| auto importer = LLVM::detail::DataLayoutImporter($_ctxt, data_layout_str); | ||
| auto dataLayoutSpec = importer.getDataLayoutSpec(); | ||
| return $_get($_ctxt, mlir::StringAttr::get($_ctxt, data_layout_str), dataLayoutSpec); | ||
| }]> | ||
| ]; | ||
| let assemblyFormat = "(`<` $data_layout_str^ `>`)?"; | ||
| let extraClassDeclaration = [{ | ||
| // Forward all DataLayoutSpecInterface methods to the underlying | ||
| // DataLayoutSpecInterface. | ||
| template <typename Ty> | ||
| DataLayoutEntryList getSpecForType() { | ||
| return getDataLayoutSpec().getSpecForType(TypeID::get<Ty>()); | ||
| } | ||
| void bucketEntriesByType( | ||
| ::llvm::MapVector<::mlir::TypeID, ::mlir::DataLayoutEntryList> &types, | ||
| ::llvm::MapVector<::mlir::StringAttr, | ||
| ::mlir::DataLayoutEntryInterface> &ids) { | ||
| getDataLayoutSpec().bucketEntriesByType(types, ids); | ||
| } | ||
| ::mlir::DataLayoutSpecInterface | ||
| combineWith(ArrayRef<::mlir::DataLayoutSpecInterface> specs) const { | ||
| return getDataLayoutSpec().combineWith(specs); | ||
| } | ||
| DataLayoutEntryListRef getEntries() const { return getDataLayoutSpec().getEntries(); } | ||
| LogicalResult verifySpec(Location loc) { | ||
| return getDataLayoutSpec().verifySpec(loc); | ||
| } | ||
| StringAttr getEndiannessIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getEndiannessIdentifier(context); | ||
| } | ||
| StringAttr getDefaultMemorySpaceIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getDefaultMemorySpaceIdentifier(context); | ||
| } | ||
| StringAttr getAllocaMemorySpaceIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getAllocaMemorySpaceIdentifier(context); | ||
| } | ||
| StringAttr getManglingModeIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getManglingModeIdentifier(context); | ||
| } | ||
| StringAttr getProgramMemorySpaceIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getProgramMemorySpaceIdentifier(context); | ||
| } | ||
| StringAttr getGlobalMemorySpaceIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getGlobalMemorySpaceIdentifier(context); | ||
| } | ||
| StringAttr getStackAlignmentIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getStackAlignmentIdentifier(context); | ||
| } | ||
| StringAttr getFunctionPointerAlignmentIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getFunctionPointerAlignmentIdentifier(context); | ||
| } | ||
| StringAttr getLegalIntWidthsIdentifier(MLIRContext *context) const { | ||
| return getDataLayoutSpec().getLegalIntWidthsIdentifier(context); | ||
| } | ||
| ::mlir::DataLayoutEntryList getSpecForType(TypeID type) const { | ||
| return getDataLayoutSpec().getSpecForType(type); | ||
| } | ||
| ::mlir::DataLayoutEntryInterface getSpecForIdentifier(StringAttr identifier) const { | ||
| return getDataLayoutSpec().getSpecForIdentifier(identifier); | ||
| } | ||
| FailureOr<Attribute> query(DataLayoutEntryKey key) const { | ||
| return getDataLayoutSpec().query(key); | ||
| } | ||
| }]; | ||
| } | ||
|
|
||
| //===----------------------------------------------------------------------===// | ||
| // UndefAttr | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -14,12 +14,15 @@ | |||||
| #ifndef MLIR_DIALECT_LLVMIR_LLVMATTRS_H_ | ||||||
| #define MLIR_DIALECT_LLVMIR_LLVMATTRS_H_ | ||||||
|
|
||||||
| #include "mlir/Dialect/LLVMIR/LLVMTypes.h" | ||||||
| #include "mlir/IR/OpImplementation.h" | ||||||
| #include "mlir/Interfaces/DataLayoutInterfaces.h" | ||||||
| #include <optional> | ||||||
|
|
||||||
| #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.h.inc" | ||||||
|
|
||||||
| #include "llvm/IR/DataLayout.h" | ||||||
| #include "llvm/Target/TargetMachine.h" | ||||||
|
||||||
| #include "llvm/IR/DataLayout.h" | |
| #include "llvm/Target/TargetMachine.h" |
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.
As the mlir::LLVM::TargetAttrInterface has methods that return the DataLayout and TargetMachine.
Look at mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.h to see that having dependency on LLVM's headers is not a big deal. For clarity's sake, due moving the parts that require linking to mlir/Target the LLVM dialect does not gain any linking dependencies.
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.
Actually those dependencies there are spurious and legacy, see #150692 for removal
Ideally the LLVM dialect shouldn't depend on llvm/IR.
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.
Will have another go at getting these bits to live in mlir/lib/Target.
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.
All LLVM dependencies are now inside include/Target / lib/Target.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| //===- Target.h - MLIR LLVM target registration -----------------*- C++ -*-===// | ||
| // | ||
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
| // See https://llvm.org/LICENSE.txt for license information. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
| // | ||
| // This provides registration calls for attaching the LLVM target interface. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef MLIR_TARGET_LLVM_TARGET_H | ||
| #define MLIR_TARGET_LLVM_TARGET_H | ||
|
|
||
| namespace mlir { | ||
| class DialectRegistry; | ||
| class MLIRContext; | ||
| namespace LLVM { | ||
| /// Registers the `TargetAttrInterface` for the `#llvm.target` attribute in the | ||
| /// given registry. | ||
| void registerLLVMTargetInterfaceExternalModels(DialectRegistry ®istry); | ||
|
|
||
| /// Registers the `TargetAttrInterface` for the `#llvm.target` attribute in the | ||
| /// registry associated with the given context. | ||
| void registerLLVMTargetInterfaceExternalModels(MLIRContext &context); | ||
| } // namespace LLVM | ||
| } // namespace mlir | ||
|
|
||
| #endif // MLIR_TARGET_LLVM_TARGET_H |
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.
What is the need to move this file to the LLVM dialect?
Uh oh!
There was an error while loading. Please reload this page.
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.
So we can have a
#llvm.data_layout<DATA_LAYOUT_STR>attribute. The DATA_LAYOUT_STR is parsed by this importer and yields an unwieldly#dlti.dl_spec<"dlti.endianness" = "little", "dlti.mangling_mode" = "e", "dlti.legal_int_widths" = array<i32: 8, 16, 32, 64>, "dlti.stack_alignment" = 128 : i64, !llvm.ptr<270> = dense<32> : vector<4xi64>, !llvm.ptr<271> = dense<32> : vector<4xi64>, !llvm.ptr<272> = dense<64> : vector<4xi64>, !llvm.ptr = dense<64> : vector<4xi64>, i64 = dense<64> : vector<2xi64>, i128 = dense<128> : vector<2xi64>, i1 = dense<8> : vector<2xi64>, i8 = dense<8> : vector<2xi64>, i16 = dense<16> : vector<2xi64>, i32 = dense<32> : vector<2xi64>, f80 = dense<128> : vector<2xi64>, f16 = dense<16> : vector<2xi64>, f64 = dense<64> : vector<2xi64>, f128 = dense<128> : vector<2xi64>>(instead of
#llvm.data_layout<"e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128">).What the attribute does is to just show the compact encoding, i.e. the string. It serves as a proxy to the
dl_specrepresentation, which is kept hidden.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.
Having these files in LLVM dialect is actually independent of whether we have
#llvm.data_layout. Either way the pass that converts a#llvm.targetattr to a representation of MLIR's data layout spec will need this parser. As this pass cannot depend on code inmlir/lib/Target, the importer should be in the LLVM dialect.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.
In general it doesn't matter if the textual version of the IR looks ugly, it's IR. It's preferable to have only one way to specify things, and in this case I'd argue that the verbose approach is better.
Re the second comment. You can make the Attr interface return the DL attribute, that way the interface impl and the importer still live in target.
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.
Side note: why is the DLTI using dense attributes for storing integers?
The example above would be much shorter with simple integers I think.
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.
I am fine with getting rid of the
#llvm.data_layoutattr. 👍I think that works. 👍
Yes, I would think an
ArrayAttrwould be a shorter and valid encoding. Will look into it after this PR lands.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.
All LLVM dependencies are now inside
include/Target/lib/Target.#llvm.data_layoutis gone.