Skip to content

Commit cf8e506

Browse files
committed
[RISCV][GISel] Add isel patterns for ADDIW/SRLIW/SRAIW/SLLIW and remove custom selection.
I had trouble getting patterns working previously because GISel was using an i32 immediate, but the instructions expected an i64 immediate because SelectionDAG doesn't have i32 as a legal type yet. After looking at other targets like AMDGPU, I discovered that I could use a SDNodeXForm and a cast to get the type checking in tablegen to allow me to do it.
1 parent a669a23 commit cf8e506

File tree

2 files changed

+38
-77
lines changed

2 files changed

+38
-77
lines changed

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

Lines changed: 11 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@ class RISCVInstructionSelector : public InstructionSelector {
6565
bool selectSelect(MachineInstr &MI, MachineIRBuilder &MIB,
6666
MachineRegisterInfo &MRI) const;
6767

68-
bool earlySelectShift(unsigned Opc, MachineInstr &I, MachineIRBuilder &MIB,
69-
const MachineRegisterInfo &MRI);
70-
7168
ComplexRendererFns selectShiftMask(MachineOperand &Root) const;
7269
ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const;
7370

@@ -76,6 +73,8 @@ class RISCVInstructionSelector : public InstructionSelector {
7673
int OpIdx) const;
7774
void renderImmPlus1(MachineInstrBuilder &MIB, const MachineInstr &MI,
7875
int OpIdx) const;
76+
void renderImm(MachineInstrBuilder &MIB, const MachineInstr &MI,
77+
int OpIdx) const;
7978

8079
const RISCVSubtarget &STI;
8180
const RISCVInstrInfo &TII;
@@ -131,30 +130,6 @@ RISCVInstructionSelector::selectAddrRegImm(MachineOperand &Root) const {
131130
[=](MachineInstrBuilder &MIB) { MIB.addImm(0); }}};
132131
}
133132

134-
// Tablegen doesn't allow us to write SRLIW/SRAIW/SLLIW patterns because the
135-
// immediate Operand has type XLenVT. GlobalISel wants it to be i32.
136-
bool RISCVInstructionSelector::earlySelectShift(
137-
unsigned Opc, MachineInstr &I, MachineIRBuilder &MIB,
138-
const MachineRegisterInfo &MRI) {
139-
if (!Subtarget->is64Bit())
140-
return false;
141-
142-
LLT Ty = MRI.getType(I.getOperand(0).getReg());
143-
if (!Ty.isScalar() || Ty.getSizeInBits() != 32)
144-
return false;
145-
146-
std::optional<int64_t> CstVal =
147-
getIConstantVRegSExtVal(I.getOperand(2).getReg(), MRI);
148-
if (!CstVal || !isUInt<5>(*CstVal))
149-
return false;
150-
151-
auto NewI = MIB.buildInstr(Opc, {I.getOperand(0).getReg()},
152-
{I.getOperand(1).getReg()})
153-
.addImm(*CstVal);
154-
I.eraseFromParent();
155-
return constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
156-
}
157-
158133
bool RISCVInstructionSelector::select(MachineInstr &MI) {
159134
MachineBasicBlock &MBB = *MI.getParent();
160135
MachineFunction &MF = *MBB.getParent();
@@ -199,55 +174,6 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
199174
return true;
200175
}
201176

202-
switch (Opc) {
203-
case TargetOpcode::G_ADD: {
204-
// Tablegen doesn't pick up the ADDIW pattern because i32 isn't a legal
205-
// type for RV64 in SelectionDAG. Manually select it here.
206-
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
207-
if (Subtarget->is64Bit() && Ty.isScalar() && Ty.getSizeInBits() == 32) {
208-
std::optional<int64_t> CstVal =
209-
getIConstantVRegSExtVal(MI.getOperand(2).getReg(), MRI);
210-
if (CstVal && isInt<12>(*CstVal)) {
211-
auto NewI = MIB.buildInstr(RISCV::ADDIW, {MI.getOperand(0).getReg()},
212-
{MI.getOperand(1).getReg()})
213-
.addImm(*CstVal);
214-
MI.eraseFromParent();
215-
return constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
216-
}
217-
}
218-
break;
219-
}
220-
case TargetOpcode::G_SUB: {
221-
// Tablegen doesn't pick up the ADDIW pattern because i32 isn't a legal
222-
// type for RV64 in SelectionDAG. Manually select it here.
223-
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
224-
if (Subtarget->is64Bit() && Ty.isScalar() && Ty.getSizeInBits() == 32) {
225-
std::optional<int64_t> CstVal =
226-
getIConstantVRegSExtVal(MI.getOperand(2).getReg(), MRI);
227-
if (CstVal && ((isInt<12>(*CstVal) && *CstVal != -2048) || *CstVal == 2048)) {
228-
auto NewI = MIB.buildInstr(RISCV::ADDIW, {MI.getOperand(0).getReg()},
229-
{MI.getOperand(1).getReg()})
230-
.addImm(-*CstVal);
231-
MI.eraseFromParent();
232-
return constrainSelectedInstRegOperands(*NewI, TII, TRI, RBI);
233-
}
234-
}
235-
break;
236-
}
237-
case TargetOpcode::G_ASHR:
238-
if (earlySelectShift(RISCV::SRAIW, MI, MIB, MRI))
239-
return true;
240-
break;
241-
case TargetOpcode::G_LSHR:
242-
if (earlySelectShift(RISCV::SRLIW, MI, MIB, MRI))
243-
return true;
244-
break;
245-
case TargetOpcode::G_SHL:
246-
if (earlySelectShift(RISCV::SLLIW, MI, MIB, MRI))
247-
return true;
248-
break;
249-
}
250-
251177
if (selectImpl(MI, *CoverageInfo))
252178
return true;
253179

@@ -323,6 +249,15 @@ void RISCVInstructionSelector::renderImmPlus1(MachineInstrBuilder &MIB,
323249
MIB.addImm(CstVal + 1);
324250
}
325251

252+
void RISCVInstructionSelector::renderImm(MachineInstrBuilder &MIB,
253+
const MachineInstr &MI,
254+
int OpIdx) const {
255+
assert(MI.getOpcode() == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
256+
"Expected G_CONSTANT");
257+
int64_t CstVal = MI.getOperand(1).getCImm()->getSExtValue();
258+
MIB.addImm(CstVal);
259+
}
260+
326261
const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank(
327262
LLT Ty, const RegisterBank &RB) const {
328263
if (RB.getID() == RISCV::GPRRegBankID) {

llvm/lib/Target/RISCV/RISCVGISel.td

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ include "RISCVCombine.td"
1818

1919
def simm12Plus1 : ImmLeaf<XLenVT, [{
2020
return (isInt<12>(Imm) && Imm != -2048) || Imm == 2048;}]>;
21+
def simm12Plus1i32 : ImmLeaf<i32, [{
22+
return (isInt<12>(Imm) && Imm != -2048) || Imm == 2048;}]>;
23+
24+
def simm12i32 : ImmLeaf<i32, [{return isInt<12>(Imm);}]>;
25+
26+
def uimm5i32 : ImmLeaf<i32, [{return isUInt<5>(Imm);}]>;
2127

2228
// FIXME: This doesn't check that the G_CONSTANT we're deriving the immediate
2329
// from is only used once
@@ -43,6 +49,14 @@ def GIAddrRegImm :
4349
GIComplexOperandMatcher<s32, "selectAddrRegImm">,
4450
GIComplexPatternEquiv<AddrRegImm>;
4551

52+
// Convert from i32 immediate to i64 target immediate to make SelectionDAG type
53+
// checking happy so we can use ADDIW which expects an XLen immediate.
54+
def as_i64imm : SDNodeXForm<imm, [{
55+
return CurDAG->getTargetConstant(N->getSExtValue(), SDLoc(N), MVT::i64);
56+
}]>;
57+
def gi_as_i64imm : GICustomOperandRenderer<"renderImm">,
58+
GISDNodeXFormEquiv<as_i64imm>;
59+
4660
// FIXME: This is labelled as handling 's32', however the ComplexPattern it
4761
// refers to handles both i32 and i64 based on the HwMode. Currently this LLT
4862
// parameter appears to be ignored so this pattern works for both, however we
@@ -60,11 +74,23 @@ let Predicates = [IsRV64] in {
6074
def : Pat<(i32 (add GPR:$rs1, GPR:$rs2)), (ADDW GPR:$rs1, GPR:$rs2)>;
6175
def : Pat<(i32 (sub GPR:$rs1, GPR:$rs2)), (SUBW GPR:$rs1, GPR:$rs2)>;
6276

77+
def : Pat<(i32 (add GPR:$rs1, simm12i32:$imm)),
78+
(ADDIW GPR:$rs1, (i64 (as_i64imm $imm)))>;
79+
def : Pat<(i32 (sub GPR:$rs1, simm12Plus1i32:$imm)),
80+
(ADDIW GPR:$rs1, (i64 (NegImm $imm)))>;
81+
6382
def : Pat<(i32 (shl GPR:$rs1, (i32 GPR:$rs2))), (SLLW GPR:$rs1, GPR:$rs2)>;
6483
def : Pat<(i32 (sra GPR:$rs1, (i32 GPR:$rs2))), (SRAW GPR:$rs1, GPR:$rs2)>;
6584
def : Pat<(i32 (srl GPR:$rs1, (i32 GPR:$rs2))), (SRLW GPR:$rs1, GPR:$rs2)>;
6685

67-
def: Pat<(i64 (sext i32:$rs)), (ADDIW GPR:$rs, 0)>;
86+
def : Pat<(i32 (shl GPR:$rs1, uimm5i32:$imm)),
87+
(SLLIW GPR:$rs1, (i64 (as_i64imm $imm)))>;
88+
def : Pat<(i32 (sra GPR:$rs1, uimm5i32:$imm)),
89+
(SRAIW GPR:$rs1, (i64 (as_i64imm $imm)))>;
90+
def : Pat<(i32 (srl GPR:$rs1, uimm5i32:$imm)),
91+
(SRLIW GPR:$rs1, (i64 (as_i64imm $imm)))>;
92+
93+
def : Pat<(i64 (sext i32:$rs)), (ADDIW GPR:$rs, 0)>;
6894
}
6995

7096
let Predicates = [HasStdExtMOrZmmul, IsRV64] in {

0 commit comments

Comments
 (0)