diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index ab2125a3615f3..a7f18c04a1907 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -26,6 +26,7 @@ #define DEBUG_TYPE "riscv-isel" using namespace llvm; +using namespace MIPatternMatch; #define GET_GLOBALISEL_PREDICATE_BITSET #include "RISCVGenGlobalISel.inc" @@ -83,6 +84,13 @@ class RISCVInstructionSelector : public InstructionSelector { void renderImm(MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const; + /// Sets CC, LHS, and RHS so that they form an equivelent G_ICMP (ICMPCC, LHS, + /// RHS) to that of MI, but whose condition code matches one of the + /// comparisons supported directly by branches in the RISC-V ISA. + void getICMPOperandsForBranch(MachineInstr &MI, MachineIRBuilder &MIB, + MachineRegisterInfo &MRI, RISCVCC::CondCode &CC, + Register &LHS, Register &RHS) const; + const RISCVSubtarget &STI; const RISCVInstrInfo &TII; const RISCVRegisterInfo &TRI; @@ -498,21 +506,111 @@ bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI, return true; } +/// Returns the RISCVCC::CondCode that corresponds to the CmpInst::Predicate CC. +/// CC Must be an ICMP Predicate. +static RISCVCC::CondCode getRISCVCCFromICMP(CmpInst::Predicate CC) { + switch (CC) { + default: + llvm_unreachable("Expected ICMP CmpInst::Predicate."); + case CmpInst::Predicate::ICMP_EQ: + return RISCVCC::COND_EQ; + case CmpInst::Predicate::ICMP_NE: + return RISCVCC::COND_NE; + case CmpInst::Predicate::ICMP_ULT: + return RISCVCC::COND_LTU; + case CmpInst::Predicate::ICMP_SLT: + return RISCVCC::COND_LT; + case CmpInst::Predicate::ICMP_UGE: + return RISCVCC::COND_GEU; + case CmpInst::Predicate::ICMP_SGE: + return RISCVCC::COND_GE; + } +} + +void RISCVInstructionSelector::getICMPOperandsForBranch( + MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, + RISCVCC::CondCode &CC, Register &LHS, Register &RHS) const { + assert(MI.getOpcode() == TargetOpcode::G_ICMP); + CmpInst::Predicate ICMPCC = + static_cast(MI.getOperand(1).getPredicate()); + LHS = MI.getOperand(2).getReg(); + RHS = MI.getOperand(3).getReg(); + + // Adjust comparisons to use comparison with 0 if possible. + if (auto Constant = getIConstantVRegSExtVal(RHS, MRI, true)) { + switch (ICMPCC) { + case CmpInst::Predicate::ICMP_SGT: + // Convert X > -1 to X >= 0 + if (*Constant == -1) { + MachineInstr *Zero = MIB.buildConstant(MRI.getType(RHS), 0); + selectConstant(*Zero, MIB, MRI); + CC = RISCVCC::COND_GE; + RHS = Zero->getOperand(0).getReg(); + return; + } + break; + case CmpInst::Predicate::ICMP_SLT: + // Convert X < 1 to 0 >= X + if (*Constant == 1) { + MachineInstr *Zero = MIB.buildConstant(MRI.getType(RHS), 0); + selectConstant(*Zero, MIB, MRI); + CC = RISCVCC::COND_GE; + RHS = LHS; + LHS = Zero->getOperand(0).getReg(); + return; + } + break; + default: + break; + } + } + + switch (ICMPCC) { + default: + llvm_unreachable("Expected ICMP CmpInst::Predicate."); + case CmpInst::Predicate::ICMP_EQ: + case CmpInst::Predicate::ICMP_NE: + case CmpInst::Predicate::ICMP_ULT: + case CmpInst::Predicate::ICMP_SLT: + case CmpInst::Predicate::ICMP_UGE: + case CmpInst::Predicate::ICMP_SGE: + // These CCs are supported directly by RISC-V branches. + CC = getRISCVCCFromICMP(ICMPCC); + return; + case CmpInst::Predicate::ICMP_SGT: + case CmpInst::Predicate::ICMP_SLE: + case CmpInst::Predicate::ICMP_UGT: + case CmpInst::Predicate::ICMP_ULE: + // These CCs are not supported directly by RISC-V branches, but changing the + // direction of the CC and swapping LHS and RHS are. + CC = getRISCVCCFromICMP(CmpInst::getSwappedPredicate(ICMPCC)); + std::swap(LHS, RHS); + return; + } +} + bool RISCVInstructionSelector::selectSelect(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const { - // TODO: Currently we check that the conditional code passed to G_SELECT is - // not equal to zero; however, in the future, we might want to try and check - // if the conditional code comes from a G_ICMP. If it does, we can directly - // use G_ICMP to get the first three input operands of the - // Select_GPR_Using_CC_GPR. This might be done here, or in the appropriate - // combiner. assert(MI.getOpcode() == TargetOpcode::G_SELECT); + + // If MI is a G_SELECT(G_ICMP(tst, A, B), C, D) then we can use (A, B, tst) + // as the (LHS, RHS, CC) of the Select_GPR_Using_CC_GPR. + Register MIOp1Reg = MI.getOperand(1).getReg(); + bool Op1IsICMP = mi_match(MIOp1Reg, MRI, m_GICmp(m_Pred(), m_Reg(), m_Reg())); + RISCVCC::CondCode CC; + Register LHS, RHS; + if (Op1IsICMP) + getICMPOperandsForBranch(*MRI.getVRegDef(MIOp1Reg), MIB, MRI, CC, LHS, RHS); + + Register Op1 = Op1IsICMP ? LHS : MI.getOperand(1).getReg(); + Register Op2 = Op1IsICMP ? RHS : RISCV::X0; + unsigned Op3 = Op1IsICMP ? CC : RISCVCC::COND_NE; MachineInstr *Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR) .addDef(MI.getOperand(0).getReg()) - .addReg(MI.getOperand(1).getReg()) - .addReg(RISCV::X0) - .addImm(RISCVCC::COND_NE) + .addReg(Op1) + .addReg(Op2) + .addImm(Op3) .addReg(MI.getOperand(2).getReg()) .addReg(MI.getOperand(3).getReg()); MI.eraseFromParent(); diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv32.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv32.mir index 828835dac8f80..b9bd9b980e2e4 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv32.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv32.mir @@ -53,3 +53,125 @@ body: | PseudoRET implicit $x10 ... +--- +name: select_icmp_ult +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_ult + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 4, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = COPY $x10 + %1:gprb(s32) = COPY $x11 + %2:gprb(s32) = COPY $x12 + %3:gprb(s32) = COPY $x13 + %4:gprb(s32) = COPY $x14 + %5:gprb(s32) = G_ICMP intpred(ult), %2, %3 + %6:gprb(s32) = G_SELECT %5, %0, %1 + $x10 = COPY %6(s32) + PseudoRET implicit $x10 + +... +--- +name: select_icmp_ugt +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_ugt + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 4, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = COPY $x10 + %1:gprb(s32) = COPY $x11 + %2:gprb(s32) = COPY $x12 + %3:gprb(s32) = COPY $x13 + %4:gprb(s32) = COPY $x14 + %5:gprb(s32) = G_ICMP intpred(ugt), %2, %3 + %6:gprb(s32) = G_SELECT %5, %0, %1 + $x10 = COPY %6(s32) + PseudoRET implicit $x10 + +... +--- +name: select_icmp_sgtneg1 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_sgtneg1 + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 3, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = COPY $x10 + %1:gprb(s32) = COPY $x11 + %2:gprb(s32) = COPY $x12 + %3:gprb(s32) = COPY $x13 + %4:gprb(s32) = COPY $x14 + %5:gprb(s32) = G_CONSTANT i32 -1 + %6:gprb(s32) = G_ICMP intpred(sgt), %2, %5 + %7:gprb(s32) = G_SELECT %6, %0, %1 + $x10 = COPY %7(s32) + PseudoRET implicit $x10 + +... +--- +name: select_icmp_slt1 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_slt1 + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 3, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s32) = COPY $x10 + %1:gprb(s32) = COPY $x11 + %2:gprb(s32) = COPY $x12 + %3:gprb(s32) = COPY $x13 + %4:gprb(s32) = COPY $x14 + %5:gprb(s32) = G_CONSTANT i32 1 + %6:gprb(s32) = G_ICMP intpred(slt), %2, %5 + %7:gprb(s32) = G_SELECT %6, %0, %1 + $x10 = COPY %7(s32) + PseudoRET implicit $x10 + +... diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv64.mir b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv64.mir index caa42f01c40ca..6eee273d320be 100644 --- a/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv64.mir +++ b/llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv64.mir @@ -53,3 +53,125 @@ body: | PseudoRET implicit $x10 ... +--- +name: select_icmp_ult +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_ult + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 4, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = COPY $x10 + %1:gprb(s64) = COPY $x11 + %2:gprb(s64) = COPY $x12 + %3:gprb(s64) = COPY $x13 + %4:gprb(s64) = COPY $x14 + %5:gprb(s64) = G_ICMP intpred(ult), %2, %3 + %6:gprb(s64) = G_SELECT %5, %0, %1 + $x10 = COPY %6(s64) + PseudoRET implicit $x10 + +... +--- +name: select_icmp_ugt +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_ugt + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 4, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = COPY $x10 + %1:gprb(s64) = COPY $x11 + %2:gprb(s64) = COPY $x12 + %3:gprb(s64) = COPY $x13 + %4:gprb(s64) = COPY $x14 + %5:gprb(s64) = G_ICMP intpred(ugt), %2, %3 + %6:gprb(s64) = G_SELECT %5, %0, %1 + $x10 = COPY %6(s64) + PseudoRET implicit $x10 + +... +--- +name: select_icmp_sgtneg1 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_sgtneg1 + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 3, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = COPY $x10 + %1:gprb(s64) = COPY $x11 + %2:gprb(s64) = COPY $x12 + %3:gprb(s64) = COPY $x13 + %4:gprb(s64) = COPY $x14 + %5:gprb(s64) = G_CONSTANT i64 -1 + %6:gprb(s64) = G_ICMP intpred(sgt), %2, %5 + %7:gprb(s64) = G_SELECT %6, %0, %1 + $x10 = COPY %7(s64) + PseudoRET implicit $x10 + +... +--- +name: select_icmp_slt1 +legalized: true +regBankSelected: true +tracksRegLiveness: true +body: | + bb.0: + liveins: $x10, $x11, $x12, $x13, $x14 + + ; CHECK-LABEL: name: select_icmp_slt1 + ; CHECK: liveins: $x10, $x11, $x12, $x13, $x14 + ; CHECK-NEXT: {{ $}} + ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10 + ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11 + ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12 + ; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0 + ; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 3, [[COPY]], [[COPY1]] + ; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]] + ; CHECK-NEXT: PseudoRET implicit $x10 + %0:gprb(s64) = COPY $x10 + %1:gprb(s64) = COPY $x11 + %2:gprb(s64) = COPY $x12 + %3:gprb(s64) = COPY $x13 + %4:gprb(s64) = COPY $x14 + %5:gprb(s64) = G_CONSTANT i64 1 + %6:gprb(s64) = G_ICMP intpred(slt), %2, %5 + %7:gprb(s64) = G_SELECT %6, %0, %1 + $x10 = COPY %7(s64) + PseudoRET implicit $x10 + +...