Skip to content

[GlobalISel] Introduce G_TRAP, G_DEBUGTRAP, G_UBSANTRAP #84941

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions llvm/docs/GlobalISel/GenericOpcode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,25 @@ The _CONVERGENT variant corresponds to an LLVM IR intrinsic marked `convergent`.
Unlike SelectionDAG, there is no _VOID variant. Both of these are permitted
to have zero, one, or multiple results.

G_TRAP, G_DEBUGTRAP, G_UBSANTRAP
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Represents :ref:`llvm.trap <llvm.trap>`, :ref:`llvm.debugtrap <llvm.debugtrap>`
and :ref:`llvm.ubsantrap <llvm.ubsantrap>` that generate a target dependent
trap instructions.

.. code-block:: none

G_TRAP

.. code-block:: none

G_DEBUGTRAP

.. code-block:: none

G_UBSANTRAP 12

Variadic Arguments
------------------

Expand Down
6 changes: 6 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26926,6 +26926,8 @@ Arguments:

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

.. _llvm.trap:

'``llvm.trap``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^

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

.. _llvm.debugtrap:

'``llvm.debugtrap``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

.. _llvm.ubsantrap:

'``llvm.ubsantrap``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
4 changes: 4 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,10 @@ class IRTranslator : public MachineFunctionPass {
bool translateMemFunc(const CallInst &CI, MachineIRBuilder &MIRBuilder,
unsigned Opcode);

/// Translate an LLVM trap intrinsic (trap, debugtrap, ubsantrap).
bool translateTrap(const CallInst &U, MachineIRBuilder &MIRBuilder,
unsigned Opcode);

// Translate @llvm.experimental.vector.interleave2 and
// @llvm.experimental.vector.deinterleave2 intrinsics for fixed-width vector
// types into vector shuffles.
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2113,6 +2113,11 @@ class MachineIRBuilder {
DstMMO, SrcMMO);
}

/// Build and insert G_TRAP or G_DEBUGTRAP
MachineInstrBuilder buildTrap(bool Debug = false) {
return buildInstr(Debug ? TargetOpcode::G_DEBUGTRAP : TargetOpcode::G_TRAP);
}

/// Build and insert \p Dst = G_SBFX \p Src, \p LSB, \p Width.
MachineInstrBuilder buildSbfx(const DstOp &Dst, const SrcOp &Src,
const SrcOp &LSB, const SrcOp &Width) {
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,11 @@ HANDLE_TARGET_OPCODE(G_MEMMOVE)
HANDLE_TARGET_OPCODE(G_MEMSET)
HANDLE_TARGET_OPCODE(G_BZERO)

/// llvm.trap, llvm.debugtrap and llvm.ubsantrap intrinsics
HANDLE_TARGET_OPCODE(G_TRAP)
HANDLE_TARGET_OPCODE(G_DEBUGTRAP)
HANDLE_TARGET_OPCODE(G_UBSANTRAP)

/// Vector reductions
HANDLE_TARGET_OPCODE(G_VECREDUCE_SEQ_FADD)
HANDLE_TARGET_OPCODE(G_VECREDUCE_SEQ_FMUL)
Expand Down
22 changes: 22 additions & 0 deletions llvm/include/llvm/Target/GenericOpcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -1575,6 +1575,28 @@ def G_BZERO : GenericInstruction {
let mayStore = true;
}

//------------------------------------------------------------------------------
// Trap intrinsics
//------------------------------------------------------------------------------
def G_TRAP : GenericInstruction {
let OutOperandList = (outs);
let InOperandList = (ins);
let hasSideEffects = true;
let mayStore = true;
}

def G_DEBUGTRAP : GenericInstruction {
let OutOperandList = (outs);
let InOperandList = (ins);
let hasSideEffects = true;
}

def G_UBSANTRAP : GenericInstruction {
let OutOperandList = (outs);
let InOperandList = (ins i8imm:$kind);
let hasSideEffects = true;
}

//------------------------------------------------------------------------------
// Bitfield extraction.
//------------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Target/GlobalISel/SelectionDAGCompat.td
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ def : GINodeEquiv<G_ATOMICRMW_UINC_WRAP, atomic_load_uinc_wrap>;
def : GINodeEquiv<G_ATOMICRMW_UDEC_WRAP, atomic_load_udec_wrap>;
def : GINodeEquiv<G_FENCE, atomic_fence>;
def : GINodeEquiv<G_PREFETCH, prefetch>;
def : GINodeEquiv<G_TRAP, trap>;
def : GINodeEquiv<G_DEBUGTRAP, debugtrap>;
def : GINodeEquiv<G_UBSANTRAP, ubsantrap>;

// Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern.
// Should be used on defs that subclass GIComplexOperandMatcher<>.
Expand Down
47 changes: 31 additions & 16 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,32 @@ bool IRTranslator::translateMemFunc(const CallInst &CI,
return true;
}

bool IRTranslator::translateTrap(const CallInst &CI,
MachineIRBuilder &MIRBuilder,
unsigned Opcode) {
StringRef TrapFuncName =
CI.getAttributes().getFnAttr("trap-func-name").getValueAsString();
if (TrapFuncName.empty()) {
if (Opcode == TargetOpcode::G_UBSANTRAP) {
uint64_t Code = cast<ConstantInt>(CI.getOperand(0))->getZExtValue();
MIRBuilder.buildInstr(Opcode, {}, ArrayRef<llvm::SrcOp>{Code});
} else {
MIRBuilder.buildInstr(Opcode);
}
return true;
}

CallLowering::CallLoweringInfo Info;
if (Opcode == TargetOpcode::G_UBSANTRAP)
Info.OrigArgs.push_back({getOrCreateVRegs(*CI.getArgOperand(0)),
CI.getArgOperand(0)->getType(), 0});

Info.Callee = MachineOperand::CreateES(TrapFuncName.data());
Info.CB = &CI;
Info.OrigRet = {Register(), Type::getVoidTy(CI.getContext()), 0};
return CLI->lowerCall(MIRBuilder, Info);
}

bool IRTranslator::translateVectorInterleave2Intrinsic(
const CallInst &CI, MachineIRBuilder &MIRBuilder) {
assert(CI.getIntrinsicID() == Intrinsic::experimental_vector_interleave2 &&
Expand Down Expand Up @@ -2459,22 +2485,11 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
return true;
}
case Intrinsic::trap:
return translateTrap(CI, MIRBuilder, TargetOpcode::G_TRAP);
case Intrinsic::debugtrap:
case Intrinsic::ubsantrap: {
StringRef TrapFuncName =
CI.getAttributes().getFnAttr("trap-func-name").getValueAsString();
if (TrapFuncName.empty())
break; // Use the default handling.
CallLowering::CallLoweringInfo Info;
if (ID == Intrinsic::ubsantrap) {
Info.OrigArgs.push_back({getOrCreateVRegs(*CI.getArgOperand(0)),
CI.getArgOperand(0)->getType(), 0});
}
Info.Callee = MachineOperand::CreateES(TrapFuncName.data());
Info.CB = &CI;
Info.OrigRet = {Register(), Type::getVoidTy(CI.getContext()), 0};
return CLI->lowerCall(MIRBuilder, Info);
}
return translateTrap(CI, MIRBuilder, TargetOpcode::G_DEBUGTRAP);
case Intrinsic::ubsantrap:
return translateTrap(CI, MIRBuilder, TargetOpcode::G_UBSANTRAP);
case Intrinsic::amdgcn_cs_chain:
return translateCallBase(CI, MIRBuilder);
case Intrinsic::fptrunc_round: {
Expand Down Expand Up @@ -3047,7 +3062,7 @@ bool IRTranslator::translateUnreachable(const User &U, MachineIRBuilder &MIRBuil
}
}

MIRBuilder.buildIntrinsic(Intrinsic::trap, ArrayRef<Register>());
MIRBuilder.buildTrap();
return true;
}

Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/CodeGen/MachineVerifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,17 @@ void MachineVerifier::verifyPreISelGenericInstruction(const MachineInstr *MI) {

break;
}
case TargetOpcode::G_UBSANTRAP: {
const MachineOperand &KindOp = MI->getOperand(0);
if (!MI->getOperand(0).isImm()) {
report("Crash kind must be an immediate", &KindOp, 0);
break;
}
int64_t Kind = MI->getOperand(0).getImm();
if (!isInt<8>(Kind))
report("Crash kind must be 8 bit wide", &KindOp, 0);
break;
}
case TargetOpcode::G_VECREDUCE_SEQ_FADD:
case TargetOpcode::G_VECREDUCE_SEQ_FMUL: {
LLT DstTy = MRI->getType(MI->getOperand(0).getReg());
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/AArch64/AArch64InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -8436,6 +8436,9 @@ def ubsan_trap_xform : SDNodeXForm<timm, [{
return CurDAG->getTargetConstant(N->getZExtValue() | ('U' << 8), SDLoc(N), MVT::i32);
}]>;

def gi_ubsan_trap_xform : GICustomOperandRenderer<"renderUbsanTrap">,
GISDNodeXFormEquiv<ubsan_trap_xform>;

def ubsan_trap_imm : TImmLeaf<i32, [{
return isUInt<8>(Imm);
}], ubsan_trap_xform>;
Expand Down
20 changes: 10 additions & 10 deletions llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,8 @@ class AArch64InstructionSelector : public InstructionSelector {
int OpIdx = -1) const;
void renderLogicalImm64(MachineInstrBuilder &MIB, const MachineInstr &I,
int OpIdx = -1) const;
void renderUbsanTrap(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx) const;
void renderFPImm16(MachineInstrBuilder &MIB, const MachineInstr &MI,
int OpIdx = -1) const;
void renderFPImm32(MachineInstrBuilder &MIB, const MachineInstr &MI,
Expand Down Expand Up @@ -6159,16 +6161,6 @@ bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
break;
}
case Intrinsic::trap:
MIB.buildInstr(AArch64::BRK, {}, {}).addImm(1);
break;
case Intrinsic::debugtrap:
MIB.buildInstr(AArch64::BRK, {}, {}).addImm(0xF000);
break;
case Intrinsic::ubsantrap:
MIB.buildInstr(AArch64::BRK, {}, {})
.addImm(I.getOperand(1).getImm() | ('U' << 8));
break;
case Intrinsic::aarch64_neon_ld1x2: {
LLT Ty = MRI.getType(I.getOperand(0).getReg());
unsigned Opc = 0;
Expand Down Expand Up @@ -7663,6 +7655,14 @@ void AArch64InstructionSelector::renderLogicalImm64(
MIB.addImm(Enc);
}

void AArch64InstructionSelector::renderUbsanTrap(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
assert(MI.getOpcode() == TargetOpcode::G_UBSANTRAP && OpIdx == 0 &&
"Expected G_UBSANTRAP");
MIB.addImm(MI.getOperand(0).getImm() | ('U' << 8));
}

void AArch64InstructionSelector::renderFPImm16(MachineInstrBuilder &MIB,
const MachineInstr &MI,
int OpIdx) const {
Expand Down
23 changes: 13 additions & 10 deletions llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2030,6 +2030,8 @@ AMDGPULegalizerInfo::AMDGPULegalizerInfo(const GCNSubtarget &ST_,
getActionDefinitionsBuilder({G_MEMCPY, G_MEMCPY_INLINE, G_MEMMOVE, G_MEMSET})
.lower();

getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP}).custom();

getActionDefinitionsBuilder({G_VASTART, G_VAARG, G_BRJT, G_JUMP_TABLE,
G_INDEXED_LOAD, G_INDEXED_SEXTLOAD,
G_INDEXED_ZEXTLOAD, G_INDEXED_STORE})
Expand Down Expand Up @@ -2134,6 +2136,10 @@ bool AMDGPULegalizerInfo::legalizeCustom(
return legalizeGetFPEnv(MI, MRI, B);
case TargetOpcode::G_SET_FPENV:
return legalizeSetFPEnv(MI, MRI, B);
case TargetOpcode::G_TRAP:
return legalizeTrap(MI, MRI, B);
case TargetOpcode::G_DEBUGTRAP:
return legalizeDebugTrap(MI, MRI, B);
default:
return false;
}
Expand Down Expand Up @@ -2925,7 +2931,7 @@ bool AMDGPULegalizerInfo::legalizeGlobalValue(
// functions that use local objects. However, if these dead functions are
// not eliminated, we don't want a compile time error. Just emit a warning
// and a trap, since there should be no callable path here.
B.buildIntrinsic(Intrinsic::trap, ArrayRef<Register>());
B.buildTrap();
B.buildUndef(DstReg);
MI.eraseFromParent();
return true;
Expand Down Expand Up @@ -6618,9 +6624,9 @@ bool AMDGPULegalizerInfo::legalizeSBufferLoad(LegalizerHelper &Helper,
}

// TODO: Move to selection
bool AMDGPULegalizerInfo::legalizeTrapIntrinsic(MachineInstr &MI,
MachineRegisterInfo &MRI,
MachineIRBuilder &B) const {
bool AMDGPULegalizerInfo::legalizeTrap(MachineInstr &MI,
MachineRegisterInfo &MRI,
MachineIRBuilder &B) const {
if (!ST.isTrapHandlerEnabled() ||
ST.getTrapHandlerAbi() != GCNSubtarget::TrapHandlerAbi::AMDHSA)
return legalizeTrapEndpgm(MI, MRI, B);
Expand Down Expand Up @@ -6726,8 +6732,9 @@ bool AMDGPULegalizerInfo::legalizeTrapHsa(
return true;
}

bool AMDGPULegalizerInfo::legalizeDebugTrapIntrinsic(
MachineInstr &MI, MachineRegisterInfo &MRI, MachineIRBuilder &B) const {
bool AMDGPULegalizerInfo::legalizeDebugTrap(MachineInstr &MI,
MachineRegisterInfo &MRI,
MachineIRBuilder &B) const {
// Is non-HSA path or trap-handler disabled? Then, report a warning
// accordingly
if (!ST.isTrapHandlerEnabled() ||
Expand Down Expand Up @@ -7270,10 +7277,6 @@ bool AMDGPULegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
case Intrinsic::amdgcn_struct_buffer_atomic_fadd_v2bf16:
case Intrinsic::amdgcn_struct_ptr_buffer_atomic_fadd_v2bf16:
return legalizeBufferAtomic(MI, B, IntrID);
case Intrinsic::trap:
return legalizeTrapIntrinsic(MI, MRI, B);
case Intrinsic::debugtrap:
return legalizeDebugTrapIntrinsic(MI, MRI, B);
case Intrinsic::amdgcn_rsq_clamp:
return legalizeRsqClampIntrinsic(MI, MRI, B);
case Intrinsic::amdgcn_ds_fadd:
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/Target/AMDGPU/AMDGPULegalizerInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,16 +226,16 @@ class AMDGPULegalizerInfo final : public LegalizerInfo {

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

bool legalizeTrapIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) const;
bool legalizeTrap(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) const;
bool legalizeTrapEndpgm(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) const;
bool legalizeTrapHsaQueuePtr(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) const;
bool legalizeTrapHsa(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) const;
bool legalizeDebugTrapIntrinsic(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) const;
bool legalizeDebugTrap(MachineInstr &MI, MachineRegisterInfo &MRI,
MachineIRBuilder &B) const;

bool legalizeIntrinsic(LegalizerHelper &Helper,
MachineInstr &MI) const override;
Expand Down
8 changes: 0 additions & 8 deletions llvm/lib/Target/Mips/MipsLegalizerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,16 +508,8 @@ bool MipsLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
MachineInstr &MI) const {
MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
const MipsSubtarget &ST = MI.getMF()->getSubtarget<MipsSubtarget>();
const MipsInstrInfo &TII = *ST.getInstrInfo();
const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
const RegisterBankInfo &RBI = *ST.getRegBankInfo();

switch (cast<GIntrinsic>(MI).getIntrinsicID()) {
case Intrinsic::trap: {
MachineInstr *Trap = MIRBuilder.buildInstr(Mips::TRAP);
MI.eraseFromParent();
return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
}
case Intrinsic::vacopy: {
MachinePointerInfo MPO;
LLT PtrTy = LLT::pointer(0, 32);
Expand Down
Loading