Skip to content

Commit d365a45

Browse files
authored
[GlobalISel] Introduce G_TRAP, G_DEBUGTRAP, G_UBSANTRAP (#84941)
Here we introduce three new GMIR instructions to cover a set of trap intrinsics. The idea behind it is that generic intrinsics shouldn't be used with G_INTRINSIC opcode. These new instructions can match perfectly with existing trap ISD nodes. It allows X86, AArch64, RISCV and Mips to reuse SelectionDAG patterns for selection and avoid manual selection. However AMDGPU is an exception. It selects traps during legalization regardless SelectionDAG or GlobalISel. Since there are not many places where traps are used, this change attempts to clean up all the usages of G_INTRINSIC with trap intrinsics. So, there is no stage when both G_TRAP and G_INTRINSIC_W_SIDE_EFFECTS(@llvm.trap) are allowed.
1 parent d7c6728 commit d365a45

File tree

27 files changed

+276
-131
lines changed

27 files changed

+276
-131
lines changed

llvm/docs/GlobalISel/GenericOpcode.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,25 @@ The _CONVERGENT variant corresponds to an LLVM IR intrinsic marked `convergent`.
939939
Unlike SelectionDAG, there is no _VOID variant. Both of these are permitted
940940
to have zero, one, or multiple results.
941941

942+
G_TRAP, G_DEBUGTRAP, G_UBSANTRAP
943+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
944+
945+
Represents :ref:`llvm.trap <llvm.trap>`, :ref:`llvm.debugtrap <llvm.debugtrap>`
946+
and :ref:`llvm.ubsantrap <llvm.ubsantrap>` that generate a target dependent
947+
trap instructions.
948+
949+
.. code-block:: none
950+
951+
G_TRAP
952+
953+
.. code-block:: none
954+
955+
G_DEBUGTRAP
956+
957+
.. code-block:: none
958+
959+
G_UBSANTRAP 12
960+
942961
Variadic Arguments
943962
------------------
944963

llvm/docs/LangRef.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26926,6 +26926,8 @@ Arguments:
2692626926

2692726927
The argument should be an MDTuple containing any number of MDStrings.
2692826928

26929+
.. _llvm.trap:
26930+
2692926931
'``llvm.trap``' Intrinsic
2693026932
^^^^^^^^^^^^^^^^^^^^^^^^^
2693126933

@@ -26953,6 +26955,8 @@ This intrinsic is lowered to the target dependent trap instruction. If
2695326955
the target does not have a trap instruction, this intrinsic will be
2695426956
lowered to a call of the ``abort()`` function.
2695526957

26958+
.. _llvm.debugtrap:
26959+
2695626960
'``llvm.debugtrap``' Intrinsic
2695726961
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2695826962

@@ -26980,6 +26984,8 @@ This intrinsic is lowered to code which is intended to cause an
2698026984
execution trap with the intention of requesting the attention of a
2698126985
debugger.
2698226986

26987+
.. _llvm.ubsantrap:
26988+
2698326989
'``llvm.ubsantrap``' Intrinsic
2698426990
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2698526991

llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,10 @@ class IRTranslator : public MachineFunctionPass {
243243
bool translateMemFunc(const CallInst &CI, MachineIRBuilder &MIRBuilder,
244244
unsigned Opcode);
245245

246+
/// Translate an LLVM trap intrinsic (trap, debugtrap, ubsantrap).
247+
bool translateTrap(const CallInst &U, MachineIRBuilder &MIRBuilder,
248+
unsigned Opcode);
249+
246250
// Translate @llvm.experimental.vector.interleave2 and
247251
// @llvm.experimental.vector.deinterleave2 intrinsics for fixed-width vector
248252
// types into vector shuffles.

llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2113,6 +2113,11 @@ class MachineIRBuilder {
21132113
DstMMO, SrcMMO);
21142114
}
21152115

2116+
/// Build and insert G_TRAP or G_DEBUGTRAP
2117+
MachineInstrBuilder buildTrap(bool Debug = false) {
2118+
return buildInstr(Debug ? TargetOpcode::G_DEBUGTRAP : TargetOpcode::G_TRAP);
2119+
}
2120+
21162121
/// Build and insert \p Dst = G_SBFX \p Src, \p LSB, \p Width.
21172122
MachineInstrBuilder buildSbfx(const DstOp &Dst, const SrcOp &Src,
21182123
const SrcOp &LSB, const SrcOp &Width) {

llvm/include/llvm/Support/TargetOpcodes.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,11 @@ HANDLE_TARGET_OPCODE(G_MEMMOVE)
837837
HANDLE_TARGET_OPCODE(G_MEMSET)
838838
HANDLE_TARGET_OPCODE(G_BZERO)
839839

840+
/// llvm.trap, llvm.debugtrap and llvm.ubsantrap intrinsics
841+
HANDLE_TARGET_OPCODE(G_TRAP)
842+
HANDLE_TARGET_OPCODE(G_DEBUGTRAP)
843+
HANDLE_TARGET_OPCODE(G_UBSANTRAP)
844+
840845
/// Vector reductions
841846
HANDLE_TARGET_OPCODE(G_VECREDUCE_SEQ_FADD)
842847
HANDLE_TARGET_OPCODE(G_VECREDUCE_SEQ_FMUL)

llvm/include/llvm/Target/GenericOpcodes.td

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,28 @@ def G_BZERO : GenericInstruction {
15751575
let mayStore = true;
15761576
}
15771577

1578+
//------------------------------------------------------------------------------
1579+
// Trap intrinsics
1580+
//------------------------------------------------------------------------------
1581+
def G_TRAP : GenericInstruction {
1582+
let OutOperandList = (outs);
1583+
let InOperandList = (ins);
1584+
let hasSideEffects = true;
1585+
let mayStore = true;
1586+
}
1587+
1588+
def G_DEBUGTRAP : GenericInstruction {
1589+
let OutOperandList = (outs);
1590+
let InOperandList = (ins);
1591+
let hasSideEffects = true;
1592+
}
1593+
1594+
def G_UBSANTRAP : GenericInstruction {
1595+
let OutOperandList = (outs);
1596+
let InOperandList = (ins i8imm:$kind);
1597+
let hasSideEffects = true;
1598+
}
1599+
15781600
//------------------------------------------------------------------------------
15791601
// Bitfield extraction.
15801602
//------------------------------------------------------------------------------

llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,9 @@ def : GINodeEquiv<G_ATOMICRMW_UINC_WRAP, atomic_load_uinc_wrap>;
250250
def : GINodeEquiv<G_ATOMICRMW_UDEC_WRAP, atomic_load_udec_wrap>;
251251
def : GINodeEquiv<G_FENCE, atomic_fence>;
252252
def : GINodeEquiv<G_PREFETCH, prefetch>;
253+
def : GINodeEquiv<G_TRAP, trap>;
254+
def : GINodeEquiv<G_DEBUGTRAP, debugtrap>;
255+
def : GINodeEquiv<G_UBSANTRAP, ubsantrap>;
253256

254257
// Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern.
255258
// Should be used on defs that subclass GIComplexOperandMatcher<>.

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,6 +1771,32 @@ bool IRTranslator::translateMemFunc(const CallInst &CI,
17711771
return true;
17721772
}
17731773

1774+
bool IRTranslator::translateTrap(const CallInst &CI,
1775+
MachineIRBuilder &MIRBuilder,
1776+
unsigned Opcode) {
1777+
StringRef TrapFuncName =
1778+
CI.getAttributes().getFnAttr("trap-func-name").getValueAsString();
1779+
if (TrapFuncName.empty()) {
1780+
if (Opcode == TargetOpcode::G_UBSANTRAP) {
1781+
uint64_t Code = cast<ConstantInt>(CI.getOperand(0))->getZExtValue();
1782+
MIRBuilder.buildInstr(Opcode, {}, ArrayRef<llvm::SrcOp>{Code});
1783+
} else {
1784+
MIRBuilder.buildInstr(Opcode);
1785+
}
1786+
return true;
1787+
}
1788+
1789+
CallLowering::CallLoweringInfo Info;
1790+
if (Opcode == TargetOpcode::G_UBSANTRAP)
1791+
Info.OrigArgs.push_back({getOrCreateVRegs(*CI.getArgOperand(0)),
1792+
CI.getArgOperand(0)->getType(), 0});
1793+
1794+
Info.Callee = MachineOperand::CreateES(TrapFuncName.data());
1795+
Info.CB = &CI;
1796+
Info.OrigRet = {Register(), Type::getVoidTy(CI.getContext()), 0};
1797+
return CLI->lowerCall(MIRBuilder, Info);
1798+
}
1799+
17741800
bool IRTranslator::translateVectorInterleave2Intrinsic(
17751801
const CallInst &CI, MachineIRBuilder &MIRBuilder) {
17761802
assert(CI.getIntrinsicID() == Intrinsic::experimental_vector_interleave2 &&
@@ -2459,22 +2485,11 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
24592485
return true;
24602486
}
24612487
case Intrinsic::trap:
2488+
return translateTrap(CI, MIRBuilder, TargetOpcode::G_TRAP);
24622489
case Intrinsic::debugtrap:
2463-
case Intrinsic::ubsantrap: {
2464-
StringRef TrapFuncName =
2465-
CI.getAttributes().getFnAttr("trap-func-name").getValueAsString();
2466-
if (TrapFuncName.empty())
2467-
break; // Use the default handling.
2468-
CallLowering::CallLoweringInfo Info;
2469-
if (ID == Intrinsic::ubsantrap) {
2470-
Info.OrigArgs.push_back({getOrCreateVRegs(*CI.getArgOperand(0)),
2471-
CI.getArgOperand(0)->getType(), 0});
2472-
}
2473-
Info.Callee = MachineOperand::CreateES(TrapFuncName.data());
2474-
Info.CB = &CI;
2475-
Info.OrigRet = {Register(), Type::getVoidTy(CI.getContext()), 0};
2476-
return CLI->lowerCall(MIRBuilder, Info);
2477-
}
2490+
return translateTrap(CI, MIRBuilder, TargetOpcode::G_DEBUGTRAP);
2491+
case Intrinsic::ubsantrap:
2492+
return translateTrap(CI, MIRBuilder, TargetOpcode::G_UBSANTRAP);
24782493
case Intrinsic::amdgcn_cs_chain:
24792494
return translateCallBase(CI, MIRBuilder);
24802495
case Intrinsic::fptrunc_round: {
@@ -3047,7 +3062,7 @@ bool IRTranslator::translateUnreachable(const User &U, MachineIRBuilder &MIRBuil
30473062
}
30483063
}
30493064

3050-
MIRBuilder.buildIntrinsic(Intrinsic::trap, ArrayRef<Register>());
3065+
MIRBuilder.buildTrap();
30513066
return true;
30523067
}
30533068

llvm/lib/CodeGen/MachineVerifier.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1867,6 +1867,17 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {
18671867

18681868
break;
18691869
}
1870+
case TargetOpcode::G_UBSANTRAP: {
1871+
const MachineOperand &KindOp = MI->getOperand(0);
1872+
if (!MI->getOperand(0).isImm()) {
1873+
report("Crash kind must be an immediate", &KindOp, 0);
1874+
break;
1875+
}
1876+
int64_t Kind = MI->getOperand(0).getImm();
1877+
if (!isInt<8>(Kind))
1878+
report("Crash kind must be 8 bit wide", &KindOp, 0);
1879+
break;
1880+
}
18701881
case TargetOpcode::G_VECREDUCE_SEQ_FADD:
18711882
case TargetOpcode::G_VECREDUCE_SEQ_FMUL: {
18721883
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8436,6 +8436,9 @@ def ubsan_trap_xform : SDNodeXForm<timm, [{
84368436
return CurDAG->getTargetConstant(N->getZExtValue() | ('U' << 8), SDLoc(N), MVT::i32);
84378437
}]>;
84388438

8439+
def gi_ubsan_trap_xform : GICustomOperandRenderer<"renderUbsanTrap">,
8440+
GISDNodeXFormEquiv<ubsan_trap_xform>;
8441+
84398442
def ubsan_trap_imm : TImmLeaf<i32, [{
84408443
return isUInt<8>(Imm);
84418444
}], ubsan_trap_xform>;

llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,8 @@ class AArch64InstructionSelector : public InstructionSelector {
479479
int OpIdx = -1) const;
480480
void renderLogicalImm64(MachineInstrBuilder &MIB, const MachineInstr &I,
481481
int OpIdx = -1) const;
482+
void renderUbsanTrap(MachineInstrBuilder &MIB, const MachineInstr &MI,
483+
int OpIdx) const;
482484
void renderFPImm16(MachineInstrBuilder &MIB, const MachineInstr &MI,
483485
int OpIdx = -1) const;
484486
void renderFPImm32(MachineInstrBuilder &MIB, const MachineInstr &MI,
@@ -6159,16 +6161,6 @@ bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
61596161
constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
61606162
break;
61616163
}
6162-
case Intrinsic::trap:
6163-
MIB.buildInstr(AArch64::BRK, {}, {}).addImm(1);
6164-
break;
6165-
case Intrinsic::debugtrap:
6166-
MIB.buildInstr(AArch64::BRK, {}, {}).addImm(0xF000);
6167-
break;
6168-
case Intrinsic::ubsantrap:
6169-
MIB.buildInstr(AArch64::BRK, {}, {})
6170-
.addImm(I.getOperand(1).getImm() | ('U' << 8));
6171-
break;
61726164
case Intrinsic::aarch64_neon_ld1x2: {
61736165
LLT Ty = MRI.getType(I.getOperand(0).getReg());
61746166
unsigned Opc = 0;
@@ -7663,6 +7655,14 @@ void AArch64InstructionSelector::renderLogicalImm64(
76637655
MIB.addImm(Enc);
76647656
}
76657657

7658+
void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
7659+
const MachineInstr &MI,
7660+
int OpIdx) const {
7661+
assert(MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
7662+
"Expected G_UBSANTRAP");
7663+
MIB.addImm(MI.getOperand(0).getImm() | ('U' << 8));
7664+
}
7665+
76667666
void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
76677667
const MachineInstr &MI,
76687668
int OpIdx) const {

llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2030,6 +2030,8 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
20302030
getActionDefinitionsBuilder({G_MEMCPY, G_MEMCPY_INLINE, G_MEMMOVE, G_MEMSET})
20312031
.lower();
20322032

2033+
getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP}).custom();
2034+
20332035
getActionDefinitionsBuilder({G_VASTART, G_VAARG, G_BRJT, G_JUMP_TABLE,
20342036
G_INDEXED_LOAD, G_INDEXED_SEXTLOAD,
20352037
G_INDEXED_ZEXTLOAD, G_INDEXED_STORE})
@@ -2134,6 +2136,10 @@ bool AMDGPULegalizerInfo::legalizeCustom(
21342136
return legalizeGetFPEnv(MI, MRI, B);
21352137
case TargetOpcode::G_SET_FPENV:
21362138
return legalizeSetFPEnv(MI, MRI, B);
2139+
case TargetOpcode::G_TRAP:
2140+
return legalizeTrap(MI, MRI, B);
2141+
case TargetOpcode::G_DEBUGTRAP:
2142+
return legalizeDebugTrap(MI, MRI, B);
21372143
default:
21382144
return false;
21392145
}
@@ -2925,7 +2931,7 @@ bool AMDGPULegalizerInfo::legalizeGlobalValue(
29252931
// functions that use local objects. However, if these dead functions are
29262932
// not eliminated, we don't want a compile time error. Just emit a warning
29272933
// and a trap, since there should be no callable path here.
2928-
B.buildIntrinsic(Intrinsic::trap, ArrayRef<Register>());
2934+
B.buildTrap();
29292935
B.buildUndef(DstReg);
29302936
MI.eraseFromParent();
29312937
return true;
@@ -6618,9 +6624,9 @@ bool AMDGPULegalizerInfo::legalizeSBufferLoad(LegalizerHelper &Helper,
66186624
}
66196625

66206626
// TODO: Move to selection
6621-
bool AMDGPULegalizerInfo::legalizeTrapIntrinsic(MachineInstr &MI,
6622-
MachineRegisterInfo &MRI,
6623-
MachineIRBuilder &B) const {
6627+
bool AMDGPULegalizerInfo::legalizeTrap(MachineInstr &MI,
6628+
MachineRegisterInfo &MRI,
6629+
MachineIRBuilder &B) const {
66246630
if (!ST.isTrapHandlerEnabled() ||
66256631
ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA)
66266632
return legalizeTrapEndpgm(MI, MRI, B);
@@ -6726,8 +6732,9 @@ bool AMDGPULegalizerInfo::legalizeTrapHsa(
67266732
return true;
67276733
}
67286734

6729-
bool AMDGPULegalizerInfo::legalizeDebugTrapIntrinsic(
6730-
MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const {
6735+
bool AMDGPULegalizerInfo::legalizeDebugTrap(MachineInstr &MI,
6736+
MachineRegisterInfo &MRI,
6737+
MachineIRBuilder &B) const {
67316738
// Is non-HSA path or trap-handler disabled? Then, report a warning
67326739
// accordingly
67336740
if (!ST.isTrapHandlerEnabled() ||
@@ -7270,10 +7277,6 @@ bool AMDGPULegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
72707277
case Intrinsic::amdgcn_struct_buffer_atomic_fadd_v2bf16:
72717278
case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd_v2bf16:
72727279
return legalizeBufferAtomic(MI, B, IntrID);
7273-
case Intrinsic::trap:
7274-
return legalizeTrapIntrinsic(MI, MRI, B);
7275-
case Intrinsic::debugtrap:
7276-
return legalizeDebugTrapIntrinsic(MI, MRI, B);
72777280
case Intrinsic::amdgcn_rsq_clamp:
72787281
return legalizeRsqClampIntrinsic(MI, MRI, B);
72797282
case Intrinsic::amdgcn_ds_fadd:

llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,16 +226,16 @@ class AMDGPULegalizerInfo final : public LegalizerInfo {
226226

227227
bool legalizeSBufferLoad(LegalizerHelper &Helper, MachineInstr &MI) const;
228228

229-
bool legalizeTrapIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI,
230-
MachineIRBuilder &B) const;
229+
bool legalizeTrap(MachineInstr &MI, MachineRegisterInfo &MRI,
230+
MachineIRBuilder &B) const;
231231
bool legalizeTrapEndpgm(MachineInstr &MI, MachineRegisterInfo &MRI,
232232
MachineIRBuilder &B) const;
233233
bool legalizeTrapHsaQueuePtr(MachineInstr &MI, MachineRegisterInfo &MRI,
234234
MachineIRBuilder &B) const;
235235
bool legalizeTrapHsa(MachineInstr &MI, MachineRegisterInfo &MRI,
236236
MachineIRBuilder &B) const;
237-
bool legalizeDebugTrapIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI,
238-
MachineIRBuilder &B) const;
237+
bool legalizeDebugTrap(MachineInstr &MI, MachineRegisterInfo &MRI,
238+
MachineIRBuilder &B) const;
239239

240240
bool legalizeIntrinsic(LegalizerHelper &Helper,
241241
MachineInstr &MI) const override;

llvm/lib/Target/Mips/MipsLegalizerInfo.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -508,16 +508,8 @@ bool MipsLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
508508
MachineInstr &MI) const {
509509
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
510510
const MipsSubtarget &ST = MI.getMF()->getSubtarget<MipsSubtarget>();
511-
const MipsInstrInfo &TII = *ST.getInstrInfo();
512-
const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
513-
const RegisterBankInfo &RBI = *ST.getRegBankInfo();
514511

515512
switch (cast<GIntrinsic>(MI).getIntrinsicID()) {
516-
case Intrinsic::trap: {
517-
MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP);
518-
MI.eraseFromParent();
519-
return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
520-
}
521513
case Intrinsic::vacopy: {
522514
MachinePointerInfo MPO;
523515
LLT PtrTy = LLT::pointer(0, 32);

0 commit comments

Comments
 (0)