From e81ab66f04e4af2ed90cebb58f506f4f7d8ed7f9 Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Tue, 3 Oct 2023 15:29:47 -0700 Subject: [PATCH 1/8] [RISCV][GISel] Select G_SELECT (G_ICMP, A, B) --- .../RISCV/GISel/RISCVInstructionSelector.cpp | 128 ++++++++++++++++-- .../instruction-select/select-rv32.mir | 122 +++++++++++++++++ .../instruction-select/select-rv64.mir | 122 +++++++++++++++++ 3 files changed, 359 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index ab2125a3615f3..f5323f6938162 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -83,6 +83,11 @@ class RISCVInstructionSelector : public InstructionSelector { void renderImm(MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const; + /// Returns a G_ICMP that is equivalent to MI, whose condition code matches + /// one of the comparisons supported directly by branches in the RISC-V ISA. + MachineInstr *createICMPForBranch(MachineInstr *MI, MachineIRBuilder &MIB, + MachineRegisterInfo &MRI) const; + const RISCVSubtarget &STI; const RISCVInstrInfo &TII; const RISCVRegisterInfo &TRI; @@ -498,23 +503,120 @@ 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; + } +} + +MachineInstr *RISCVInstructionSelector::createICMPForBranch( + MachineInstr *MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const { + assert(MI->getOpcode() == TargetOpcode::G_ICMP); + CmpInst::Predicate CC = + static_cast(MI->getOperand(1).getPredicate()); + MachineOperand &LHS = MI->getOperand(2); + MachineOperand &RHS = MI->getOperand(3); + + // Adjust comparisons to use comparison with 0 if possible. + MachineInstr *MaybeConstant = MRI.getVRegDef(RHS.getReg()); + if (MaybeConstant && MaybeConstant->getOpcode() == TargetOpcode::G_CONSTANT) { + switch (CC) { + case CmpInst::Predicate::ICMP_SGT: + // Convert X > -1 to X >= 0 + if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == -1) { + MachineInstr *Zero = MIB.buildConstant( + MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); + selectConstant(*Zero, MIB, MRI); + return MIB.buildICmp(CmpInst::Predicate::ICMP_SGE, MI->getOperand(0), + LHS, Zero->getOperand(0)); + } + break; + case CmpInst::Predicate::ICMP_SLT: + // Convert X < 1 to 0 >= X + if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == 1) { + MachineInstr *Zero= MIB.buildConstant( + MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); + selectConstant(*Zero, MIB, MRI); + return MIB.buildICmp(CmpInst::Predicate::ICMP_SGE, MI->getOperand(0), + Zero->getOperand(0), LHS); + } + break; + default: + break; + } + } + + switch (CC) { + 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. + return MI; + 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. + return MIB.buildICmp(CmpInst::getSwappedPredicate(CC), MI->getOperand(0), + RHS, LHS); + } +} + 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); - 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(MI.getOperand(2).getReg()) - .addReg(MI.getOperand(3).getReg()); + MachineInstr *Result; + MachineInstr *MaybeICMP = MRI.getVRegDef(MI.getOperand(1).getReg()); + if (MaybeICMP && MaybeICMP->getOpcode() == TargetOpcode::G_ICMP) { + // 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. + MachineInstr *ICMPForBranch = createICMPForBranch(MaybeICMP, MIB, MRI); + CmpInst::Predicate CC = static_cast( + ICMPForBranch->getOperand(1).getPredicate()); + Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR) + .addDef(MI.getOperand(0).getReg()); + Result->addOperand(ICMPForBranch->getOperand(2)); + Result->addOperand(ICMPForBranch->getOperand(3)); + Result->addOperand( + MachineOperand::CreateImm(getRISCVCCFromICMP(CC))); + Result->addOperand(MI.getOperand(2)); + Result->addOperand(MI.getOperand(3)); + + // Delete ICMPForBranch since we know it has no users. Let the original + // G_ICMP be selected normally in case it has other users. + if (ICMPForBranch != MaybeICMP) + ICMPForBranch->eraseFromParent(); + } else { + 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(MI.getOperand(2).getReg()) + .addReg(MI.getOperand(3).getReg()); + } MI.eraseFromParent(); return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI); } 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 + +... From a1b9d386f75d5c41887ea066c13f2a57beea25b3 Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Wed, 4 Oct 2023 13:02:54 -0700 Subject: [PATCH 2/8] fixup! [RISCV][GISel] Select G_SELECT (G_ICMP, A, B) Don't create new G_ICMP --- .../RISCV/GISel/RISCVInstructionSelector.cpp | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index f5323f6938162..dd0673d245978 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -83,10 +83,13 @@ class RISCVInstructionSelector : public InstructionSelector { void renderImm(MachineInstrBuilder &MIB, const MachineInstr &MI, int OpIdx) const; - /// Returns a G_ICMP that is equivalent to MI, whose condition code matches - /// one of the comparisons supported directly by branches in the RISC-V ISA. - MachineInstr *createICMPForBranch(MachineInstr *MI, MachineIRBuilder &MIB, - MachineRegisterInfo &MRI) const; + /// Sets CC, LHS, and RHS so that they form an equivelent G_ICMP (CC, 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 setICMPOperandsForBranch(MachineInstr &MI, MachineIRBuilder &MIB, + MachineRegisterInfo &MRI, + CmpInst::Predicate &CC, MachineOperand &LHS, + MachineOperand &RHS) const; const RISCVSubtarget &STI; const RISCVInstrInfo &TII; @@ -524,13 +527,13 @@ static RISCVCC::CondCode getRISCVCCFromICMP(CmpInst::Predicate CC) { } } -MachineInstr *RISCVInstructionSelector::createICMPForBranch( - MachineInstr *MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const { - assert(MI->getOpcode() == TargetOpcode::G_ICMP); - CmpInst::Predicate CC = - static_cast(MI->getOperand(1).getPredicate()); - MachineOperand &LHS = MI->getOperand(2); - MachineOperand &RHS = MI->getOperand(3); +void RISCVInstructionSelector::setICMPOperandsForBranch( + MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, + CmpInst::Predicate &CC, MachineOperand &LHS, MachineOperand &RHS) const { + assert(MI.getOpcode() == TargetOpcode::G_ICMP); + CC = static_cast(MI.getOperand(1).getPredicate()); + LHS = MI.getOperand(2); + RHS = MI.getOperand(3); // Adjust comparisons to use comparison with 0 if possible. MachineInstr *MaybeConstant = MRI.getVRegDef(RHS.getReg()); @@ -542,20 +545,21 @@ MachineInstr *RISCVInstructionSelector::createICMPForBranch( MachineInstr *Zero = MIB.buildConstant( MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); selectConstant(*Zero, MIB, MRI); - return MIB.buildICmp(CmpInst::Predicate::ICMP_SGE, MI->getOperand(0), - LHS, Zero->getOperand(0)); + CC = CmpInst::Predicate::ICMP_SGE; + RHS = MachineOperand::CreateReg(Zero->getOperand(0).getReg(), false); } - break; + return; case CmpInst::Predicate::ICMP_SLT: // Convert X < 1 to 0 >= X if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == 1) { - MachineInstr *Zero= MIB.buildConstant( + MachineInstr *Zero = MIB.buildConstant( MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); selectConstant(*Zero, MIB, MRI); - return MIB.buildICmp(CmpInst::Predicate::ICMP_SGE, MI->getOperand(0), - Zero->getOperand(0), LHS); + CC = CmpInst::Predicate::ICMP_SGE; + RHS = LHS; + LHS = MachineOperand::CreateReg(Zero->getOperand(0).getReg(), false); } - break; + return; default: break; } @@ -571,15 +575,16 @@ MachineInstr *RISCVInstructionSelector::createICMPForBranch( case CmpInst::Predicate::ICMP_UGE: case CmpInst::Predicate::ICMP_SGE: // These CCs are supported directly by RISC-V branches. - return MI; + 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. - return MIB.buildICmp(CmpInst::getSwappedPredicate(CC), MI->getOperand(0), - RHS, LHS); + CC = CmpInst::getSwappedPredicate(CC); + std::swap(LHS, RHS); + return; } } @@ -592,22 +597,17 @@ bool RISCVInstructionSelector::selectSelect(MachineInstr &MI, if (MaybeICMP && MaybeICMP->getOpcode() == TargetOpcode::G_ICMP) { // 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. - MachineInstr *ICMPForBranch = createICMPForBranch(MaybeICMP, MIB, MRI); - CmpInst::Predicate CC = static_cast( - ICMPForBranch->getOperand(1).getPredicate()); + CmpInst::Predicate CC; + MachineOperand LHS = MaybeICMP->getOperand(2); + MachineOperand RHS = MaybeICMP->getOperand(3); + setICMPOperandsForBranch(*MaybeICMP, MIB, MRI, CC, LHS, RHS); Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR) .addDef(MI.getOperand(0).getReg()); - Result->addOperand(ICMPForBranch->getOperand(2)); - Result->addOperand(ICMPForBranch->getOperand(3)); - Result->addOperand( - MachineOperand::CreateImm(getRISCVCCFromICMP(CC))); + Result->addOperand(LHS); + Result->addOperand(RHS); + Result->addOperand(MachineOperand::CreateImm(getRISCVCCFromICMP(CC))); Result->addOperand(MI.getOperand(2)); Result->addOperand(MI.getOperand(3)); - - // Delete ICMPForBranch since we know it has no users. Let the original - // G_ICMP be selected normally in case it has other users. - if (ICMPForBranch != MaybeICMP) - ICMPForBranch->eraseFromParent(); } else { Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR) .addDef(MI.getOperand(0).getReg()) From 1a572375c8265ef3c6d9297738bdd98e0727fbcc Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Wed, 4 Oct 2023 14:24:37 -0700 Subject: [PATCH 3/8] fixup! [RISCV][GISel] Select G_SELECT (G_ICMP, A, B) Refactor NFC --- .../RISCV/GISel/RISCVInstructionSelector.cpp | 80 +++++++++---------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index dd0673d245978..1c27e28eb1de0 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -83,13 +83,12 @@ 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 (CC, LHS, + /// 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 setICMPOperandsForBranch(MachineInstr &MI, MachineIRBuilder &MIB, - MachineRegisterInfo &MRI, - CmpInst::Predicate &CC, MachineOperand &LHS, - MachineOperand &RHS) const; + void getICMPOperandsForBranch(MachineInstr &MI, MachineIRBuilder &MIB, + MachineRegisterInfo &MRI, RISCVCC::CondCode &CC, + Register &LHS, Register &RHS) const; const RISCVSubtarget &STI; const RISCVInstrInfo &TII; @@ -527,26 +526,27 @@ static RISCVCC::CondCode getRISCVCCFromICMP(CmpInst::Predicate CC) { } } -void RISCVInstructionSelector::setICMPOperandsForBranch( +void RISCVInstructionSelector::getICMPOperandsForBranch( MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI, - CmpInst::Predicate &CC, MachineOperand &LHS, MachineOperand &RHS) const { + RISCVCC::CondCode &CC, Register &LHS, Register &RHS) const { assert(MI.getOpcode() == TargetOpcode::G_ICMP); - CC = static_cast(MI.getOperand(1).getPredicate()); - LHS = MI.getOperand(2); - RHS = MI.getOperand(3); + 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. - MachineInstr *MaybeConstant = MRI.getVRegDef(RHS.getReg()); + MachineInstr *MaybeConstant = MRI.getVRegDef(RHS); if (MaybeConstant && MaybeConstant->getOpcode() == TargetOpcode::G_CONSTANT) { - switch (CC) { + switch (ICMPCC) { case CmpInst::Predicate::ICMP_SGT: // Convert X > -1 to X >= 0 if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == -1) { MachineInstr *Zero = MIB.buildConstant( MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); selectConstant(*Zero, MIB, MRI); - CC = CmpInst::Predicate::ICMP_SGE; - RHS = MachineOperand::CreateReg(Zero->getOperand(0).getReg(), false); + CC = getRISCVCCFromICMP(CmpInst::Predicate::ICMP_SGE); + RHS = Zero->getOperand(0).getReg(); } return; case CmpInst::Predicate::ICMP_SLT: @@ -555,9 +555,9 @@ void RISCVInstructionSelector::setICMPOperandsForBranch( MachineInstr *Zero = MIB.buildConstant( MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); selectConstant(*Zero, MIB, MRI); - CC = CmpInst::Predicate::ICMP_SGE; + CC = getRISCVCCFromICMP(CmpInst::Predicate::ICMP_SGE); RHS = LHS; - LHS = MachineOperand::CreateReg(Zero->getOperand(0).getReg(), false); + LHS = Zero->getOperand(0).getReg(); } return; default: @@ -565,7 +565,7 @@ void RISCVInstructionSelector::setICMPOperandsForBranch( } } - switch (CC) { + switch (ICMPCC) { default: llvm_unreachable("Expected ICMP CmpInst::Predicate."); case CmpInst::Predicate::ICMP_EQ: @@ -575,6 +575,7 @@ void RISCVInstructionSelector::setICMPOperandsForBranch( 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: @@ -582,7 +583,7 @@ void RISCVInstructionSelector::setICMPOperandsForBranch( 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 = CmpInst::getSwappedPredicate(CC); + CC = getRISCVCCFromICMP(CmpInst::getSwappedPredicate(ICMPCC)); std::swap(LHS, RHS); return; } @@ -592,31 +593,26 @@ bool RISCVInstructionSelector::selectSelect(MachineInstr &MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const { assert(MI.getOpcode() == TargetOpcode::G_SELECT); - MachineInstr *Result; + + // 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. MachineInstr *MaybeICMP = MRI.getVRegDef(MI.getOperand(1).getReg()); - if (MaybeICMP && MaybeICMP->getOpcode() == TargetOpcode::G_ICMP) { - // 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. - CmpInst::Predicate CC; - MachineOperand LHS = MaybeICMP->getOperand(2); - MachineOperand RHS = MaybeICMP->getOperand(3); - setICMPOperandsForBranch(*MaybeICMP, MIB, MRI, CC, LHS, RHS); - Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR) - .addDef(MI.getOperand(0).getReg()); - Result->addOperand(LHS); - Result->addOperand(RHS); - Result->addOperand(MachineOperand::CreateImm(getRISCVCCFromICMP(CC))); - Result->addOperand(MI.getOperand(2)); - Result->addOperand(MI.getOperand(3)); - } else { - 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(MI.getOperand(2).getReg()) - .addReg(MI.getOperand(3).getReg()); - } + bool Op1IsICMP = MaybeICMP && MaybeICMP->getOpcode() == TargetOpcode::G_ICMP; + RISCVCC::CondCode CC; + Register LHS, RHS; + if (Op1IsICMP) + getICMPOperandsForBranch(*MaybeICMP, 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(Op1) + .addReg(Op2) + .addImm(Op3) + .addReg(MI.getOperand(2).getReg()) + .addReg(MI.getOperand(3).getReg()); MI.eraseFromParent(); return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI); } From ecc4c5c6fa15ab8f3bc8222a12d84fc79b87902a Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Wed, 4 Oct 2023 14:47:02 -0700 Subject: [PATCH 4/8] fixup! [RISCV][GISel] Select G_SELECT (G_ICMP, A, B) simplify cond code and fix returns --- .../Target/RISCV/GISel/RISCVInstructionSelector.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index 1c27e28eb1de0..bbf9a6eb2bc86 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -545,21 +545,23 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( MachineInstr *Zero = MIB.buildConstant( MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); selectConstant(*Zero, MIB, MRI); - CC = getRISCVCCFromICMP(CmpInst::Predicate::ICMP_SGE); + CC = RISCVCC::COND_GE; RHS = Zero->getOperand(0).getReg(); + return; } - return; + break; case CmpInst::Predicate::ICMP_SLT: // Convert X < 1 to 0 >= X if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == 1) { MachineInstr *Zero = MIB.buildConstant( MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); selectConstant(*Zero, MIB, MRI); - CC = getRISCVCCFromICMP(CmpInst::Predicate::ICMP_SGE); + CC = RISCVCC::COND_GE; RHS = LHS; LHS = Zero->getOperand(0).getReg(); + return; } - return; + break; default: break; } From 99a5521961d37d7b8e79da8d49c9688ca0d70939 Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Wed, 4 Oct 2023 15:33:26 -0700 Subject: [PATCH 5/8] Use match to simplify checks --- .../RISCV/GISel/RISCVInstructionSelector.cpp | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index bbf9a6eb2bc86..bb89211926f30 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" @@ -536,14 +537,12 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( RHS = MI.getOperand(3).getReg(); // Adjust comparisons to use comparison with 0 if possible. - MachineInstr *MaybeConstant = MRI.getVRegDef(RHS); - if (MaybeConstant && MaybeConstant->getOpcode() == TargetOpcode::G_CONSTANT) { + if (auto Constant = matchConstant(RHS, MRI)) { switch (ICMPCC) { case CmpInst::Predicate::ICMP_SGT: // Convert X > -1 to X >= 0 - if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == -1) { - MachineInstr *Zero = MIB.buildConstant( - MRI.getType(MaybeConstant->getOperand(0).getReg()), 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(); @@ -552,9 +551,8 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( break; case CmpInst::Predicate::ICMP_SLT: // Convert X < 1 to 0 >= X - if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == 1) { - MachineInstr *Zero = MIB.buildConstant( - MRI.getType(MaybeConstant->getOperand(0).getReg()), 0); + if (*Constant == 1) { + MachineInstr *Zero = MIB.buildConstant(MRI.getType(RHS), 0); selectConstant(*Zero, MIB, MRI); CC = RISCVCC::COND_GE; RHS = LHS; @@ -598,12 +596,12 @@ bool RISCVInstructionSelector::selectSelect(MachineInstr &MI, // 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. - MachineInstr *MaybeICMP = MRI.getVRegDef(MI.getOperand(1).getReg()); - bool Op1IsICMP = MaybeICMP && MaybeICMP->getOpcode() == TargetOpcode::G_ICMP; + 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(*MaybeICMP, MIB, MRI, CC, LHS, RHS); + getICMPOperandsForBranch(*MRI.getVRegDef(MIOp1Reg), MIB, MRI, CC, LHS, RHS); Register Op1 = Op1IsICMP ? LHS : MI.getOperand(1).getReg(); Register Op2 = Op1IsICMP ? RHS : RISCV::X0; From 0e1d1d73be83d42cc574b0b7558d04799badc76f Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Wed, 4 Oct 2023 15:42:34 -0700 Subject: [PATCH 6/8] Use mICst --- llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index bb89211926f30..e5274d6414c5b 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -537,11 +537,12 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( RHS = MI.getOperand(3).getReg(); // Adjust comparisons to use comparison with 0 if possible. - if (auto Constant = matchConstant(RHS, MRI)) { + int64_t Constant; + if (mi_match(RHS, MRI, m_ICst(Constant))) { switch (ICMPCC) { case CmpInst::Predicate::ICMP_SGT: // Convert X > -1 to X >= 0 - if (*Constant == -1) { + if (Constant == -1) { MachineInstr *Zero = MIB.buildConstant(MRI.getType(RHS), 0); selectConstant(*Zero, MIB, MRI); CC = RISCVCC::COND_GE; @@ -551,7 +552,7 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( break; case CmpInst::Predicate::ICMP_SLT: // Convert X < 1 to 0 >= X - if (*Constant == 1) { + if (Constant == 1) { MachineInstr *Zero = MIB.buildConstant(MRI.getType(RHS), 0); selectConstant(*Zero, MIB, MRI); CC = RISCVCC::COND_GE; From 9408b96fe3d75965d4d244ae64963fb6eeb9f3b7 Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Thu, 5 Oct 2023 07:24:37 -0700 Subject: [PATCH 7/8] Use getIConstantVRegSExtVal --- llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index e5274d6414c5b..d7aa46fbb76ee 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -537,12 +537,11 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( RHS = MI.getOperand(3).getReg(); // Adjust comparisons to use comparison with 0 if possible. - int64_t Constant; - if (mi_match(RHS, MRI, m_ICst(Constant))) { + if (auto Constant = getIConstantVRegSExtVal(RHS, MRI)) { switch (ICMPCC) { case CmpInst::Predicate::ICMP_SGT: // Convert X > -1 to X >= 0 - if (Constant == -1) { + if (*Constant == -1) { MachineInstr *Zero = MIB.buildConstant(MRI.getType(RHS), 0); selectConstant(*Zero, MIB, MRI); CC = RISCVCC::COND_GE; @@ -552,7 +551,7 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( break; case CmpInst::Predicate::ICMP_SLT: // Convert X < 1 to 0 >= X - if (Constant == 1) { + if (*Constant == 1) { MachineInstr *Zero = MIB.buildConstant(MRI.getType(RHS), 0); selectConstant(*Zero, MIB, MRI); CC = RISCVCC::COND_GE; From e6fbfc9246fe1c870da9cfc4f68220e00bdfa6c7 Mon Sep 17 00:00:00 2001 From: Michael Maitland Date: Thu, 5 Oct 2023 09:04:54 -0700 Subject: [PATCH 8/8] Use LookThroughInstrs --- llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp index d7aa46fbb76ee..a7f18c04a1907 100644 --- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp +++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp @@ -537,7 +537,7 @@ void RISCVInstructionSelector::getICMPOperandsForBranch( RHS = MI.getOperand(3).getReg(); // Adjust comparisons to use comparison with 0 if possible. - if (auto Constant = getIConstantVRegSExtVal(RHS, MRI)) { + if (auto Constant = getIConstantVRegSExtVal(RHS, MRI, true)) { switch (ICMPCC) { case CmpInst::Predicate::ICMP_SGT: // Convert X > -1 to X >= 0