@@ -50,6 +50,15 @@ class RISCVInstructionSelector : public InstructionSelector {
50
50
bool selectConstant (MachineInstr &MI, MachineIRBuilder &MIB,
51
51
MachineRegisterInfo &MRI) const ;
52
52
53
+ bool earlySelectShift (unsigned Opc, MachineInstr &I, MachineIRBuilder &MIB,
54
+ const MachineRegisterInfo &MRI);
55
+
56
+ ComplexRendererFns selectShiftMask (MachineOperand &Root) const ;
57
+
58
+ // Custom renderers for tablegen
59
+ void renderNegImm (MachineInstrBuilder &MIB, const MachineInstr &MI,
60
+ int OpIdx) const ;
61
+
53
62
const RISCVSubtarget &STI;
54
63
const RISCVInstrInfo &TII;
55
64
const RISCVRegisterInfo &TRI;
@@ -89,12 +98,43 @@ RISCVInstructionSelector::RISCVInstructionSelector(
89
98
{
90
99
}
91
100
101
+ InstructionSelector::ComplexRendererFns
102
+ RISCVInstructionSelector::selectShiftMask (MachineOperand &Root) const {
103
+ // TODO: Also check if we are seeing the result of an AND operation which
104
+ // could be bypassed since we only check the lower log2(xlen) bits.
105
+ return {{[=](MachineInstrBuilder &MIB) { MIB.add (Root); }}};
106
+ }
107
+
108
+ // Tablegen doesn't allow us to write SRLIW/SRAIW/SLLIW patterns because the
109
+ // immediate Operand has type XLenVT. GlobalISel wants it to be i32.
110
+ bool RISCVInstructionSelector::earlySelectShift (
111
+ unsigned Opc, MachineInstr &I, MachineIRBuilder &MIB,
112
+ const MachineRegisterInfo &MRI) {
113
+ if (!Subtarget->is64Bit ())
114
+ return false ;
115
+
116
+ LLT Ty = MRI.getType (I.getOperand (0 ).getReg ());
117
+ if (!Ty.isScalar () || Ty.getSizeInBits () != 32 )
118
+ return false ;
119
+
120
+ std::optional<int64_t > CstVal =
121
+ getIConstantVRegSExtVal (I.getOperand (2 ).getReg (), MRI);
122
+ if (!CstVal || !isUInt<5 >(*CstVal))
123
+ return false ;
124
+
125
+ auto NewI = MIB.buildInstr (Opc, {I.getOperand (0 ).getReg ()},
126
+ {I.getOperand (1 ).getReg ()})
127
+ .addImm (*CstVal);
128
+ I.eraseFromParent ();
129
+ return constrainSelectedInstRegOperands (*NewI, TII, TRI, RBI);
130
+ }
131
+
92
132
bool RISCVInstructionSelector::select (MachineInstr &MI) {
93
133
unsigned Opc = MI.getOpcode ();
94
134
MachineBasicBlock &MBB = *MI.getParent ();
95
135
MachineFunction &MF = *MBB.getParent ();
96
136
MachineRegisterInfo &MRI = MF.getRegInfo ();
97
- MachineIRBuilder MIB (MF );
137
+ MachineIRBuilder MIB (MI );
98
138
99
139
if (!isPreISelGenericOpcode (Opc)) {
100
140
// Certain non-generic instructions also need some special handling.
@@ -104,13 +144,61 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
104
144
return true ;
105
145
}
106
146
147
+ switch (Opc) {
148
+ case TargetOpcode::G_ADD: {
149
+ // Tablegen doesn't pick up the ADDIW pattern because i32 isn't a legal
150
+ // type for RV64 in SelectionDAG. Manually select it here.
151
+ LLT Ty = MRI.getType (MI.getOperand (0 ).getReg ());
152
+ if (Subtarget->is64Bit () && Ty.isScalar () && Ty.getSizeInBits () == 32 ) {
153
+ std::optional<int64_t > CstVal =
154
+ getIConstantVRegSExtVal (MI.getOperand (2 ).getReg (), MRI);
155
+ if (CstVal && isInt<12 >(*CstVal)) {
156
+ auto NewI = MIB.buildInstr (RISCV::ADDIW, {MI.getOperand (0 ).getReg ()},
157
+ {MI.getOperand (1 ).getReg ()})
158
+ .addImm (*CstVal);
159
+ MI.eraseFromParent ();
160
+ return constrainSelectedInstRegOperands (*NewI, TII, TRI, RBI);
161
+ }
162
+ }
163
+ break ;
164
+ }
165
+ case TargetOpcode::G_SUB: {
166
+ // Tablegen doesn't pick up the ADDIW pattern because i32 isn't a legal
167
+ // type for RV64 in SelectionDAG. Manually select it here.
168
+ LLT Ty = MRI.getType (MI.getOperand (0 ).getReg ());
169
+ if (Subtarget->is64Bit () && Ty.isScalar () && Ty.getSizeInBits () == 32 ) {
170
+ std::optional<int64_t > CstVal =
171
+ getIConstantVRegSExtVal (MI.getOperand (2 ).getReg (), MRI);
172
+ if (CstVal && ((isInt<12 >(*CstVal) && *CstVal != -2048 ) || *CstVal == 2048 )) {
173
+ auto NewI = MIB.buildInstr (RISCV::ADDIW, {MI.getOperand (0 ).getReg ()},
174
+ {MI.getOperand (1 ).getReg ()})
175
+ .addImm (-*CstVal);
176
+ MI.eraseFromParent ();
177
+ return constrainSelectedInstRegOperands (*NewI, TII, TRI, RBI);
178
+ }
179
+ }
180
+ break ;
181
+ }
182
+ case TargetOpcode::G_ASHR:
183
+ if (earlySelectShift (RISCV::SRAIW, MI, MIB, MRI))
184
+ return true ;
185
+ break ;
186
+ case TargetOpcode::G_LSHR:
187
+ if (earlySelectShift (RISCV::SRLIW, MI, MIB, MRI))
188
+ return true ;
189
+ break ;
190
+ case TargetOpcode::G_SHL:
191
+ if (earlySelectShift (RISCV::SLLIW, MI, MIB, MRI))
192
+ return true ;
193
+ break ;
194
+ }
195
+
107
196
if (selectImpl (MI, *CoverageInfo))
108
197
return true ;
109
198
110
- MIB.setInstrAndDebugLoc (MI);
111
-
112
199
switch (Opc) {
113
200
case TargetOpcode::G_ANYEXT:
201
+ case TargetOpcode::G_TRUNC:
114
202
MI.setDesc (TII.get (TargetOpcode::COPY));
115
203
return true ;
116
204
case TargetOpcode::G_CONSTANT:
@@ -126,10 +214,19 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
126
214
return true ;
127
215
}
128
216
217
+ void RISCVInstructionSelector::renderNegImm (MachineInstrBuilder &MIB,
218
+ const MachineInstr &MI,
219
+ int OpIdx) const {
220
+ assert (MI.getOpcode () == TargetOpcode::G_CONSTANT && OpIdx == -1 &&
221
+ " Expected G_CONSTANT" );
222
+ int64_t CstVal = MI.getOperand (1 ).getCImm ()->getSExtValue ();
223
+ MIB.addImm (-CstVal);
224
+ }
225
+
129
226
const TargetRegisterClass *RISCVInstructionSelector::getRegClassForTypeOnBank (
130
227
LLT Ty, const RegisterBank &RB, bool GetAllRegSet) const {
131
228
if (RB.getID () == RISCV::GPRRegBankID) {
132
- if (Ty.getSizeInBits () == (STI.is64Bit () ? 64 : 32 ))
229
+ if (Ty.getSizeInBits () <= 32 || (STI.is64Bit () && Ty. getSizeInBits () == 64 ))
133
230
return &RISCV::GPRRegClass;
134
231
}
135
232
0 commit comments