[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