[MLIR][LLVM] Preserve default function attributes on invokes (#212263)

Represent `default_func_attrs` on `LLVM::InvokeOp` and translate the
collection onto the generated LLVM invoke instruction. Preserve default
call-site attributes when throwing calls are lowered through the LLVM
dialect, including CIR `try_call` operations.
This commit is contained in:
Akimasa Watanuki 2026-07-28 16:09:11 +09:00 committed by GitHub
parent 022bf7ba97
commit 9ccf2a81a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 56 additions and 4 deletions

View file

@ -0,0 +1,26 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -default-function-attr "key=value" -default-function-attr "just_key" -fcxx-exceptions -fexceptions -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -default-function-attr "key=value" -default-function-attr "just_key" -fcxx-exceptions -fexceptions -fclangir -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -default-function-attr "key=value" -default-function-attr "just_key" -fcxx-exceptions -fexceptions -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
extern "C" void may_throw();
// CIR-LABEL: cir.func {{.*}}@caller()
// CIR: cir.call @may_throw()
// LLVM-LABEL: define{{.*}}@caller()
// LLVM: invoke void @may_throw() #[[ATTRS:[0-9]+]]
extern "C" void caller() {
try {
may_throw();
} catch (...) {
}
}
// CIR-SAME: default_func_attrs
// CIR-SAME: just_key
// CIR-SAME: key = "value"
// LLVM: attributes #[[ATTRS]]
// LLVM-SAME: "just_key"
// LLVM-SAME: "key"="value"

View file

@ -743,6 +743,7 @@ def LLVM_InvokeOp
Variadic<LLVM_Type>:$unwindDestOperands,
OptionalAttr<DenseI32ArrayAttr>:$branch_weights,
DefaultValuedAttr<CConv, "CConv::C">:$CConv,
OptionalAttr<DictionaryAttr>:$default_func_attrs,
VariadicOfVariadic<LLVM_Type,
"op_bundle_sizes">:$op_bundle_operands,
DenseI32ArrayAttr:$op_bundle_sizes,

View file

@ -1569,7 +1569,8 @@ void InvokeOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func,
build(builder, state, getCallOpResultTypes(calleeType),
getCallOpVarCalleeType(calleeType), SymbolRefAttr::get(func), ops,
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, normalOps, unwindOps,
nullptr, nullptr, {}, {}, normal, unwind);
nullptr, nullptr, /*default_func_attrs=*/nullptr, {}, {}, normal,
unwind);
}
void InvokeOp::build(OpBuilder &builder, OperationState &state, TypeRange tys,
@ -1578,8 +1579,8 @@ void InvokeOp::build(OpBuilder &builder, OperationState &state, TypeRange tys,
ValueRange unwindOps) {
build(builder, state, tys,
/*var_callee_type=*/nullptr, callee, ops, /*arg_attrs=*/nullptr,
/*res_attrs=*/nullptr, normalOps, unwindOps, nullptr, nullptr, {}, {},
normal, unwind);
/*res_attrs=*/nullptr, normalOps, unwindOps, nullptr, nullptr,
/*default_func_attrs=*/nullptr, {}, {}, normal, unwind);
}
void InvokeOp::build(OpBuilder &builder, OperationState &state,
@ -1589,7 +1590,8 @@ void InvokeOp::build(OpBuilder &builder, OperationState &state,
build(builder, state, getCallOpResultTypes(calleeType),
getCallOpVarCalleeType(calleeType), callee, ops,
/*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, normalOps, unwindOps,
nullptr, nullptr, {}, {}, normal, unwind);
nullptr, nullptr, /*default_func_attrs=*/nullptr, {}, {}, normal,
unwind);
}
SuccessorOperands InvokeOp::getSuccessorOperands(unsigned index) {

View file

@ -689,6 +689,9 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
operandsRef.drop_front(), opBundles);
}
result->setCallingConv(convertCConvToLLVM(invOp.getCConv()));
moduleTranslation.convertFunctionAttrCollection(
invOp.getDefaultFuncAttrsAttr(), result,
ModuleTranslation::convertDefaultFuncAttr);
if (failed(moduleTranslation.convertArgAndResultAttrs(invOp, result)))
return failure();
moduleTranslation.mapBranch(invOp, result);

View file

@ -3131,6 +3131,26 @@ llvm.func @default_func_attrs_call() {
// -----
llvm.func @f()
llvm.func @__gxx_personality_v0(...) -> i32
// CHECK-LABEL: @default_func_attrs_invoke
// CHECK: invoke void @f() #[[ATTRS:[0-9]+]]
llvm.func @default_func_attrs_invoke() attributes {personality = @__gxx_personality_v0} {
llvm.invoke @f() to ^bb2 unwind ^bb1 {default_func_attrs={key="value", justKey}} : () -> ()
^bb1:
%0 = llvm.landingpad cleanup : !llvm.struct<(ptr, i32)>
llvm.return
^bb2:
llvm.return
}
// CHECK: #[[ATTRS]]
// CHECK-SAME: "justKey"
// CHECK-SAME: "key"="value"
// -----
llvm.func @f()
// CHECK-LABEL: @builtin_call