From 5d48cb826e7f4bf1b8365231603deb9a76b525de Mon Sep 17 00:00:00 2001 From: xlauko Date: Sat, 6 Dec 2025 22:25:53 +0100 Subject: [PATCH] [CIR] Implement function personality attribute and its lowering --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 5 +++++ clang/include/clang/CIR/MissingFeatures.h | 2 +- clang/lib/CIR/CodeGen/CIRGenException.cpp | 20 ++++++++++++++++-- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 21 +++++++++++++++---- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 19 +++++++++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 19 +++-------------- clang/test/CIR/IR/func.cir | 8 +++++++ clang/test/CIR/Lowering/eh-inflight.cir | 9 +++++--- 8 files changed, 77 insertions(+), 26 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 4922f83df0efb..868b813458aae 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2746,6 +2746,10 @@ def CIR_FuncOp : CIR_Op<"func", [ The `always_inline` attribute marks a function that should always be inlined. The `inline_hint` attribute suggests that the function should be inlined. + The `personality` attribute specifies the personality function to use for + exception handling. This is a symbol reference to the personality function + (e.g., `@__gxx_personality_v0` for C++ exceptions). + Example: ```mlir @@ -2792,6 +2796,7 @@ def CIR_FuncOp : CIR_Op<"func", [ OptionalAttr:$arg_attrs, OptionalAttr:$res_attrs, OptionalAttr:$aliasee, + OptionalAttr:$personality, CIR_OptionalPriorityAttr:$global_ctor_priority, CIR_OptionalPriorityAttr:$global_dtor_priority, OptionalAttr:$cxx_special_member diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 9975ee0142d77..ad8c7ca7336e6 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -93,7 +93,6 @@ struct MissingFeatures { static bool opFuncNoReturn() { return false; } static bool setFunctionAttributes() { return false; } static bool setLLVMFunctionFEnvAttributes() { return false; } - static bool setFunctionPersonality() { return false; } // CallOp handling static bool opCallAggregateArgs() { return false; } @@ -279,6 +278,7 @@ struct MissingFeatures { static bool fpConstraints() { return false; } static bool generateDebugInfo() { return false; } + static bool getRuntimeFunctionDecl() { return false; } static bool globalViewIndices() { return false; } static bool globalViewIntLowering() { return false; } static bool handleBuiltinICEArguments() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenException.cpp b/clang/lib/CIR/CodeGen/CIRGenException.cpp index 06b3aec38daa4..70812452ed999 100644 --- a/clang/lib/CIR/CodeGen/CIRGenException.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenException.cpp @@ -185,6 +185,18 @@ const EHPersonality &EHPersonality::get(CIRGenFunction &cgf) { return get(cgf.cgm, dyn_cast_or_null(fg)); } +static llvm::StringRef getPersonalityFn(CIRGenModule &cgm, + const EHPersonality &personality) { + // Create the personality function type: i32 (...) + mlir::Type i32Ty = cgm.getBuilder().getI32Type(); + auto funcTy = cir::FuncType::get({}, i32Ty, /*isVarArg=*/true); + + cir::FuncOp personalityFn = cgm.createRuntimeFunction( + funcTy, personality.personalityFn, mlir::ArrayAttr(), /*isLocal=*/true); + + return personalityFn.getSymName(); +} + void CIRGenFunction::emitCXXThrowExpr(const CXXThrowExpr *e) { const llvm::Triple &triple = getTarget().getTriple(); if (cgm.getLangOpts().OpenMPIsTargetDevice && @@ -641,10 +653,14 @@ void CIRGenFunction::populateCatchHandlersIfRequired(cir::TryOp tryOp) { assert(ehStack.requiresCatchOrCleanup()); assert(!ehStack.empty()); - assert(!cir::MissingFeatures::setFunctionPersonality()); + const EHPersonality &personality = EHPersonality::get(*this); + + // Set personality function if not already set + auto funcOp = mlir::cast(curFn); + if (!funcOp.getPersonality()) + funcOp.setPersonality(getPersonalityFn(cgm, personality)); // CIR does not cache landing pads. - const EHPersonality &personality = EHPersonality::get(*this); if (personality.usesFuncletPads()) { cgm.errorNYI("getInvokeDestImpl: usesFuncletPads"); } else { diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 1ad1c2fa41aa1..edaf1c46eb097 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2354,14 +2354,27 @@ void CIRGenModule::setCXXSpecialMemberAttr( } } +static void setWindowsItaniumDLLImport(CIRGenModule &cgm, bool isLocal, + cir::FuncOp funcOp, StringRef name) { + // In Windows Itanium environments, try to mark runtime functions + // dllimport. For Mingw and MSVC, don't. We don't really know if the user + // will link their standard library statically or dynamically. Marking + // functions imported when they are not imported can cause linker errors + // and warnings. + if (!isLocal && cgm.getTarget().getTriple().isWindowsItaniumEnvironment() && + !cgm.getCodeGenOpts().LTOVisibilityPublicStd) { + assert(!cir::MissingFeatures::getRuntimeFunctionDecl()); + assert(!cir::MissingFeatures::setDLLStorageClass()); + assert(!cir::MissingFeatures::opGlobalDLLImportExport()); + } +} + cir::FuncOp CIRGenModule::createRuntimeFunction(cir::FuncType ty, StringRef name, mlir::ArrayAttr, - [[maybe_unused]] bool isLocal, + bool isLocal, bool assumeConvergent) { if (assumeConvergent) errorNYI("createRuntimeFunction: assumeConvergent"); - if (isLocal) - errorNYI("createRuntimeFunction: local"); cir::FuncOp entry = getOrCreateCIRFunction(name, ty, GlobalDecl(), /*forVtable=*/false); @@ -2370,7 +2383,7 @@ cir::FuncOp CIRGenModule::createRuntimeFunction(cir::FuncType ty, // TODO(cir): set the attributes of the function. assert(!cir::MissingFeatures::setLLVMFunctionFEnvAttributes()); assert(!cir::MissingFeatures::opFuncCallingConv()); - assert(!cir::MissingFeatures::opGlobalDLLImportExport()); + setWindowsItaniumDLLImport(*this, isLocal, entry, name); entry.setDSOLocal(true); } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index ffe93c5b4124b..95fc3afffb156 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1910,6 +1910,19 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { hasAlias = true; } + mlir::StringAttr personalityNameAttr = getPersonalityAttrName(state.name); + if (parser.parseOptionalKeyword("personality").succeeded()) { + if (parser.parseLParen().failed()) + return failure(); + mlir::StringAttr personalityAttr; + if (parser.parseOptionalSymbolName(personalityAttr).failed()) + return failure(); + state.addAttribute(personalityNameAttr, + FlatSymbolRefAttr::get(personalityAttr)); + if (parser.parseRParen().failed()) + return failure(); + } + auto parseGlobalDtorCtor = [&](StringRef keyword, llvm::function_ref prio)> createAttr) @@ -2111,6 +2124,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p << ")"; } + if (std::optional personalityName = getPersonality()) { + p << " personality("; + p.printSymbolName(*personalityName); + p << ")"; + } + if (auto specialMemberAttr = getCxxSpecialMember()) { p << " special_member<"; p.printAttribute(*specialMemberAttr); diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index c01b2c1487709..7d854997848aa 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2053,6 +2053,9 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite( fn.setAlwaysInline(*inlineKind == cir::InlineKind::AlwaysInline); } + if (std::optional personality = op.getPersonality()) + fn.setPersonality(*personality); + fn.setVisibility_( lowerCIRVisibilityToLLVMVisibility(op.getGlobalVisibility())); @@ -3412,22 +3415,6 @@ mlir::LogicalResult CIRToLLVMEhInflightOpLowering::matchAndRewrite( mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 1); rewriter.replaceOp(op, mlir::ValueRange{slot, selector}); - // Landing pads are required to be in LLVM functions with personality - // attribute. - // TODO(cir): for now hardcode personality creation in order to start - // adding exception tests, once we annotate CIR with such information, - // change it to be in FuncOp lowering instead. - mlir::OpBuilder::InsertionGuard guard(rewriter); - // Insert personality decl before the current function. - rewriter.setInsertionPoint(llvmFn); - auto personalityFnTy = - mlir::LLVM::LLVMFunctionType::get(rewriter.getI32Type(), {}, - /*isVarArg=*/true); - - const StringRef fnName = "__gxx_personality_v0"; - createLLVMFuncOpIfNotExist(rewriter, op, fnName, personalityFnTy); - llvmFn.setPersonality(fnName); - return mlir::success(); } diff --git a/clang/test/CIR/IR/func.cir b/clang/test/CIR/IR/func.cir index d8906ab3e1301..52589c8a5e39e 100644 --- a/clang/test/CIR/IR/func.cir +++ b/clang/test/CIR/IR/func.cir @@ -44,6 +44,14 @@ cir.func @intfunc() -> !s32i { cir.func @a_empty() alias(@empty) // CHECK: cir.func @a_empty() alias(@empty) +// Should print/parse function personality. +cir.func @personality_func() personality(@__gxx_personality_v0) { + cir.return +} +// CHECK: cir.func @personality_func() personality(@__gxx_personality_v0) { +// CHECK: cir.return +// CHECK: } + // int scopes() { // { // { diff --git a/clang/test/CIR/Lowering/eh-inflight.cir b/clang/test/CIR/Lowering/eh-inflight.cir index 31e1e474a046b..89f585f439fa4 100644 --- a/clang/test/CIR/Lowering/eh-inflight.cir +++ b/clang/test/CIR/Lowering/eh-inflight.cir @@ -1,12 +1,15 @@ // RUN: cir-opt %s -cir-to-llvm -o %t.cir +!s32i = !cir.int !u8i = !cir.int module { +cir.func private @__gxx_personality_v0(...) -> !s32i + // CHECK: llvm.func @__gxx_personality_v0(...) -> i32 -cir.func @inflight_exception() { +cir.func @inflight_exception() personality(@__gxx_personality_v0) { %exception_ptr, %type_id = cir.eh.inflight_exception cir.return } @@ -19,7 +22,7 @@ cir.func @inflight_exception() { // CHECK: llvm.return // CHECK: } -cir.func @inflight_exception_with_cleanup() { +cir.func @inflight_exception_with_cleanup() personality(@__gxx_personality_v0) { %exception_ptr, %type_id = cir.eh.inflight_exception cleanup cir.return } @@ -35,7 +38,7 @@ cir.func @inflight_exception_with_cleanup() { cir.global "private" constant external @_ZTIi : !cir.ptr cir.global "private" constant external @_ZTIPKc : !cir.ptr -cir.func @inflight_exception_with_catch_type_list() { +cir.func @inflight_exception_with_catch_type_list() personality(@__gxx_personality_v0) { %exception_ptr, %type_id = cir.eh.inflight_exception [@_ZTIi, @_ZTIPKc] cir.return }