[MLIR][LLVMIR][DLTI] Add LLVM::TargetAttrInterface
and #llvm.target
attr (#145899)
Adds the `#llvm.target<triple = $TRIPLE, chip = $CHIP, features = $FEATURES>` attribute and along with a `-llvm-target-to-data-layout` pass to derive a MLIR data layout from the LLVM data layout string (using the existing `DataLayoutImporter`). The attribute implements the relevant DLTI-interfaces, to expose the `triple`, `chip` (AKA `cpu`) and `features` on `#llvm.target` and the full `DataLayoutSpecInterface`. The pass combines the generated `#dlti.dl_spec` with an existing `dl_spec` in case one is already present, e.g. a `dl_spec` which is there to specify size of the `index` type. Adds a `TargetAttrInterface` which can be implemented by all attributes representing LLVM targets. Similar to the Draft PR https://github.com/llvm/llvm-project/pull/78073. RFC on which this PR is based: https://discourse.llvm.org/t/mandatory-data-layout-in-the-llvm-dialect/85875
This commit is contained in:
parent
2a66ce5edb
commit
cbfa265e98
@ -4,4 +4,5 @@ add_subdirectory(Dialect)
|
||||
add_subdirectory(IR)
|
||||
add_subdirectory(Interfaces)
|
||||
add_subdirectory(Reducer)
|
||||
add_subdirectory(Target)
|
||||
add_subdirectory(Transforms)
|
||||
|
@ -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,34 @@ def LLVM_TargetFeaturesAttr : LLVM_Attr<"TargetFeatures", "target_features">
|
||||
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<Attribute> query(DataLayoutEntryKey key);
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UndefAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#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"
|
||||
@ -89,8 +90,8 @@ public:
|
||||
// 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
|
||||
|
||||
|
@ -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"; }
|
||||
|
@ -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
|
||||
|
1
mlir/include/mlir/Target/CMakeLists.txt
Normal file
1
mlir/include/mlir/Target/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(LLVMIR)
|
1
mlir/include/mlir/Target/LLVMIR/CMakeLists.txt
Normal file
1
mlir/include/mlir/Target/LLVMIR/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(Transforms)
|
@ -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 @@ public:
|
||||
ArrayRef<StringRef> 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 @@ private:
|
||||
/// 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_TARGET_LLVMIR_DATALAYOUTIMPORTER_H
|
@ -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)
|
27
mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
Normal file
27
mlir/include/mlir/Target/LLVMIR/Transforms/Passes.h
Normal file
@ -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
|
30
mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
Normal file
30
mlir/include/mlir/Target/LLVMIR/Transforms/Passes.td
Normal file
@ -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
|
@ -24,7 +24,7 @@ LogicalResult mlir::impl::verifyHasDefaultDLTIDataLayoutTrait(Operation *op) {
|
||||
}
|
||||
|
||||
DataLayoutSpecInterface mlir::impl::getDataLayoutSpec(Operation *op) {
|
||||
return op->getAttrOfType<DataLayoutSpecAttr>(
|
||||
return op->getAttrOfType<DataLayoutSpecInterface>(
|
||||
DLTIDialect::kDataLayoutAttrName);
|
||||
}
|
||||
|
||||
|
@ -402,3 +402,20 @@ ModuleFlagAttr::verify(function_ref<InFlightDiagnostic()> emitError,
|
||||
"supported for unknown key '"
|
||||
<< key << "'";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LLVM_TargetAttr
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
FailureOr<::mlir::Attribute> TargetAttr::query(DataLayoutEntryKey key) {
|
||||
if (auto stringAttrKey = dyn_cast<StringAttr>(key)) {
|
||||
if (stringAttrKey.getValue() == "triple")
|
||||
return getTriple();
|
||||
if (stringAttrKey.getValue() == "chip")
|
||||
return getChip();
|
||||
if (stringAttrKey.getValue() == "features" && getFeatures())
|
||||
return getFeatures();
|
||||
}
|
||||
|
||||
return failure();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -1,4 +1,5 @@
|
||||
add_subdirectory(Dialect)
|
||||
add_subdirectory(Transforms)
|
||||
|
||||
set(LLVM_OPTIONAL_SOURCES
|
||||
ConvertFromLLVMIR.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<StringRef> tokens;
|
||||
layout.split(tokens, '-');
|
||||
StringRef(dataLayoutStr).split(tokens, '-');
|
||||
|
||||
for (StringRef token : tokens) {
|
||||
lastToken = token;
|
||||
FailureOr<StringRef> 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<uint64_t> 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<uint64_t> 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<uint64_t> 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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
21
mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
Normal file
21
mlir/lib/Target/LLVMIR/Transforms/CMakeLists.txt
Normal file
@ -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
|
||||
)
|
104
mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
Normal file
104
mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
Normal file
@ -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<std::unique_ptr<llvm::TargetMachine>>
|
||||
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<llvm::TargetMachine>(target->createTargetMachine(
|
||||
llvm::Triple(triple), chipAKAcpu, features, {}, {}));
|
||||
}
|
||||
|
||||
static FailureOr<llvm::DataLayout>
|
||||
getDataLayout(LLVM::TargetAttrInterface attr) {
|
||||
FailureOr<std::unique_ptr<llvm::TargetMachine>> 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<TargetToDataLayoutPass> {
|
||||
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::TargetAttrInterface>(
|
||||
LLVM::LLVMDialect::getTargetAttrName());
|
||||
if (!targetAttr) {
|
||||
op->emitError()
|
||||
<< "no TargetAttrInterface-implementing attribute at key \""
|
||||
<< LLVM::LLVMDialect::getTargetAttrName() << "\"";
|
||||
return signalPassFailure();
|
||||
}
|
||||
|
||||
FailureOr<llvm::DataLayout> 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<DataLayoutSpecInterface>(
|
||||
DLTIDialect::kDataLayoutAttrName)) {
|
||||
dataLayoutSpec = existingDlSpec.combineWith({dataLayoutSpec});
|
||||
}
|
||||
|
||||
op->setAttr(DLTIDialect::kDataLayoutAttrName, dataLayoutSpec);
|
||||
}
|
||||
};
|
@ -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<index = 32>,
|
||||
llvm.target =
|
||||
#llvm.target<triple="x64_86-unknown-linux",
|
||||
chip="NON-EXISTING CHIP"> } {
|
||||
}
|
12
mlir/test/Dialect/LLVMIR/target-to-data-layout-no-init.mlir
Normal file
12
mlir/test/Dialect/LLVMIR/target-to-data-layout-no-init.mlir
Normal file
@ -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<index = 32>,
|
||||
llvm.target =
|
||||
#llvm.target<triple="x64_86-unknown-linux",
|
||||
chip="skylake"> } {
|
||||
}
|
75
mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir
Normal file
75
mlir/test/Dialect/LLVMIR/target-to-data-layout.mlir
Normal file
@ -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<triple = "x86_64-unknown-linux",
|
||||
chip = ""> } {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// 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<triple = "x86_64-unknown-linux",
|
||||
chip = "",
|
||||
features = "+mmx,+sse"> } {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// 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<triple = "x86_64-unknown-linux",
|
||||
chip = "skylake"> } {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// 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<triple = "x86_64-unknown-linux",
|
||||
chip = "skylake",
|
||||
features = "+mmx,+sse"> } {
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// 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<index = 32>,
|
||||
llvm.target = #llvm.target<triple = "x86_64-unknown-linux",
|
||||
chip = "skylake",
|
||||
features = "+mmx,+sse"> } {
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user