Skip to content
Open
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
25 changes: 24 additions & 1 deletion llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ static cl::opt<bool> ZeroDivCheck("loongarch-check-zero-division", cl::Hidden,
cl::desc("Trap on integer division by zero."),
cl::init(false));

static cl::opt<int> TrapBreakCode("loongarch-trap-break-code", cl::init(-1),
cl::desc("Use 'break CODE' for traps "
"supposed to be unrecoverable, "
"or an 'amswap.w' instruction "
"leading to INE if CODE is out "
"of range."));

LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
const LoongArchSubtarget &STI)
: TargetLowering(TM), Subtarget(STI) {
Expand Down Expand Up @@ -125,7 +132,7 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
setOperationAction({ISD::VAARG, ISD::VACOPY, ISD::VAEND}, MVT::Other, Expand);

setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal);
setOperationAction(ISD::TRAP, MVT::Other, Legal);
setOperationAction(ISD::TRAP, MVT::Other, Custom);

setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom);
Expand Down Expand Up @@ -610,10 +617,25 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op,
return lowerVECREDUCE(Op, DAG);
case ISD::ConstantFP:
return lowerConstantFP(Op, DAG);
case ISD::TRAP:
return lowerTrap(Op, DAG);
}
return SDValue();
}

SDValue LoongArchTargetLowering::lowerTrap(SDValue Op,
SelectionDAG &DAG) const {
SDLoc DL(Op);
SDValue Chain = Op.getOperand(0);

if (isUInt<15>(TrapBreakCode))
return DAG.getNode(
LoongArchISD::BREAK, DL, MVT::Other, Chain,
DAG.getConstant(TrapBreakCode, DL, Subtarget.getGRLenVT()));

return DAG.getNode(LoongArchISD::UNIMP, DL, MVT::Other, Chain);
}

SDValue LoongArchTargetLowering::lowerConstantFP(SDValue Op,
SelectionDAG &DAG) const {
EVT VT = Op.getValueType();
Expand Down Expand Up @@ -7500,6 +7522,7 @@ const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(TAIL)
NODE_NAME_CASE(TAIL_MEDIUM)
NODE_NAME_CASE(TAIL_LARGE)
NODE_NAME_CASE(UNIMP)
NODE_NAME_CASE(SELECT_CC)
NODE_NAME_CASE(BR_CC)
NODE_NAME_CASE(BRCOND)
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum NodeType : unsigned {
TAIL,
TAIL_MEDIUM,
TAIL_LARGE,
UNIMP,

// Select
SELECT_CC,
Expand Down Expand Up @@ -415,6 +416,7 @@ class LoongArchTargetLowering : public TargetLowering {
SDValue lowerVECREDUCE_ADD(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerVECREDUCE(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerConstantFP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerTrap(SDValue Op, SelectionDAG &DAG) const;

bool isFPImmLegal(const APFloat &Imm, EVT VT,
bool ForCodeSize) const override;
Expand Down
19 changes: 14 additions & 5 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ def loongarch_call_large : SDNode<"LoongArchISD::CALL_LARGE", SDT_LoongArchCall,
def loongarch_tail_large : SDNode<"LoongArchISD::TAIL_LARGE", SDT_LoongArchCall,
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
SDNPVariadic]>;
def loongarch_unimp : SDNode<"LoongArchISD::UNIMP", SDTypeProfile<0, 0, []>,
[SDNPHasChain, SDNPSideEffect]>;
def loongarch_selectcc : SDNode<"LoongArchISD::SELECT_CC", SDT_LoongArchSelectCC>;
def loongarch_brcc : SDNode<"LoongArchISD::BR_CC", SDT_LoongArchBrCC,
[SDNPHasChain]>;
Expand Down Expand Up @@ -1373,11 +1375,18 @@ def : Pat<(and GPR:$rj, BstrinsImm:$imm),

/// Traps

// We lower `trap` to `amswap.w rd:$r0, rk:$r1, rj:$r0`, as this is guaranteed
// to trap with an INE (non-existent on LA32, explicitly documented to INE on
// LA64). And the resulting signal is different from `debugtrap` like on some
// other existing ports so programs/porters might have an easier time.
def PseudoUNIMP : Pseudo<(outs), (ins), [(trap)]>,
// ISD::TRAP is lowered to either LoongArchISD::UNIMP or LoongArchISD::BREAK
// depending on the --loongarch-trap-break-code=<N> option (default: -1).
// - If N is a valid 15-bit unsigned integer (0 <= N <= 32767), it expands to
// LoongArchISD::BREAK N, producing a BREAK instruction with the specified
// code.
// - Otherwise, it expands to LoongArchISD::UNIMP.

// We lower `loongarch_unimp` to `amswap.w rd:$r0, rk:$r1, rj:$r0`, as this is
// guaranteed to trap with an INE (non-existent on LA32, explicitly documented
// to INE on LA64). And the resulting signal is different from `debugtrap` like
// on some other existing ports so programs/porters might have an easier time.
def PseudoUNIMP : Pseudo<(outs), (ins), [(loongarch_unimp)]>,
PseudoInstExpansion<(AMSWAP_W R0, R1, R0)>;

// We lower `debugtrap` to `break 0`, as this is guaranteed to exist and work,
Expand Down
25 changes: 19 additions & 6 deletions llvm/test/CodeGen/LoongArch/trap.ll
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc --mtriple=loongarch32 -mattr=+d --verify-machineinstrs < %s | FileCheck %s
; RUN: llc --mtriple=loongarch64 -mattr=+d --verify-machineinstrs < %s | FileCheck %s
; RUN: llc --mtriple=loongarch32 -mattr=+d --verify-machineinstrs < %s | \
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-AMSWAP
; RUN: llc --mtriple=loongarch32 -mattr=+d --verify-machineinstrs \
; RUN: --loongarch-trap-break-code=1 < %s | \
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-BREAK
; RUN: llc --mtriple=loongarch64 -mattr=+d --verify-machineinstrs < %s | \
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-AMSWAP
; RUN: llc --mtriple=loongarch64 -mattr=+d --verify-machineinstrs \
; RUN: --loongarch-trap-break-code=1 < %s | \
; RUN: FileCheck %s --check-prefixes=CHECK,CHECK-BREAK

;; Verify that we lower @llvm.trap() and @llvm.debugtrap() correctly.

declare void @llvm.trap()
declare void @llvm.debugtrap()

define void @test_trap() nounwind {
; CHECK-LABEL: test_trap:
; CHECK: # %bb.0:
; CHECK-NEXT: amswap.w $zero, $ra, $zero
; CHECK-NEXT: ret
; CHECK-AMSWAP-LABEL: test_trap:
; CHECK-AMSWAP: # %bb.0:
; CHECK-AMSWAP-NEXT: amswap.w $zero, $ra, $zero
; CHECK-AMSWAP-NEXT: ret
;
; CHECK-BREAK-LABEL: test_trap:
; CHECK-BREAK: # %bb.0:
; CHECK-BREAK-NEXT: break 1
; CHECK-BREAK-NEXT: ret
tail call void @llvm.trap()
ret void
}
Expand Down