[llvm] [RISCV] Add isel patterns for generating XAndesPerf branch immediate instructions (PR #145147)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 20 21:09:57 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-risc-v
Author: Jim Lin (tclin914)
<details>
<summary>Changes</summary>
Similar to #<!-- -->139872. This patch adds isel patterns to match
`riscv_brcc` and `riscv_selectcc_frag` to XAndesPerf branch instructions.
---
Full diff: https://github.com/llvm/llvm-project/pull/145147.diff
7 Files Affected:
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+16-3)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.cpp (+29)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.h (+4)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfo.td (+1-1)
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td (+72)
- (modified) llvm/lib/Target/RISCV/RISCVInstrPredicates.td (+2)
- (modified) llvm/test/CodeGen/RISCV/rv32xandesperf.ll (+168)
``````````diff
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index b8ef221742a26..6a65747733466 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -2408,11 +2408,16 @@ unsigned RISCVTargetLowering::getVectorTypeBreakdownForCallingConv(
// with 1/-1.
static void translateSetCCForBranch(const SDLoc &DL, SDValue &LHS, SDValue &RHS,
ISD::CondCode &CC, SelectionDAG &DAG) {
+ const RISCVSubtarget &Subtarget =
+ DAG.getMachineFunction().getSubtarget<RISCVSubtarget>();
+
// If this is a single bit test that can't be handled by ANDI, shift the
// bit to be tested to the MSB and perform a signed compare with 0.
if (isIntEqualitySetCC(CC) && isNullConstant(RHS) &&
LHS.getOpcode() == ISD::AND && LHS.hasOneUse() &&
- isa<ConstantSDNode>(LHS.getOperand(1))) {
+ isa<ConstantSDNode>(LHS.getOperand(1)) &&
+ // XAndesPerf supports branch on test bit.
+ !Subtarget.hasVendorXAndesPerf()) {
uint64_t Mask = LHS.getConstantOperandVal(1);
if ((isPowerOf2_64(Mask) || isMask_64(Mask)) && !isInt<12>(Mask)) {
unsigned ShAmt = 0;
@@ -2433,8 +2438,6 @@ static void translateSetCCForBranch(const SDLoc &DL, SDValue &LHS, SDValue &RHS,
if (auto *RHSC = dyn_cast<ConstantSDNode>(RHS)) {
int64_t C = RHSC->getSExtValue();
- const RISCVSubtarget &Subtarget =
- DAG.getMachineFunction().getSubtarget<RISCVSubtarget>();
switch (CC) {
default: break;
case ISD::SETGT:
@@ -18195,6 +18198,14 @@ static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
uint64_t Mask = LHS0.getConstantOperandVal(1);
uint64_t ShAmt = LHS.getConstantOperandVal(1);
if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
+ // XAndesPerf supports branch on test bit.
+ if (Subtarget.hasVendorXAndesPerf()) {
+ LHS =
+ DAG.getNode(ISD::AND, DL, LHS.getValueType(), LHS0.getOperand(0),
+ DAG.getConstant(Mask, DL, LHS.getValueType()));
+ return true;
+ }
+
CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
CC = DAG.getCondCode(CCVal);
@@ -21720,6 +21731,8 @@ RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case RISCV::Select_GPRNoX0_Using_CC_UImm5NonZero_QC:
case RISCV::Select_GPRNoX0_Using_CC_SImm16NonZero_QC:
case RISCV::Select_GPRNoX0_Using_CC_UImm16NonZero_QC:
+ case RISCV::Select_GPR_Using_CC_UImmLog2XLen_NDS:
+ case RISCV::Select_GPR_Using_CC_UImm7_NDS:
case RISCV::Select_FPR16_Using_CC_GPR:
case RISCV::Select_FPR16INX_Using_CC_GPR:
case RISCV::Select_FPR32_Using_CC_GPR:
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index d9ef911b9a32e..67c666e38545f 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1002,6 +1002,14 @@ static RISCVCC::CondCode getCondFromBranchOpc(unsigned Opc) {
return RISCVCC::COND_QC_BGEUI;
case RISCV::QC_E_BGEUI:
return RISCVCC::COND_QC_E_BGEUI;
+ case RISCV::NDS_BBC:
+ return RISCVCC::COND_NDS_BBC;
+ case RISCV::NDS_BBS:
+ return RISCVCC::COND_NDS_BBS;
+ case RISCV::NDS_BEQC:
+ return RISCVCC::COND_NDS_BEQC;
+ case RISCV::NDS_BNEC:
+ return RISCVCC::COND_NDS_BNEC;
}
}
@@ -1083,6 +1091,14 @@ unsigned RISCVCC::getBrCond(RISCVCC::CondCode CC) {
return RISCV::QC_BGEUI;
case RISCVCC::COND_QC_E_BGEUI:
return RISCV::QC_E_BGEUI;
+ case RISCVCC::COND_NDS_BBC:
+ return RISCV::NDS_BBC;
+ case RISCVCC::COND_NDS_BBS:
+ return RISCV::NDS_BBS;
+ case RISCVCC::COND_NDS_BEQC:
+ return RISCV::NDS_BEQC;
+ case RISCVCC::COND_NDS_BNEC:
+ return RISCV::NDS_BNEC;
}
}
@@ -1134,6 +1150,14 @@ RISCVCC::CondCode RISCVCC::getOppositeBranchCondition(RISCVCC::CondCode CC) {
return RISCVCC::COND_QC_BLTUI;
case RISCVCC::COND_QC_E_BGEUI:
return RISCVCC::COND_QC_E_BLTUI;
+ case RISCVCC::COND_NDS_BBC:
+ return RISCVCC::COND_NDS_BBS;
+ case RISCVCC::COND_NDS_BBS:
+ return RISCVCC::COND_NDS_BBC;
+ case RISCVCC::COND_NDS_BEQC:
+ return RISCVCC::COND_NDS_BNEC;
+ case RISCVCC::COND_NDS_BNEC:
+ return RISCVCC::COND_NDS_BEQC;
}
}
@@ -1501,6 +1525,11 @@ bool RISCVInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
switch (BranchOp) {
default:
llvm_unreachable("Unexpected opcode!");
+ case RISCV::NDS_BBC:
+ case RISCV::NDS_BBS:
+ case RISCV::NDS_BEQC:
+ case RISCV::NDS_BNEC:
+ return isIntN(11, BrOffset);
case RISCV::BEQ:
case RISCV::BNE:
case RISCV::BLT:
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
index 020be91e90e0b..ba90570ba8ec3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
@@ -55,6 +55,10 @@ enum CondCode {
COND_QC_E_BGEI,
COND_QC_E_BLTUI,
COND_QC_E_BGEUI,
+ COND_NDS_BBC,
+ COND_NDS_BBS,
+ COND_NDS_BEQC,
+ COND_NDS_BNEC,
COND_INVALID
};
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 70fad925cf070..7944fbd8b501c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -321,7 +321,7 @@ def uimm6 : RISCVUImmLeafOp<6>;
def uimm7_opcode : RISCVUImmOp<7> {
let ParserMatchClass = InsnDirectiveOpcode;
}
-def uimm7 : RISCVUImmOp<7>;
+def uimm7 : RISCVUImmLeafOp<7>;
def uimm8 : RISCVUImmOp<8>;
def uimm16 : RISCVUImmOp<16>;
def uimm32 : RISCVUImmOp<32>;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td b/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td
index 4b8d40d1429aa..655974e2b76c5 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td
@@ -53,6 +53,42 @@ def simm20_lsb000 : Operand<XLenVT> {
let DecoderMethod = "decodeSImmOperandAndLslN<20, 3>";
}
+// Predicate: True if immediate is a power of 2.
+def PowerOf2 : PatLeaf<(imm), [{
+ if (N->getValueType(0) == MVT::i32)
+ return isPowerOf2_32(N->getZExtValue());
+ else if (N->getValueType(0) == MVT::i64)
+ return isPowerOf2_64(N->getZExtValue());
+ else
+ return false;
+}]>;
+
+// Transformation function: Get log2 of immediate.
+def Log2 : SDNodeXForm<imm, [{
+ uint64_t Imm;
+ if (N->getValueType(0) == MVT::i32)
+ Imm = Log2_32(N->getZExtValue());
+ else
+ Imm = Log2_64(N->getZExtValue());
+ return CurDAG->getTargetConstant(Imm, SDLoc(N), N->getValueType(0));
+}]>;
+
+def IntCCtoNDSBBRISCVCC : SDNodeXForm<riscv_selectcc, [{
+ ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
+ assert(CC == ISD::SETEQ || CC == ISD::SETNE);
+ RISCVCC::CondCode BrCC =
+ CC == ISD::SETEQ ? RISCVCC::COND_NDS_BBC : RISCVCC::COND_NDS_BBS;
+ return CurDAG->getTargetConstant(BrCC, SDLoc(N), Subtarget->getXLenVT());
+}]>;
+
+def IntCCtoNDSBCRISCVCC : SDNodeXForm<riscv_selectcc, [{
+ ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get();
+ assert(CC == ISD::SETEQ || CC == ISD::SETNE);
+ RISCVCC::CondCode BrCC =
+ CC == ISD::SETEQ ? RISCVCC::COND_NDS_BEQC : RISCVCC::COND_NDS_BNEC;
+ return CurDAG->getTargetConstant(BrCC, SDLoc(N), Subtarget->getXLenVT());
+}]>;
+
//===----------------------------------------------------------------------===//
// Instruction Class Templates
//===----------------------------------------------------------------------===//
@@ -516,8 +552,44 @@ def NDS_VD4DOTSU_VV : NDSRVInstVD4DOT<0b000101, "nds.vd4dotsu">;
// Pseudo-instructions and codegen patterns
//===----------------------------------------------------------------------===//
+class NDS_BBPat<CondCode Cond, NDSRVInstBB Inst>
+ : Pat<(riscv_brcc(and(XLenVT GPR:$rs1), PowerOf2:$mask), 0, Cond,
+ bb:$imm10),
+ (Inst GPR:$rs1, (Log2 PowerOf2:$mask), bare_simm11_lsb0:$imm10)>;
+
+class NDS_BCPat<CondCode Cond, NDSRVInstBC Inst>
+ : Pat<(riscv_brcc(XLenVT GPR:$rs1), uimm7:$cimm, Cond, bb:$imm10),
+ (Inst GPR:$rs1, uimm7:$cimm, bare_simm11_lsb0:$imm10)>;
+
+defm CC_UImmLog2XLen_NDS : SelectCC_GPR_riirr<GPR, uimmlog2xlen>;
+defm CC_UImm7_NDS : SelectCC_GPR_riirr<GPR, uimm7>;
+
+class SelectNDS_BB<CondCode Cond>
+ : Pat<(riscv_selectcc_frag:$cc(and(XLenVT GPR:$lhs), PowerOf2:$mask), 0,
+ Cond, (XLenVT GPR:$truev), GPR:$falsev),
+ (Select_GPR_Using_CC_UImmLog2XLen_NDS GPR:$lhs, (Log2 PowerOf2:$mask),
+ (IntCCtoNDSBBRISCVCC $cc), GPR:$truev, GPR:$falsev)>;
+
+class SelectNDS_BC<CondCode Cond>
+ : Pat<(riscv_selectcc_frag:$cc(XLenVT GPR:$lhs), uimm7:$cimm, Cond,
+ (XLenVT GPR:$truev), GPR:$falsev),
+ (Select_GPR_Using_CC_UImm7_NDS GPR:$lhs, uimm7:$cimm,
+ (IntCCtoNDSBCRISCVCC $cc), GPR:$truev, GPR:$falsev)>;
+
let Predicates = [HasVendorXAndesPerf] in {
+def : NDS_BBPat<SETEQ, NDS_BBC>;
+def : NDS_BBPat<SETNE, NDS_BBS>;
+
+def : SelectNDS_BB<SETEQ>;
+def : SelectNDS_BB<SETNE>;
+
+def : NDS_BCPat<SETEQ, NDS_BEQC>;
+def : NDS_BCPat<SETNE, NDS_BNEC>;
+
+def : SelectNDS_BC<SETEQ>;
+def : SelectNDS_BC<SETNE>;
+
def : Pat<(sext_inreg (XLenVT GPR:$rs1), i16), (NDS_BFOS GPR:$rs1, 15, 0)>;
def : Pat<(sext_inreg (XLenVT GPR:$rs1), i8), (NDS_BFOS GPR:$rs1, 7, 0)>;
def : Pat<(sext_inreg (XLenVT GPR:$rs1), i1), (NDS_BFOS GPR:$rs1, 0, 0)>;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrPredicates.td b/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
index 1057eeee31d65..4abe62f4e874c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrPredicates.td
@@ -54,6 +54,8 @@ def isSelectPseudo
Select_GPRNoX0_Using_CC_UImm5NonZero_QC,
Select_GPRNoX0_Using_CC_SImm16NonZero_QC,
Select_GPRNoX0_Using_CC_UImm16NonZero_QC,
+ Select_GPR_Using_CC_UImmLog2XLen_NDS,
+ Select_GPR_Using_CC_UImm7_NDS,
Select_FPR16_Using_CC_GPR,
Select_FPR16INX_Using_CC_GPR,
Select_FPR32_Using_CC_GPR,
diff --git a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
index 3e7f09f3d6c22..f511ba2e93b01 100644
--- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
+++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll
@@ -2,6 +2,174 @@
; RUN: llc -O0 -mtriple=riscv32 -mattr=+xandesperf -verify-machineinstrs < %s \
; RUN: | FileCheck %s
+; NDS.BBC
+
+define i32 @bbc(i32 %a) nounwind {
+; CHECK-LABEL: bbc:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bbc a0, 16, .LBB0_2
+; CHECK-NEXT: j .LBB0_1
+; CHECK-NEXT: .LBB0_1: # %f
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB0_2: # %t
+; CHECK-NEXT: li a0, 1
+; CHECK-NEXT: ret
+ %mask = shl i32 1, 16
+ %and = and i32 %a, %mask
+ %tst = icmp eq i32 %and, 0
+ br i1 %tst, label %t, label %f
+f:
+ ret i32 0
+t:
+ ret i32 1
+}
+
+define i32 @select_bbc(i32 %a, i32 %b, i32 %c) nounwind {
+; CHECK-LABEL: select_bbc:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sw a2, 8(sp) # 4-byte Folded Spill
+; CHECK-NEXT: sw a1, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: nds.bbc a0, 16, .LBB1_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: lw a0, 8(sp) # 4-byte Folded Reload
+; CHECK-NEXT: sw a0, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: .LBB1_2:
+; CHECK-NEXT: lw a0, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %mask = shl i32 1, 16
+ %and = and i32 %a, %mask
+ %tst = icmp eq i32 %and, 0
+ %ret = select i1 %tst, i32 %b, i32 %c
+ ret i32 %ret
+}
+
+; NDS.BBS
+
+define i32 @bbs(i32 %a) nounwind {
+; CHECK-LABEL: bbs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bbs a0, 16, .LBB2_2
+; CHECK-NEXT: j .LBB2_1
+; CHECK-NEXT: .LBB2_1: # %f
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB2_2: # %t
+; CHECK-NEXT: li a0, 1
+; CHECK-NEXT: ret
+ %mask = shl i32 1, 16
+ %and = and i32 %a, %mask
+ %tst = icmp ne i32 %and, 0
+ br i1 %tst, label %t, label %f
+f:
+ ret i32 0
+t:
+ ret i32 1
+}
+
+define i32 @select_bbs(i32 %a, i32 %b, i32 %c) nounwind {
+; CHECK-LABEL: select_bbs:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sw a2, 8(sp) # 4-byte Folded Spill
+; CHECK-NEXT: sw a1, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: nds.bbs a0, 16, .LBB3_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: lw a0, 8(sp) # 4-byte Folded Reload
+; CHECK-NEXT: sw a0, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: .LBB3_2:
+; CHECK-NEXT: lw a0, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %mask = shl i32 1, 16
+ %and = and i32 %a, %mask
+ %tst = icmp ne i32 %and, 0
+ %ret = select i1 %tst, i32 %b, i32 %c
+ ret i32 %ret
+}
+
+; NDS.BEQC
+
+define i32 @beqc(i32 %a) nounwind {
+; CHECK-LABEL: beqc:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.beqc a0, 5, .LBB4_2
+; CHECK-NEXT: j .LBB4_1
+; CHECK-NEXT: .LBB4_1: # %f
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB4_2: # %t
+; CHECK-NEXT: li a0, 1
+; CHECK-NEXT: ret
+ %tst = icmp eq i32 %a, 5
+ br i1 %tst, label %t, label %f
+f:
+ ret i32 0
+t:
+ ret i32 1
+}
+
+define i32 @select_beqc(i32 %a, i32 %b, i32 %c) nounwind {
+; CHECK-LABEL: select_beqc:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sw a2, 8(sp) # 4-byte Folded Spill
+; CHECK-NEXT: sw a1, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: nds.beqc a0, 5, .LBB5_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: lw a0, 8(sp) # 4-byte Folded Reload
+; CHECK-NEXT: sw a0, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: .LBB5_2:
+; CHECK-NEXT: lw a0, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %tst = icmp eq i32 %a, 5
+ %ret = select i1 %tst, i32 %b, i32 %c
+ ret i32 %ret
+}
+
+; NDS.BNEC
+
+define i32 @bnec(i32 %a) nounwind {
+; CHECK-LABEL: bnec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: nds.bnec a0, 5, .LBB6_2
+; CHECK-NEXT: j .LBB6_1
+; CHECK-NEXT: .LBB6_1: # %f
+; CHECK-NEXT: li a0, 0
+; CHECK-NEXT: ret
+; CHECK-NEXT: .LBB6_2: # %t
+; CHECK-NEXT: li a0, 1
+; CHECK-NEXT: ret
+ %tst = icmp ne i32 %a, 5
+ br i1 %tst, label %t, label %f
+f:
+ ret i32 0
+t:
+ ret i32 1
+}
+
+define i32 @select_bnec(i32 %a, i32 %b, i32 %c) nounwind {
+; CHECK-LABEL: select_bnec:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sw a2, 8(sp) # 4-byte Folded Spill
+; CHECK-NEXT: sw a1, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: nds.bnec a0, 5, .LBB7_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: lw a0, 8(sp) # 4-byte Folded Reload
+; CHECK-NEXT: sw a0, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT: .LBB7_2:
+; CHECK-NEXT: lw a0, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %tst = icmp ne i32 %a, 5
+ %ret = select i1 %tst, i32 %b, i32 %c
+ ret i32 %ret
+}
+
; NDS.BFOZ
; MSB >= LSB
``````````
</details>
https://github.com/llvm/llvm-project/pull/145147
More information about the llvm-commits
mailing list