Skip to content

Commit 0e97975

Browse files
committed
[RISCV] Add hasAllNBitUsers Functional change, change allows for the generation of packw instructions along with other generic instructions with narrow w type.
Signed-off-by: Luke Quinn <[email protected]>
1 parent 4759107 commit 0e97975

File tree

6 files changed

+227
-68
lines changed

6 files changed

+227
-68
lines changed

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

Lines changed: 172 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,20 @@ class RISCVInstructionSelector : public InstructionSelector {
5757
const TargetRegisterClass *
5858
getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) const;
5959

60+
static constexpr unsigned MaxRecursionDepth = 6;
61+
6062
// const MachineInstr &MI
61-
bool hasAllNBitUsers(const MachineInstr &MI, unsigned Bits, const unsigned Depth = 0) const;
62-
bool hasAllBUsers(const MachineInstr &MI) const { return hasAllNBitUsers(MI, 8); }
63-
bool hasAllHUsers(const MachineInstr &MI) const { return hasAllNBitUsers(MI, 16); }
64-
bool hasAllWUsers(const MachineInstr &MI) const { return hasAllNBitUsers(MI, 32); }
63+
bool hasAllNBitUsers(const MachineInstr &MI, unsigned Bits,
64+
const unsigned Depth = 0) const;
65+
bool hasAllBUsers(const MachineInstr &MI) const {
66+
return hasAllNBitUsers(MI, 8);
67+
}
68+
bool hasAllHUsers(const MachineInstr &MI) const {
69+
return hasAllNBitUsers(MI, 16);
70+
}
71+
bool hasAllWUsers(const MachineInstr &MI) const {
72+
return hasAllNBitUsers(MI, 32);
73+
}
6574

6675
bool isRegInGprb(Register Reg) const;
6776
bool isRegInFprb(Register Reg) const;
@@ -192,9 +201,166 @@ RISCVInstructionSelector::RISCVInstructionSelector(
192201
{
193202
}
194203

195-
bool RISCVInstructionSelector::hasAllNBitUsers(const MachineInstr &MI, unsigned Bits, const unsigned Depth) const {
204+
bool RISCVInstructionSelector::hasAllNBitUsers(const MachineInstr &MI,
205+
unsigned Bits,
206+
const unsigned Depth) const {
207+
208+
assert((MI.getOpcode() == TargetOpcode::G_ADD ||
209+
MI.getOpcode() == TargetOpcode::G_SUB ||
210+
MI.getOpcode() == TargetOpcode::G_MUL ||
211+
MI.getOpcode() == TargetOpcode::G_SHL ||
212+
MI.getOpcode() == TargetOpcode::G_LSHR ||
213+
MI.getOpcode() == TargetOpcode::G_AND ||
214+
MI.getOpcode() == TargetOpcode::G_OR ||
215+
MI.getOpcode() == TargetOpcode::G_XOR ||
216+
MI.getOpcode() == TargetOpcode::G_SEXT_INREG || Depth != 0) &&
217+
"Unexpected opcode");
218+
219+
if (Depth >= RISCVInstructionSelector::MaxRecursionDepth)
196220
return false;
197-
};
221+
222+
auto DestReg = MI.getOperand(0).getReg();
223+
for (auto &UserOp : MRI->use_nodbg_operands(DestReg)) {
224+
assert(UserOp.getParent() && "UserOp must have a parent");
225+
const MachineInstr &UserMI = *UserOp.getParent();
226+
unsigned OpIdx = UserOp.getOperandNo();
227+
228+
switch (UserMI.getOpcode()) {
229+
default:
230+
return false;
231+
case RISCV::ADDW:
232+
case RISCV::ADDIW:
233+
case RISCV::SUBW:
234+
case RISCV::MULW:
235+
case RISCV::SLLW:
236+
case RISCV::SLLIW:
237+
case RISCV::SRAW:
238+
case RISCV::SRAIW:
239+
case RISCV::SRLW:
240+
case RISCV::SRLIW:
241+
case RISCV::DIVW:
242+
case RISCV::DIVUW:
243+
case RISCV::REMW:
244+
case RISCV::REMUW:
245+
case RISCV::ROLW:
246+
case RISCV::RORW:
247+
case RISCV::RORIW:
248+
case RISCV::CLZW:
249+
case RISCV::CTZW:
250+
case RISCV::CPOPW:
251+
case RISCV::SLLI_UW:
252+
case RISCV::FMV_W_X:
253+
case RISCV::FCVT_H_W:
254+
case RISCV::FCVT_H_W_INX:
255+
case RISCV::FCVT_H_WU:
256+
case RISCV::FCVT_H_WU_INX:
257+
case RISCV::FCVT_S_W:
258+
case RISCV::FCVT_S_W_INX:
259+
case RISCV::FCVT_S_WU:
260+
case RISCV::FCVT_S_WU_INX:
261+
case RISCV::FCVT_D_W:
262+
case RISCV::FCVT_D_W_INX:
263+
case RISCV::FCVT_D_WU:
264+
case RISCV::FCVT_D_WU_INX:
265+
case RISCV::TH_REVW:
266+
case RISCV::TH_SRRIW:
267+
if (Bits >= 32)
268+
break;
269+
return false;
270+
case RISCV::SLL:
271+
case RISCV::SRA:
272+
case RISCV::SRL:
273+
case RISCV::ROL:
274+
case RISCV::ROR:
275+
case RISCV::BSET:
276+
case RISCV::BCLR:
277+
case RISCV::BINV:
278+
// Shift amount operands only use log2(Xlen) bits.
279+
if (OpIdx == 2 && Bits >= Log2_32(Subtarget->getXLen()))
280+
break;
281+
return false;
282+
case RISCV::SLLI:
283+
// SLLI only uses the lower (XLen - ShAmt) bits.
284+
if (Bits >= Subtarget->getXLen() - UserMI.getOperand(2).getImm())
285+
break;
286+
return false;
287+
case RISCV::ANDI:
288+
if (Bits >= (unsigned)llvm::bit_width<uint64_t>(
289+
(uint64_t)UserMI.getOperand(2).getImm()))
290+
break;
291+
goto RecCheck;
292+
case RISCV::ORI: {
293+
uint64_t Imm = UserMI.getOperand(2).getImm();
294+
if (Bits >= (unsigned)llvm::bit_width<uint64_t>(~Imm))
295+
break;
296+
[[fallthrough]];
297+
}
298+
case RISCV::AND:
299+
case RISCV::OR:
300+
case RISCV::XOR:
301+
case RISCV::XORI:
302+
case RISCV::ANDN:
303+
case RISCV::ORN:
304+
case RISCV::XNOR:
305+
case RISCV::SH1ADD:
306+
case RISCV::SH2ADD:
307+
case RISCV::SH3ADD:
308+
RecCheck:
309+
if (hasAllNBitUsers(UserMI, Bits, Depth + 1))
310+
break;
311+
return false;
312+
case RISCV::SRLI: {
313+
unsigned ShAmt = UserMI.getOperand(2).getImm();
314+
// If we are shifting right by less than Bits, and users don't demand any
315+
// bits that were shifted into [Bits-1:0], then we can consider this as an
316+
// N-Bit user.
317+
if (Bits > ShAmt && hasAllNBitUsers(UserMI, Bits - ShAmt, Depth + 1))
318+
break;
319+
return false;
320+
}
321+
case RISCV::SEXT_B:
322+
case RISCV::PACKH:
323+
if (Bits >= 8)
324+
break;
325+
return false;
326+
case RISCV::SEXT_H:
327+
case RISCV::FMV_H_X:
328+
case RISCV::ZEXT_H_RV32:
329+
case RISCV::ZEXT_H_RV64:
330+
case RISCV::PACKW:
331+
if (Bits >= 16)
332+
break;
333+
return false;
334+
case RISCV::PACK:
335+
if (Bits >= (Subtarget->getXLen() / 2))
336+
break;
337+
return false;
338+
case RISCV::ADD_UW:
339+
case RISCV::SH1ADD_UW:
340+
case RISCV::SH2ADD_UW:
341+
case RISCV::SH3ADD_UW:
342+
// The first operand to add.uw/shXadd.uw is implicitly zero extended from
343+
// 32 bits.
344+
if (OpIdx == 1 && Bits >= 32)
345+
break;
346+
return false;
347+
case RISCV::SB:
348+
if (OpIdx == 0 && Bits >= 8)
349+
break;
350+
return false;
351+
case RISCV::SH:
352+
if (OpIdx == 0 && Bits >= 16)
353+
break;
354+
return false;
355+
case RISCV::SW:
356+
if (OpIdx == 0 && Bits >= 32)
357+
break;
358+
return false;
359+
}
360+
}
361+
362+
return true;
363+
}
198364

199365
InstructionSelector::ComplexRendererFns
200366
RISCVInstructionSelector::selectShiftMask(MachineOperand &Root,

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,17 +1943,17 @@ def : Pat<(i64 (shl (and GPR:$rs1, 0xffffffff), uimm5:$shamt)),
19431943

19441944
class binop_allhusers<SDPatternOperator operator>
19451945
: PatFrag<(ops node:$lhs, node:$rhs),
1946-
(XLenVT (operator node:$lhs, node:$rhs)), [{
1946+
(XLenVT(operator node:$lhs, node:$rhs)), [{
19471947
return hasAllHUsers(Node);
19481948
}]> {
1949-
let GISelPredicateCode = [{ return hasAllHUsers(MI); }];
1949+
let GISelPredicateCode = [{ return hasAllHUsers(MI); }];
19501950
}
19511951

19521952
// PatFrag to allow ADDW/SUBW/MULW/SLLW to be selected from i64 add/sub/mul/shl
19531953
// if only the lower 32 bits of their result is used.
19541954
class binop_allwusers<SDPatternOperator operator>
1955-
: PatFrag<(ops node:$lhs, node:$rhs),
1956-
(i64 (operator node:$lhs, node:$rhs)), [{
1955+
: PatFrag<(ops node:$lhs, node:$rhs), (i64(operator node:$lhs, node:$rhs)),
1956+
[{
19571957
return hasAllWUsers(Node);
19581958
}]> {
19591959
let GISelPredicateCode = [{ return hasAllWUsers(MI); }];

llvm/test/CodeGen/RISCV/GlobalISel/combine.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ define i32 @constant_to_rhs(i32 %x) {
2020
; RV64-O0: # %bb.0:
2121
; RV64-O0-NEXT: mv a1, a0
2222
; RV64-O0-NEXT: li a0, 1
23-
; RV64-O0-NEXT: add a0, a0, a1
23+
; RV64-O0-NEXT: addw a0, a0, a1
2424
; RV64-O0-NEXT: sext.w a0, a0
2525
; RV64-O0-NEXT: ret
2626
;

llvm/test/CodeGen/RISCV/GlobalISel/rv64zbb-zbkb.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ declare i32 @llvm.fshl.i32(i32, i32, i32)
107107
define signext i32 @rol_i32(i32 signext %a, i32 signext %b) nounwind {
108108
; RV64I-LABEL: rol_i32:
109109
; RV64I: # %bb.0:
110-
; RV64I-NEXT: neg a2, a1
110+
; RV64I-NEXT: negw a2, a1
111111
; RV64I-NEXT: sllw a1, a0, a1
112112
; RV64I-NEXT: srlw a0, a0, a2
113113
; RV64I-NEXT: or a0, a1, a0
@@ -125,7 +125,7 @@ define signext i32 @rol_i32(i32 signext %a, i32 signext %b) nounwind {
125125
define void @rol_i32_nosext(i32 signext %a, i32 signext %b, ptr %x) nounwind {
126126
; RV64I-LABEL: rol_i32_nosext:
127127
; RV64I: # %bb.0:
128-
; RV64I-NEXT: neg a3, a1
128+
; RV64I-NEXT: negw a3, a1
129129
; RV64I-NEXT: sllw a1, a0, a1
130130
; RV64I-NEXT: srlw a0, a0, a3
131131
; RV64I-NEXT: or a0, a1, a0
@@ -146,7 +146,7 @@ define signext i32 @rol_i32_neg_constant_rhs(i32 signext %a) nounwind {
146146
; RV64I-LABEL: rol_i32_neg_constant_rhs:
147147
; RV64I: # %bb.0:
148148
; RV64I-NEXT: li a1, -2
149-
; RV64I-NEXT: neg a2, a0
149+
; RV64I-NEXT: negw a2, a0
150150
; RV64I-NEXT: sllw a0, a1, a0
151151
; RV64I-NEXT: srlw a1, a1, a2
152152
; RV64I-NEXT: or a0, a0, a1
@@ -166,7 +166,7 @@ declare i64 @llvm.fshl.i64(i64, i64, i64)
166166
define i64 @rol_i64(i64 %a, i64 %b) nounwind {
167167
; RV64I-LABEL: rol_i64:
168168
; RV64I: # %bb.0:
169-
; RV64I-NEXT: neg a2, a1
169+
; RV64I-NEXT: negw a2, a1
170170
; RV64I-NEXT: sll a1, a0, a1
171171
; RV64I-NEXT: srl a0, a0, a2
172172
; RV64I-NEXT: or a0, a1, a0
@@ -185,7 +185,7 @@ declare i32 @llvm.fshr.i32(i32, i32, i32)
185185
define signext i32 @ror_i32(i32 signext %a, i32 signext %b) nounwind {
186186
; RV64I-LABEL: ror_i32:
187187
; RV64I: # %bb.0:
188-
; RV64I-NEXT: neg a2, a1
188+
; RV64I-NEXT: negw a2, a1
189189
; RV64I-NEXT: srlw a1, a0, a1
190190
; RV64I-NEXT: sllw a0, a0, a2
191191
; RV64I-NEXT: or a0, a1, a0
@@ -203,7 +203,7 @@ define signext i32 @ror_i32(i32 signext %a, i32 signext %b) nounwind {
203203
define void @ror_i32_nosext(i32 signext %a, i32 signext %b, ptr %x) nounwind {
204204
; RV64I-LABEL: ror_i32_nosext:
205205
; RV64I: # %bb.0:
206-
; RV64I-NEXT: neg a3, a1
206+
; RV64I-NEXT: negw a3, a1
207207
; RV64I-NEXT: srlw a1, a0, a1
208208
; RV64I-NEXT: sllw a0, a0, a3
209209
; RV64I-NEXT: or a0, a1, a0
@@ -224,7 +224,7 @@ define signext i32 @ror_i32_neg_constant_rhs(i32 signext %a) nounwind {
224224
; RV64I-LABEL: ror_i32_neg_constant_rhs:
225225
; RV64I: # %bb.0:
226226
; RV64I-NEXT: li a1, -2
227-
; RV64I-NEXT: neg a2, a0
227+
; RV64I-NEXT: negw a2, a0
228228
; RV64I-NEXT: srlw a0, a1, a0
229229
; RV64I-NEXT: sllw a1, a1, a2
230230
; RV64I-NEXT: or a0, a0, a1
@@ -244,7 +244,7 @@ declare i64 @llvm.fshr.i64(i64, i64, i64)
244244
define i64 @ror_i64(i64 %a, i64 %b) nounwind {
245245
; RV64I-LABEL: ror_i64:
246246
; RV64I: # %bb.0:
247-
; RV64I-NEXT: neg a2, a1
247+
; RV64I-NEXT: negw a2, a1
248248
; RV64I-NEXT: srl a1, a0, a1
249249
; RV64I-NEXT: sll a0, a0, a2
250250
; RV64I-NEXT: or a0, a1, a0

0 commit comments

Comments
 (0)