diff --git a/mlir/include/mlir/CMakeLists.txt b/mlir/include/mlir/CMakeLists.txt index 9cf3b442aa4ad..f88a35ba1efc7 100644 --- a/mlir/include/mlir/CMakeLists.txt +++ b/mlir/include/mlir/CMakeLists.txt @@ -4,4 +4,5 @@ add_subdirectory(Dialect) add_subdirectory(IR) add_subdirectory(Interfaces) add_subdirectory(Reducer) +add_subdirectory(Target) add_subdirectory(Transforms) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td index 790d2e77ea874..138dd7703a5e7 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td @@ -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 let genVerifyDecl = 1; } +//===----------------------------------------------------------------------===// +// LLVM_TargetAttr +//===----------------------------------------------------------------------===// + +def LLVM_TargetAttr : LLVM_Attr<"Target", "target", + [LLVM_TargetAttrInterface]> { + 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 is optional. + + 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); + + let assemblyFormat = [{`<` struct($triple, $chip, $features) `>`}]; + + let extraClassDeclaration = [{ + FailureOr query(DataLayoutEntryKey key); + }]; +} + //===----------------------------------------------------------------------===// // UndefAttr //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h index 3ede857733242..1ceeb7e4ba2a5 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h @@ -16,6 +16,7 @@ #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/OpImplementation.h" +#include "mlir/Interfaces/DataLayoutInterfaces.h" #include #include "mlir/Dialect/LLVMIR/LLVMOpsEnums.h.inc" @@ -89,8 +90,8 @@ class TBAANodeAttr : public Attribute { // TODO: this shouldn't be needed after we unify the attribute generation, i.e. // --gen-attr-* and --gen-attrdef-*. using cconv::CConv; -using tailcallkind::TailCallKind; using linkage::Linkage; +using tailcallkind::TailCallKind; } // namespace LLVM } // namespace mlir diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td index 107bf3edb657a..ab0462f945a33 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialect.td @@ -27,6 +27,7 @@ def LLVM_Dialect : Dialect { ); let extraClassDeclaration = [{ + static StringRef getTargetAttrName() { return "llvm.target"; } /// Name of the data layout attributes. static StringRef getDataLayoutAttrName() { return "llvm.data_layout"; } static StringRef getNoAliasScopesAttrName() { return "noalias_scopes"; } diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td index 138170f8c8762..64600e86bedfb 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMInterfaces.td @@ -14,6 +14,7 @@ #define LLVMIR_INTERFACES include "mlir/IR/OpBase.td" +include "mlir/Interfaces/DataLayoutInterfaces.td" def FastmathFlagsInterface : OpInterface<"FastmathFlagsInterface"> { let description = [{ @@ -532,4 +533,39 @@ def LLVM_DIRecursiveTypeAttrInterface ]; } +def LLVM_TargetAttrInterface + : AttrInterface<"TargetAttrInterface", [DLTIQueryInterface]> { + let description = [{ + Interface for attributes that describe LLVM targets. + + These attributes should be able to return the specified target `triple`, + `chip` and `features`. + + Implementing attributes should provide a `DLTIQueryInterface::query()` + implementation which responds to keys `"triple"`, `"chip"` and `"features"` + by returning appropriate `StringAttr`s. + }]; + let cppNamespace = "::mlir::LLVM"; + let methods = [ + InterfaceMethod< + /*description=*/"Returns the target triple identifier.", + /*retTy=*/"StringAttr", + /*methodName=*/"getTriple", + /*args=*/(ins) + >, + InterfaceMethod< + /*description=*/"Returns the target chip (i.e. \"cpu\") identifier.", + /*retTy=*/"StringAttr", + /*methodName=*/"getChip", + /*args=*/(ins) + >, + InterfaceMethod< + /*description=*/"Returns the target features as a string.", + /*retTy=*/"StringAttr", + /*methodName=*/"getFeatures", + /*args=*/(ins) + > + ]; +} + #endif // LLVMIR_INTERFACES diff --git a/mlir/include/mlir/Target/CMakeLists.txt b/mlir/include/mlir/Target/CMakeLists.txt new file mode 100644 index 0000000000000..39d31dc9b5e9c --- /dev/null +++ b/mlir/include/mlir/Target/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(LLVMIR) diff --git a/mlir/include/mlir/Target/LLVMIR/CMakeLists.txt b/mlir/include/mlir/Target/LLVMIR/CMakeLists.txt new file mode 100644 index 0000000000000..e31af32661164 --- /dev/null +++ b/mlir/include/mlir/Target/LLVMIR/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(Transforms) diff --git a/mlir/lib/Target/LLVMIR/DataLayoutImporter.h b/mlir/include/mlir/Target/LLVMIR/DataLayoutImporter.h similarity index 71% rename from mlir/lib/Target/LLVMIR/DataLayoutImporter.h rename to mlir/include/mlir/Target/LLVMIR/DataLayoutImporter.h index 88ceaf1a74e62..4d432df493c3f 100644 --- a/mlir/lib/Target/LLVMIR/DataLayoutImporter.h +++ b/mlir/include/mlir/Target/LLVMIR/DataLayoutImporter.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_ -#define MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_ +#ifndef MLIR_TARGET_LLVMIR_DATALAYOUTIMPORTER_H +#define MLIR_TARGET_LLVMIR_DATALAYOUTIMPORTER_H #include "mlir/Dialect/LLVMIR/LLVMTypes.h" #include "mlir/IR/BuiltinAttributes.h" @@ -38,23 +38,31 @@ 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, +/// 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) { + // Translate the `dataLayoutStr`. First, append the default data layout + // string specified in the language reference + // (https://llvm.org/docs/LangRef.html#data-layout) to the supplied 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. @@ -65,8 +73,9 @@ class DataLayoutImporter { ArrayRef getUnhandledTokens() const { return unhandledTokens; } private: - /// Translates the LLVM `dataLayout` to an MLIR data layout specification. - void translateDataLayout(const llvm::DataLayout &llvmDataLayout); + /// Translate the LLVM data layout string to an MLIR data layout + /// specification. + DataLayoutSpecInterface dataLayoutSpecFromDataLayoutStr(); /// Tries to parse the letter only prefix that identifies the specification /// and removes the consumed characters from the beginning of the string. @@ -116,17 +125,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 unhandledTokens; llvm::MapVector keyEntries; llvm::MapVector typeEntries; MLIRContext *context; - DataLayoutSpecInterface dataLayout; }; } // namespace detail } // namespace LLVM } // namespace mlir -#endif // MLIR_LIB_TARGET_LLVMIR_DATALAYOUTIMPORTER_H_ +#endif // MLIR_TARGET_LLVMIR_DATALAYOUTIMPORTER_H diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/CMakeLists.txt b/mlir/include/mlir/Target/LLVMIR/Transforms/CMakeLists.txt new file mode 100644 index 0000000000000..b1a3c79b9b837 --- /dev/null +++ b/mlir/include/mlir/Target/LLVMIR/Transforms/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_TARGET_DEFINITIONS Passes.td) +mlir_tablegen(Passes.h.inc -gen-pass-decls -name TargetLLVMIRTransforms) +add_public_tablegen_target(MLIRTargetLLVMIRTransformsIncGen) + +add_mlir_doc(Passes TargetLLVMIRTransforms ./ -gen-pass-doc) diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h new file mode 100644 index 0000000000000..1e6419154108c --- /dev/null +++ b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h @@ -0,0 +1,27 @@ +//===- Passes.h - LLVM Target Pass Construction and Registration ----------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES_H +#define MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES_H + +#include "mlir/Pass/Pass.h" + +namespace mlir { + +namespace LLVM { + +#define GEN_PASS_DECL +#define GEN_PASS_REGISTRATION +#include "mlir/Target/LLVMIR/Transforms/Passes.h.inc" + +void registerTargetLLVMPasses(); + +} // namespace LLVM +} // namespace mlir + +#endif // MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES_H diff --git a/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td new file mode 100644 index 0000000000000..906f6e82efa50 --- /dev/null +++ b/mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td @@ -0,0 +1,30 @@ +//===-- Passes.td - LLVM Target pass definition file -------*- tablegen -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES +#define MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES + +include "mlir/Pass/PassBase.td" + +def LLVMTargetToDataLayout : Pass<"llvm-target-to-data-layout"> { + let summary = "Derive data layout attributes from LLVM target attributes"; + let dependentDialects = ["mlir::DLTIDialect"]; + let description = [{ + Derive a `DataLayoutSpecInterface`-implementing data layout attribute from + the LLVM-backend target specified by the `TargetAttrInterface`-implementing + attribute attached to the target op at the name `llvm.target`. + }]; + let options = [ + Option<"initializeLLVMTargets", "initialize-llvm-targets", "bool", + /*default=*/"true", + "Whether to pre-load all available target machines, that LLVM is " + "configured to support, into the TargetRegistry."> + ]; +} + +#endif // MLIR_TARGET_LLVMIR_TRANSFORMS_PASSES diff --git a/mlir/lib/Dialect/DLTI/Traits.cpp b/mlir/lib/Dialect/DLTI/Traits.cpp index 34f2dd5896083..3f6dd2900a915 100644 --- a/mlir/lib/Dialect/DLTI/Traits.cpp +++ b/mlir/lib/Dialect/DLTI/Traits.cpp @@ -24,7 +24,7 @@ LogicalResult mlir::impl::verifyHasDefaultDLTIDataLayoutTrait(Operation *op) { } DataLayoutSpecInterface mlir::impl::getDataLayoutSpec(Operation *op) { - return op->getAttrOfType( + return op->getAttrOfType( DLTIDialect::kDataLayoutAttrName); } diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp index 1e02bfe62f379..634efcaea794e 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp @@ -402,3 +402,20 @@ ModuleFlagAttr::verify(function_ref emitError, "supported for unknown key '" << key << "'"; } + +//===----------------------------------------------------------------------===// +// LLVM_TargetAttr +//===----------------------------------------------------------------------===// + +FailureOr<::mlir::Attribute> TargetAttr::query(DataLayoutEntryKey key) { + if (auto stringAttrKey = dyn_cast(key)) { + if (stringAttrKey.getValue() == "triple") + return getTriple(); + if (stringAttrKey.getValue() == "chip") + return getChip(); + if (stringAttrKey.getValue() == "features" && getFeatures()) + return getFeatures(); + } + + return failure(); +} diff --git a/mlir/lib/RegisterAllPasses.cpp b/mlir/lib/RegisterAllPasses.cpp index 1ed3a3798b0d2..c67b24226ae45 100644 --- a/mlir/lib/RegisterAllPasses.cpp +++ b/mlir/lib/RegisterAllPasses.cpp @@ -45,6 +45,7 @@ #include "mlir/Dialect/Transform/Transforms/Passes.h" #include "mlir/Dialect/Vector/Transforms/Passes.h" #include "mlir/Dialect/XeGPU/Transforms/Passes.h" +#include "mlir/Target/LLVMIR/Transforms/Passes.h" #include "mlir/Transforms/Passes.h" // This function may be called to register the MLIR passes with the @@ -74,6 +75,7 @@ void mlir::registerAllPasses() { registerNVGPUPasses(); registerSparseTensorPasses(); LLVM::registerLLVMPasses(); + LLVM::registerTargetLLVMIRTransformsPasses(); math::registerMathPasses(); memref::registerMemRefPasses(); shard::registerShardPasses(); diff --git a/mlir/lib/Target/LLVMIR/CMakeLists.txt b/mlir/lib/Target/LLVMIR/CMakeLists.txt index 9ea5c6835e8ef..d39b35526daf9 100644 --- a/mlir/lib/Target/LLVMIR/CMakeLists.txt +++ b/mlir/lib/Target/LLVMIR/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(Dialect) +add_subdirectory(Transforms) set(LLVM_OPTIONAL_SOURCES ConvertFromLLVMIR.cpp diff --git a/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp index fbad5c2fb78d9..8bd07cd4e2ed9 100644 --- a/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp +++ b/mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp @@ -6,13 +6,14 @@ // //===----------------------------------------------------------------------===// -#include "DataLayoutImporter.h" +#include "mlir/Target/LLVMIR/DataLayoutImporter.h" #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" #include "mlir/Target/LLVMIR/Import.h" + #include "llvm/IR/DataLayout.h" using namespace mlir; @@ -274,101 +275,88 @@ DataLayoutImporter::tryToEmplaceLegalIntWidthsEntry(StringRef token) { return success(); } -void DataLayoutImporter::translateDataLayout( - const llvm::DataLayout &llvmDataLayout) { - dataLayout = {}; - - // Transform the data layout to its string representation and append the - // default data layout string specified in the language reference - // (https://llvm.org/docs/LangRef.html#data-layout). 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. - layoutStr = llvmDataLayout.getStringRepresentation(); - if (!layoutStr.empty()) - layoutStr += "-"; - layoutStr += kDefaultDataLayout; - StringRef layout(layoutStr); +DataLayoutSpecInterface DataLayoutImporter::dataLayoutSpecFromDataLayoutStr() { + if (!dataLayoutStr.empty()) + dataLayoutStr += "-"; + dataLayoutStr += kDefaultDataLayout; // Split the data layout string into tokens separated by a dash. SmallVector tokens; - layout.split(tokens, '-'); + StringRef(dataLayoutStr).split(tokens, '-'); for (StringRef token : tokens) { lastToken = token; FailureOr prefix = tryToParseAlphaPrefix(token); if (failed(prefix)) - return; + return {}; // Parse the endianness. if (*prefix == "e") { if (failed(tryToEmplaceEndiannessEntry( DLTIDialect::kDataLayoutEndiannessLittle, token))) - return; + return {}; continue; } if (*prefix == "E") { if (failed(tryToEmplaceEndiannessEntry( DLTIDialect::kDataLayoutEndiannessBig, token))) - return; + return {}; continue; } // Parse the program address space. if (*prefix == "P") { if (failed(tryToEmplaceAddrSpaceEntry( token, DLTIDialect::kDataLayoutProgramMemorySpaceKey))) - return; + return {}; continue; } // Parse the mangling mode. if (*prefix == "m") { if (failed(tryToEmplaceManglingModeEntry( token, DLTIDialect::kDataLayoutManglingModeKey))) - return; + return {}; continue; } // Parse the global address space. if (*prefix == "G") { if (failed(tryToEmplaceAddrSpaceEntry( token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey))) - return; + return {}; continue; } // Parse the alloca address space. if (*prefix == "A") { if (failed(tryToEmplaceAddrSpaceEntry( token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey))) - return; + return {}; continue; } // Parse the stack alignment. if (*prefix == "S") { if (failed(tryToEmplaceStackAlignmentEntry(token))) - return; + return {}; continue; } // Parse integer alignment specifications. if (*prefix == "i") { FailureOr width = tryToParseInt(token); if (failed(width)) - return; + return {}; Type type = IntegerType::get(context, *width); if (failed(tryToEmplaceAlignmentEntry(type, token))) - return; + return {}; continue; } // Parse float alignment specifications. if (*prefix == "f") { FailureOr width = tryToParseInt(token); if (failed(width)) - return; + return {}; Type type = getFloatType(context, *width); if (failed(tryToEmplaceAlignmentEntry(type, token))) - return; + return {}; continue; } // Parse pointer alignment specifications. @@ -376,17 +364,17 @@ void DataLayoutImporter::translateDataLayout( FailureOr space = token.starts_with(":") ? 0 : tryToParseInt(token); if (failed(space)) - return; + return {}; auto type = LLVMPointerType::get(context, *space); if (failed(tryToEmplacePointerAlignmentEntry(type, token))) - return; + return {}; continue; } // Parse native integer widths specifications. if (*prefix == "n") { if (failed(tryToEmplaceLegalIntWidthsEntry(token))) - return; + return {}; continue; } // Parse function pointer alignment specifications. @@ -394,7 +382,7 @@ void DataLayoutImporter::translateDataLayout( if (prefix->starts_with("F")) { StringRef nextPrefix = prefix->drop_front(1); if (failed(tryToEmplaceFunctionPointerAlignmentEntry(nextPrefix, token))) - return; + return {}; continue; } @@ -409,11 +397,12 @@ void DataLayoutImporter::translateDataLayout( entries.push_back(it.second); for (const auto &it : keyEntries) entries.push_back(it.second); - dataLayout = DataLayoutSpecAttr::get(context, entries); + return DataLayoutSpecAttr::get(context, entries); } DataLayoutSpecInterface mlir::translateDataLayout(const llvm::DataLayout &dataLayout, MLIRContext *context) { - return DataLayoutImporter(context, dataLayout).getDataLayout(); + return DataLayoutImporter(context, dataLayout.getStringRepresentation()) + .getDataLayoutSpec(); } diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 6325480e63657..40726365cd06e 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -16,7 +16,6 @@ #include "mlir/Target/LLVMIR/Import.h" #include "AttrKindDetail.h" -#include "DataLayoutImporter.h" #include "DebugImporter.h" #include "LoopAnnotationImporter.h" @@ -25,6 +24,7 @@ #include "mlir/IR/Builders.h" #include "mlir/IR/Matchers.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" +#include "mlir/Target/LLVMIR/DataLayoutImporter.h" #include "mlir/Tools/mlir-translate/Translation.h" #include "llvm/ADT/DepthFirstIterator.h" @@ -1045,8 +1045,9 @@ LogicalResult ModuleImport::convertIFuncs() { LogicalResult ModuleImport::convertDataLayout() { Location loc = mlirModule.getLoc(); - DataLayoutImporter dataLayoutImporter(context, llvmModule->getDataLayout()); - if (!dataLayoutImporter.getDataLayout()) + DataLayoutImporter dataLayoutImporter( + context, llvmModule->getDataLayout().getStringRepresentation()); + if (!dataLayoutImporter.getDataLayoutSpec()) return emitError(loc, "cannot translate data layout: ") << dataLayoutImporter.getLastToken(); @@ -1054,7 +1055,7 @@ LogicalResult ModuleImport::convertDataLayout() { emitWarning(loc, "unhandled data layout token: ") << token; mlirModule->setAttr(DLTIDialect::kDataLayoutAttrName, - dataLayoutImporter.getDataLayout()); + dataLayoutImporter.getDataLayoutSpec()); return success(); } diff --git a/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt b/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt new file mode 100644 index 0000000000000..a0232601c5f9c --- /dev/null +++ b/mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt @@ -0,0 +1,21 @@ +add_mlir_dialect_library(MLIRTargetLLVMIRTransforms + TargetToDataLayout.cpp + + DEPENDS + MLIRTargetLLVMIRTransformsIncGen + + LINK_COMPONENTS + MC + Target + TargetParser + AllTargetsAsmParsers + AllTargetsCodeGens + AllTargetsDescs + AllTargetsInfos + + LINK_LIBS PUBLIC + MLIRDLTIDialect + MLIRLLVMDialect + MLIRPass + MLIRTargetLLVMIRImport + ) diff --git a/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp new file mode 100644 index 0000000000000..d41d441812039 --- /dev/null +++ b/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp @@ -0,0 +1,104 @@ +//===- TargetToDataLayout.cpp - extract data layout from TargetMachine ----===// +// +// 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 +// +//===----------------------------------------------------------------------===// +#include "mlir/Target/LLVMIR/Transforms/Passes.h" + +#include "mlir/Dialect/DLTI/DLTI.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" +#include "mlir/Target/LLVMIR/Import.h" + +#include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetMachine.h" + +#define DEBUG_TYPE "mlir-llvm-target-to-data-layout" +#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ") +#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n") + +namespace mlir { +namespace LLVM { +#define GEN_PASS_DEF_LLVMTARGETTODATALAYOUT +#include "mlir/Target/LLVMIR/Transforms/Passes.h.inc" +} // namespace LLVM +} // namespace mlir + +using namespace mlir; + +static FailureOr> +getTargetMachine(LLVM::TargetAttrInterface attr) { + StringRef triple = attr.getTriple(); + StringRef chipAKAcpu = attr.getChip(); + StringRef features = attr.getFeatures() ? attr.getFeatures().getValue() : ""; + + std::string error; + const llvm::Target *target = + llvm::TargetRegistry::lookupTarget(triple, error); + if (!target || !error.empty()) { + LDBG("Looking up target '" << triple << "' failed: " << error << "\n"); + return failure(); + } + + return std::unique_ptr(target->createTargetMachine( + llvm::Triple(triple), chipAKAcpu, features, {}, {})); +} + +static FailureOr +getDataLayout(LLVM::TargetAttrInterface attr) { + FailureOr> targetMachine = + getTargetMachine(attr); + if (failed(targetMachine)) { + LDBG("Failed to retrieve the target machine for data layout.\n"); + return failure(); + } + return (targetMachine.value())->createDataLayout(); +} + +struct TargetToDataLayoutPass + : public LLVM::impl::LLVMTargetToDataLayoutBase { + using LLVM::impl::LLVMTargetToDataLayoutBase< + TargetToDataLayoutPass>::LLVMTargetToDataLayoutBase; + + void runOnOperation() override { + Operation *op = getOperation(); + + if (initializeLLVMTargets) { + static llvm::once_flag initializeBackendsOnce; + llvm::call_once(initializeBackendsOnce, []() { + // Ensure that the targets, that LLVM has been configured to support, + // are loaded into the TargetRegistry. + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + }); + } + + auto targetAttr = op->getAttrOfType( + LLVM::LLVMDialect::getTargetAttrName()); + if (!targetAttr) { + op->emitError() + << "no TargetAttrInterface-implementing attribute at key \"" + << LLVM::LLVMDialect::getTargetAttrName() << "\""; + return signalPassFailure(); + } + + FailureOr dataLayout = getDataLayout(targetAttr); + if (failed(dataLayout)) { + op->emitError() << "failed to obtain llvm::DataLayout for " << targetAttr; + return signalPassFailure(); + } + + DataLayoutSpecInterface dataLayoutSpec = + mlir::translateDataLayout(dataLayout.value(), &getContext()); + + if (auto existingDlSpec = op->getAttrOfType( + DLTIDialect::kDataLayoutAttrName)) { + dataLayoutSpec = existingDlSpec.combineWith({dataLayoutSpec}); + } + + op->setAttr(DLTIDialect::kDataLayoutAttrName, dataLayoutSpec); + } +}; diff --git a/mlir/test/Dialect/LLVMIR/target-to-data-layout-invalid.mlir b/mlir/test/Dialect/LLVMIR/target-to-data-layout-invalid.mlir new file mode 100644 index 0000000000000..c0ff53457d17e --- /dev/null +++ b/mlir/test/Dialect/LLVMIR/target-to-data-layout-invalid.mlir @@ -0,0 +1,9 @@ +// REQUIRES: target=x86{{.*}} +// RUN: mlir-opt %s -llvm-target-to-data-layout --split-input-file --verify-diagnostics + +// expected-error @+1 {{failed to obtain llvm::DataLayout for #llvm.target}} +module attributes { dlti.dl_spec = #dlti.dl_spec, +llvm.target = + #llvm.target } { +} diff --git a/mlir/test/Dialect/LLVMIR/target-to-data-layout-no-init.mlir b/mlir/test/Dialect/LLVMIR/target-to-data-layout-no-init.mlir new file mode 100644 index 0000000000000..2a9e9783eacb1 --- /dev/null +++ b/mlir/test/Dialect/LLVMIR/target-to-data-layout-no-init.mlir @@ -0,0 +1,12 @@ +// REQUIRES: target=x86{{.*}} +// RUN: mlir-opt %s -llvm-target-to-data-layout="initialize-llvm-targets=false" --split-input-file --verify-diagnostics + +// Without initializing the (right) LLVM targets/backends ("initialize-llvm-targets=false"), +// it is not possible to obtain LLVM's DataLayout for the target. + +// expected-error @+1 {{failed to obtain llvm::DataLayout for #llvm.target}} +module attributes { dlti.dl_spec = #dlti.dl_spec, +llvm.target = + #llvm.target } { +} diff --git a/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir b/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir new file mode 100644 index 0000000000000..45bfd6a465d7c --- /dev/null +++ b/mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir @@ -0,0 +1,75 @@ +// REQUIRES: target=x86{{.*}} +// RUN: mlir-opt -llvm-target-to-data-layout -split-input-file %s | FileCheck %s + +// CHECK: module attributes +// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec +// CHECK-SAME: "dlti.endianness" = "little" +// CHECK-SAME: llvm.target = #llvm.target< +// CHECK-SAME: triple = "x86_64-unknown-linux" +// CHECK-SAME: chip = "" +// CHECK-NOT: features = + +module attributes { llvm.target = #llvm.target } { +} + +// ----- + +// CHECK: module attributes +// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec +// CHECK-SAME: "dlti.endianness" = "little" +// CHECK-SAME: llvm.target = #llvm.target< +// CHECK-SAME: triple = "x86_64-unknown-linux" +// CHECK-SAME: chip = "" +// CHECK-SAME: features = "+mmx,+sse" + +module attributes { llvm.target = #llvm.target } { +} + +// ----- + +// CHECK: module attributes +// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec +// CHECK-SAME: "dlti.endianness" = "little" +// CHECK-SAME: llvm.target = #llvm.target< +// CHECK-SAME: triple = "x86_64-unknown-linux" +// CHECK-SAME: chip = "skylake" +// CHECK-NOT: features = + +module attributes { llvm.target = #llvm.target } { +} + +// ----- + +// CHECK: module attributes +// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec +// CHECK-SAME: "dlti.endianness" = "little" +// CHECK-SAME: llvm.target = #llvm.target< +// CHECK-SAME: triple = "x86_64-unknown-linux" +// CHECK-SAME: chip = "skylake" +// CHECK-SAME: features = "+mmx,+sse"> + +module attributes { llvm.target = #llvm.target } { +} + +// ----- + +// CHECK: module attributes +// CHECK-SAME: dlti.dl_spec = #dlti.dl_spec +// CHECK-SAME: "dlti.endianness" = "little" +// CHECK-SAME: index = 32 +// CHECK-SAME: llvm.target = #llvm.target< +// CHECK-SAME: triple = "x86_64-unknown-linux" +// CHECK-SAME: chip = "skylake" +// CHECK-SAME: features = "+mmx,+sse" + +module attributes { dlti.dl_spec = #dlti.dl_spec, + llvm.target = #llvm.target } { +}