Skip to content

Commit 0b8c636

Browse files
committed
[MLIR] Move builtin.module LLVM IR translation to before nested operations
This patch moves the call for translating an MLIR module to LLVM IR to the beginning of the translation process. This enables the use of dialect attributes attached to `builtin.module` operations and the `amendOperation()` flow to initialize dialect-specific global configuration before translating the contents of the module. Currently, this patch does not impact the generated IR on its own. Testing infrastructure to allow translating the Test dialect to LLVM IR is added, so that it can be checked that the current behavior is not broken in the future. Differential Revision: https://reviews.llvm.org/D158278
1 parent 8eb3470 commit 0b8c636

File tree

5 files changed

+174
-6
lines changed

5 files changed

+174
-6
lines changed

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,15 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
13771377
LLVM::ensureDistinctSuccessors(module);
13781378

13791379
ModuleTranslation translator(module, std::move(llvmModule));
1380+
llvm::IRBuilder<> llvmBuilder(llvmContext);
1381+
1382+
// Convert module before functions and operations inside, so dialect
1383+
// attributes can be used to change dialect-specific global configurations via
1384+
// `amendOperation()`. These configurations can then influence the translation
1385+
// of operations afterwards.
1386+
if (failed(translator.convertOperation(*module, llvmBuilder)))
1387+
return nullptr;
1388+
13801389
if (failed(translator.convertComdats()))
13811390
return nullptr;
13821391
if (failed(translator.convertFunctionSignatures()))
@@ -1387,7 +1396,6 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
13871396
return nullptr;
13881397

13891398
// Convert other top-level operations if possible.
1390-
llvm::IRBuilder<> llvmBuilder(llvmContext);
13911399
for (Operation &o : getModuleBody(module).getOperations()) {
13921400
if (!isa<LLVM::LLVMFuncOp, LLVM::GlobalOp, LLVM::GlobalCtorsOp,
13931401
LLVM::GlobalDtorsOp, LLVM::ComdatOp>(&o) &&
@@ -1403,10 +1411,6 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
14031411
if (failed(translator.convertFunctions()))
14041412
return nullptr;
14051413

1406-
// Convert module itself.
1407-
if (failed(translator.convertOperation(*module, llvmBuilder)))
1408-
return nullptr;
1409-
14101414
if (llvm::verifyModule(*translator.llvmModule, &llvm::errs()))
14111415
return nullptr;
14121416

mlir/test/Target/LLVMIR/test.mlir

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: mlir-translate -test-to-llvmir -split-input-file %s | FileCheck %s
2+
3+
module {
4+
"test.symbol"() <{sym_name = "foo"}> : () -> ()
5+
}
6+
7+
// CHECK-NOT: @sym_from_attr
8+
// CHECK: @foo = external global i32
9+
// CHECK-NOT: @sym_from_attr
10+
11+
// -----
12+
13+
// Make sure that the module attribute is processed before its body, so that the
14+
// `test.symbol` that is created as a result of the `test.discardable_mod_attr`
15+
// attribute is later picked up and translated to LLVM IR.
16+
module attributes {test.discardable_mod_attr = true} {}
17+
18+
// CHECK: @sym_from_attr = external global i32

mlir/test/lib/Dialect/Test/CMakeLists.txt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ set(LLVM_OPTIONAL_SOURCES
22
TestDialect.cpp
33
TestPatterns.cpp
44
TestTraits.cpp
5+
TestToLLVMIRTranslation.cpp
56
)
67

78
set(LLVM_TARGET_DEFINITIONS TestInterfaces.td)
@@ -83,4 +84,19 @@ add_mlir_library(MLIRTestDialect
8384
MLIRTensorDialect
8485
MLIRTransformUtils
8586
MLIRTransforms
86-
)
87+
)
88+
89+
add_mlir_translation_library(MLIRTestToLLVMIRTranslation
90+
TestToLLVMIRTranslation.cpp
91+
92+
LINK_COMPONENTS
93+
Core
94+
95+
LINK_LIBS PUBLIC
96+
MLIRIR
97+
MLIRLLVMDialect
98+
MLIRTestDialect
99+
MLIRSupport
100+
MLIRBuiltinToLLVMIRTranslation
101+
MLIRLLVMToLLVMIRTranslation
102+
)
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//===- TestToLLVMIRTranslation.cpp - Translate Test dialect to LLVM IR ----===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file implements a translation between the MLIR Test dialect and LLVM IR.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "TestDialect.h"
14+
#include "mlir/IR/Builders.h"
15+
#include "mlir/IR/BuiltinAttributes.h"
16+
#include "mlir/IR/BuiltinOps.h"
17+
#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h"
18+
#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
19+
#include "mlir/Target/LLVMIR/LLVMTranslationInterface.h"
20+
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
21+
#include "mlir/Tools/mlir-translate/Translation.h"
22+
#include "llvm/ADT/StringSwitch.h"
23+
#include "llvm/ADT/TypeSwitch.h"
24+
25+
using namespace mlir;
26+
27+
namespace {
28+
29+
class TestDialectLLVMIRTranslationInterface
30+
: public LLVMTranslationDialectInterface {
31+
public:
32+
using LLVMTranslationDialectInterface::LLVMTranslationDialectInterface;
33+
34+
LogicalResult
35+
amendOperation(Operation *op, NamedAttribute attribute,
36+
LLVM::ModuleTranslation &moduleTranslation) const final;
37+
38+
LogicalResult
39+
convertOperation(Operation *op, llvm::IRBuilderBase &builder,
40+
LLVM::ModuleTranslation &moduleTranslation) const final;
41+
};
42+
43+
} // namespace
44+
45+
LogicalResult TestDialectLLVMIRTranslationInterface::amendOperation(
46+
Operation *op, NamedAttribute attribute,
47+
LLVM::ModuleTranslation &moduleTranslation) const {
48+
return llvm::StringSwitch<llvm::function_ref<LogicalResult(Attribute)>>(
49+
attribute.getName())
50+
// The `test.discardable_mod_attr` attribute, if present and set to
51+
// `true`, results in the addition of a `test.symbol` in the module it is
52+
// attached to with name "sym_from_attr".
53+
.Case("test.discardable_mod_attr",
54+
[&](Attribute attr) {
55+
if (!isa<ModuleOp>(op)) {
56+
op->emitOpError("attribute 'test.discardable_mod_attr' only "
57+
"supported in modules");
58+
return failure();
59+
}
60+
61+
bool createSymbol = false;
62+
if (auto boolAttr = attr.dyn_cast<BoolAttr>())
63+
createSymbol = boolAttr.getValue();
64+
65+
if (createSymbol) {
66+
OpBuilder builder(op->getRegion(0));
67+
builder.create<test::SymbolOp>(
68+
op->getLoc(),
69+
StringAttr::get(op->getContext(), "sym_from_attr"),
70+
/*sym_visibility=*/nullptr);
71+
}
72+
73+
return success();
74+
})
75+
.Default([](Attribute) {
76+
// Skip other discardable dialect attributes.
77+
return success();
78+
})(attribute.getValue());
79+
}
80+
81+
LogicalResult TestDialectLLVMIRTranslationInterface::convertOperation(
82+
Operation *op, llvm::IRBuilderBase &builder,
83+
LLVM::ModuleTranslation &moduleTranslation) const {
84+
return llvm::TypeSwitch<Operation *, LogicalResult>(op)
85+
// `test.symbol`s are translated into global integers in LLVM IR, with a
86+
// name equal to the symbol they are translated from.
87+
.Case([&](test::SymbolOp symOp) {
88+
llvm::Module *mod = moduleTranslation.getLLVMModule();
89+
llvm::IntegerType *i32Type =
90+
llvm::IntegerType::get(moduleTranslation.getLLVMContext(), 32);
91+
mod->getOrInsertGlobal(symOp.getSymName(), i32Type);
92+
return success();
93+
})
94+
.Default([&](Operation *) {
95+
return op->emitOpError("unsupported translation of test operation");
96+
});
97+
}
98+
99+
namespace mlir {
100+
101+
void registerTestToLLVMIR() {
102+
TranslateFromMLIRRegistration registration(
103+
"test-to-llvmir", "test dialect to LLVM IR",
104+
[](Operation *op, raw_ostream &output) {
105+
llvm::LLVMContext llvmContext;
106+
auto llvmModule = translateModuleToLLVMIR(op, llvmContext);
107+
if (!llvmModule)
108+
return failure();
109+
110+
llvmModule->print(output, nullptr);
111+
return success();
112+
},
113+
[](DialectRegistry &registry) {
114+
registry.insert<test::TestDialect>();
115+
registerBuiltinDialectTranslation(registry);
116+
registerLLVMDialectTranslation(registry);
117+
registry.addExtension(
118+
+[](MLIRContext *ctx, test::TestDialect *dialect) {
119+
dialect->addInterfaces<TestDialectLLVMIRTranslationInterface>();
120+
});
121+
});
122+
}
123+
124+
} // namespace mlir

mlir/tools/mlir-translate/mlir-translate.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,17 @@ namespace mlir {
2121
// Defined in the test directory, no public header.
2222
void registerTestRoundtripSPIRV();
2323
void registerTestRoundtripDebugSPIRV();
24+
#ifdef MLIR_INCLUDE_TESTS
25+
void registerTestToLLVMIR();
26+
#endif
2427
} // namespace mlir
2528

2629
static void registerTestTranslations() {
2730
registerTestRoundtripSPIRV();
2831
registerTestRoundtripDebugSPIRV();
32+
#ifdef MLIR_INCLUDE_TESTS
33+
registerTestToLLVMIR();
34+
#endif
2935
}
3036

3137
int main(int argc, char **argv) {

0 commit comments

Comments
 (0)