Skip to content

Commit 8ebcad4

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 d0a0de5 commit 8ebcad4

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
@@ -284,6 +285,12 @@ class ModuleImport {
284285
void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
285286
ArrayAttr &resAttr, OpBuilder &builder);
286287

288+
/// Whether the importer should try to convert all intrinsics to
289+
/// llvm.call_intrinsic instead of dialect supported operations.
290+
bool useUnregisteredIntrinsicsOnly() const {
291+
return preferUnregisteredIntrinsics;
292+
}
293+
287294
private:
288295
/// Clears the accumulated state before processing a new region.
289296
void clearRegionState() {
@@ -481,6 +488,10 @@ class ModuleImport {
481488
/// emitted. Avoids generating warnings for unhandled debug intrinsics and
482489
/// metadata that otherwise dominate the translation time for large inputs.
483490
bool emitExpensiveWarnings;
491+
492+
/// An option to control whether to disable supported intrinsic support in
493+
/// favor a more generic version via `llvm.intrinsic_call`.
494+
bool preferUnregisteredIntrinsics;
484495
};
485496

486497
} // 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

@@ -2552,11 +2554,10 @@ ModuleImport::translateDereferenceableAttr(const llvm::MDNode *node,
25522554
return derefAttr;
25532555
}
25542556

2555-
OwningOpRef<ModuleOp>
2556-
mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
2557-
MLIRContext *context, bool emitExpensiveWarnings,
2558-
bool dropDICompositeTypeElements,
2559-
bool loadAllDialects) {
2557+
OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
2558+
std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
2559+
bool emitExpensiveWarnings, bool dropDICompositeTypeElements,
2560+
bool loadAllDialects, bool preferUnregisteredIntrinsics) {
25602561
// Preload all registered dialects to allow the import to iterate the
25612562
// registered LLVMImportDialectInterface implementations and query the
25622563
// supported LLVM IR constructs before starting the translation. Assumes the
@@ -2573,7 +2574,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
25732574
/*column=*/0)));
25742575

25752576
ModuleImport moduleImport(module.get(), std::move(llvmModule),
2576-
emitExpensiveWarnings, dropDICompositeTypeElements);
2577+
emitExpensiveWarnings, dropDICompositeTypeElements,
2578+
preferUnregisteredIntrinsics);
25772579
if (failed(moduleImport.initializeImportInterface()))
25782580
return {};
25792581
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)