Skip to content

Commit d95b79a

Browse files
committed
[MLIR][LLVMIR] Import: add flag to prefer using unregistered intrinsics
Currently, there is no common mechanism for supported intrinsics to be generically annotated with arg and ret attributes. Since there are many supported intrinsics around different dialects, the amount of work to teach all them about these attributes is not trivial. This PR adds a new flag `-prefer-unregistered-intrinsics` that can be used alongside `--import-llvm` to always use `llvm.intrinsic_call` during import time (ignoring dialect hooks for custom intrinsic support). Using this flag allow us to roundtrip the LLVM IR while eliminating a whole set of differences coming from lack of arg/ret attributes on supported intrinsics. Note `convertIntrinsic` has to be moved to an implementation file because it queries into `moduleImport` state, which is a fwd declaration in `LLVMImportInterface.h`
1 parent ae23dd5 commit d95b79a

File tree

7 files changed

+79
-37
lines changed

7 files changed

+79
-37
lines changed

mlir/include/mlir/Target/LLVMIR/Import.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,13 @@ class ModuleOp;
4141
/// adversarial inputs.
4242
/// The `loadAllDialects` flag (default on) will load all dialects in the
4343
/// context.
44-
OwningOpRef<ModuleOp>
45-
translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
46-
MLIRContext *context, bool emitExpensiveWarnings = true,
47-
bool dropDICompositeTypeElements = false,
48-
bool loadAllDialects = true);
44+
/// The `preferUnregisteredIntrinsics` flag (default off) controls whether to
45+
/// prefer generic version of imported intrinsics with `llvm.intrinsic_call`
46+
/// than using versions supported by a dialects.
47+
OwningOpRef<ModuleOp> translateLLVMIRToModule(
48+
std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
49+
bool emitExpensiveWarnings = true, bool dropDICompositeTypeElements = false,
50+
bool loadAllDialects = true, bool preferUnregisteredIntrinsics = false);
4951

5052
/// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
5153
/// dialect.

mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -153,26 +153,7 @@ class LLVMImportInterface
153153
/// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
154154
/// Returns failure otherwise.
155155
LogicalResult convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst,
156-
LLVM::ModuleImport &moduleImport) const {
157-
// Lookup the dialect interface for the given intrinsic.
158-
// Verify the intrinsic identifier maps to an actual intrinsic.
159-
llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
160-
assert(intrinId != llvm::Intrinsic::not_intrinsic);
161-
162-
// First lookup the intrinsic across different dialects for known
163-
// supported conversions, examples include arm-neon, nvm-sve, etc.
164-
Dialect *dialect = intrinsicToDialect.lookup(intrinId);
165-
166-
// No specialized (supported) intrinsics, attempt to generate a generic
167-
// version via llvm.call_intrinsic (if available).
168-
if (!dialect)
169-
return convertUnregisteredIntrinsic(builder, inst, moduleImport);
170-
171-
// Dispatch the conversion to the dialect interface.
172-
const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
173-
assert(iface && "expected to find a dialect interface");
174-
return iface->convertIntrinsic(builder, inst, moduleImport);
175-
}
156+
LLVM::ModuleImport &moduleImport) const;
176157

177158
/// Returns true if the given LLVM IR intrinsic is convertible to an MLIR
178159
/// operation.

mlir/include/mlir/Target/LLVMIR/ModuleImport.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ class LoopAnnotationImporter;
4747
class ModuleImport {
4848
public:
4949
ModuleImport(ModuleOp mlirModule, std::unique_ptr<llvm::Module> llvmModule,
50-
bool emitExpensiveWarnings, bool importEmptyDICompositeTypes);
50+
bool emitExpensiveWarnings, bool importEmptyDICompositeTypes,
51+
bool preferUnregisteredIntrinsics);
5152

5253
/// Calls the LLVMImportInterface initialization that queries the registered
5354
/// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds
@@ -277,6 +278,12 @@ class ModuleImport {
277278
void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
278279
ArrayAttr &resAttr, OpBuilder &builder);
279280

281+
/// Whether the importer should try to convert all intrinsics to
282+
/// llvm.call_intrinsic instead of dialect supported operations.
283+
bool useUnregisteredIntrinsicsOnly() const {
284+
return preferUnregisteredIntrinsics;
285+
}
286+
280287
private:
281288
/// Clears the accumulated state before processing a new region.
282289
void clearRegionState() {
@@ -474,6 +481,10 @@ class ModuleImport {
474481
/// emitted. Avoids generating warnings for unhandled debug intrinsics and
475482
/// metadata that otherwise dominate the translation time for large inputs.
476483
bool emitExpensiveWarnings;
484+
485+
/// An option to control whether to disable supported intrinsic support in
486+
/// favor a more generic version via `llvm.intrinsic_call`.
487+
bool preferUnregisteredIntrinsics;
477488
};
478489

479490
} // namespace LLVM

mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,13 @@ void registerFromLLVMIRTranslation() {
3737
"the LLVM IR import (discouraged: testing only!)"),
3838
llvm::cl::init(false));
3939

40+
static llvm::cl::opt<bool> preferUnregisteredIntrinsics(
41+
"prefer-unregistered-intrinsics",
42+
llvm::cl::desc(
43+
"Prefer translation all intrinsics into llvm.call_intrinsic instead "
44+
"of using dialect supported intrinsics"),
45+
llvm::cl::init(false));
46+
4047
TranslateToMLIRRegistration registration(
4148
"import-llvm", "Translate LLVMIR to MLIR",
4249
[](llvm::SourceMgr &sourceMgr,
@@ -60,9 +67,10 @@ void registerFromLLVMIRTranslation() {
6067
if (llvmModule->IsNewDbgInfoFormat)
6168
llvmModule->convertFromNewDbgValues();
6269

63-
return translateLLVMIRToModule(std::move(llvmModule), context,
64-
emitExpensiveWarnings,
65-
dropDICompositeTypeElements);
70+
return translateLLVMIRToModule(
71+
std::move(llvmModule), context, emitExpensiveWarnings,
72+
dropDICompositeTypeElements, /*loadAllDialects=*/true,
73+
preferUnregisteredIntrinsics);
6674
},
6775
[](DialectRegistry &registry) {
6876
// Register the DLTI dialect used to express the data layout

mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,31 @@ LogicalResult mlir::LLVMImportInterface::convertUnregisteredIntrinsic(
6262

6363
return success();
6464
}
65+
66+
/// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
67+
/// Returns failure otherwise.
68+
LogicalResult mlir::LLVMImportInterface::convertIntrinsic(
69+
OpBuilder &builder, llvm::CallInst *inst,
70+
LLVM::ModuleImport &moduleImport) const {
71+
// Lookup the dialect interface for the given intrinsic.
72+
// Verify the intrinsic identifier maps to an actual intrinsic.
73+
llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
74+
assert(intrinId != llvm::Intrinsic::not_intrinsic);
75+
76+
// First lookup the intrinsic across different dialects for known
77+
// supported conversions, examples include arm-neon, nvm-sve, etc.
78+
Dialect *dialect = nullptr;
79+
80+
if (!moduleImport.useUnregisteredIntrinsicsOnly())
81+
dialect = intrinsicToDialect.lookup(intrinId);
82+
83+
// No specialized (supported) intrinsics, attempt to generate a generic
84+
// version via llvm.call_intrinsic (if available).
85+
if (!dialect)
86+
return convertUnregisteredIntrinsic(builder, inst, moduleImport);
87+
88+
// Dispatch the conversion to the dialect interface.
89+
const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
90+
assert(iface && "expected to find a dialect interface");
91+
return iface->convertIntrinsic(builder, inst, moduleImport);
92+
}

mlir/lib/Target/LLVMIR/ModuleImport.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ getTopologicallySortedBlocks(ArrayRef<llvm::BasicBlock *> basicBlocks) {
162162
ModuleImport::ModuleImport(ModuleOp mlirModule,
163163
std::unique_ptr<llvm::Module> llvmModule,
164164
bool emitExpensiveWarnings,
165-
bool importEmptyDICompositeTypes)
165+
bool importEmptyDICompositeTypes,
166+
bool preferUnregisteredIntrinsics)
166167
: builder(mlirModule->getContext()), context(mlirModule->getContext()),
167168
mlirModule(mlirModule), llvmModule(std::move(llvmModule)),
168169
iface(mlirModule->getContext()),
@@ -171,7 +172,8 @@ ModuleImport::ModuleImport(ModuleOp mlirModule,
171172
mlirModule, importEmptyDICompositeTypes)),
172173
loopAnnotationImporter(
173174
std::make_unique<LoopAnnotationImporter>(*this, builder)),
174-
emitExpensiveWarnings(emitExpensiveWarnings) {
175+
emitExpensiveWarnings(emitExpensiveWarnings),
176+
preferUnregisteredIntrinsics(preferUnregisteredIntrinsics) {
175177
builder.setInsertionPointToStart(mlirModule.getBody());
176178
}
177179

@@ -2527,11 +2529,10 @@ ModuleImport::translateLoopAnnotationAttr(const llvm::MDNode *node,
25272529
return loopAnnotationImporter->translateLoopAnnotation(node, loc);
25282530
}
25292531

2530-
OwningOpRef<ModuleOp>
2531-
mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
2532-
MLIRContext *context, bool emitExpensiveWarnings,
2533-
bool dropDICompositeTypeElements,
2534-
bool loadAllDialects) {
2532+
OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
2533+
std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
2534+
bool emitExpensiveWarnings, bool dropDICompositeTypeElements,
2535+
bool loadAllDialects, bool preferUnregisteredIntrinsics) {
25352536
// Preload all registered dialects to allow the import to iterate the
25362537
// registered LLVMImportDialectInterface implementations and query the
25372538
// supported LLVM IR constructs before starting the translation. Assumes the
@@ -2548,7 +2549,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
25482549
/*column=*/0)));
25492550

25502551
ModuleImport moduleImport(module.get(), std::move(llvmModule),
2551-
emitExpensiveWarnings, dropDICompositeTypeElements);
2552+
emitExpensiveWarnings, dropDICompositeTypeElements,
2553+
preferUnregisteredIntrinsics);
25522554
if (failed(moduleImport.initializeImportInterface()))
25532555
return {};
25542556
if (failed(moduleImport.convertDataLayout()))
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
; RUN: mlir-translate -import-llvm -prefer-unregistered-intrinsics %s | FileCheck %s
2+
3+
; CHECK-LABEL: llvm.func @lifetime
4+
define void @lifetime(ptr %0) {
5+
; CHECK: llvm.call_intrinsic "llvm.lifetime.start.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
6+
call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %0)
7+
; CHECK: llvm.call_intrinsic "llvm.lifetime.end.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
8+
call void @llvm.lifetime.end.p0(i64 32, ptr nonnull %0)
9+
ret void
10+
}

0 commit comments

Comments
 (0)