llvm-project/mlir/lib/Target/LLVMIR/Transforms/TargetToDataLayout.cpp
Rolf Morel cbfa265e98
[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
2025-08-20 22:00:30 +01:00

105 lines
3.6 KiB
C++

//===- 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);
}
};