Skip to content

Commit e81ab66

Browse files
[RISCV][GISel] Select G_SELECT (G_ICMP, A, B)
1 parent 0a1472b commit e81ab66

File tree

3 files changed

+359
-13
lines changed

3 files changed

+359
-13
lines changed

llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp

Lines changed: 115 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ class RISCVInstructionSelector : public InstructionSelector {
8383
void renderImm(MachineInstrBuilder &MIB, const MachineInstr &MI,
8484
int OpIdx) const;
8585

86+
/// Returns a G_ICMP that is equivalent to MI, whose condition code matches
87+
/// one of the comparisons supported directly by branches in the RISC-V ISA.
88+
MachineInstr *createICMPForBranch(MachineInstr *MI, MachineIRBuilder &MIB,
89+
MachineRegisterInfo &MRI) const;
90+
8691
const RISCVSubtarget &STI;
8792
const RISCVInstrInfo &TII;
8893
const RISCVRegisterInfo &TRI;
@@ -498,23 +503,120 @@ bool RISCVInstructionSelector::selectSExtInreg(MachineInstr &MI,
498503
return true;
499504
}
500505

506+
/// Returns the RISCVCC::CondCode that corresponds to the CmpInst::Predicate CC.
507+
/// CC Must be an ICMP Predicate.
508+
static RISCVCC::CondCode getRISCVCCFromICMP(CmpInst::Predicate CC) {
509+
switch (CC) {
510+
default:
511+
llvm_unreachable("Expected ICMP CmpInst::Predicate.");
512+
case CmpInst::Predicate::ICMP_EQ:
513+
return RISCVCC::COND_EQ;
514+
case CmpInst::Predicate::ICMP_NE:
515+
return RISCVCC::COND_NE;
516+
case CmpInst::Predicate::ICMP_ULT:
517+
return RISCVCC::COND_LTU;
518+
case CmpInst::Predicate::ICMP_SLT:
519+
return RISCVCC::COND_LT;
520+
case CmpInst::Predicate::ICMP_UGE:
521+
return RISCVCC::COND_GEU;
522+
case CmpInst::Predicate::ICMP_SGE:
523+
return RISCVCC::COND_GE;
524+
}
525+
}
526+
527+
MachineInstr *RISCVInstructionSelector::createICMPForBranch(
528+
MachineInstr *MI, MachineIRBuilder &MIB, MachineRegisterInfo &MRI) const {
529+
assert(MI->getOpcode() == TargetOpcode::G_ICMP);
530+
CmpInst::Predicate CC =
531+
static_cast<CmpInst::Predicate>(MI->getOperand(1).getPredicate());
532+
MachineOperand &LHS = MI->getOperand(2);
533+
MachineOperand &RHS = MI->getOperand(3);
534+
535+
// Adjust comparisons to use comparison with 0 if possible.
536+
MachineInstr *MaybeConstant = MRI.getVRegDef(RHS.getReg());
537+
if (MaybeConstant && MaybeConstant->getOpcode() == TargetOpcode::G_CONSTANT) {
538+
switch (CC) {
539+
case CmpInst::Predicate::ICMP_SGT:
540+
// Convert X > -1 to X >= 0
541+
if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == -1) {
542+
MachineInstr *Zero = MIB.buildConstant(
543+
MRI.getType(MaybeConstant->getOperand(0).getReg()), 0);
544+
selectConstant(*Zero, MIB, MRI);
545+
return MIB.buildICmp(CmpInst::Predicate::ICMP_SGE, MI->getOperand(0),
546+
LHS, Zero->getOperand(0));
547+
}
548+
break;
549+
case CmpInst::Predicate::ICMP_SLT:
550+
// Convert X < 1 to 0 >= X
551+
if (MaybeConstant->getOperand(1).getCImm()->getSExtValue() == 1) {
552+
MachineInstr *Zero= MIB.buildConstant(
553+
MRI.getType(MaybeConstant->getOperand(0).getReg()), 0);
554+
selectConstant(*Zero, MIB, MRI);
555+
return MIB.buildICmp(CmpInst::Predicate::ICMP_SGE, MI->getOperand(0),
556+
Zero->getOperand(0), LHS);
557+
}
558+
break;
559+
default:
560+
break;
561+
}
562+
}
563+
564+
switch (CC) {
565+
default:
566+
llvm_unreachable("Expected ICMP CmpInst::Predicate.");
567+
case CmpInst::Predicate::ICMP_EQ:
568+
case CmpInst::Predicate::ICMP_NE:
569+
case CmpInst::Predicate::ICMP_ULT:
570+
case CmpInst::Predicate::ICMP_SLT:
571+
case CmpInst::Predicate::ICMP_UGE:
572+
case CmpInst::Predicate::ICMP_SGE:
573+
// These CCs are supported directly by RISC-V branches.
574+
return MI;
575+
case CmpInst::Predicate::ICMP_SGT:
576+
case CmpInst::Predicate::ICMP_SLE:
577+
case CmpInst::Predicate::ICMP_UGT:
578+
case CmpInst::Predicate::ICMP_ULE:
579+
// These CCs are not supported directly by RISC-V branches, but changing the
580+
// direction of the CC and swapping LHS and RHS are.
581+
return MIB.buildICmp(CmpInst::getSwappedPredicate(CC), MI->getOperand(0),
582+
RHS, LHS);
583+
}
584+
}
585+
501586
bool RISCVInstructionSelector::selectSelect(MachineInstr &MI,
502587
MachineIRBuilder &MIB,
503588
MachineRegisterInfo &MRI) const {
504-
// TODO: Currently we check that the conditional code passed to G_SELECT is
505-
// not equal to zero; however, in the future, we might want to try and check
506-
// if the conditional code comes from a G_ICMP. If it does, we can directly
507-
// use G_ICMP to get the first three input operands of the
508-
// Select_GPR_Using_CC_GPR. This might be done here, or in the appropriate
509-
// combiner.
510589
assert(MI.getOpcode() == TargetOpcode::G_SELECT);
511-
MachineInstr *Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR)
512-
.addDef(MI.getOperand(0).getReg())
513-
.addReg(MI.getOperand(1).getReg())
514-
.addReg(RISCV::X0)
515-
.addImm(RISCVCC::COND_NE)
516-
.addReg(MI.getOperand(2).getReg())
517-
.addReg(MI.getOperand(3).getReg());
590+
MachineInstr *Result;
591+
MachineInstr *MaybeICMP = MRI.getVRegDef(MI.getOperand(1).getReg());
592+
if (MaybeICMP && MaybeICMP->getOpcode() == TargetOpcode::G_ICMP) {
593+
// If MI is a G_SELECT(G_ICMP(tst, A, B), C, D) then we can use (A, B, tst)
594+
// as the (LHS, RHS, CC) of the Select_GPR_Using_CC_GPR.
595+
MachineInstr *ICMPForBranch = createICMPForBranch(MaybeICMP, MIB, MRI);
596+
CmpInst::Predicate CC = static_cast<CmpInst::Predicate>(
597+
ICMPForBranch->getOperand(1).getPredicate());
598+
Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR)
599+
.addDef(MI.getOperand(0).getReg());
600+
Result->addOperand(ICMPForBranch->getOperand(2));
601+
Result->addOperand(ICMPForBranch->getOperand(3));
602+
Result->addOperand(
603+
MachineOperand::CreateImm(getRISCVCCFromICMP(CC)));
604+
Result->addOperand(MI.getOperand(2));
605+
Result->addOperand(MI.getOperand(3));
606+
607+
// Delete ICMPForBranch since we know it has no users. Let the original
608+
// G_ICMP be selected normally in case it has other users.
609+
if (ICMPForBranch != MaybeICMP)
610+
ICMPForBranch->eraseFromParent();
611+
} else {
612+
Result = MIB.buildInstr(RISCV::Select_GPR_Using_CC_GPR)
613+
.addDef(MI.getOperand(0).getReg())
614+
.addReg(MI.getOperand(1).getReg())
615+
.addReg(RISCV::X0)
616+
.addImm(RISCVCC::COND_NE)
617+
.addReg(MI.getOperand(2).getReg())
618+
.addReg(MI.getOperand(3).getReg());
619+
}
518620
MI.eraseFromParent();
519621
return constrainSelectedInstRegOperands(*Result, TII, TRI, RBI);
520622
}

llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv32.mir

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,125 @@ body: |
5353
PseudoRET implicit $x10
5454
5555
...
56+
---
57+
name: select_icmp_ult
58+
legalized: true
59+
regBankSelected: true
60+
tracksRegLiveness: true
61+
body: |
62+
bb.0:
63+
liveins: $x10, $x11, $x12, $x13, $x14
64+
65+
; CHECK-LABEL: name: select_icmp_ult
66+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
67+
; CHECK-NEXT: {{ $}}
68+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
69+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
70+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
71+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13
72+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 4, [[COPY]], [[COPY1]]
73+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
74+
; CHECK-NEXT: PseudoRET implicit $x10
75+
%0:gprb(s32) = COPY $x10
76+
%1:gprb(s32) = COPY $x11
77+
%2:gprb(s32) = COPY $x12
78+
%3:gprb(s32) = COPY $x13
79+
%4:gprb(s32) = COPY $x14
80+
%5:gprb(s32) = G_ICMP intpred(ult), %2, %3
81+
%6:gprb(s32) = G_SELECT %5, %0, %1
82+
$x10 = COPY %6(s32)
83+
PseudoRET implicit $x10
84+
85+
...
86+
---
87+
name: select_icmp_ugt
88+
legalized: true
89+
regBankSelected: true
90+
tracksRegLiveness: true
91+
body: |
92+
bb.0:
93+
liveins: $x10, $x11, $x12, $x13, $x14
94+
95+
; CHECK-LABEL: name: select_icmp_ugt
96+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
97+
; CHECK-NEXT: {{ $}}
98+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
99+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
100+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
101+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13
102+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 4, [[COPY]], [[COPY1]]
103+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
104+
; CHECK-NEXT: PseudoRET implicit $x10
105+
%0:gprb(s32) = COPY $x10
106+
%1:gprb(s32) = COPY $x11
107+
%2:gprb(s32) = COPY $x12
108+
%3:gprb(s32) = COPY $x13
109+
%4:gprb(s32) = COPY $x14
110+
%5:gprb(s32) = G_ICMP intpred(ugt), %2, %3
111+
%6:gprb(s32) = G_SELECT %5, %0, %1
112+
$x10 = COPY %6(s32)
113+
PseudoRET implicit $x10
114+
115+
...
116+
---
117+
name: select_icmp_sgtneg1
118+
legalized: true
119+
regBankSelected: true
120+
tracksRegLiveness: true
121+
body: |
122+
bb.0:
123+
liveins: $x10, $x11, $x12, $x13, $x14
124+
125+
; CHECK-LABEL: name: select_icmp_sgtneg1
126+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
127+
; CHECK-NEXT: {{ $}}
128+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
129+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
130+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
131+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0
132+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 3, [[COPY]], [[COPY1]]
133+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
134+
; CHECK-NEXT: PseudoRET implicit $x10
135+
%0:gprb(s32) = COPY $x10
136+
%1:gprb(s32) = COPY $x11
137+
%2:gprb(s32) = COPY $x12
138+
%3:gprb(s32) = COPY $x13
139+
%4:gprb(s32) = COPY $x14
140+
%5:gprb(s32) = G_CONSTANT i32 -1
141+
%6:gprb(s32) = G_ICMP intpred(sgt), %2, %5
142+
%7:gprb(s32) = G_SELECT %6, %0, %1
143+
$x10 = COPY %7(s32)
144+
PseudoRET implicit $x10
145+
146+
...
147+
---
148+
name: select_icmp_slt1
149+
legalized: true
150+
regBankSelected: true
151+
tracksRegLiveness: true
152+
body: |
153+
bb.0:
154+
liveins: $x10, $x11, $x12, $x13, $x14
155+
156+
; CHECK-LABEL: name: select_icmp_slt1
157+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
158+
; CHECK-NEXT: {{ $}}
159+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
160+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
161+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
162+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0
163+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 3, [[COPY]], [[COPY1]]
164+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
165+
; CHECK-NEXT: PseudoRET implicit $x10
166+
%0:gprb(s32) = COPY $x10
167+
%1:gprb(s32) = COPY $x11
168+
%2:gprb(s32) = COPY $x12
169+
%3:gprb(s32) = COPY $x13
170+
%4:gprb(s32) = COPY $x14
171+
%5:gprb(s32) = G_CONSTANT i32 1
172+
%6:gprb(s32) = G_ICMP intpred(slt), %2, %5
173+
%7:gprb(s32) = G_SELECT %6, %0, %1
174+
$x10 = COPY %7(s32)
175+
PseudoRET implicit $x10
176+
177+
...

llvm/test/CodeGen/RISCV/GlobalISel/instruction-select/select-rv64.mir

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,125 @@ body: |
5353
PseudoRET implicit $x10
5454
5555
...
56+
---
57+
name: select_icmp_ult
58+
legalized: true
59+
regBankSelected: true
60+
tracksRegLiveness: true
61+
body: |
62+
bb.0:
63+
liveins: $x10, $x11, $x12, $x13, $x14
64+
65+
; CHECK-LABEL: name: select_icmp_ult
66+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
67+
; CHECK-NEXT: {{ $}}
68+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
69+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
70+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
71+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13
72+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 4, [[COPY]], [[COPY1]]
73+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
74+
; CHECK-NEXT: PseudoRET implicit $x10
75+
%0:gprb(s64) = COPY $x10
76+
%1:gprb(s64) = COPY $x11
77+
%2:gprb(s64) = COPY $x12
78+
%3:gprb(s64) = COPY $x13
79+
%4:gprb(s64) = COPY $x14
80+
%5:gprb(s64) = G_ICMP intpred(ult), %2, %3
81+
%6:gprb(s64) = G_SELECT %5, %0, %1
82+
$x10 = COPY %6(s64)
83+
PseudoRET implicit $x10
84+
85+
...
86+
---
87+
name: select_icmp_ugt
88+
legalized: true
89+
regBankSelected: true
90+
tracksRegLiveness: true
91+
body: |
92+
bb.0:
93+
liveins: $x10, $x11, $x12, $x13, $x14
94+
95+
; CHECK-LABEL: name: select_icmp_ugt
96+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
97+
; CHECK-NEXT: {{ $}}
98+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
99+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
100+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
101+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x13
102+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 4, [[COPY]], [[COPY1]]
103+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
104+
; CHECK-NEXT: PseudoRET implicit $x10
105+
%0:gprb(s64) = COPY $x10
106+
%1:gprb(s64) = COPY $x11
107+
%2:gprb(s64) = COPY $x12
108+
%3:gprb(s64) = COPY $x13
109+
%4:gprb(s64) = COPY $x14
110+
%5:gprb(s64) = G_ICMP intpred(ugt), %2, %3
111+
%6:gprb(s64) = G_SELECT %5, %0, %1
112+
$x10 = COPY %6(s64)
113+
PseudoRET implicit $x10
114+
115+
...
116+
---
117+
name: select_icmp_sgtneg1
118+
legalized: true
119+
regBankSelected: true
120+
tracksRegLiveness: true
121+
body: |
122+
bb.0:
123+
liveins: $x10, $x11, $x12, $x13, $x14
124+
125+
; CHECK-LABEL: name: select_icmp_sgtneg1
126+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
127+
; CHECK-NEXT: {{ $}}
128+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
129+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
130+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
131+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0
132+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY2]], [[COPY3]], 3, [[COPY]], [[COPY1]]
133+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
134+
; CHECK-NEXT: PseudoRET implicit $x10
135+
%0:gprb(s64) = COPY $x10
136+
%1:gprb(s64) = COPY $x11
137+
%2:gprb(s64) = COPY $x12
138+
%3:gprb(s64) = COPY $x13
139+
%4:gprb(s64) = COPY $x14
140+
%5:gprb(s64) = G_CONSTANT i64 -1
141+
%6:gprb(s64) = G_ICMP intpred(sgt), %2, %5
142+
%7:gprb(s64) = G_SELECT %6, %0, %1
143+
$x10 = COPY %7(s64)
144+
PseudoRET implicit $x10
145+
146+
...
147+
---
148+
name: select_icmp_slt1
149+
legalized: true
150+
regBankSelected: true
151+
tracksRegLiveness: true
152+
body: |
153+
bb.0:
154+
liveins: $x10, $x11, $x12, $x13, $x14
155+
156+
; CHECK-LABEL: name: select_icmp_slt1
157+
; CHECK: liveins: $x10, $x11, $x12, $x13, $x14
158+
; CHECK-NEXT: {{ $}}
159+
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr = COPY $x10
160+
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr = COPY $x11
161+
; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr = COPY $x12
162+
; CHECK-NEXT: [[COPY3:%[0-9]+]]:gpr = COPY $x0
163+
; CHECK-NEXT: [[Select_GPR_Using_CC_GPR:%[0-9]+]]:gpr = Select_GPR_Using_CC_GPR [[COPY3]], [[COPY2]], 3, [[COPY]], [[COPY1]]
164+
; CHECK-NEXT: $x10 = COPY [[Select_GPR_Using_CC_GPR]]
165+
; CHECK-NEXT: PseudoRET implicit $x10
166+
%0:gprb(s64) = COPY $x10
167+
%1:gprb(s64) = COPY $x11
168+
%2:gprb(s64) = COPY $x12
169+
%3:gprb(s64) = COPY $x13
170+
%4:gprb(s64) = COPY $x14
171+
%5:gprb(s64) = G_CONSTANT i64 1
172+
%6:gprb(s64) = G_ICMP intpred(slt), %2, %5
173+
%7:gprb(s64) = G_SELECT %6, %0, %1
174+
$x10 = COPY %7(s64)
175+
PseudoRET implicit $x10
176+
177+
...

0 commit comments

Comments
 (0)