https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/238128
>From 779c1eb8584bb32ad09c0c55cf9d0286b657c098 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Mon, 2 Nov 2026 14:07:52 -0800 Subject: [PATCH 1/3] libunwind: Use libgcc's function context layout for sjlj Make call_site an i32 and the __data words pointer sized. compiler-rt's SjLj_Function_Context was not defined in the same way as libgcc. This was broken for all 64-bit targets. Every field was i32, so the exception pointer in __data[0] was truncated. It just happens that no 64-bit target defaults to SJLJ exceptions except VE. Instead of fixing that, a VE special case was introduced in the libunwind sources and SjLjEHPrepare, which had a special TargetMachine hook for this data size. In reality it should just be a uintptr_t which we can already infer from the DataLayout. This is an ABI break for 64-bit targets other than VE when using libunwind built for SjLj: the __data, personality, lsda and jbuf offsets move, so compiled code and libunwind must be updated together. That configuration was already broken by the pointer truncation and is not the default anywhere. 32-bit targets are unchanged, and on VE only call_site narrows; all offsets are unchanged. Co-authored-by: Claude Opus 5.5 <[email protected]> --- libunwind/src/Unwind-sjlj.c | 26 +++------- llvm/include/llvm/CodeGen/Passes.h | 2 +- llvm/include/llvm/CodeGen/SjLjEHPrepare.h | 5 -- llvm/include/llvm/Target/TargetMachine.h | 4 -- llvm/lib/CodeGen/SjLjEHPrepare.cpp | 21 +++----- llvm/lib/CodeGen/TargetPassConfig.cpp | 2 +- llvm/lib/Passes/CodeGenPassBuilder.cpp | 2 +- llvm/lib/Passes/PassRegistry.def | 2 +- llvm/lib/Target/VE/VEISelLowering.cpp | 6 +-- llvm/lib/Target/VE/VETargetMachine.h | 2 - llvm/lib/Target/X86/X86ISelLowering.cpp | 2 +- .../VE/Scalar/builtin_sjlj_callsite.ll | 8 ++-- .../VE/Scalar/builtin_sjlj_landingpad.ll | 4 +- .../X86/indirect-branch-tracking-eh2.ll | 48 +++++++++---------- llvm/test/CodeGen/X86/sjlj-eh.ll | 10 ++-- .../SjLjEHPrepare/function-context-layout.ll | 34 +++++++++++++ 16 files changed, 91 insertions(+), 87 deletions(-) create mode 100644 llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll diff --git a/libunwind/src/Unwind-sjlj.c b/libunwind/src/Unwind-sjlj.c index a3551b328950d1..d70a384a5a6719 100644 --- a/libunwind/src/Unwind-sjlj.c +++ b/libunwind/src/Unwind-sjlj.c @@ -32,23 +32,11 @@ struct _Unwind_FunctionContext { // next function in stack of handlers struct _Unwind_FunctionContext *prev; -#if defined(__ve__) - // VE requires to store 64 bit pointers in the buffer for SjLj exception. - // We expand the size of values defined here. This size must be matched - // to the size returned by TargetMachine::getSjLjDataSize(). - - // set by calling function before registering to be the landing pad - uint64_t resumeLocation; - - // set by personality handler to be parameters passed to landing pad function - uint64_t resumeParameters[4]; -#else // set by calling function before registering to be the landing pad - uint32_t resumeLocation; + int resumeLocation; // set by personality handler to be parameters passed to landing pad function - uint32_t resumeParameters[4]; -#endif + uintptr_t resumeParameters[4]; // set by calling function before registering _Unwind_Personality_Fn personality; // arm offset=24 @@ -439,8 +427,8 @@ _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR, - (void *)context, ufc->resumeLocation + 1); - return ufc->resumeLocation + 1; + (void *)context, (uintptr_t)(ufc->resumeLocation + 1)); + return (uintptr_t)(ufc->resumeLocation + 1); } @@ -453,8 +441,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context, *ipBefore = 0; _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%" PRIxPTR, (void *)context, (void *)ipBefore, - ufc->resumeLocation + 1); - return ufc->resumeLocation + 1; + (uintptr_t)(ufc->resumeLocation + 1)); + return (uintptr_t)(ufc->resumeLocation + 1); } @@ -464,7 +452,7 @@ _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%" PRIxPTR ")", (void *)context, new_value); _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; - ufc->resumeLocation = new_value - 1; + ufc->resumeLocation = (int)(new_value - 1); } diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index d49cad427ab065..a380a849c3fa57 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -425,7 +425,7 @@ LLVM_ABI FunctionPass *createWinEHPass(); /// createSjLjEHPreparePass - This pass adapts exception handling code to use /// the GCC-style builtin setjmp/longjmp (sjlj) to handling EH control flow. /// -LLVM_ABI FunctionPass *createSjLjEHPreparePass(const TargetMachine *TM); +LLVM_ABI FunctionPass *createSjLjEHPreparePass(); /// createWasmEHPass - This pass adapts exception handling code to use /// WebAssembly's exception handling scheme. diff --git a/llvm/include/llvm/CodeGen/SjLjEHPrepare.h b/llvm/include/llvm/CodeGen/SjLjEHPrepare.h index d91d87bb29ecd1..62a421107c1090 100644 --- a/llvm/include/llvm/CodeGen/SjLjEHPrepare.h +++ b/llvm/include/llvm/CodeGen/SjLjEHPrepare.h @@ -13,13 +13,8 @@ namespace llvm { -class TargetMachine; - class SjLjEHPreparePass : public RequiredPassInfoMixin<SjLjEHPreparePass> { - const TargetMachine *TM; - public: - explicit SjLjEHPreparePass(const TargetMachine *TM) : TM(TM) {} LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); }; diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h index bc151c3ea8f55e..90608e0d3051ac 100644 --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -496,10 +496,6 @@ class LLVM_ABI TargetMachine { Mangler &Mang, bool MayAlwaysUsePrivate = false) const; MCSymbol *getSymbol(const GlobalValue *GV) const; - /// The integer bit size to use for SjLj based exception handling. - static constexpr unsigned DefaultSjLjDataSize = 32; - virtual unsigned getSjLjDataSize() const { return DefaultSjLjDataSize; } - /// getAddressSpaceForPseudoSourceKind - Given the kind of memory /// (e.g. stack) the target returns the corresponding address space. virtual unsigned getAddressSpaceForPseudoSourceKind(unsigned Kind) const { diff --git a/llvm/lib/CodeGen/SjLjEHPrepare.cpp b/llvm/lib/CodeGen/SjLjEHPrepare.cpp index 590383a5ed05ea..0cc406aaf87c2a 100644 --- a/llvm/lib/CodeGen/SjLjEHPrepare.cpp +++ b/llvm/lib/CodeGen/SjLjEHPrepare.cpp @@ -28,7 +28,6 @@ #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/Local.h" using namespace llvm; @@ -53,13 +52,11 @@ class SjLjEHPrepareImpl { Function *CallSiteFn = nullptr; Function *FuncCtxFn = nullptr; AllocaInst *FuncCtx = nullptr; - const TargetMachine *TM = nullptr; // The module's "exception-model" flag. ExceptionHandling ExceptionModel = ExceptionHandling::Default; public: - explicit SjLjEHPrepareImpl(const TargetMachine *TM = nullptr) : TM(TM) {} bool doInitialization(Module &M); bool runOnFunction(Function &F); @@ -77,8 +74,7 @@ class SjLjEHPrepare : public FunctionPass { public: static char ID; // Pass identification, replacement for typeid - explicit SjLjEHPrepare(const TargetMachine *TM = nullptr) - : FunctionPass(ID), Impl(TM) {} + SjLjEHPrepare() : FunctionPass(ID) {} bool doInitialization(Module &M) override { return Impl.doInitialization(M); } bool runOnFunction(Function &F) override { return Impl.runOnFunction(F); }; @@ -91,7 +87,7 @@ class SjLjEHPrepare : public FunctionPass { PreservedAnalyses SjLjEHPreparePass::run(Function &F, FunctionAnalysisManager &FAM) { - SjLjEHPrepareImpl Impl(TM); + SjLjEHPrepareImpl Impl; Impl.doInitialization(*F.getParent()); bool Changed = Impl.runOnFunction(F); return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all(); @@ -102,9 +98,7 @@ INITIALIZE_PASS(SjLjEHPrepare, DEBUG_TYPE, "Prepare SjLj exceptions", false, false) // Public Interface To the SjLjEHPrepare pass. -FunctionPass *llvm::createSjLjEHPreparePass(const TargetMachine *TM) { - return new SjLjEHPrepare(TM); -} +FunctionPass *llvm::createSjLjEHPreparePass() { return new SjLjEHPrepare(); } // doInitialization - Set up decalarations and types needed to process // exceptions. @@ -114,13 +108,12 @@ bool SjLjEHPrepareImpl::doInitialization(Module &M) { // Build the function context structure. // builtin_setjmp uses a five word jbuf Type *VoidPtrTy = PointerType::getUnqual(M.getContext()); - unsigned DataBits = - TM ? TM->getSjLjDataSize() : TargetMachine::DefaultSjLjDataSize; - DataTy = Type::getIntNTy(M.getContext(), DataBits); + DataTy = M.getDataLayout().getIntPtrType(M.getContext()); doubleUnderDataTy = ArrayType::get(DataTy, 4); doubleUnderJBufTy = ArrayType::get(VoidPtrTy, 5); + Type *Int32Ty = Type::getInt32Ty(M.getContext()); FunctionContextTy = StructType::get(VoidPtrTy, // __prev - DataTy, // call_site + Int32Ty, // call_site doubleUnderDataTy, // __data VoidPtrTy, // __personality VoidPtrTy, // __lsda @@ -144,7 +137,7 @@ void SjLjEHPrepareImpl::insertCallSiteStore(Instruction *I, int Number) { Builder.CreateGEP(FunctionContextTy, FuncCtx, Idxs, "call_site"); // Insert a store of the call-site number - ConstantInt *CallSiteNoC = ConstantInt::getSigned(DataTy, Number); + ConstantInt *CallSiteNoC = Builder.getInt32(Number); Builder.CreateStore(CallSiteNoC, CallSite, true /*volatile*/); } diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index 37462163d4f919..cf57b318e98221 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -778,7 +778,7 @@ void TargetPassConfig::addPassesToHandleExceptions() { // pad is shared by multiple invokes and is also a target of a normal // edge from elsewhere. if (TM->supportsExceptionModel(ExceptionHandling::SjLj)) { - addPass(createSjLjEHPreparePass(TM)); + addPass(createSjLjEHPreparePass()); HasEHPrep = true; } diff --git a/llvm/lib/Passes/CodeGenPassBuilder.cpp b/llvm/lib/Passes/CodeGenPassBuilder.cpp index 7741b361b8dd44..cd37670a2ae6a4 100644 --- a/llvm/lib/Passes/CodeGenPassBuilder.cpp +++ b/llvm/lib/Passes/CodeGenPassBuilder.cpp @@ -460,7 +460,7 @@ void CodeGenPassBuilder::addPassesToHandleExceptions(PassManagerWrapper &PMW) { // pad is shared by multiple invokes and is also a target of a normal // edge from elsewhere. if (TM.supportsExceptionModel(ExceptionHandling::SjLj)) { - addFunctionPass(SjLjEHPreparePass(&TM), PMW); + addFunctionPass(SjLjEHPreparePass(), PMW); HasEHPrep = true; } // We support using both GCC-style and MSVC-style exceptions on Windows, so diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index c5b7001d550c0f..eb7eddfe9eae86 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -547,7 +547,7 @@ FUNCTION_PASS("select-optimize", SelectOptimizePass(*TM)) FUNCTION_PASS("separate-const-offset-from-gep", SeparateConstOffsetFromGEPPass()) FUNCTION_PASS("sink", SinkingPass()) -FUNCTION_PASS("sjlj-eh-prepare", SjLjEHPreparePass(TM)) +FUNCTION_PASS("sjlj-eh-prepare", SjLjEHPreparePass()) FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass()) FUNCTION_PASS("slsr", StraightLineStrengthReducePass()) FUNCTION_PASS("stack-protector", StackProtectorPass(*TM)) diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp index afef0a3f0d6b5e..18163c8ae1c7df 100644 --- a/llvm/lib/Target/VE/VEISelLowering.cpp +++ b/llvm/lib/Target/VE/VEISelLowering.cpp @@ -2369,10 +2369,10 @@ VETargetLowering::emitSjLjDispatchBlock(MachineInstr &MI, "No landing pad destinations for the dispatch jump table!"); // The %fn_context is allocated like below (from --print-after=sjljehprepare): - // %fn_context = alloca { i8*, i64, [4 x i64], i8*, i8*, [5 x i8*] } + // %fn_context = alloca { ptr, i32, [4 x i64], ptr, ptr, [5 x ptr] } // - // This `[5 x i8*]` is jmpbuf, so jmpbuf[1] is FI+72. - // First `i64` is callsite, so callsite is FI+8. + // This `[5 x ptr]` is jmpbuf, so jmpbuf[1] is FI+72. + // First `i32` is callsite, so callsite is FI+8. static const int OffsetIC = 72; static const int OffsetCS = 8; diff --git a/llvm/lib/Target/VE/VETargetMachine.h b/llvm/lib/Target/VE/VETargetMachine.h index 2031d5c66905ee..3ae9919ebe740d 100644 --- a/llvm/lib/Target/VE/VETargetMachine.h +++ b/llvm/lib/Target/VE/VETargetMachine.h @@ -58,8 +58,6 @@ class VETargetMachine : public CodeGenTargetMachineImpl { TargetTransformInfo getTargetTransformInfo(const Function &F) const override; - unsigned getSjLjDataSize() const override { return 64; } - void registerPassBuilderCallbacks(PassBuilder &PB) override; Error buildCodeGenPipeline(ModulePassManager &MPM, ModuleAnalysisManager &MAM, diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 238250a8b67a87..ec2fb6c7751d4f 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -38819,7 +38819,7 @@ void X86TargetLowering::SetupEntryBlockForSjLj(MachineInstr &MI, } MachineInstrBuilder MIB = BuildMI(*MBB, MI, MIMD, TII->get(Op)); - addFrameReference(MIB, FI, Subtarget.is64Bit() ? 56 : 36); + addFrameReference(MIB, FI, Subtarget.is64Bit() ? 72 : 36); if (UseImmLabel) MIB.addMBB(DispatchBB); else diff --git a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_callsite.ll b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_callsite.ll index d12ab649c55d57..faa38eaaf50111 100644 --- a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_callsite.ll +++ b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_callsite.ll @@ -58,7 +58,7 @@ define void @test_callsite() personality ptr @__gxx_personality_sj0 { ; CHECK-NEXT: lea %s0, -104(, %s9) ; CHECK-NEXT: bsic %s10, (, %s12) ; CHECK-NEXT: or %s0, 1, (0)1 -; CHECK-NEXT: st %s0, -96(, %s9) +; CHECK-NEXT: stl %s0, -96(, %s9) ; CHECK-NEXT: .Ltmp0: ; CHECK-NEXT: lea %s0, f@lo ; CHECK-NEXT: and %s0, %s0, (32)0 @@ -67,7 +67,7 @@ define void @test_callsite() personality ptr @__gxx_personality_sj0 { ; CHECK-NEXT: .Ltmp1: ; CHECK-NEXT: .LBB0_2: # %try.cont ; CHECK-NEXT: or %s0, -1, (0)1 -; CHECK-NEXT: st %s0, -96(, %s9) +; CHECK-NEXT: stl %s0, -96(, %s9) ; CHECK-NEXT: lea %s0, _Unwind_SjLj_Unregister@lo ; CHECK-NEXT: and %s0, %s0, (32)0 ; CHECK-NEXT: lea.sl %s18, _Unwind_SjLj_Unregister@hi(, %s0) @@ -179,7 +179,7 @@ define void @test_callsite() personality ptr @__gxx_personality_sj0 { ; PIC-NEXT: lea %s0, -104(, %s9) ; PIC-NEXT: bsic %s10, (, %s12) ; PIC-NEXT: or %s0, 1, (0)1 -; PIC-NEXT: st %s0, -96(, %s9) +; PIC-NEXT: stl %s0, -96(, %s9) ; PIC-NEXT: .Ltmp0: ; PIC-NEXT: lea %s12, f@plt_lo(-24) ; PIC-NEXT: and %s12, %s12, (32)0 @@ -189,7 +189,7 @@ define void @test_callsite() personality ptr @__gxx_personality_sj0 { ; PIC-NEXT: .Ltmp1: ; PIC-NEXT: .LBB0_2: # %try.cont ; PIC-NEXT: or %s0, -1, (0)1 -; PIC-NEXT: st %s0, -96(, %s9) +; PIC-NEXT: stl %s0, -96(, %s9) ; PIC-NEXT: lea %s18, _Unwind_SjLj_Unregister@plt_lo(-24) ; PIC-NEXT: and %s18, %s18, (32)0 ; PIC-NEXT: sic %s16 diff --git a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_landingpad.ll b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_landingpad.ll index ed6ddb3e91efe6..527040a2f17ebf 100644 --- a/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_landingpad.ll +++ b/llvm/test/CodeGen/VE/Scalar/builtin_sjlj_landingpad.ll @@ -59,7 +59,7 @@ define dso_local i32 @foo(i32 %arg) local_unnamed_addr personality ptr @__gxx_pe ; CHECK-NEXT: lea %s0, -104(, %s9) ; CHECK-NEXT: bsic %s10, (, %s12) ; CHECK-NEXT: or %s0, 1, (0)1 -; CHECK-NEXT: st %s0, -96(, %s9) +; CHECK-NEXT: stl %s0, -96(, %s9) ; CHECK-NEXT: .Ltmp0: ; CHECK-NEXT: lea %s0, errorbar@lo ; CHECK-NEXT: and %s0, %s0, (32)0 @@ -182,7 +182,7 @@ define dso_local i32 @foo(i32 %arg) local_unnamed_addr personality ptr @__gxx_pe ; PIC-NEXT: lea %s0, -104(, %s9) ; PIC-NEXT: bsic %s10, (, %s12) ; PIC-NEXT: or %s0, 1, (0)1 -; PIC-NEXT: st %s0, -96(, %s9) +; PIC-NEXT: stl %s0, -96(, %s9) ; PIC-NEXT: .Ltmp0: ; PIC-NEXT: lea %s12, errorbar@plt_lo(-24) ; PIC-NEXT: and %s12, %s12, (32)0 diff --git a/llvm/test/CodeGen/X86/indirect-branch-tracking-eh2.ll b/llvm/test/CodeGen/X86/indirect-branch-tracking-eh2.ll index 1c48e8c5814464..f5bb1d17aacec0 100644 --- a/llvm/test/CodeGen/X86/indirect-branch-tracking-eh2.ll +++ b/llvm/test/CodeGen/X86/indirect-branch-tracking-eh2.ll @@ -17,16 +17,16 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; NUM-NEXT: pushq %r13 ; NUM-NEXT: pushq %r12 ; NUM-NEXT: pushq %rbx -; NUM-NEXT: subq $120, %rsp +; NUM-NEXT: subq $136, %rsp ; NUM-NEXT: movl $0, -44(%rbp) ; NUM-NEXT: movq $__gxx_personality_sj0, -120(%rbp) ; NUM-NEXT: movq $GCC_except_table0, -112(%rbp) ; NUM-NEXT: movq %rbp, -104(%rbp) ; NUM-NEXT: movq %rsp, -88(%rbp) ; NUM-NEXT: movq $.LBB0_9, -96(%rbp) -; NUM-NEXT: leaq -152(%rbp), %rdi +; NUM-NEXT: leaq -168(%rbp), %rdi ; NUM-NEXT: callq _Unwind_SjLj_Register@PLT -; NUM-NEXT: movl $1, -144(%rbp) +; NUM-NEXT: movl $1, -160(%rbp) ; NUM-NEXT: .Ltmp0: ; NUM-NEXT: callq _Z3foov ; NUM-NEXT: .Ltmp1: @@ -34,10 +34,10 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; NUM-NEXT: movl $1, -44(%rbp) ; NUM-NEXT: .LBB0_7: # %return ; NUM-NEXT: movl -44(%rbp), %ebx -; NUM-NEXT: leaq -152(%rbp), %rdi +; NUM-NEXT: leaq -168(%rbp), %rdi ; NUM-NEXT: callq _Unwind_SjLj_Unregister@PLT ; NUM-NEXT: movl %ebx, %eax -; NUM-NEXT: addq $120, %rsp +; NUM-NEXT: addq $136, %rsp ; NUM-NEXT: popq %rbx ; NUM-NEXT: popq %r12 ; NUM-NEXT: popq %r13 @@ -47,7 +47,7 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; NUM-NEXT: retq ; NUM-NEXT: .LBB0_9: ; NUM-NEXT: endbr64 -; NUM-NEXT: movl -144(%rbp), %eax +; NUM-NEXT: movl -160(%rbp), %eax ; NUM-NEXT: cmpl $1, %eax ; NUM-NEXT: jb .LBB0_10 ; NUM-NEXT: # %bb.11: @@ -58,15 +58,15 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; NUM-NEXT: .LBB0_2: # %lpad ; NUM-NEXT: .Ltmp2: ; NUM-NEXT: endbr64 -; NUM-NEXT: movl -140(%rbp), %ecx -; NUM-NEXT: movl -136(%rbp), %eax +; NUM-NEXT: movq -152(%rbp), %rcx +; NUM-NEXT: movq -144(%rbp), %rax ; NUM-NEXT: movq %rcx, -56(%rbp) ; NUM-NEXT: movl %eax, -64(%rbp) ; NUM-NEXT: cmpl $2, %eax ; NUM-NEXT: jne .LBB0_4 ; NUM-NEXT: # %bb.3: # %catch3 ; NUM-NEXT: movq -56(%rbp), %rdi -; NUM-NEXT: movl $-1, -144(%rbp) +; NUM-NEXT: movl $-1, -160(%rbp) ; NUM-NEXT: callq __cxa_begin_catch ; NUM-NEXT: movl (%rax), %eax ; NUM-NEXT: movl %eax, -60(%rbp) @@ -78,7 +78,7 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; NUM-NEXT: jne .LBB0_8 ; NUM-NEXT: # %bb.5: # %catch ; NUM-NEXT: movq -56(%rbp), %rdi -; NUM-NEXT: movl $-1, -144(%rbp) +; NUM-NEXT: movl $-1, -160(%rbp) ; NUM-NEXT: callq __cxa_begin_catch ; NUM-NEXT: movzbl (%rax), %eax ; NUM-NEXT: movb %al, -45(%rbp) @@ -87,11 +87,11 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; NUM-NEXT: .LBB0_6: # %return ; NUM-NEXT: setne %cl ; NUM-NEXT: movl %ecx, -44(%rbp) -; NUM-NEXT: movl $-1, -144(%rbp) +; NUM-NEXT: movl $-1, -160(%rbp) ; NUM-NEXT: callq __cxa_end_catch ; NUM-NEXT: jmp .LBB0_7 ; NUM-NEXT: .LBB0_8: # %eh.resume -; NUM-NEXT: movl $-1, -144(%rbp) +; NUM-NEXT: movl $-1, -160(%rbp) ; ; SJLJ-LABEL: main: ; SJLJ: # %bb.0: # %entry @@ -103,16 +103,16 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; SJLJ-NEXT: pushq %r13 ; SJLJ-NEXT: pushq %r12 ; SJLJ-NEXT: pushq %rbx -; SJLJ-NEXT: subq $120, %rsp +; SJLJ-NEXT: subq $136, %rsp ; SJLJ-NEXT: movl $0, -44(%rbp) ; SJLJ-NEXT: movq $__gxx_personality_sj0, -120(%rbp) ; SJLJ-NEXT: movq $GCC_except_table0, -112(%rbp) ; SJLJ-NEXT: movq %rbp, -104(%rbp) ; SJLJ-NEXT: movq %rsp, -88(%rbp) ; SJLJ-NEXT: movq $.LBB0_9, -96(%rbp) -; SJLJ-NEXT: leaq -152(%rbp), %rdi +; SJLJ-NEXT: leaq -168(%rbp), %rdi ; SJLJ-NEXT: callq _Unwind_SjLj_Register@PLT -; SJLJ-NEXT: movl $1, -144(%rbp) +; SJLJ-NEXT: movl $1, -160(%rbp) ; SJLJ-NEXT: .Ltmp0: ; SJLJ-NEXT: callq _Z3foov ; SJLJ-NEXT: .Ltmp1: @@ -120,10 +120,10 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; SJLJ-NEXT: movl $1, -44(%rbp) ; SJLJ-NEXT: .LBB0_7: # %return ; SJLJ-NEXT: movl -44(%rbp), %ebx -; SJLJ-NEXT: leaq -152(%rbp), %rdi +; SJLJ-NEXT: leaq -168(%rbp), %rdi ; SJLJ-NEXT: callq _Unwind_SjLj_Unregister@PLT ; SJLJ-NEXT: movl %ebx, %eax -; SJLJ-NEXT: addq $120, %rsp +; SJLJ-NEXT: addq $136, %rsp ; SJLJ-NEXT: popq %rbx ; SJLJ-NEXT: popq %r12 ; SJLJ-NEXT: popq %r13 @@ -133,7 +133,7 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; SJLJ-NEXT: retq ; SJLJ-NEXT: .LBB0_9: ; SJLJ-NEXT: endbr64 -; SJLJ-NEXT: movl -144(%rbp), %eax +; SJLJ-NEXT: movl -160(%rbp), %eax ; SJLJ-NEXT: cmpl $1, %eax ; SJLJ-NEXT: jb .LBB0_10 ; SJLJ-NEXT: # %bb.11: @@ -144,15 +144,15 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; SJLJ-NEXT: .LBB0_2: # %lpad ; SJLJ-NEXT: .Ltmp2: ; SJLJ-NEXT: endbr64 -; SJLJ-NEXT: movl -140(%rbp), %ecx -; SJLJ-NEXT: movl -136(%rbp), %eax +; SJLJ-NEXT: movq -152(%rbp), %rcx +; SJLJ-NEXT: movq -144(%rbp), %rax ; SJLJ-NEXT: movq %rcx, -56(%rbp) ; SJLJ-NEXT: movl %eax, -64(%rbp) ; SJLJ-NEXT: cmpl $2, %eax ; SJLJ-NEXT: jne .LBB0_4 ; SJLJ-NEXT: # %bb.3: # %catch3 ; SJLJ-NEXT: movq -56(%rbp), %rdi -; SJLJ-NEXT: movl $-1, -144(%rbp) +; SJLJ-NEXT: movl $-1, -160(%rbp) ; SJLJ-NEXT: callq __cxa_begin_catch ; SJLJ-NEXT: movl (%rax), %eax ; SJLJ-NEXT: movl %eax, -60(%rbp) @@ -164,7 +164,7 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; SJLJ-NEXT: jne .LBB0_8 ; SJLJ-NEXT: # %bb.5: # %catch ; SJLJ-NEXT: movq -56(%rbp), %rdi -; SJLJ-NEXT: movl $-1, -144(%rbp) +; SJLJ-NEXT: movl $-1, -160(%rbp) ; SJLJ-NEXT: callq __cxa_begin_catch ; SJLJ-NEXT: movzbl (%rax), %eax ; SJLJ-NEXT: movb %al, -45(%rbp) @@ -173,11 +173,11 @@ define dso_local i32 @main() #0 personality ptr @__gxx_personality_sj0 { ; SJLJ-NEXT: .LBB0_6: # %return ; SJLJ-NEXT: setne %cl ; SJLJ-NEXT: movl %ecx, -44(%rbp) -; SJLJ-NEXT: movl $-1, -144(%rbp) +; SJLJ-NEXT: movl $-1, -160(%rbp) ; SJLJ-NEXT: callq __cxa_end_catch ; SJLJ-NEXT: jmp .LBB0_7 ; SJLJ-NEXT: .LBB0_8: # %eh.resume -; SJLJ-NEXT: movl $-1, -144(%rbp) +; SJLJ-NEXT: movl $-1, -160(%rbp) entry: %retval = alloca i32, align 4 %exn.slot = alloca ptr diff --git a/llvm/test/CodeGen/X86/sjlj-eh.ll b/llvm/test/CodeGen/X86/sjlj-eh.ll index 2c9aa6fd7d55d4..87aa9fe2953ebf 100644 --- a/llvm/test/CodeGen/X86/sjlj-eh.ll +++ b/llvm/test/CodeGen/X86/sjlj-eh.ll @@ -99,18 +99,18 @@ try.cont: ; CHECK-X64: leaq .[[RESUME:LBB[0-9]+_[0-9]+]](%rip), %rax ; CHECK-X64: movq %rax, -256(%rbp) ; _Unwind_SjLj_Register(&UFC); -; CHECK-X64: leaq -312(%rbp), %rcx +; CHECK-X64: leaq -328(%rbp), %rcx ; CHECK-X64: callq _Unwind_SjLj_Register ; function_that_throws(); -; CHECK-X64: movl $1, -304(%rbp) +; CHECK-X64: movl $1, -320(%rbp) ; CHECK-X64: callq _Z20function_that_throwsv ; _Unwind_SjLj_Unregister(&UFC); -; CHECK-X64: leaq -312(%rbp), %rcx +; CHECK-X64: leaq -328(%rbp), %rcx ; CHECK-X64: callq _Unwind_SjLj_Unregister ; ; CHECK-X64: [[RESUME]]: ; assert(UFC.__callsite < 1); -; CHECK-X64: movl -304(%rbp), %eax +; CHECK-X64: movl -320(%rbp), %eax ; CHECK-X64: cmpl $1, %eax ; CHECK-X64: jb .[[CONT:LBB[0-9]+_[0-9]+]] ; CHECK-X64: ud2 @@ -124,7 +124,7 @@ try.cont: ; CHECK-X64-LINUX: .[[RESUME:LBB[0-9]+_[0-9]+]]: ; assert(UFC.__callsite < 1); -; CHECK-X64-LINUX: movl -120(%rbp), %eax +; CHECK-X64-LINUX: movl -136(%rbp), %eax ; CHECK-X64-LINUX: cmpl $1, %eax ; CHECK-X64-LINUX: jb .[[CONT:LBB[0-9]+_[0-9]+]] ; CHECK-X64-LINUX: ud2 diff --git a/llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll b/llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll new file mode 100644 index 00000000000000..4db9e1d14e3660 --- /dev/null +++ b/llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll @@ -0,0 +1,34 @@ +; RUN: opt -S -passes=sjlj-eh-prepare -data-layout=p:32:32 < %s | FileCheck -check-prefix=P32 %s +; RUN: opt -S -passes=sjlj-eh-prepare -data-layout=p:64:64 < %s | FileCheck -check-prefix=P64 %s + +; The function context matches libgcc's SjLj_Function_Context: call_site is +; always i32, and the __data words are pointer sized. + +; P32: %fn_context = alloca { ptr, i32, [4 x i32], ptr, ptr, [5 x ptr] } +; P32: store volatile i32 1, ptr %call_site +; P32: %exn_val = load volatile i32, ptr %exception_gep +; P32: %exn_selector_val = load volatile i32, ptr %exn_selector_gep + +; P64: %fn_context = alloca { ptr, i32, [4 x i64], ptr, ptr, [5 x ptr] } +; P64: store volatile i32 1, ptr %call_site +; P64: %exn_val = load volatile i64, ptr %exception_gep +; P64: %exn_selector_val = load volatile i64, ptr %exn_selector_gep +define void @test() personality ptr @__gxx_personality_sj0 { +entry: + invoke void @may_throw() + to label %cont unwind label %lpad + +cont: + ret void + +lpad: + %lp = landingpad { ptr, i32 } + cleanup + resume { ptr, i32 } %lp +} + +declare void @may_throw() +declare i32 @__gxx_personality_sj0(...) + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"exception-model", !"sjlj"} >From 3234969f7cd73a680a7ebd7d638a32793770e1fc Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Tue, 3 Nov 2026 00:02:06 -0800 Subject: [PATCH 2/3] Size the __data words as unwind words --- libunwind/src/Unwind-sjlj.c | 6 ++-- llvm/include/llvm/CodeGen/SjLjEHPrepare.h | 7 ++++ llvm/lib/CodeGen/SjLjEHPrepare.cpp | 35 +++++++++++-------- llvm/lib/Target/VE/VEISelLowering.cpp | 13 ++++--- llvm/lib/Target/X86/X86ISelLowering.cpp | 10 ++++-- llvm/test/CodeGen/X86/sjlj-eh.ll | 15 ++++++++ .../SjLjEHPrepare/function-context-layout.ll | 12 +++++-- .../respect-exception-model-flag.ll | 4 +-- .../SjLjEHPrepare/sjlj-eh-prepare.ll | 2 +- 9 files changed, 72 insertions(+), 32 deletions(-) diff --git a/libunwind/src/Unwind-sjlj.c b/libunwind/src/Unwind-sjlj.c index d70a384a5a6719..fe39eca3945864 100644 --- a/libunwind/src/Unwind-sjlj.c +++ b/libunwind/src/Unwind-sjlj.c @@ -28,6 +28,8 @@ #if defined(_LIBUNWIND_BUILD_SJLJ_APIS) +typedef unsigned _Unwind_SjLj_Word __attribute__((__mode__(__unwind_word__))); + struct _Unwind_FunctionContext { // next function in stack of handlers struct _Unwind_FunctionContext *prev; @@ -36,7 +38,7 @@ struct _Unwind_FunctionContext { int resumeLocation; // set by personality handler to be parameters passed to landing pad function - uintptr_t resumeParameters[4]; + _Unwind_SjLj_Word resumeParameters[4]; // set by calling function before registering _Unwind_Personality_Fn personality; // arm offset=24 @@ -408,7 +410,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)", (void *)context, index); _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context; - return ufc->resumeParameters[index]; + return (uintptr_t)ufc->resumeParameters[index]; } diff --git a/llvm/include/llvm/CodeGen/SjLjEHPrepare.h b/llvm/include/llvm/CodeGen/SjLjEHPrepare.h index 62a421107c1090..df2038cf5e7717 100644 --- a/llvm/include/llvm/CodeGen/SjLjEHPrepare.h +++ b/llvm/include/llvm/CodeGen/SjLjEHPrepare.h @@ -13,6 +13,13 @@ namespace llvm { +class Module; +class StructType; + +/// Returns the type of the function context registered with the SjLj unwinder, +/// laid out like libgcc's SjLj_Function_Context. +LLVM_ABI StructType *getSjLjFunctionContextType(const Module &M); + class SjLjEHPreparePass : public RequiredPassInfoMixin<SjLjEHPreparePass> { public: LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM); diff --git a/llvm/lib/CodeGen/SjLjEHPrepare.cpp b/llvm/lib/CodeGen/SjLjEHPrepare.cpp index 0cc406aaf87c2a..428a4d68f66064 100644 --- a/llvm/lib/CodeGen/SjLjEHPrepare.cpp +++ b/llvm/lib/CodeGen/SjLjEHPrepare.cpp @@ -41,7 +41,7 @@ class SjLjEHPrepareImpl { IntegerType *DataTy = nullptr; Type *doubleUnderDataTy = nullptr; Type *doubleUnderJBufTy = nullptr; - Type *FunctionContextTy = nullptr; + StructType *FunctionContextTy = nullptr; FunctionCallee RegisterFn; FunctionCallee UnregisterFn; Function *BuiltinSetupDispatchFn = nullptr; @@ -100,25 +100,30 @@ INITIALIZE_PASS(SjLjEHPrepare, DEBUG_TYPE, "Prepare SjLj exceptions", // Public Interface To the SjLjEHPrepare pass. FunctionPass *llvm::createSjLjEHPreparePass() { return new SjLjEHPrepare(); } +StructType *llvm::getSjLjFunctionContextType(const Module &M) { + LLVMContext &Ctx = M.getContext(); + Type *DataTy = + Type::getIntNTy(Ctx, M.getTargetTriple().getArchPointerBitWidth()); + // builtin_setjmp uses a five word jbuf + Type *VoidPtrTy = PointerType::getUnqual(Ctx); + return StructType::get(VoidPtrTy, // __prev + Type::getInt32Ty(Ctx), // call_site + ArrayType::get(DataTy, 4), // __data + VoidPtrTy, // __personality + VoidPtrTy, // __lsda + ArrayType::get(VoidPtrTy, 5) // __jbuf + ); +} + // doInitialization - Set up decalarations and types needed to process // exceptions. bool SjLjEHPrepareImpl::doInitialization(Module &M) { ExceptionModel = M.getExceptionModel(); - // Build the function context structure. - // builtin_setjmp uses a five word jbuf - Type *VoidPtrTy = PointerType::getUnqual(M.getContext()); - DataTy = M.getDataLayout().getIntPtrType(M.getContext()); - doubleUnderDataTy = ArrayType::get(DataTy, 4); - doubleUnderJBufTy = ArrayType::get(VoidPtrTy, 5); - Type *Int32Ty = Type::getInt32Ty(M.getContext()); - FunctionContextTy = StructType::get(VoidPtrTy, // __prev - Int32Ty, // call_site - doubleUnderDataTy, // __data - VoidPtrTy, // __personality - VoidPtrTy, // __lsda - doubleUnderJBufTy // __jbuf - ); + FunctionContextTy = getSjLjFunctionContextType(M); + doubleUnderDataTy = FunctionContextTy->getElementType(2); + doubleUnderJBufTy = FunctionContextTy->getElementType(5); + DataTy = cast<IntegerType>(doubleUnderDataTy->getArrayElementType()); return false; } diff --git a/llvm/lib/Target/VE/VEISelLowering.cpp b/llvm/lib/Target/VE/VEISelLowering.cpp index 18163c8ae1c7df..3d9b4dbab3460c 100644 --- a/llvm/lib/Target/VE/VEISelLowering.cpp +++ b/llvm/lib/Target/VE/VEISelLowering.cpp @@ -28,6 +28,7 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAG.h" +#include "llvm/CodeGen/SjLjEHPrepare.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" @@ -2368,13 +2369,11 @@ VETargetLowering::emitSjLjDispatchBlock(MachineInstr &MI, assert(!LPadList.empty() && "No landing pad destinations for the dispatch jump table!"); - // The %fn_context is allocated like below (from --print-after=sjljehprepare): - // %fn_context = alloca { ptr, i32, [4 x i64], ptr, ptr, [5 x ptr] } - // - // This `[5 x ptr]` is jmpbuf, so jmpbuf[1] is FI+72. - // First `i32` is callsite, so callsite is FI+8. - static const int OffsetIC = 72; - static const int OffsetCS = 8; + const DataLayout &Layout = MF->getDataLayout(); + const StructLayout *SL = Layout.getStructLayout( + getSjLjFunctionContextType(*MF->getFunction().getParent())); + const int OffsetIC = SL->getElementOffset(5) + Layout.getPointerSize(); + const int OffsetCS = SL->getElementOffset(1); // Create the MBBs for the dispatch code like following: // diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index ec2fb6c7751d4f..6e1d55d7cfa649 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -38,6 +38,7 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SDPatternMatch.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/CodeGen/SjLjEHPrepare.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/WinEHFuncInfo.h" #include "llvm/IR/CallingConv.h" @@ -38818,8 +38819,11 @@ void X86TargetLowering::SetupEntryBlockForSjLj(MachineInstr &MI, .addReg(0); } + const DataLayout &DL = MF->getDataLayout(); + const StructLayout *SL = DL.getStructLayout( + getSjLjFunctionContextType(*MF->getFunction().getParent())); MachineInstrBuilder MIB = BuildMI(*MBB, MI, MIMD, TII->get(Op)); - addFrameReference(MIB, FI, Subtarget.is64Bit() ? 72 : 36); + addFrameReference(MIB, FI, SL->getElementOffset(5) + DL.getPointerSize()); if (UseImmLabel) MIB.addMBB(DispatchBB); else @@ -38925,8 +38929,10 @@ X86TargetLowering::EmitSjLjDispatchBlock(MachineInstr &MI, // IReg is used as an index in a memory operand and therefore can't be SP Register IReg = MRI->createVirtualRegister(&X86::GR32_NOSPRegClass); + const StructLayout *SL = MF->getDataLayout().getStructLayout( + getSjLjFunctionContextType(*MF->getFunction().getParent())); addFrameReference(BuildMI(DispatchBB, MIMD, TII->get(X86::MOV32rm), IReg), FI, - Subtarget.is64Bit() ? 8 : 4); + SL->getElementOffset(1)); BuildMI(DispatchBB, MIMD, TII->get(X86::CMP32ri)) .addReg(IReg) .addImm(LPadList.size()); diff --git a/llvm/test/CodeGen/X86/sjlj-eh.ll b/llvm/test/CodeGen/X86/sjlj-eh.ll index 87aa9fe2953ebf..dac5c9490453fc 100644 --- a/llvm/test/CodeGen/X86/sjlj-eh.ll +++ b/llvm/test/CodeGen/X86/sjlj-eh.ll @@ -2,6 +2,7 @@ ; RUN: llc -mtriple i386-windows-gnu -regalloc-csr-cost-scale=0 -exception-model sjlj -filetype asm -o - %s -verify-machineinstrs=0 | FileCheck %s ; RUN: llc -mtriple x86_64-windows-gnu -exception-model sjlj -filetype asm -o - %s -verify-machineinstrs=0 | FileCheck %s -check-prefix CHECK-X64 ; RUN: llc -mtriple x86_64-linux -exception-model sjlj -filetype asm -o - %s -verify-machineinstrs=0 | FileCheck %s -check-prefix CHECK-X64-LINUX +; RUN: llc -mtriple x86_64-linux-gnux32 -exception-model sjlj -filetype asm -o - %s -verify-machineinstrs=0 | FileCheck %s -check-prefix CHECK-X32 declare void @_Z20function_that_throwsv() declare i32 @__gxx_personality_sj0(...) @@ -132,3 +133,17 @@ try.cont: ; *Handlers[UFC.__callsite] ; CHECK-X64-LINUX: leaq .[[TABLE:LJTI[0-9]+_[0-9]+]](%rip), %rcx ; CHECK-X64-LINUX: jmpq *(%rcx,%rax,8) + +; x32 has 32-bit pointers and 64-bit __data words. +; CHECK-X32: movl %eax, -72(%ebp) +; CHECK-X32: movl $GCC_except_table0, -68(%ebp) +; CHECK-X32: movl %ebp, -64(%ebp) +; CHECK-X32: movl %esp, -56(%ebp) +; CHECK-X32: movl $.[[RESUME:LBB[0-9]+_[0-9]+]], -60(%ebp) +; CHECK-X32: leal -112(%rbp), %edi +; CHECK-X32: callq _Unwind_SjLj_Register@PLT +; CHECK-X32: movl $1, -108(%ebp) +; CHECK-X32: .[[RESUME]]: +; CHECK-X32: movl -108(%ebp), %eax +; CHECK-X32: movq -104(%ebp), %rax +; CHECK-X32: movq -96(%ebp), %rcx diff --git a/llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll b/llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll index 4db9e1d14e3660..140e994159712c 100644 --- a/llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll +++ b/llvm/test/Transforms/SjLjEHPrepare/function-context-layout.ll @@ -1,8 +1,9 @@ -; RUN: opt -S -passes=sjlj-eh-prepare -data-layout=p:32:32 < %s | FileCheck -check-prefix=P32 %s -; RUN: opt -S -passes=sjlj-eh-prepare -data-layout=p:64:64 < %s | FileCheck -check-prefix=P64 %s +; RUN: opt -S -passes=sjlj-eh-prepare -mtriple=i686-linux-gnu < %s | FileCheck -check-prefix=P32 %s +; RUN: opt -S -passes=sjlj-eh-prepare -mtriple=x86_64-linux-gnu < %s | FileCheck -check-prefix=P64 %s +; RUN: opt -S -passes=sjlj-eh-prepare -mtriple=x86_64-linux-gnux32 -data-layout=p:32:32 < %s | FileCheck -check-prefix=X32 %s ; The function context matches libgcc's SjLj_Function_Context: call_site is -; always i32, and the __data words are pointer sized. +; always i32, and the __data words are register sized. ; P32: %fn_context = alloca { ptr, i32, [4 x i32], ptr, ptr, [5 x ptr] } ; P32: store volatile i32 1, ptr %call_site @@ -13,6 +14,11 @@ ; P64: store volatile i32 1, ptr %call_site ; P64: %exn_val = load volatile i64, ptr %exception_gep ; P64: %exn_selector_val = load volatile i64, ptr %exn_selector_gep + +; X32: %fn_context = alloca { ptr, i32, [4 x i64], ptr, ptr, [5 x ptr] } +; X32: store volatile i32 1, ptr %call_site +; X32: %exn_val = load volatile i64, ptr %exception_gep +; X32: %exn_selector_val = load volatile i64, ptr %exn_selector_gep define void @test() personality ptr @__gxx_personality_sj0 { entry: invoke void @may_throw() diff --git a/llvm/test/Transforms/SjLjEHPrepare/respect-exception-model-flag.ll b/llvm/test/Transforms/SjLjEHPrepare/respect-exception-model-flag.ll index bd496bcb0d61ad..94d26dcda5dd73 100644 --- a/llvm/test/Transforms/SjLjEHPrepare/respect-exception-model-flag.ll +++ b/llvm/test/Transforms/SjLjEHPrepare/respect-exception-model-flag.ll @@ -3,8 +3,8 @@ ; any other model. ; RUN: split-file %s %t -; RUN: opt -passes=sjlj-eh-prepare -S %t/sjlj.ll | FileCheck --check-prefix=SJLJ %s -; RUN: opt -passes=sjlj-eh-prepare -S %t/other.ll | FileCheck --check-prefix=OTHER %s +; RUN: opt -passes=sjlj-eh-prepare -mtriple=x86_64-linux-gnu -S %t/sjlj.ll | FileCheck --check-prefix=SJLJ %s +; RUN: opt -passes=sjlj-eh-prepare -mtriple=x86_64-linux-gnu -S %t/other.ll | FileCheck --check-prefix=OTHER %s ;--- sjlj.ll ; SJLJ-LABEL: define void @f() personality ptr @__gxx_personality_sj0 { diff --git a/llvm/test/Transforms/SjLjEHPrepare/sjlj-eh-prepare.ll b/llvm/test/Transforms/SjLjEHPrepare/sjlj-eh-prepare.ll index 208b78c80c4e37..1df767f8ce9a97 100644 --- a/llvm/test/Transforms/SjLjEHPrepare/sjlj-eh-prepare.ll +++ b/llvm/test/Transforms/SjLjEHPrepare/sjlj-eh-prepare.ll @@ -1,4 +1,4 @@ -; RUN: opt -p sjlj-eh-prepare %s -S -o - | FileCheck %s +; RUN: opt -p sjlj-eh-prepare -mtriple=x86_64-linux-gnu %s -S -o - | FileCheck %s ; Check that callsites are set up correctly: ; 1. Throwing call in the entry block does not set call_site >From f6bf815713d52f1a603ca895feb23535a2d777af Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Tue, 3 Nov 2026 00:14:24 -0800 Subject: [PATCH 3/3] X86: Update the SjLj function context layout comments in sjlj-eh.ll Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> --- llvm/test/CodeGen/X86/sjlj-eh.ll | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/llvm/test/CodeGen/X86/sjlj-eh.ll b/llvm/test/CodeGen/X86/sjlj-eh.ll index dac5c9490453fc..7c99955805f66b 100644 --- a/llvm/test/CodeGen/X86/sjlj-eh.ll +++ b/llvm/test/CodeGen/X86/sjlj-eh.ll @@ -28,11 +28,11 @@ try.cont: ; struct _Unwind_FunctionContext { ; +00 struct _Unwind_FunctionContext *prev; -64(%ebp) -; +04 uint32_t __callsite; -60(%ebp) -; +08 uint32_t __buffer[4]; -56(%ebp) +; +04 int __callsite; -60(%ebp) +; +08 _Unwind_Word __buffer[4]; -56(%ebp) ; +24 __personality_routine __personality; -40(%ebp) ; +28 uintptr_t __lsda; -36(%ebp) -; +32 ptr__jbuf[]; -32(%ebp) +; +32 void *__jbuf[]; -32(%ebp) ; }; @@ -74,12 +74,12 @@ try.cont: ; struct _Unwind_FunctionContext { -; +00 struct _Unwind_FunctionContext *prev; -312(%rbp) -; +08 uint32_t __callsite; -304(%rbp) -; +12 uint32_t __buffer[4]; -300(%rbp) -; +32 __personality_routine __personality; -280(%rbp) -; +40 uintptr_t __lsda; -272(%rbp) -; +48 ptr__jbuf[]; -264(%rbp) +; +00 struct _Unwind_FunctionContext *prev; -328(%rbp) +; +08 int __callsite; -320(%rbp) +; +16 _Unwind_Word __buffer[4]; -312(%rbp) +; +48 __personality_routine __personality; -280(%rbp) +; +56 uintptr_t __lsda; -272(%rbp) +; +64 void *__jbuf[]; -264(%rbp) ; }; @@ -135,6 +135,15 @@ try.cont: ; CHECK-X64-LINUX: jmpq *(%rcx,%rax,8) ; x32 has 32-bit pointers and 64-bit __data words. +; struct _Unwind_FunctionContext { +; +00 struct _Unwind_FunctionContext *prev; -112(%ebp) +; +04 int __callsite; -108(%ebp) +; +08 _Unwind_Word __buffer[4]; -104(%ebp) +; +40 __personality_routine __personality; -72(%ebp) +; +44 uintptr_t __lsda; -68(%ebp) +; +48 void *__jbuf[]; -64(%ebp) +; }; + ; CHECK-X32: movl %eax, -72(%ebp) ; CHECK-X32: movl $GCC_except_table0, -68(%ebp) ; CHECK-X32: movl %ebp, -64(%ebp) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
