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(); + // 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(LHS.getOperand(1))) { + isa(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(RHS)) { int64_t C = RHSC->getSExtValue(); - const RISCVSubtarget &Subtarget = - DAG.getMachineFunction().getSubtarget(); 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..11cc80e3ffe73 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 isInt<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..5c40b1aa2f83f 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoXAndes.td @@ -53,6 +53,33 @@ def simm20_lsb000 : Operand { let DecoderMethod = "decodeSImmOperandAndLslN<20, 3>"; } +// Predicate: True if immediate is a power of 2. +def PowerOf2 : PatLeaf<(imm), [{ + return isPowerOf2_64(N->getZExtValue()); +}]>; + +// Transformation function: Get log2 of immediate. +def Log2 : SDNodeXFormgetZExtValue()); + return CurDAG->getTargetConstant(Imm, SDLoc(N), N->getValueType(0)); +}]>; + +def IntCCtoNDSBBRISCVCC : SDNodeXForm(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(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 +543,44 @@ def NDS_VD4DOTSU_VV : NDSRVInstVD4DOT<0b000101, "nds.vd4dotsu">; // Pseudo-instructions and codegen patterns //===----------------------------------------------------------------------===// +class NDS_BBPat + : 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 + : 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; +defm CC_UImm7_NDS : SelectCC_GPR_riirr; + +class SelectNDS_BB + : 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 + : 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; +def : NDS_BBPat; + +def : SelectNDS_BB; +def : SelectNDS_BB; + +def : NDS_BCPat; +def : NDS_BCPat; + +def : SelectNDS_BC; +def : SelectNDS_BC; + 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..5cabb8c53e261 100644 --- a/llvm/test/CodeGen/RISCV/rv32xandesperf.ll +++ b/llvm/test/CodeGen/RISCV/rv32xandesperf.ll @@ -2,6 +2,170 @@ ; 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 + %and = and i32 %a, 65536 + %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 + %and = and i32 %a, 65536 + %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 + %and = and i32 %a, 65536 + %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 + %and = and i32 %a, 65536 + %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