https://github.com/xlauko updated https://github.com/llvm/llvm-project/pull/171001
>From 68ca1b86b97366f0c1768cc60c02cd947710e20a Mon Sep 17 00:00:00 2001 From: xlauko <[email protected]> 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 caa047a51b689..3d6de2a97d650 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -2676,6 +2676,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 @@ -2722,6 +2726,7 @@ def CIR_FuncOp : CIR_Op<"func", [ OptionalAttr<DictArrayAttr>:$arg_attrs, OptionalAttr<DictArrayAttr>:$res_attrs, OptionalAttr<FlatSymbolRefAttr>:$aliasee, + OptionalAttr<FlatSymbolRefAttr>:$personality, CIR_OptionalPriorityAttr:$global_ctor_priority, CIR_OptionalPriorityAttr:$global_dtor_priority, OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 826a4b13f5c0c..95b3bfa58956e 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; } @@ -274,6 +273,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 375828421eb1b..3a229d4b51160 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<FunctionDecl>(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 && @@ -640,10 +652,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<cir::FuncOp>(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 e1894c040dd53..f784eb929248e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2301,14 +2301,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); @@ -2317,7 +2330,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 ec8cae62d6bc8..61f3850285c1a 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1939,6 +1939,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<void(std::optional<int> prio)> createAttr) @@ -2140,6 +2153,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p << ")"; } + if (std::optional<StringRef> 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 6b4d3b4fc585b..aea9e26341f8f 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2015,6 +2015,9 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite( fn.setAlwaysInline(*inlineKind == cir::InlineKind::AlwaysInline); } + if (std::optional<llvm::StringRef> personality = op.getPersonality()) + fn.setPersonality(*personality); + fn.setVisibility_( lowerCIRVisibilityToLLVMVisibility(op.getGlobalVisibility())); @@ -3342,22 +3345,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<s, 32> !u8i = !cir.int<u, 8> 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<!u8i> cir.global "private" constant external @_ZTIPKc : !cir.ptr<!u8i> -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 } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
