summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWANG Rui <wangrui@loongson.cn>2025-11-07 17:29:18 +0800
committerWANG Rui <wangrui@loongson.cn>2025-11-07 17:29:18 +0800
commitb1b3c8e60ff4f19b9c6f416c3d13f3a7c5a229b2 (patch)
treeb2fe0ad94f26a3095bc9f70783d052b7f2de6a7e
parent1a34007f5f86088d59b0c5ce86ead58fb12177e0 (diff)
[LoongArch] Make the code generation of the trap pattern configurableusers/hev/trap-cfg
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp25
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchISelLowering.h2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchInstrInfo.td19
-rw-r--r--llvm/test/CodeGen/LoongArch/trap.ll25
4 files changed, 59 insertions, 12 deletions
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index cf4ffc82f600..f3b725c731a9 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -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) {
@@ -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 8a4d7748467c..86682d4b9e9e 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 @@ private:
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 9565a55e4c6c..72cda642d054 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=<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,
diff --git a/llvm/test/CodeGen/LoongArch/trap.ll b/llvm/test/CodeGen/LoongArch/trap.ll
index 15a7ad82bd7a..434807207f63 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
}