aboutsummaryrefslogtreecommitdiff
path: root/mlir/lib/Target/LLVMIR/ModuleImport.cpp
diff options
context:
space:
mode:
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>2025-05-05 16:27:36 -0700
committerGitHub <noreply@github.com>2025-05-05 16:27:36 -0700
commit7682f663b571830c937156a338017caf0c83e7cd (patch)
tree805c54c5214064b5eef09be659cbacba90cfcc6b /mlir/lib/Target/LLVMIR/ModuleImport.cpp
parent37da5a10f0cf8375c8d1237e9015efae8a8161c1 (diff)
downloadllvm-7682f663b571830c937156a338017caf0c83e7cd.zip
llvm-7682f663b571830c937156a338017caf0c83e7cd.tar.gz
llvm-7682f663b571830c937156a338017caf0c83e7cd.tar.bz2
[MLIR][LLVMIR] Import calls with mismatching signature as indirect call (#135895)
LLVM IR currently [accepts](https://godbolt.org/z/nqnEsW1ja): ``` define void @incompatible_call_and_callee_types() { call void @callee(i64 0) ret void } define void @callee({ptr, i64}, i32) { ret void } ``` This currently fails to import. Even though these constructs are dangerous and probably indicate some ODR violation (or optimization bug), they are "valid" and should be imported into LLVM IR dialect. This PR implements that by using an indirect call to represent it. Translation already works nicely and outputs the same source llvm IR file. The error is now a warning, the tests in `mlir/test/Target/LLVMIR/Import/import-failure.ll` already use `CHECK` lines, so no need to add extra diagnostic tests.
Diffstat (limited to 'mlir/lib/Target/LLVMIR/ModuleImport.cpp')
-rw-r--r--mlir/lib/Target/LLVMIR/ModuleImport.cpp72
1 files changed, 55 insertions, 17 deletions
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 6f56a17..77094d4 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1993,8 +1993,8 @@ ModuleImport::convertCallOperands(llvm::CallBase *callInst,
/// Checks if `callType` and `calleeType` are compatible and can be represented
/// in MLIR.
static LogicalResult
-verifyFunctionTypeCompatibility(LLVMFunctionType callType,
- LLVMFunctionType calleeType) {
+checkFunctionTypeCompatibility(LLVMFunctionType callType,
+ LLVMFunctionType calleeType) {
if (callType.getReturnType() != calleeType.getReturnType())
return failure();
@@ -2020,7 +2020,9 @@ verifyFunctionTypeCompatibility(LLVMFunctionType callType,
}
FailureOr<LLVMFunctionType>
-ModuleImport::convertFunctionType(llvm::CallBase *callInst) {
+ModuleImport::convertFunctionType(llvm::CallBase *callInst,
+ bool &isIncompatibleCall) {
+ isIncompatibleCall = false;
auto castOrFailure = [](Type convertedType) -> FailureOr<LLVMFunctionType> {
auto funcTy = dyn_cast_or_null<LLVMFunctionType>(convertedType);
if (!funcTy)
@@ -2043,11 +2045,14 @@ ModuleImport::convertFunctionType(llvm::CallBase *callInst) {
if (failed(calleeType))
return failure();
- // Compare the types to avoid constructing illegal call/invoke operations.
- if (failed(verifyFunctionTypeCompatibility(*callType, *calleeType))) {
+ // Compare the types and notify users via `isIncompatibleCall` if they are not
+ // compatible.
+ if (failed(checkFunctionTypeCompatibility(*callType, *calleeType))) {
+ isIncompatibleCall = true;
Location loc = translateLoc(callInst->getDebugLoc());
- return emitError(loc) << "incompatible call and callee types: " << *callType
- << " and " << *calleeType;
+ emitWarning(loc) << "incompatible call and callee types: " << *callType
+ << " and " << *calleeType;
+ return callType;
}
return calleeType;
@@ -2164,16 +2169,34 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
/*operand_attrs=*/nullptr)
.getOperation();
}
- FailureOr<LLVMFunctionType> funcTy = convertFunctionType(callInst);
+ bool isIncompatibleCall;
+ FailureOr<LLVMFunctionType> funcTy =
+ convertFunctionType(callInst, isIncompatibleCall);
if (failed(funcTy))
return failure();
- FlatSymbolRefAttr callee = convertCalleeName(callInst);
- auto callOp = builder.create<CallOp>(loc, *funcTy, callee, *operands);
+ FlatSymbolRefAttr callee = nullptr;
+ if (isIncompatibleCall) {
+ // Use an indirect call (in order to represent valid and verifiable LLVM
+ // IR). Build the indirect call by passing an empty `callee` operand and
+ // insert into `operands` to include the indirect call target.
+ FlatSymbolRefAttr calleeSym = convertCalleeName(callInst);
+ Value indirectCallVal = builder.create<LLVM::AddressOfOp>(
+ loc, LLVM::LLVMPointerType::get(context), calleeSym);
+ operands->insert(operands->begin(), indirectCallVal);
+ } else {
+ // Regular direct call using callee name.
+ callee = convertCalleeName(callInst);
+ }
+ CallOp callOp = builder.create<CallOp>(loc, *funcTy, callee, *operands);
+
if (failed(convertCallAttributes(callInst, callOp)))
return failure();
- // Handle parameter and result attributes.
- convertParameterAttributes(callInst, callOp, builder);
+
+ // Handle parameter and result attributes unless it's an incompatible
+ // call.
+ if (!isIncompatibleCall)
+ convertParameterAttributes(callInst, callOp, builder);
return callOp.getOperation();
}();
@@ -2238,12 +2261,25 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
unwindArgs)))
return failure();
- FailureOr<LLVMFunctionType> funcTy = convertFunctionType(invokeInst);
+ bool isIncompatibleInvoke;
+ FailureOr<LLVMFunctionType> funcTy =
+ convertFunctionType(invokeInst, isIncompatibleInvoke);
if (failed(funcTy))
return failure();
- FlatSymbolRefAttr calleeName = convertCalleeName(invokeInst);
-
+ FlatSymbolRefAttr calleeName = nullptr;
+ if (isIncompatibleInvoke) {
+ // Use an indirect invoke (in order to represent valid and verifiable LLVM
+ // IR). Build the indirect invoke by passing an empty `callee` operand and
+ // insert into `operands` to include the indirect invoke target.
+ FlatSymbolRefAttr calleeSym = convertCalleeName(invokeInst);
+ Value indirectInvokeVal = builder.create<LLVM::AddressOfOp>(
+ loc, LLVM::LLVMPointerType::get(context), calleeSym);
+ operands->insert(operands->begin(), indirectInvokeVal);
+ } else {
+ // Regular direct invoke using callee name.
+ calleeName = convertCalleeName(invokeInst);
+ }
// Create the invoke operation. Normal destination block arguments will be
// added later on to handle the case in which the operation result is
// included in this list.
@@ -2254,8 +2290,10 @@ LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {
if (failed(convertInvokeAttributes(invokeInst, invokeOp)))
return failure();
- // Handle parameter and result attributes.
- convertParameterAttributes(invokeInst, invokeOp, builder);
+ // Handle parameter and result attributes unless it's an incompatible
+ // invoke.
+ if (!isIncompatibleInvoke)
+ convertParameterAttributes(invokeInst, invokeOp, builder);
if (!invokeInst->getType()->isVoidTy())
mapValue(inst, invokeOp.getResults().front());