Repository: llvm/llvm-project
Pull request #130685: [MLIR][LLVMIR] Import: add flag to prefer using unregistered intrinsics
Author: login: bcardosolopes
Labels: name: mlir:llvm
name: mlir
Created: 2025-03-10T23:45:48Z | Merged: 2025-03-15T01:04:33Z

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`


Diff:
diff --git a/mlir/include/mlir/Target/LLVMIR/Import.h b/mlir/include/mlir/Target/LLVMIR/Import.h
index 4aa8f2ab7d8ce..c6181243a06b0 100644
--- a/mlir/include/mlir/Target/LLVMIR/Import.h
+++ b/mlir/include/mlir/Target/LLVMIR/Import.h
@@ -41,11 +41,15 @@ class ModuleOp;
 /// adversarial inputs.
 /// The `loadAllDialects` flag (default on) will load all dialects in the
 /// context.
-OwningOpRef<ModuleOp>
-translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
-                        MLIRContext *context, bool emitExpensiveWarnings = true,
-                        bool dropDICompositeTypeElements = false,
-                        bool loadAllDialects = true);
+/// The `preferUnregisteredIntrinsics` flag (default off) controls whether to
+/// import all intrinsics using `llvm.intrinsic_call` even if a dialect
+/// registered an explicit intrinsic operation. Warning: passes that rely on
+/// matching explicit intrinsic operations may not work properly if this flag is
+/// enabled.
+OwningOpRef<ModuleOp> translateLLVMIRToModule(
+    std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
+    bool emitExpensiveWarnings = true, bool dropDICompositeTypeElements = false,
+    bool loadAllDialects = true, bool preferUnregisteredIntrinsics = false);
 
 /// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
 /// dialect.
diff --git a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
index 686969f891f20..6a42627e17e60 100644
--- a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
+++ b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
@@ -153,26 +153,7 @@ class LLVMImportInterface
   /// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
   /// Returns failure otherwise.
   LogicalResult convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst,
-                                 LLVM::ModuleImport &moduleImport) const {
-    // Lookup the dialect interface for the given intrinsic.
-    // Verify the intrinsic identifier maps to an actual intrinsic.
-    llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
-    assert(intrinId != llvm::Intrinsic::not_intrinsic);
-
-    // First lookup the intrinsic across different dialects for known
-    // supported conversions, examples include arm-neon, nvm-sve, etc.
-    Dialect *dialect = intrinsicToDialect.lookup(intrinId);
-
-    // No specialized (supported) intrinsics, attempt to generate a generic
-    // version via llvm.call_intrinsic (if available).
-    if (!dialect)
-      return convertUnregisteredIntrinsic(builder, inst, moduleImport);
-
-    // Dispatch the conversion to the dialect interface.
-    const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
-    assert(iface && "expected to find a dialect interface");
-    return iface->convertIntrinsic(builder, inst, moduleImport);
-  }
+                                 LLVM::ModuleImport &moduleImport) const;
 
   /// Returns true if the given LLVM IR intrinsic is convertible to an MLIR
   /// operation.
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index a4d108e349c00..6763a7831f25f 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -47,7 +47,8 @@ class LoopAnnotationImporter;
 class ModuleImport {
 public:
   ModuleImport(ModuleOp mlirModule, std::unique_ptr<llvm::Module> llvmModule,
-               bool emitExpensiveWarnings, bool importEmptyDICompositeTypes);
+               bool emitExpensiveWarnings, bool importEmptyDICompositeTypes,
+               bool preferUnregisteredIntrinsics);
 
   /// Calls the LLVMImportInterface initialization that queries the registered
   /// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds
@@ -284,6 +285,12 @@ class ModuleImport {
   void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
                                   ArrayAttr &resAttr, OpBuilder &builder);
 
+  /// Whether the importer should try to convert all intrinsics to
+  /// llvm.call_intrinsic instead of dialect supported operations.
+  bool useUnregisteredIntrinsicsOnly() const {
+    return preferUnregisteredIntrinsics;
+  }
+
 private:
   /// Clears the accumulated state before processing a new region.
   void clearRegionState() {
@@ -481,6 +488,10 @@ class ModuleImport {
   /// emitted. Avoids generating warnings for unhandled debug intrinsics and
   /// metadata that otherwise dominate the translation time for large inputs.
   bool emitExpensiveWarnings;
+
+  /// An option to control whether the importer should try to convert all
+  /// intrinsics to llvm.call_intrinsic instead of dialect supported operations.
+  bool preferUnregisteredIntrinsics;
 };
 
 } // namespace LLVM
diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
index 0784c3c95e47e..b21db4aa18284 100644
--- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
@@ -37,6 +37,13 @@ void registerFromLLVMIRTranslation() {
           "the LLVM IR import (discouraged: testing only!)"),
       llvm::cl::init(false));
 
+  static llvm::cl::opt<bool> preferUnregisteredIntrinsics(
+      "prefer-unregistered-intrinsics",
+      llvm::cl::desc(
+          "Prefer translating all intrinsics into llvm.call_intrinsic instead "
+          "of using dialect supported intrinsics"),
+      llvm::cl::init(false));
+
   TranslateToMLIRRegistration registration(
       "import-llvm", "Translate LLVMIR to MLIR",
       [](llvm::SourceMgr &sourceMgr,
@@ -60,9 +67,10 @@ void registerFromLLVMIRTranslation() {
         if (llvmModule->IsNewDbgInfoFormat)
           llvmModule->convertFromNewDbgValues();
 
-        return translateLLVMIRToModule(std::move(llvmModule), context,
-                                       emitExpensiveWarnings,
-                                       dropDICompositeTypeElements);
+        return translateLLVMIRToModule(
+            std::move(llvmModule), context, emitExpensiveWarnings,
+            dropDICompositeTypeElements, /*loadAllDialects=*/true,
+            preferUnregisteredIntrinsics);
       },
       [](DialectRegistry &registry) {
         // Register the DLTI dialect used to express the data layout
diff --git a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
index fbf2d709c240c..2d7257a2d9698 100644
--- a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
+++ b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
@@ -62,3 +62,31 @@ LogicalResult mlir::LLVMImportInterface::convertUnregisteredIntrinsic(
 
   return success();
 }
+
+/// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
+/// Returns failure otherwise.
+LogicalResult mlir::LLVMImportInterface::convertIntrinsic(
+    OpBuilder &builder, llvm::CallInst *inst,
+    LLVM::ModuleImport &moduleImport) const {
+  // Lookup the dialect interface for the given intrinsic.
+  // Verify the intrinsic identifier maps to an actual intrinsic.
+  llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
+  assert(intrinId != llvm::Intrinsic::not_intrinsic);
+
+  // First lookup the intrinsic across different dialects for known
+  // supported conversions, examples include arm-neon, nvm-sve, etc.
+  Dialect *dialect = nullptr;
+
+  if (!moduleImport.useUnregisteredIntrinsicsOnly())
+    dialect = intrinsicToDialect.lookup(intrinId);
+
+  // No specialized (supported) intrinsics, attempt to generate a generic
+  // version via llvm.call_intrinsic (if available).
+  if (!dialect)
+    return convertUnregisteredIntrinsic(builder, inst, moduleImport);
+
+  // Dispatch the conversion to the dialect interface.
+  const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
+  assert(iface && "expected to find a dialect interface");
+  return iface->convertIntrinsic(builder, inst, moduleImport);
+}
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index ab187cd05de75..f5dc55277cc12 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -162,7 +162,8 @@ getTopologicallySortedBlocks(ArrayRef<llvm::BasicBlock *> basicBlocks) {
 ModuleImport::ModuleImport(ModuleOp mlirModule,
                            std::unique_ptr<llvm::Module> llvmModule,
                            bool emitExpensiveWarnings,
-                           bool importEmptyDICompositeTypes)
+                           bool importEmptyDICompositeTypes,
+                           bool preferUnregisteredIntrinsics)
     : builder(mlirModule->getContext()), context(mlirModule->getContext()),
       mlirModule(mlirModule), llvmModule(std::move(llvmModule)),
       iface(mlirModule->getContext()),
@@ -171,7 +172,8 @@ ModuleImport::ModuleImport(ModuleOp mlirModule,
           mlirModule, importEmptyDICompositeTypes)),
       loopAnnotationImporter(
           std::make_unique<LoopAnnotationImporter>(*this, builder)),
-      emitExpensiveWarnings(emitExpensiveWarnings) {
+      emitExpensiveWarnings(emitExpensiveWarnings),
+      preferUnregisteredIntrinsics(preferUnregisteredIntrinsics) {
   builder.setInsertionPointToStart(mlirModule.getBody());
 }
 
@@ -2552,11 +2554,10 @@ ModuleImport::translateDereferenceableAttr(const llvm::MDNode *node,
   return derefAttr;
 }
 
-OwningOpRef<ModuleOp>
-mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
-                              MLIRContext *context, bool emitExpensiveWarnings,
-                              bool dropDICompositeTypeElements,
-                              bool loadAllDialects) {
+OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
+    std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
+    bool emitExpensiveWarnings, bool dropDICompositeTypeElements,
+    bool loadAllDialects, bool preferUnregisteredIntrinsics) {
   // Preload all registered dialects to allow the import to iterate the
   // registered LLVMImportDialectInterface implementations and query the
   // supported LLVM IR constructs before starting the translation. Assumes the
@@ -2573,7 +2574,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
       /*column=*/0)));
 
   ModuleImport moduleImport(module.get(), std::move(llvmModule),
-                            emitExpensiveWarnings, dropDICompositeTypeElements);
+                            emitExpensiveWarnings, dropDICompositeTypeElements,
+                            preferUnregisteredIntrinsics);
   if (failed(moduleImport.initializeImportInterface()))
     return {};
   if (failed(moduleImport.convertDataLayout()))
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll
new file mode 100644
index 0000000000000..778289469c4a5
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll
@@ -0,0 +1,10 @@
+; RUN: mlir-translate -import-llvm -prefer-unregistered-intrinsics %s | FileCheck %s
+
+; CHECK-LABEL: llvm.func @lifetime
+define void @lifetime(ptr %0) {
+  ; CHECK: llvm.call_intrinsic "llvm.lifetime.start.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
+  call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %0)
+  ; CHECK: llvm.call_intrinsic "llvm.lifetime.end.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
+  call void @llvm.lifetime.end.p0(i64 32, ptr nonnull %0)
+  ret void
+}


Reviews:
user: login: gysit
body: I think we need to put a fat warning on the flag since this may fail if passes rely on detecting the explicit intrinsic operation.

I also wonder if we should move the handling of the unregistered intrinsics in ModuleImport? It feels like the right place given we need to leak more an more information to the interface. Or is there a need to handle them in the interface?
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T07:40:01Z
user: login: bcardosolopes
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T19:01:08Z
user: login: gysit
body: Thanks for tracking the issue.

LGTM modulo last nits.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T07:24:32Z

Review comments:
diff_hunk: @@ -41,11 +41,13 @@ class ModuleOp;
 /// adversarial inputs.
 /// The `loadAllDialects` flag (default on) will load all dialects in the
 /// context.
-OwningOpRef<ModuleOp>
-translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
-                        MLIRContext *context, bool emitExpensiveWarnings = true,
-                        bool dropDICompositeTypeElements = false,
-                        bool loadAllDialects = true);
+/// The `preferUnregisteredIntrinsics` flag (default off) controls whether to
+/// prefer generic version of imported intrinsics with `llvm.intrinsic_call`
+/// than using versions supported by a dialects.
path: mlir/include/mlir/Target/LLVMIR/Import.h
user: login: gysit
body: ```suggestion
/// import all intrinsics using `llvm.intrinsic_call` even if a dialect registered an explicit intrinsic operation.
/// Warning: passes that rely on matching explicit intrinsic operations may not work properly if this flag is enabled.
```
I think we should add a warning here that this may not work with passes that rely on matching explicit intrinsics. Upstream there is probably no problem, but downstream we have passes that need to match specific intrinsic.

created_at: 2025-03-11T07:31:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -277,6 +278,12 @@ class ModuleImport {
   void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
                                   ArrayAttr &resAttr, OpBuilder &builder);
 
+  /// Whether the importer should try to convert all intrinsics to
+  /// llvm.call_intrinsic instead of dialect supported operations.
+  bool useUnregisteredIntrinsicsOnly() const {
path: mlir/include/mlir/Target/LLVMIR/ModuleImport.h
user: login: gysit
body: I wonder if we should start moving the entire unregistered intrinsic handling back into module import:

https://github.com/llvm/llvm-project/blob/f120b0d6d2629e226e6fa75974fbd17f46206bca/mlir/lib/Target/LLVMIR/ModuleImport.cpp#L1651C1-L1652C1

I this function we could try to convert with a dialect interface if preferUnregisteredIntrinsics is not set and then fallback to the translation with call_intrinsic? That way we can make a couple of functions internal to the import and the interface does not need to deal with the unregistered intrinsics?
created_at: 2025-03-11T07:37:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -277,6 +278,12 @@ class ModuleImport {
   void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
                                   ArrayAttr &resAttr, OpBuilder &builder);
 
+  /// Whether the importer should try to convert all intrinsics to
+  /// llvm.call_intrinsic instead of dialect supported operations.
+  bool useUnregisteredIntrinsicsOnly() const {
path: mlir/include/mlir/Target/LLVMIR/ModuleImport.h
user: login: bcardosolopes
body: Looks like follow up work attempt? (I do volunteer, but I don't want to mix unrelated work here)
created_at: 2025-03-11T19:01:08Z
author_association: MEMBER
diff_hunk: @@ -474,6 +481,10 @@ class ModuleImport {
   /// emitted. Avoids generating warnings for unhandled debug intrinsics and
   /// metadata that otherwise dominate the translation time for large inputs.
   bool emitExpensiveWarnings;
+
+  /// An option to control whether to disable supported intrinsic support in
+  /// favor a more generic version via `llvm.intrinsic_call`.
path: mlir/include/mlir/Target/LLVMIR/ModuleImport.h
user: login: gysit
body: ```suggestion
  /// An option to control whether the importer should try to convert all intrinsics to
  /// llvm.call_intrinsic instead of dialect supported operations.
```
nit I prefer the comment from the function.
created_at: 2025-03-14T07:22:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -37,6 +37,13 @@ void registerFromLLVMIRTranslation() {
           "the LLVM IR import (discouraged: testing only!)"),
       llvm::cl::init(false));
 
+  static llvm::cl::opt<bool> preferUnregisteredIntrinsics(
+      "prefer-unregistered-intrinsics",
+      llvm::cl::desc(
+          "Prefer translation all intrinsics into llvm.call_intrinsic instead "
path: mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
user: login: gysit
body: ```suggestion
          "Prefer translating all intrinsics into llvm.call_intrinsic instead "
```
nit:
created_at: 2025-03-14T07:23:56Z
author_association: CONTRIBUTOR

PR comments:
user: login: llvmbot
created_at: 2025-03-10T23:46:21Z
body: 
<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-llvm

Author: Bruno Cardoso Lopes (bcardosolopes)

<details>
<summary>Changes</summary>

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`

---
Full diff: https://github.com/llvm/llvm-project/pull/130685.diff


7 Files Affected:

- (modified) mlir/include/mlir/Target/LLVMIR/Import.h (+7-5) 
- (modified) mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h (+1-20) 
- (modified) mlir/include/mlir/Target/LLVMIR/ModuleImport.h (+12-1) 
- (modified) mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp (+11-3) 
- (modified) mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp (+28) 
- (modified) mlir/lib/Target/LLVMIR/ModuleImport.cpp (+10-8) 
- (added) mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll (+10) 


``````````diff
diff --git a/mlir/include/mlir/Target/LLVMIR/Import.h b/mlir/include/mlir/Target/LLVMIR/Import.h
index 4aa8f2ab7d8ce..2fef44947b6c2 100644
--- a/mlir/include/mlir/Target/LLVMIR/Import.h
+++ b/mlir/include/mlir/Target/LLVMIR/Import.h
@@ -41,11 +41,13 @@ class ModuleOp;
 /// adversarial inputs.
 /// The `loadAllDialects` flag (default on) will load all dialects in the
 /// context.
-OwningOpRef<ModuleOp>
-translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
-                        MLIRContext *context, bool emitExpensiveWarnings = true,
-                        bool dropDICompositeTypeElements = false,
-                        bool loadAllDialects = true);
+/// The `preferUnregisteredIntrinsics` flag (default off) controls whether to
+/// prefer generic version of imported intrinsics with `llvm.intrinsic_call`
+/// than using versions supported by a dialects.
+OwningOpRef<ModuleOp> translateLLVMIRToModule(
+    std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
+    bool emitExpensiveWarnings = true, bool dropDICompositeTypeElements = false,
+    bool loadAllDialects = true, bool preferUnregisteredIntrinsics = false);
 
 /// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
 /// dialect.
diff --git a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
index 686969f891f20..6a42627e17e60 100644
--- a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
+++ b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
@@ -153,26 +153,7 @@ class LLVMImportInterface
   /// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
   /// Returns failure otherwise.
   LogicalResult convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst,
-                                 LLVM::ModuleImport &moduleImport) const {
-    // Lookup the dialect interface for the given intrinsic.
-    // Verify the intrinsic identifier maps to an actual intrinsic.
-    llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
-    assert(intrinId != llvm::Intrinsic::not_intrinsic);
-
-    // First lookup the intrinsic across different dialects for known
-    // supported conversions, examples include arm-neon, nvm-sve, etc.
-    Dialect *dialect = intrinsicToDialect.lookup(intrinId);
-
-    // No specialized (supported) intrinsics, attempt to generate a generic
-    // version via llvm.call_intrinsic (if available).
-    if (!dialect)
-      return convertUnregisteredIntrinsic(builder, inst, moduleImport);
-
-    // Dispatch the conversion to the dialect interface.
-    const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
-    assert(iface && "expected to find a dialect interface");
-    return iface->convertIntrinsic(builder, inst, moduleImport);
-  }
+                                 LLVM::ModuleImport &moduleImport) const;
 
   /// Returns true if the given LLVM IR intrinsic is convertible to an MLIR
   /// operation.
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index c0af924e0aecd..3e239e0112afc 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -47,7 +47,8 @@ class LoopAnnotationImporter;
 class ModuleImport {
 public:
   ModuleImport(ModuleOp mlirModule, std::unique_ptr<llvm::Module> llvmModule,
-               bool emitExpensiveWarnings, bool importEmptyDICompositeTypes);
+               bool emitExpensiveWarnings, bool importEmptyDICompositeTypes,
+               bool preferUnregisteredIntrinsics);
 
   /// Calls the LLVMImportInterface initialization that queries the registered
   /// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds
@@ -277,6 +278,12 @@ class ModuleImport {
   void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
                                   ArrayAttr &resAttr, OpBuilder &builder);
 
+  /// Whether the importer should try to convert all intrinsics to
+  /// llvm.call_intrinsic instead of dialect supported operations.
+  bool useUnregisteredIntrinsicsOnly() const {
+    return preferUnregisteredIntrinsics;
+  }
+
 private:
   /// Clears the accumulated state before processing a new region.
   void clearRegionState() {
@@ -474,6 +481,10 @@ class ModuleImport {
   /// emitted. Avoids generating warnings for unhandled debug intrinsics and
   /// metadata that otherwise dominate the translation time for large inputs.
   bool emitExpensiveWarnings;
+
+  /// An option to control whether to disable supported intrinsic support in
+  /// favor a more generic version via `llvm.intrinsic_call`.
+  bool preferUnregisteredIntrinsics;
 };
 
 } // namespace LLVM
diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
index 0784c3c95e47e..b10fdd6f37f79 100644
--- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
@@ -37,6 +37,13 @@ void registerFromLLVMIRTranslation() {
           "the LLVM IR import (discouraged: testing only!)"),
       llvm::cl::init(false));
 
+  static llvm::cl::opt<bool> preferUnregisteredIntrinsics(
+      "prefer-unregistered-intrinsics",
+      llvm::cl::desc(
+          "Prefer translation all intrinsics into llvm.call_intrinsic instead "
+          "of using dialect supported intrinsics"),
+      llvm::cl::init(false));
+
   TranslateToMLIRRegistration registration(
       "import-llvm", "Translate LLVMIR to MLIR",
       [](llvm::SourceMgr &sourceMgr,
@@ -60,9 +67,10 @@ void registerFromLLVMIRTranslation() {
         if (llvmModule->IsNewDbgInfoFormat)
           llvmModule->convertFromNewDbgValues();
 
-        return translateLLVMIRToModule(std::move(llvmModule), context,
-                                       emitExpensiveWarnings,
-                                       dropDICompositeTypeElements);
+        return translateLLVMIRToModule(
+            std::move(llvmModule), context, emitExpensiveWarnings,
+            dropDICompositeTypeElements, /*loadAllDialects=*/true,
+            preferUnregisteredIntrinsics);
       },
       [](DialectRegistry &registry) {
         // Register the DLTI dialect used to express the data layout
diff --git a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
index fbf2d709c240c..2d7257a2d9698 100644
--- a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
+++ b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
@@ -62,3 +62,31 @@ LogicalResult mlir::LLVMImportInterface::convertUnregisteredIntrinsic(
 
   return success();
 }
+
+/// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
+/// Returns failure otherwise.
+LogicalResult mlir::LLVMImportInterface::convertIntrinsic(
+    OpBuilder &builder, llvm::CallInst *inst,
+    LLVM::ModuleImport &moduleImport) const {
+  // Lookup the dialect interface for the given intrinsic.
+  // Verify the intrinsic identifier maps to an actual intrinsic.
+  llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
+  assert(intrinId != llvm::Intrinsic::not_intrinsic);
+
+  // First lookup the intrinsic across different dialects for known
+  // supported conversions, examples include arm-neon, nvm-sve, etc.
+  Dialect *dialect = nullptr;
+
+  if (!moduleImport.useUnregisteredIntrinsicsOnly())
+    dialect = intrinsicToDialect.lookup(intrinId);
+
+  // No specialized (supported) intrinsics, attempt to generate a generic
+  // version via llvm.call_intrinsic (if available).
+  if (!dialect)
+    return convertUnregisteredIntrinsic(builder, inst, moduleImport);
+
+  // Dispatch the conversion to the dialect interface.
+  const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
+  assert(iface && "expected to find a dialect interface");
+  return iface->convertIntrinsic(builder, inst, moduleImport);
+}
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index f24c2777cbbb8..0f156779b46b5 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -162,7 +162,8 @@ getTopologicallySortedBlocks(ArrayRef<llvm::BasicBlock *> basicBlocks) {
 ModuleImport::ModuleImport(ModuleOp mlirModule,
                            std::unique_ptr<llvm::Module> llvmModule,
                            bool emitExpensiveWarnings,
-                           bool importEmptyDICompositeTypes)
+                           bool importEmptyDICompositeTypes,
+                           bool preferUnregisteredIntrinsics)
     : builder(mlirModule->getContext()), context(mlirModule->getContext()),
       mlirModule(mlirModule), llvmModule(std::move(llvmModule)),
       iface(mlirModule->getContext()),
@@ -171,7 +172,8 @@ ModuleImport::ModuleImport(ModuleOp mlirModule,
           mlirModule, importEmptyDICompositeTypes)),
       loopAnnotationImporter(
           std::make_unique<LoopAnnotationImporter>(*this, builder)),
-      emitExpensiveWarnings(emitExpensiveWarnings) {
+      emitExpensiveWarnings(emitExpensiveWarnings),
+      preferUnregisteredIntrinsics(preferUnregisteredIntrinsics) {
   builder.setInsertionPointToStart(mlirModule.getBody());
 }
 
@@ -2527,11 +2529,10 @@ ModuleImport::translateLoopAnnotationAttr(const llvm::MDNode *node,
   return loopAnnotationImporter->translateLoopAnnotation(node, loc);
 }
 
-OwningOpRef<ModuleOp>
-mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
-                              MLIRContext *context, bool emitExpensiveWarnings,
-                              bool dropDICompositeTypeElements,
-                              bool loadAllDialects) {
+OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
+    std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
+    bool emitExpensiveWarnings, bool dropDICompositeTypeElements,
+    bool loadAllDialects, bool preferUnregisteredIntrinsics) {
   // Preload all registered dialects to allow the import to iterate the
   // registered LLVMImportDialectInterface implementations and query the
   // supported LLVM IR constructs before starting the translation. Assumes the
@@ -2548,7 +2549,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
       /*column=*/0)));
 
   ModuleImport moduleImport(module.get(), std::move(llvmModule),
-                            emitExpensiveWarnings, dropDICompositeTypeElements);
+                            emitExpensiveWarnings, dropDICompositeTypeElements,
+                            preferUnregisteredIntrinsics);
   if (failed(moduleImport.initializeImportInterface()))
     return {};
   if (failed(moduleImport.convertDataLayout()))
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll
new file mode 100644
index 0000000000000..778289469c4a5
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll
@@ -0,0 +1,10 @@
+; RUN: mlir-translate -import-llvm -prefer-unregistered-intrinsics %s | FileCheck %s
+
+; CHECK-LABEL: llvm.func @lifetime
+define void @lifetime(ptr %0) {
+  ; CHECK: llvm.call_intrinsic "llvm.lifetime.start.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
+  call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %0)
+  ; CHECK: llvm.call_intrinsic "llvm.lifetime.end.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
+  call void @llvm.lifetime.end.p0(i64 32, ptr nonnull %0)
+  ret void
+}

``````````

</details>

author_association: MEMBER
user: login: llvmbot
created_at: 2025-03-10T23:46:22Z
body: 
<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Bruno Cardoso Lopes (bcardosolopes)

<details>
<summary>Changes</summary>

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`

---
Full diff: https://github.com/llvm/llvm-project/pull/130685.diff


7 Files Affected:

- (modified) mlir/include/mlir/Target/LLVMIR/Import.h (+7-5) 
- (modified) mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h (+1-20) 
- (modified) mlir/include/mlir/Target/LLVMIR/ModuleImport.h (+12-1) 
- (modified) mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp (+11-3) 
- (modified) mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp (+28) 
- (modified) mlir/lib/Target/LLVMIR/ModuleImport.cpp (+10-8) 
- (added) mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll (+10) 


``````````diff
diff --git a/mlir/include/mlir/Target/LLVMIR/Import.h b/mlir/include/mlir/Target/LLVMIR/Import.h
index 4aa8f2ab7d8ce..2fef44947b6c2 100644
--- a/mlir/include/mlir/Target/LLVMIR/Import.h
+++ b/mlir/include/mlir/Target/LLVMIR/Import.h
@@ -41,11 +41,13 @@ class ModuleOp;
 /// adversarial inputs.
 /// The `loadAllDialects` flag (default on) will load all dialects in the
 /// context.
-OwningOpRef<ModuleOp>
-translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
-                        MLIRContext *context, bool emitExpensiveWarnings = true,
-                        bool dropDICompositeTypeElements = false,
-                        bool loadAllDialects = true);
+/// The `preferUnregisteredIntrinsics` flag (default off) controls whether to
+/// prefer generic version of imported intrinsics with `llvm.intrinsic_call`
+/// than using versions supported by a dialects.
+OwningOpRef<ModuleOp> translateLLVMIRToModule(
+    std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
+    bool emitExpensiveWarnings = true, bool dropDICompositeTypeElements = false,
+    bool loadAllDialects = true, bool preferUnregisteredIntrinsics = false);
 
 /// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
 /// dialect.
diff --git a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
index 686969f891f20..6a42627e17e60 100644
--- a/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
+++ b/mlir/include/mlir/Target/LLVMIR/LLVMImportInterface.h
@@ -153,26 +153,7 @@ class LLVMImportInterface
   /// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
   /// Returns failure otherwise.
   LogicalResult convertIntrinsic(OpBuilder &builder, llvm::CallInst *inst,
-                                 LLVM::ModuleImport &moduleImport) const {
-    // Lookup the dialect interface for the given intrinsic.
-    // Verify the intrinsic identifier maps to an actual intrinsic.
-    llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
-    assert(intrinId != llvm::Intrinsic::not_intrinsic);
-
-    // First lookup the intrinsic across different dialects for known
-    // supported conversions, examples include arm-neon, nvm-sve, etc.
-    Dialect *dialect = intrinsicToDialect.lookup(intrinId);
-
-    // No specialized (supported) intrinsics, attempt to generate a generic
-    // version via llvm.call_intrinsic (if available).
-    if (!dialect)
-      return convertUnregisteredIntrinsic(builder, inst, moduleImport);
-
-    // Dispatch the conversion to the dialect interface.
-    const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
-    assert(iface && "expected to find a dialect interface");
-    return iface->convertIntrinsic(builder, inst, moduleImport);
-  }
+                                 LLVM::ModuleImport &moduleImport) const;
 
   /// Returns true if the given LLVM IR intrinsic is convertible to an MLIR
   /// operation.
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
index c0af924e0aecd..3e239e0112afc 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h
@@ -47,7 +47,8 @@ class LoopAnnotationImporter;
 class ModuleImport {
 public:
   ModuleImport(ModuleOp mlirModule, std::unique_ptr<llvm::Module> llvmModule,
-               bool emitExpensiveWarnings, bool importEmptyDICompositeTypes);
+               bool emitExpensiveWarnings, bool importEmptyDICompositeTypes,
+               bool preferUnregisteredIntrinsics);
 
   /// Calls the LLVMImportInterface initialization that queries the registered
   /// dialect interfaces for the supported LLVM IR intrinsics and metadata kinds
@@ -277,6 +278,12 @@ class ModuleImport {
   void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr,
                                   ArrayAttr &resAttr, OpBuilder &builder);
 
+  /// Whether the importer should try to convert all intrinsics to
+  /// llvm.call_intrinsic instead of dialect supported operations.
+  bool useUnregisteredIntrinsicsOnly() const {
+    return preferUnregisteredIntrinsics;
+  }
+
 private:
   /// Clears the accumulated state before processing a new region.
   void clearRegionState() {
@@ -474,6 +481,10 @@ class ModuleImport {
   /// emitted. Avoids generating warnings for unhandled debug intrinsics and
   /// metadata that otherwise dominate the translation time for large inputs.
   bool emitExpensiveWarnings;
+
+  /// An option to control whether to disable supported intrinsic support in
+  /// favor a more generic version via `llvm.intrinsic_call`.
+  bool preferUnregisteredIntrinsics;
 };
 
 } // namespace LLVM
diff --git a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
index 0784c3c95e47e..b10fdd6f37f79 100644
--- a/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
+++ b/mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp
@@ -37,6 +37,13 @@ void registerFromLLVMIRTranslation() {
           "the LLVM IR import (discouraged: testing only!)"),
       llvm::cl::init(false));
 
+  static llvm::cl::opt<bool> preferUnregisteredIntrinsics(
+      "prefer-unregistered-intrinsics",
+      llvm::cl::desc(
+          "Prefer translation all intrinsics into llvm.call_intrinsic instead "
+          "of using dialect supported intrinsics"),
+      llvm::cl::init(false));
+
   TranslateToMLIRRegistration registration(
       "import-llvm", "Translate LLVMIR to MLIR",
       [](llvm::SourceMgr &sourceMgr,
@@ -60,9 +67,10 @@ void registerFromLLVMIRTranslation() {
         if (llvmModule->IsNewDbgInfoFormat)
           llvmModule->convertFromNewDbgValues();
 
-        return translateLLVMIRToModule(std::move(llvmModule), context,
-                                       emitExpensiveWarnings,
-                                       dropDICompositeTypeElements);
+        return translateLLVMIRToModule(
+            std::move(llvmModule), context, emitExpensiveWarnings,
+            dropDICompositeTypeElements, /*loadAllDialects=*/true,
+            preferUnregisteredIntrinsics);
       },
       [](DialectRegistry &registry) {
         // Register the DLTI dialect used to express the data layout
diff --git a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
index fbf2d709c240c..2d7257a2d9698 100644
--- a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
+++ b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp
@@ -62,3 +62,31 @@ LogicalResult mlir::LLVMImportInterface::convertUnregisteredIntrinsic(
 
   return success();
 }
+
+/// Converts the LLVM intrinsic to an MLIR operation if a conversion exists.
+/// Returns failure otherwise.
+LogicalResult mlir::LLVMImportInterface::convertIntrinsic(
+    OpBuilder &builder, llvm::CallInst *inst,
+    LLVM::ModuleImport &moduleImport) const {
+  // Lookup the dialect interface for the given intrinsic.
+  // Verify the intrinsic identifier maps to an actual intrinsic.
+  llvm::Intrinsic::ID intrinId = inst->getIntrinsicID();
+  assert(intrinId != llvm::Intrinsic::not_intrinsic);
+
+  // First lookup the intrinsic across different dialects for known
+  // supported conversions, examples include arm-neon, nvm-sve, etc.
+  Dialect *dialect = nullptr;
+
+  if (!moduleImport.useUnregisteredIntrinsicsOnly())
+    dialect = intrinsicToDialect.lookup(intrinId);
+
+  // No specialized (supported) intrinsics, attempt to generate a generic
+  // version via llvm.call_intrinsic (if available).
+  if (!dialect)
+    return convertUnregisteredIntrinsic(builder, inst, moduleImport);
+
+  // Dispatch the conversion to the dialect interface.
+  const LLVMImportDialectInterface *iface = getInterfaceFor(dialect);
+  assert(iface && "expected to find a dialect interface");
+  return iface->convertIntrinsic(builder, inst, moduleImport);
+}
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index f24c2777cbbb8..0f156779b46b5 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -162,7 +162,8 @@ getTopologicallySortedBlocks(ArrayRef<llvm::BasicBlock *> basicBlocks) {
 ModuleImport::ModuleImport(ModuleOp mlirModule,
                            std::unique_ptr<llvm::Module> llvmModule,
                            bool emitExpensiveWarnings,
-                           bool importEmptyDICompositeTypes)
+                           bool importEmptyDICompositeTypes,
+                           bool preferUnregisteredIntrinsics)
     : builder(mlirModule->getContext()), context(mlirModule->getContext()),
       mlirModule(mlirModule), llvmModule(std::move(llvmModule)),
       iface(mlirModule->getContext()),
@@ -171,7 +172,8 @@ ModuleImport::ModuleImport(ModuleOp mlirModule,
           mlirModule, importEmptyDICompositeTypes)),
       loopAnnotationImporter(
           std::make_unique<LoopAnnotationImporter>(*this, builder)),
-      emitExpensiveWarnings(emitExpensiveWarnings) {
+      emitExpensiveWarnings(emitExpensiveWarnings),
+      preferUnregisteredIntrinsics(preferUnregisteredIntrinsics) {
   builder.setInsertionPointToStart(mlirModule.getBody());
 }
 
@@ -2527,11 +2529,10 @@ ModuleImport::translateLoopAnnotationAttr(const llvm::MDNode *node,
   return loopAnnotationImporter->translateLoopAnnotation(node, loc);
 }
 
-OwningOpRef<ModuleOp>
-mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
-                              MLIRContext *context, bool emitExpensiveWarnings,
-                              bool dropDICompositeTypeElements,
-                              bool loadAllDialects) {
+OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(
+    std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,
+    bool emitExpensiveWarnings, bool dropDICompositeTypeElements,
+    bool loadAllDialects, bool preferUnregisteredIntrinsics) {
   // Preload all registered dialects to allow the import to iterate the
   // registered LLVMImportDialectInterface implementations and query the
   // supported LLVM IR constructs before starting the translation. Assumes the
@@ -2548,7 +2549,8 @@ mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
       /*column=*/0)));
 
   ModuleImport moduleImport(module.get(), std::move(llvmModule),
-                            emitExpensiveWarnings, dropDICompositeTypeElements);
+                            emitExpensiveWarnings, dropDICompositeTypeElements,
+                            preferUnregisteredIntrinsics);
   if (failed(moduleImport.initializeImportInterface()))
     return {};
   if (failed(moduleImport.convertDataLayout()))
diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll
new file mode 100644
index 0000000000000..778289469c4a5
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic-prefer-unregistered.ll
@@ -0,0 +1,10 @@
+; RUN: mlir-translate -import-llvm -prefer-unregistered-intrinsics %s | FileCheck %s
+
+; CHECK-LABEL: llvm.func @lifetime
+define void @lifetime(ptr %0) {
+  ; CHECK: llvm.call_intrinsic "llvm.lifetime.start.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
+  call void @llvm.lifetime.start.p0(i64 16, ptr nonnull %0)
+  ; CHECK: llvm.call_intrinsic "llvm.lifetime.end.p0"({{.*}}, %arg0) : (i64, !llvm.ptr {llvm.nonnull}) -> !llvm.void
+  call void @llvm.lifetime.end.p0(i64 32, ptr nonnull %0)
+  ret void
+}

``````````

</details>

author_association: MEMBER
user: login: bcardosolopes
created_at: 2025-03-11T18:59:07Z
body: > I think we need to put a fat warning on the flag since this may fail if passes rely on detecting the explicit intrinsic operation.

Do you mean emitting an warning or just writing a warning in a comment? If the former: we might want to use LLVM IR without the supported intrinsics in production (i.e. not only for testing) - in which case the warning feels like a constant annoyance / misleading. Should I introduce an extra flag for controlling such warning?

> I also wonder if we should move the handling of the unregistered intrinsics in ModuleImport? 

Hmm, while working on the PR that added the unregistered intrinsics you asked similar and I couldn't easily make it happen - there were complications in the interaction between querying other dialects via interfaces along side the fallback mechanism which is LLVM dialect only. It's probably possible but might need moving enough pieces around that should be done in its own PR.
author_association: MEMBER
user: login: gysit
created_at: 2025-03-11T19:03:36Z
body: > Do you mean emitting an warning or just writing a warning in a comment? If the former: we might want to use LLVM IR without the supported intrinsics in production (i.e. not only for testing) - in which case the warning feels like a constant annoyance / misleading. Should I introduce an extra flag for controlling such warning?

I meant just writing a warning in the comment (basically something like the one I suggested above)! It is a potential foot gun if you do transformations on the IR that expect explicit intrinsics. 

author_association: CONTRIBUTOR
user: login: gysit
created_at: 2025-03-11T19:13:03Z
body: > Hmm, while working on the PR that added the unregistered intrinsics you asked similar and I couldn't easily make it happen - there were complications in the interaction between querying other dialects via interfaces along side the fallback mechanism which is LLVM dialect only. It's probably possible but might need moving enough pieces around that should be done in its own PR.

Couldn't interface do the following:
- Try to convert intrinsics to registered intrinsics in one of the dialects.
- Return failure if it couldn't convert the intrinsic.
(no handling for unregistered intrinsics at all)

The module import could then:
- Try to convert the intrinsic to an operation using the interface (except of course your new flag is set).
- If the conversion fails instead of emitting en error just translate to llvm intrinsic call.

I would expect that this works quite smoothly except there is some issue with the error handling. I coming back to it bcs the interface should usually do the dialect specific stuff while the import itself contains most of the LLVM IR specific stuff. 

Anyway let's postpone to a later pr.
author_association: CONTRIBUTOR
user: login: bcardosolopes
created_at: 2025-03-14T01:33:23Z
body: Created an issue to track next steps. Fixed comment and added a warning.
author_association: MEMBER