Skip to content

[RISCV][GISel] Select G_SELECT (G_ICMP, A, B) #68247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 107 additions & 9 deletions llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define DEBUG_TYPE "riscv-isel"

using namespace llvm;
using namespace MIPatternMatch;

#define GET_GLOBALISEL_PREDICATE_BITSET
#include "RISCVGenGlobalISel.inc"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<CmpInst::Predicate>(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();
Expand Down
122 changes: 122 additions & 0 deletions llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv32.mir
Original file line number Diff line number Diff line change
Expand Up @@ -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

...
122 changes: 122 additions & 0 deletions llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv64.mir
Original file line number Diff line number Diff line change
Expand Up @@ -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

...