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

Reply via email to