[llvm] [Hexagon] Shrink __builtin_trap lowering from two words to one (PR #189210)

Brian Cain via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 28 21:22:05 PDT 2026


https://github.com/androm3da created https://github.com/llvm/llvm-project/pull/189210

Replace the two-word misaligned load (PS_loadrdabs + constant extender for 0xBADC0FEE) with a single 32-bit zero word emitted directly by the AsmPrinter.  The zero word decodes as a duplex with both slots writing R0, which is an illegal packet -- the hardware raises a "multiple writes to register" exception.

This halves the code size of every __builtin_trap / unreachable-with- trap-unreachable from 8 bytes to 4 bytes.

With libc++'s hardening mode https://libcxx.llvm.org/Hardening.html, we see many __builtin_trap()s inlined into call sites to C++ library functionality, so the overhead of this pseudo-instruction is very signficant and creates a barrier to its deployment.

>From 66dea2d2ea5281e0a2ba2cd5fa992285f7127d0b Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Sat, 28 Mar 2026 21:00:27 -0700
Subject: [PATCH] [Hexagon] Shrink __builtin_trap lowering from two words to
 one

Replace the two-word misaligned load (PS_loadrdabs + constant extender
for 0xBADC0FEE) with a single 32-bit zero word emitted directly by the
AsmPrinter.  The zero word decodes as a duplex with both slots writing
R0, which is an illegal packet -- the hardware raises a "multiple
writes to register" exception.

This halves the code size of every __builtin_trap / unreachable-with-
trap-unreachable from 8 bytes to 4 bytes.

With libc++'s hardening mode https://libcxx.llvm.org/Hardening.html,
we see many __builtin_trap()s inlined into call sites to C++ library
functionality, so the overhead of this pseudo-instruction is very
signficant and creates a barrier to its deployment.
---
 llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp |  9 +++++
 llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp  | 38 +++----------------
 llvm/lib/Target/Hexagon/HexagonPseudo.td      |  4 +-
 llvm/test/CodeGen/Hexagon/trap-crash.ll       |  7 ++--
 llvm/test/CodeGen/Hexagon/trap-unreachable.ll |  4 +-
 5 files changed, 24 insertions(+), 38 deletions(-)

diff --git a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
index 37a44d6033b84..ddc50b16b197f 100644
--- a/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonAsmPrinter.cpp
@@ -753,6 +753,15 @@ void HexagonAsmPrinter::emitInstruction(const MachineInstr *MI) {
   Hexagon_MC::verifyInstructionPredicates(MI->getOpcode(),
                                           getSubtargetInfo().getFeatureBits());
 
+  // Crash is emitted as a raw 32-bit zero, which the processor decodes as a
+  // duplex with both slots writing R0 -- an illegal packet that raises a
+  // hardware exception.  We bypass the normal MCInst path because the
+  // assembler would (correctly) reject the duplicate destination.
+  if (MI->getOpcode() == Hexagon::PS_crash) {
+    OutStreamer->emitInt32(0);
+    return;
+  }
+
   MCInst MCB;
   MCB.setOpcode(Hexagon::BUNDLE);
   MCB.addOperand(MCOperand::createImm(0));
diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
index 732256f61556f..77f4aed7cb646 100644
--- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp
@@ -1439,38 +1439,12 @@ bool HexagonInstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
       return true;
     }
 
-    case Hexagon::PS_crash: {
-      // Generate a misaligned load that is guaranteed to cause a crash.
-      class CrashPseudoSourceValue : public PseudoSourceValue {
-      public:
-        CrashPseudoSourceValue(const TargetMachine &TM)
-            : PseudoSourceValue(TargetCustom, TM) {}
-
-        bool isConstant(const MachineFrameInfo *) const override {
-          return false;
-        }
-        bool isAliased(const MachineFrameInfo *) const override {
-          return false;
-        }
-        bool mayAlias(const MachineFrameInfo *) const override {
-          return false;
-        }
-        void printCustom(raw_ostream &OS) const override {
-          OS << "MisalignedCrash";
-        }
-      };
-
-      static const CrashPseudoSourceValue CrashPSV(MF.getTarget());
-      MachineMemOperand *MMO = MF.getMachineMemOperand(
-          MachinePointerInfo(&CrashPSV),
-          MachineMemOperand::MOLoad | MachineMemOperand::MOVolatile, 8,
-          Align(1));
-      BuildMI(MBB, MI, DL, get(Hexagon::PS_loadrdabs), Hexagon::D13)
-        .addImm(0xBADC0FEE)  // Misaligned load.
-        .addMemOperand(MMO);
-      MBB.erase(MI);
-      return true;
-    }
+    case Hexagon::PS_crash:
+      // PS_crash is handled directly by HexagonAsmPrinter, which emits
+      // a single word (0x00000000) that decodes as an illegal duplex with
+      // both slots writing R0.  The hardware raises a "multiple writes to
+      // register" exception.
+      return false;
 
     case Hexagon::PS_tailcall_i:
       MI.setDesc(get(Hexagon::J2_jump));
diff --git a/llvm/lib/Target/Hexagon/HexagonPseudo.td b/llvm/lib/Target/Hexagon/HexagonPseudo.td
index 4e5e8c3d26f00..d1741b06c137c 100644
--- a/llvm/lib/Target/Hexagon/HexagonPseudo.td
+++ b/llvm/lib/Target/Hexagon/HexagonPseudo.td
@@ -617,7 +617,9 @@ defm PS_storeri : NewCircularStore<IntRegs, WordAccess>;
 defm PS_storerd : NewCircularStore<DoubleRegs, WordAccess>;
 
 // A pseudo that generates a runtime crash. This is used to implement
-// __builtin_trap.
+// __builtin_trap.  It is emitted directly by the AsmPrinter as a single
+// 32-bit zero word, which decodes as a duplex with both slots writing R0.
+// The hardware raises a "multiple writes to register" exception.
 let hasSideEffects = 1, isPseudo = 1, isCodeGenOnly = 1, isSolo = 1 in
 def PS_crash: InstHexagon<(outs), (ins), "", [], "", PSEUDO, TypePSEUDO>;
 
diff --git a/llvm/test/CodeGen/Hexagon/trap-crash.ll b/llvm/test/CodeGen/Hexagon/trap-crash.ll
index c19f90c297abb..7b0ee02ae718b 100644
--- a/llvm/test/CodeGen/Hexagon/trap-crash.ll
+++ b/llvm/test/CodeGen/Hexagon/trap-crash.ll
@@ -1,9 +1,10 @@
 ; RUN: llc -mtriple=hexagon --verify-machineinstrs < %s | FileCheck %s
 
-; Generate code that is guaranteed to crash. At the moment, it's a
-; misaligned load.
+; Generate code that is guaranteed to crash.  The trap is a 32-bit zero word
+; that decodes as a duplex writing R0 from both slots, which triggers a
+; hardware exception.
 ; CHECK-LABEL: f0
-; CHECK: memd(##3134984174)
+; CHECK: .word 0
 
 target triple = "hexagon"
 
diff --git a/llvm/test/CodeGen/Hexagon/trap-unreachable.ll b/llvm/test/CodeGen/Hexagon/trap-unreachable.ll
index 7051dda1432c3..065d07e38deee 100644
--- a/llvm/test/CodeGen/Hexagon/trap-unreachable.ll
+++ b/llvm/test/CodeGen/Hexagon/trap-unreachable.ll
@@ -1,7 +1,7 @@
 ; RUN: llc -mtriple=hexagon -trap-unreachable < %s | FileCheck %s
 
-; Trap is implemented via a misaligned load.
-; CHECK: memd(##3134984174)
+; Trap is a 32-bit zero word that the processor decodes as an illegal duplex.
+; CHECK: .word 0
 
 define void @fred() #0 {
   unreachable



More information about the llvm-commits mailing list