diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index cf4ffc82f6009..f3b725c731a95 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -74,6 +74,13 @@ static cl::opt ZeroDivCheck("loongarch-check-zero-division", cl::Hidden, cl::desc("Trap on integer division by zero."), cl::init(false)); +static cl::opt 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) { @@ -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); @@ -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(); @@ -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) diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h index 8a4d7748467c7..86682d4b9e9e6 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -33,6 +33,7 @@ enum NodeType : unsigned { TAIL, TAIL_MEDIUM, TAIL_LARGE, + UNIMP, // Select SELECT_CC, @@ -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; diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td index 9565a55e4c6c5..72cda642d0546 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -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]>; @@ -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= 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, diff --git a/llvm/test/CodeGen/LoongArch/trap.ll b/llvm/test/CodeGen/LoongArch/trap.ll index 15a7ad82bd7a8..434807207f63d 100644 --- a/llvm/test/CodeGen/LoongArch/trap.ll +++ b/llvm/test/CodeGen/LoongArch/trap.ll @@ -1,6 +1,14 @@ ; 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. @@ -8,10 +16,15 @@ 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 }