[Mlir-commits] [mlir] [MLIR][LLVMIR] Allow llvm.call and llvm.invoke to use llvm.mlir.alias as callee (PR #189154)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Mar 28 03:00:29 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Mehdi Amini (joker-eph)

<details>
<summary>Changes</summary>

Previously, the verifier for `llvm.call` and `llvm.invoke` would reject calls where the callee was an `llvm.mlir.alias`, reporting that the symbol does not reference a valid LLVM function or IFunc. Similarly, the MLIR-to-LLVM-IR translation had no handling for aliases as callees.

This patch extends both the verifier and the translation to accept `llvm.mlir.alias` as a valid callee for `llvm.call` and `llvm.invoke`, mirroring the existing support for `llvm.mlir.ifunc`. The function type for alias calls is derived from the call operands and result types, and the translation emits a call through the alias global value.

Fixes #<!-- -->147057

Assisted-by: Claude Code

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


4 Files Affected:

- (modified) mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp (+6-1) 
- (modified) mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp (+30-8) 
- (modified) mlir/test/Dialect/LLVMIR/alias.mlir (+21) 
- (modified) mlir/test/Target/LLVMIR/alias.mlir (+23) 


``````````diff
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index ce51884368b69..88b4857b52957 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -1255,10 +1255,15 @@ LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
       fnType = fn.getFunctionType();
     } else if (auto ifunc = dyn_cast<IFuncOp>(callee)) {
       fnType = ifunc.getIFuncType();
+    } else if (isa<AliasOp>(callee)) {
+      // Aliases can alias functions, so calling through an alias is valid.
+      // The function type is determined by the call's operands and result
+      // types.
+      fnType = getCalleeFunctionType();
     } else {
       return emitOpError()
              << "'" << calleeName.getValue()
-             << "' does not reference a valid LLVM function or IFunc";
+             << "' does not reference a valid LLVM function, IFunc, or alias";
     }
   }
 
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 8c3680033b2b9..7900c3ee4f4a2 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -449,12 +449,16 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
         call = builder.CreateCall(function, operandsRef, opBundles);
       } else {
         Operation *moduleOp = parentLLVMModule(&opInst);
-        Operation *ifuncOp =
+        Operation *calleeOp =
             moduleTranslation.symbolTable().lookupSymbolIn(moduleOp, attr);
-        llvm::GlobalValue *ifunc = moduleTranslation.lookupIFunc(ifuncOp);
         llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
             moduleTranslation.convertType(callOp.getCalleeFunctionType()));
-        call = builder.CreateCall(calleeType, ifunc, operandsRef, opBundles);
+        llvm::GlobalValue *calleeGV;
+        if (isa<LLVM::AliasOp>(calleeOp))
+          calleeGV = moduleTranslation.lookupAlias(calleeOp);
+        else
+          calleeGV = moduleTranslation.lookupIFunc(calleeOp);
+        call = builder.CreateCall(calleeType, calleeGV, operandsRef, opBundles);
       }
     } else {
       llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
@@ -639,11 +643,29 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
     ArrayRef<llvm::Value *> operandsRef(operands);
     llvm::InvokeInst *result;
     if (auto attr = opInst.getAttrOfType<FlatSymbolRefAttr>("callee")) {
-      result = builder.CreateInvoke(
-          moduleTranslation.lookupFunction(attr.getValue()),
-          moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
-          moduleTranslation.lookupBlock(invOp.getSuccessor(1)), operandsRef,
-          opBundles);
+      if (llvm::Function *function =
+              moduleTranslation.lookupFunction(attr.getValue())) {
+        result = builder.CreateInvoke(
+            function, moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
+            moduleTranslation.lookupBlock(invOp.getSuccessor(1)), operandsRef,
+            opBundles);
+      } else {
+        Operation *moduleOp = parentLLVMModule(&opInst);
+        Operation *calleeOp =
+            moduleTranslation.symbolTable().lookupSymbolIn(moduleOp, attr);
+        llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
+            moduleTranslation.convertType(invOp.getCalleeFunctionType()));
+        llvm::GlobalValue *calleeGV;
+        if (isa<LLVM::AliasOp>(calleeOp))
+          calleeGV = moduleTranslation.lookupAlias(calleeOp);
+        else
+          calleeGV = moduleTranslation.lookupIFunc(calleeOp);
+        result = builder.CreateInvoke(
+            calleeType, calleeGV,
+            moduleTranslation.lookupBlock(invOp.getSuccessor(0)),
+            moduleTranslation.lookupBlock(invOp.getSuccessor(1)), operandsRef,
+            opBundles);
+      }
     } else {
       llvm::FunctionType *calleeType = llvm::cast<llvm::FunctionType>(
           moduleTranslation.convertType(invOp.getCalleeFunctionType()));
diff --git a/mlir/test/Dialect/LLVMIR/alias.mlir b/mlir/test/Dialect/LLVMIR/alias.mlir
index 7ce54f35a5557..5f578a382a668 100644
--- a/mlir/test/Dialect/LLVMIR/alias.mlir
+++ b/mlir/test/Dialect/LLVMIR/alias.mlir
@@ -139,3 +139,24 @@ llvm.mlir.alias private thread_local unnamed_addr @a30 {dso_local} : i32 {
 // CHECK:   %0 = llvm.mlir.addressof @g30 : !llvm.ptr
 // CHECK:   llvm.return %0 : !llvm.ptr
 // CHECK: }
+
+// -----
+
+// Test that llvm.call and llvm.invoke can use an alias as the callee.
+
+llvm.func @aliased_func() {
+  llvm.return
+}
+
+llvm.mlir.alias external @func_alias {addr_space = 0 : i32} : !llvm.ptr {
+  %0 = llvm.mlir.addressof @aliased_func : !llvm.ptr
+  llvm.return %0 : !llvm.ptr
+}
+
+llvm.func @caller() {
+  llvm.call @func_alias() : () -> ()
+  llvm.return
+}
+
+// CHECK-LABEL: llvm.func @caller()
+// CHECK:         llvm.call @func_alias() : () -> ()
diff --git a/mlir/test/Target/LLVMIR/alias.mlir b/mlir/test/Target/LLVMIR/alias.mlir
index 56832a4900746..c4e67305c2038 100644
--- a/mlir/test/Target/LLVMIR/alias.mlir
+++ b/mlir/test/Target/LLVMIR/alias.mlir
@@ -90,3 +90,26 @@ llvm.mlir.global internal constant @g3() {dso_local} : !llvm.ptr {
 // CHECK: @g3 = internal constant ptr @a2
 // CHECK: @a1 = private alias i32, ptr @g1
 // CHECK: @a2 = private alias ptr, ptr @a1
+
+// -----
+
+// Test that llvm.call and llvm.invoke can use an alias as the callee, and that
+// the translation emits a call through the alias.
+
+llvm.func @aliased_func() {
+  llvm.return
+}
+
+llvm.mlir.alias external @func_alias {addr_space = 0 : i32} : !llvm.ptr {
+  %0 = llvm.mlir.addressof @aliased_func : !llvm.ptr
+  llvm.return %0 : !llvm.ptr
+}
+
+llvm.func @caller() {
+  llvm.call @func_alias() : () -> ()
+  llvm.return
+}
+
+// CHECK: @func_alias = alias ptr, ptr @aliased_func
+// CHECK-LABEL: define void @caller()
+// CHECK:         call void @func_alias()

``````````

</details>


https://github.com/llvm/llvm-project/pull/189154


More information about the Mlir-commits mailing list