[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