https://github.com/trungnt2910 created 
https://github.com/llvm/llvm-project/pull/184953

This commit implements Windows Structured Exception Handling (SEH) support for 
ARM `clang` in MSVC mode.

This includes enabling the relevant language constructs in the Clang frontend 
and adding new ARM-specific code lowering logic.

>From b44eb075b248044353a44f5379809699de0a2cac Mon Sep 17 00:00:00 2001
From: Trung Nguyen <[email protected]>
Date: Fri, 6 Mar 2026 16:52:19 +1100
Subject: [PATCH] [ARM] Add support for Windows SEH

This commit implements Windows Structured Exception Handling (SEH)
support for ARM `clang` in MSVC mode.

This includes enabling the relevant language constructs in the
Clang frontend and adding new ARM-specific code lowering logic.
---
 clang/include/clang/Basic/TargetInfo.h       |  3 ++-
 llvm/lib/CodeGen/AsmPrinter/WinException.cpp |  7 ++++---
 llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp | 10 ++++++++++
 llvm/lib/Target/ARM/ARMFrameLowering.cpp     |  6 ++++++
 llvm/lib/Target/ARM/ARMISelLowering.cpp      | 17 +++++++++++++++++
 llvm/lib/Target/ARM/ARMInstrInfo.td          |  6 ++++++
 6 files changed, 45 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/TargetInfo.h 
b/clang/include/clang/Basic/TargetInfo.h
index ec6cd2be7c3c5..05c8615deb3ce 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1664,7 +1664,8 @@ class TargetInfo : public TransferrableTargetInfo,
   bool isSEHTrySupported() const {
     return getTriple().isOSWindows() &&
            (getTriple().isX86() ||
-            getTriple().getArch() == llvm::Triple::aarch64);
+            getTriple().getArch() == llvm::Triple::aarch64 ||
+            getTriple().isThumb());
   }
 
   /// Return true if {|} are normal characters in the asm string.
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp 
b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
index 90d8196ffb82a..ca579c22f66be 100644
--- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
@@ -33,9 +33,10 @@
 using namespace llvm;
 
 WinException::WinException(AsmPrinter *A) : EHStreamer(A) {
-  // MSVC's EH tables are always composed of 32-bit words.  All known 64-bit
-  // platforms use an imagerel32 relocation to refer to symbols.
-  useImageRel32 = (A->getDataLayout().getPointerSizeInBits() == 64);
+  // MSVC's EH tables are always composed of 32-bit words. All known
+  // architectures use an imagerel32 relocation to refer to symbols, except
+  // 32-bit x86.
+  useImageRel32 = A->TM.getTargetTriple().getArch() != Triple::x86;
   isAArch64 = Asm->TM.getTargetTriple().isAArch64();
   isThumb = Asm->TM.getTargetTriple().isThumb();
 }
diff --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp 
b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
index 14e4c19a8ac1a..69154fd6e749a 100644
--- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -2242,6 +2242,16 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
       return true;
     }
 
+    case ARM::CLEANUPRET:
+    case ARM::CATCHRET: {
+      bool isThumb = STI->isThumb();
+      unsigned RetOpc = isThumb ? ARM::tBX_RET : ARM::BX_RET;
+      BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(RetOpc))
+          .add(predOps(ARMCC::AL));
+      MI.eraseFromParent();
+      return true;
+    }
+
     case ARM::TCRETURNdi:
     case ARM::TCRETURNri:
     case ARM::TCRETURNrinotr12: {
diff --git a/llvm/lib/Target/ARM/ARMFrameLowering.cpp 
b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
index 7d6be065d208a..940ae6006777c 100644
--- a/llvm/lib/Target/ARM/ARMFrameLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMFrameLowering.cpp
@@ -443,6 +443,9 @@ static MachineBasicBlock::iterator 
insertSEH(MachineBasicBlock::iterator MBBI,
   default:
     report_fatal_error("No SEH Opcode for instruction " + TII.getName(Opc));
     break;
+  case ARM::CLEANUPRET:
+  case ARM::CATCHRET:
+    break;
   case ARM::t2ADDri:   // add.w r11, sp, #xx
   case ARM::t2ADDri12: // add.w r11, sp, #xx
   case ARM::t2MOVTi16: // movt  r4, #xx
@@ -2369,6 +2372,9 @@ static unsigned estimateRSStackSizeLimit(MachineFunction 
&MF,
         if (!MI.getOperand(i).isFI())
           continue;
 
+        if (MI.getOpcode() == TargetOpcode::LOCAL_ESCAPE)
+          break;
+
         // When using ADDri to get the address of a stack object, 255 is the
         // largest offset guaranteed to fit in the immediate offset.
         if (MI.getOpcode() == ARM::ADDri) {
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp 
b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index eb757df6a9f28..c1b5879e10276 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -3838,6 +3838,23 @@ ARMTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, 
SelectionDAG &DAG,
   SDLoc dl(Op);
   switch (IntNo) {
   default: return SDValue();    // Don't custom lower most intrinsics.
+  case Intrinsic::localaddress: {
+    const MachineFunction &MF = DAG.getMachineFunction();
+    const TargetRegisterInfo *RegInfo = Subtarget->getRegisterInfo();
+    unsigned Reg = RegInfo->getFrameRegister(MF);
+    return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg,
+                              Op.getSimpleValueType());
+  }
+  case Intrinsic::eh_recoverfp: {
+    SDValue FnOp = Op.getOperand(1);
+    SDValue IncomingFPOp = Op.getOperand(2);
+    GlobalAddressSDNode *GSD = dyn_cast<GlobalAddressSDNode>(FnOp);
+    auto *Fn = dyn_cast_or_null<Function>(GSD ? GSD->getGlobal() : nullptr);
+    if (!Fn)
+      report_fatal_error(
+          "llvm.eh.recoverfp must take a function as the first argument");
+    return IncomingFPOp;
+  }
   case Intrinsic::thread_pointer: {
     EVT PtrVT = getPointerTy(DAG.getDataLayout());
     return DAG.getNode(ARMISD::THREAD_POINTER, dl, PtrVT);
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td 
b/llvm/lib/Target/ARM/ARMInstrInfo.td
index b72aa4b28736e..b2c7337041800 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -6725,3 +6725,9 @@ let isPseudo = 1 in {
   let isTerminator = 1 in
   def SEH_EpilogEnd : PseudoInst<(outs), (ins), NoItinerary, []>, Sched<[]>;
 }
+
+// C++ Exception / SEH Pseudo Instructions
+let isTerminator = 1, isReturn = 1, isBarrier = 1, isCodeGenOnly = 1, 
hasNoSchedulingInfo = 1 in {
+  def CLEANUPRET : PseudoInst<(outs), (ins), NoItinerary, [(cleanupret bb)]>, 
Sched<[]>;
+  def CATCHRET : PseudoInst<(outs), (ins arm_br_target:$dst, 
arm_br_target:$src), NoItinerary, [(catchret bb:$dst, bb:$src)]>, Sched<[]>;
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to