Skip to content

Commit 5265412

Browse files
[MLIR][LLVMIR] Import: add flag to prefer using unregistered intrinsics (#130685)
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 (though it would be nice in the long term). 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 29a0000 commit 5265412

File tree

7 files changed

+81
-37
lines changed

7 files changed

+81
-37
lines changed

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,15 @@ 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+
/// import all intrinsics using `llvm.intrinsic_call` even if a dialect
46+
/// registered an explicit intrinsic operation. Warning: passes that rely on
47+
/// matching explicit intrinsic operations may not work properly if this flag is
48+
/// enabled.
49+
OwningOpRef<ModuleOp> translateLLVMIRToModule(
50+
std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
51+
bool emitExpensiveWarnings = true, bool dropDICompositeTypeElements = false,
52+
bool loadAllDialects = true, bool preferUnregisteredIntrinsics = false);
4953

5054
/// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
5155
/// 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
@@ -287,6 +288,12 @@ class ModuleImport {
287288
void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
288289
ArrayAttr &resAttr, OpBuilder &builder);
289290

291+
/// Whether the importer should try to convert all intrinsics to
292+
/// llvm.call_intrinsic instead of dialect supported operations.
293+
bool useUnregisteredIntrinsicsOnly() const {
294+
return preferUnregisteredIntrinsics;
295+
}
296+
290297
private:
291298
/// Clears the accumulated state before processing a new region.
292299
void clearRegionState() {
@@ -484,6 +491,10 @@ class ModuleImport {
484491
/// emitted. Avoids generating warnings for unhandled debug intrinsics and
485492
/// metadata that otherwise dominate the translation time for large inputs.
486493
bool emitExpensiveWarnings;
494+
495+
/// An option to control whether the importer should try to convert all
496+
/// intrinsics to llvm.call_intrinsic instead of dialect supported operations.
497+
bool preferUnregisteredIntrinsics;
487498
};
488499

489500
} // 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 translating 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

@@ -2581,11 +2583,10 @@ ModuleImport::translateDereferenceableAttr(const llvm::MDNode *node,
25812583
return derefAttr;
25822584
}
25832585

2584-
OwningOpRef<ModuleOp>
2585-
mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
2586-
MLIRContext *context, bool emitExpensiveWarnings,
2587-
bool dropDICompositeTypeElements,
2588-
bool loadAllDialects) {
2586+
OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
2587+
std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
2588+
bool emitExpensiveWarnings, bool dropDICompositeTypeElements,
2589+
bool loadAllDialects, bool preferUnregisteredIntrinsics) {
25892590
// Preload all registered dialects to allow the import to iterate the
25902591
// registered LLVMImportDialectInterface implementations and query the
25912592
// supported LLVM IR constructs before starting the translation. Assumes the
@@ -2602,7 +2603,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
26022603
/*column=*/0)));
26032604

26042605
ModuleImport moduleImport(module.get(), std::move(llvmModule),
2605-
emitExpensiveWarnings, dropDICompositeTypeElements);
2606+
emitExpensiveWarnings, dropDICompositeTypeElements,
2607+
preferUnregisteredIntrinsics);
26062608
if (failed(moduleImport.initializeImportInterface()))
26072609
return {};
26082610
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)