[llvm] [AArch64] Report SEH pseudos as zero-size (PR #219276)

Jonas Heinle via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 13:47:18 PDT 2026


https://github.com/Kataglyphis updated https://github.com/llvm/llvm-project/pull/219276

>From 40f1b36c642e7e5ea552b82976a2e5e31a0313d8 Mon Sep 17 00:00:00 2001
From: Jonas Heinle <jonasheinle at googlemail.com>
Date: Thu, 27 Aug 2026 21:07:22 +0200
Subject: [PATCH] [AArch64] Report SEH pseudos as zero-size

The SEH_* pseudos only emit unwind opcodes into .xdata, never a code
byte. They are not meta-instructions, so getInstSizeInBytes fell through
to the default case and reported each one as a normal 4-byte
instruction. A prologue emits one per saved register, so on Windows
every function's size estimate was inflated.

This one is conservative, not a miscompile: BranchRelaxation relaxes
branches it does not need to, and AArch64CompressJumpTables leaves jump
tables wider than they have to be.

Size = 0 in AArch64InstrInfo.td cannot express this. The default case
tests `if (Desc.getSize())`, so a declared zero reads as "unset" and
still gives 4. I tried that first and measured no change at all.

Assisted-by: Claude (Anthropic)
---
 llvm/lib/Target/AArch64/AArch64InstrInfo.cpp  |  5 ++
 .../CodeGen/AArch64/wineh-seh-pseudo-size.mir | 46 +++++++++++++++++++
 2 files changed, 51 insertions(+)
 create mode 100644 llvm/test/CodeGen/AArch64/wineh-seh-pseudo-size.mir

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index 43aab1400e81f..673ee8bd5949b 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -220,6 +220,11 @@ unsigned AArch64InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
   if (MI.isMetaInstruction())
     return 0;
 
+  // SEH pseudos only emit unwind opcodes into .xdata. Size = 0 in the .td does
+  // not work: the default case below treats getSize() == 0 as "unset".
+  if (isSEHInstruction(MI))
+    return 0;
+
   // FIXME: We currently only handle pseudoinstructions that don't get expanded
   //        before the assembly printer.
   unsigned NumBytes = 0;
diff --git a/llvm/test/CodeGen/AArch64/wineh-seh-pseudo-size.mir b/llvm/test/CodeGen/AArch64/wineh-seh-pseudo-size.mir
new file mode 100644
index 0000000000000..3f5ace721d7d2
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/wineh-seh-pseudo-size.mir
@@ -0,0 +1,46 @@
+# SEH pseudos only emit unwind opcodes into .xdata, so they must not be counted
+# as 4-byte instructions. The branch range is narrowed so that counting the ten
+# SEH_Nops here would push the TBZ out of range and relax it needlessly.
+# RUN: llc -mtriple=aarch64-pc-windows-msvc -run-pass branch-relaxation \
+# RUN:     -aarch64-tbz-offset-bits=5 %s -o - | FileCheck %s
+
+# CHECK-LABEL: name: seh
+# CHECK:     TBZW renamable $w0, 0, %bb.2
+# CHECK-NOT: TBNZW
+
+--- |
+  define void @seh(i32 %x, ptr %p) {
+    ret void
+  }
+...
+---
+name:            seh
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    successors: %bb.1, %bb.2
+    liveins: $w0, $x1
+    TBZW renamable $w0, 0, %bb.2
+
+  bb.1:
+    successors: %bb.2
+    liveins: $x1
+    renamable $x2 = LDRXui renamable $x1, 0
+    renamable $x2 = LDRXui renamable $x1, 1
+    renamable $x2 = LDRXui renamable $x1, 2
+    renamable $x2 = LDRXui renamable $x1, 3
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    frame-setup SEH_Nop
+    B %bb.2
+
+  bb.2:
+    RET undef $lr
+...



More information about the llvm-commits mailing list