Option<"indexBitwidth", "index-bitwidth", "unsigned",
/*default=kDeriveIndexBitwidthFromDataLayout*/"0",
"Bitwidth of the index type, 0 to use size of machine word">,
+ Option<"dataLayout", "data-layout", "std::string",
+ /*default=*/"\"\"",
+ "String description (LLVM format) of the data layout that is "
+ "expected on the produced module">
];
}
/// pointers to memref descriptors for arguments.
LLVM::LLVMType convertFunctionTypeCWrapper(FunctionType type);
+ /// Returns the data layout to use during and after conversion.
+ const llvm::DataLayout &getDataLayout() { return options.dataLayout; }
+
/// Gets the LLVM representation of the index type. The returned type is an
/// integer type with the size configured for this type converter.
LLVM::LLVMType getIndexType();
#ifndef MLIR_CONVERSION_STANDARDTOLLVM_CONVERTSTANDARDTOLLVMPASS_H_
#define MLIR_CONVERSION_STANDARDTOLLVM_CONVERTSTANDARDTOLLVMPASS_H_
+#include "llvm/IR/DataLayout.h"
+
#include <memory>
namespace mlir {
/// Use aligned_alloc for heap allocations.
bool useAlignedAlloc = false;
+ /// The data layout of the module to produce. This must be consistent with the
+ /// data layout used in the upper levels of the lowering pipeline.
+ // TODO: this should be replaced by MLIR data layout when one exists.
+ llvm::DataLayout dataLayout = llvm::DataLayout("");
+
/// Get a statically allocated copy of the default LowerToLLVMOptions.
static const LowerToLLVMOptions &getDefaultOptions() {
static LowerToLLVMOptions options;
let name = "llvm";
let cppNamespace = "LLVM";
let hasRegionArgAttrVerify = 1;
+ let hasOperationAttrVerify = 1;
let extraClassDeclaration = [{
- ~LLVMDialect();
- const llvm::DataLayout &getDataLayout();
+ /// Name of the data layout attributes.
+ static StringRef getDataLayoutAttrName() { return "llvm.data_layout"; }
- private:
- friend LLVMType;
-
- // This can't be a unique_ptr because the ctor is generated inline
- // in the class definition at the moment.
- detail::LLVMDialectImpl *impl;
+ /// Verifies if the given string is a well-formed data layout descriptor.
+ /// Uses `reportError` to report errors.
+ static LogicalResult verifyDataLayoutString(
+ StringRef descr, llvm::function_ref<void (const Twine &)> reportError);
}];
}
options(options) {
assert(llvmDialect && "LLVM IR dialect is not registered");
if (options.indexBitwidth == kDeriveIndexBitwidthFromDataLayout)
- this->options.indexBitwidth =
- llvmDialect->getDataLayout().getPointerSizeInBits();
+ this->options.indexBitwidth = options.dataLayout.getPointerSizeInBits();
// Register conversions for the standard types.
addConversion([&](ComplexType type) { return convertComplexType(type); });
}
unsigned LLVMTypeConverter::getPointerBitwidth(unsigned addressSpace) {
- return llvmDialect->getDataLayout().getPointerSizeInBits(addressSpace);
+ return options.dataLayout.getPointerSizeInBits(addressSpace);
}
Type LLVMTypeConverter::convertIndexType(IndexType type) {
struct LLVMLoweringPass : public ConvertStandardToLLVMBase<LLVMLoweringPass> {
LLVMLoweringPass() = default;
LLVMLoweringPass(bool useBarePtrCallConv, bool emitCWrappers,
- unsigned indexBitwidth, bool useAlignedAlloc) {
+ unsigned indexBitwidth, bool useAlignedAlloc,
+ const llvm::DataLayout &dataLayout) {
this->useBarePtrCallConv = useBarePtrCallConv;
this->emitCWrappers = emitCWrappers;
this->indexBitwidth = indexBitwidth;
this->useAlignedAlloc = useAlignedAlloc;
+ this->dataLayout = dataLayout.getStringRepresentation();
}
/// Run the dialect converter on the module.
signalPassFailure();
return;
}
+ if (failed(LLVM::LLVMDialect::verifyDataLayoutString(
+ this->dataLayout, [this](const Twine &message) {
+ getOperation().emitError() << message.str();
+ }))) {
+ signalPassFailure();
+ return;
+ }
ModuleOp m = getOperation();
LowerToLLVMOptions options = {useBarePtrCallConv, emitCWrappers,
- indexBitwidth, useAlignedAlloc};
+ indexBitwidth, useAlignedAlloc,
+ llvm::DataLayout(this->dataLayout)};
LLVMTypeConverter typeConverter(&getContext(), options);
OwningRewritePatternList patterns;
LLVMConversionTarget target(getContext());
if (failed(applyPartialConversion(m, target, patterns)))
signalPassFailure();
+ m.setAttr(LLVM::LLVMDialect::getDataLayoutAttrName(),
+ StringAttr::get(this->dataLayout, m.getContext()));
}
};
} // end namespace
mlir::createLowerToLLVMPass(const LowerToLLVMOptions &options) {
return std::make_unique<LLVMLoweringPass>(
options.useBarePtrCallConv, options.emitCWrappers, options.indexBitwidth,
- options.useAlignedAlloc);
+ options.useAlignedAlloc, options.dataLayout);
}
// TODO: this should use the MLIR data layout when it becomes available and
// stop depending on translation.
- LLVM::LLVMDialect *dialect = typeConverter.getDialect();
llvm::LLVMContext llvmContext;
align = LLVM::TypeToLLVMIRTranslator(llvmContext)
.getPreferredAlignment(elementTy.cast<LLVM::LLVMType>(),
- dialect->getDataLayout());
+ typeConverter.getDataLayout());
return success();
}
// LLVMDialect initialization, type parsing, and registration.
//===----------------------------------------------------------------------===//
-namespace mlir {
-namespace LLVM {
-namespace detail {
-struct LLVMDialectImpl {
- LLVMDialectImpl() : layout("") {}
-
- /// Default data layout to use.
- // TODO: this should be moved to some Op equivalent to LLVM module and
- // eventually replaced with a proper MLIR data layout.
- llvm::DataLayout layout;
-};
-} // end namespace detail
-} // end namespace LLVM
-} // end namespace mlir
-
void LLVMDialect::initialize() {
- impl = new detail::LLVMDialectImpl();
// clang-format off
addTypes<LLVMVoidType,
LLVMHalfType,
allowUnknownOperations();
}
-LLVMDialect::~LLVMDialect() { delete impl; }
-
#define GET_OP_CLASSES
#include "mlir/Dialect/LLVMIR/LLVMOps.cpp.inc"
-const llvm::DataLayout &LLVMDialect::getDataLayout() { return impl->layout; }
-
/// Parse a type registered to this dialect.
Type LLVMDialect::parseType(DialectAsmParser &parser) const {
return detail::parseType(parser);
return detail::printType(type.cast<LLVMType>(), os);
}
+LogicalResult LLVMDialect::verifyDataLayoutString(
+ StringRef descr, llvm::function_ref<void(const Twine &)> reportError) {
+ llvm::Expected<llvm::DataLayout> maybeDataLayout =
+ llvm::DataLayout::parse(descr);
+ if (maybeDataLayout)
+ return success();
+
+ std::string message;
+ llvm::raw_string_ostream messageStream(message);
+ llvm::logAllUnhandledErrors(maybeDataLayout.takeError(), messageStream);
+ reportError("invalid data layout descriptor: " + messageStream.str());
+ return failure();
+}
+
+/// Verify LLVM dialect attributes.
+LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
+ NamedAttribute attr) {
+ // If the data layout attribute is present, it must use the LLVM data layout
+ // syntax. Try parsing it and report errors in case of failure. Users of this
+ // attribute may assume it is well-formed and can pass it to the (asserting)
+ // llvm::DataLayout constructor.
+ if (attr.first.strref() != LLVM::LLVMDialect::getDataLayoutAttrName())
+ return success();
+ if (auto stringAttr = attr.second.dyn_cast<StringAttr>())
+ return verifyDataLayoutString(
+ stringAttr.getValue(),
+ [op](const Twine &message) { op->emitOpError() << message.str(); });
+
+ return op->emitOpError() << "expected '"
+ << LLVM::LLVMDialect::getDataLayoutAttrName()
+ << "' to be a string attribute";
+}
+
/// Verify LLVMIR function argument attributes.
LogicalResult LLVMDialect::verifyRegionArgAttribute(Operation *op,
unsigned regionIdx,
std::unique_ptr<llvm::Module> ModuleTranslation::prepareLLVMModule(
Operation *m, llvm::LLVMContext &llvmContext, StringRef name) {
- auto *dialect = m->getContext()->getRegisteredDialect<LLVM::LLVMDialect>();
- assert(dialect && "LLVM dialect must be registered");
-
auto llvmModule = std::make_unique<llvm::Module>(name, llvmContext);
- llvmModule->setDataLayout(dialect->getDataLayout());
+
+ if (auto dataLayoutAttr =
+ m->getAttr(LLVM::LLVMDialect::getDataLayoutAttrName()))
+ llvmModule->setDataLayout(dataLayoutAttr.cast<StringAttr>().getValue());
// Inject declarations for `malloc` and `free` functions that can be used in
// memref allocation/deallocation coming from standard ops lowering.
--- /dev/null
+// RUN: mlir-opt -convert-std-to-llvm %s | FileCheck %s
+// RUN-32: mlir-opt -convert-std-to-llvm='data-layout=p:32:32:32' %s | FileCheck %s
+
+// CHECK: module attributes {llvm.data_layout = ""}
+// CHECK-32: module attributes {llvm.data_layout ="p:32:32:32"}
+module {}
// expected-error @+1 {{can be given only acquire, release, acq_rel, and seq_cst orderings}}
llvm.fence syncscope("agent") monotonic
}
+
+// -----
+
+// expected-error @+1 {{invalid data layout descriptor}}
+module attributes {llvm.data_layout = "#vjkr32"} {
+ func @invalid_data_layout()
+}
}
// CHECK: ![[NODE]] = !{i32 1}
+
+// -----
+
+// Check that the translation does not crash in absence of a data layout.
+module {
+ // CHECK: declare void @module_default_layout
+ llvm.func @module_default_layout()
+}
+
+// -----
+
+// CHECK: target datalayout = "E"
+module attributes {llvm.data_layout = "E"} {
+ llvm.func @module_big_endian()
+}
+