Skip to content

Commit 354e045

Browse files
committed
[RISCV] Make custom isel for (add X, imm) used by load/stores more selective.
Only handle immediates that would produce an ADDI or ADDIW of Lo12 as the final instruction in their materialization. As the test change show this removes immediates that materialize with lui+addiw that is not the same as lui+addi.
1 parent acab4b6 commit 354e045

File tree

2 files changed

+39
-21
lines changed

2 files changed

+39
-21
lines changed

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,8 @@ static bool hasMemOffset(SDNode *N, unsigned &BaseOpIdx,
187187
return false;
188188
}
189189

190-
static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT,
191-
int64_t Imm, const RISCVSubtarget &Subtarget) {
192-
RISCVMatInt::InstSeq Seq =
193-
RISCVMatInt::generateInstSeq(Imm, Subtarget.getFeatureBits());
194-
190+
static SDNode *selectImmSeq(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT,
191+
RISCVMatInt::InstSeq &Seq) {
195192
SDNode *Result = nullptr;
196193
SDValue SrcReg = CurDAG->getRegister(RISCV::X0, VT);
197194
for (RISCVMatInt::Inst &Inst : Seq) {
@@ -219,6 +216,14 @@ static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT,
219216
return Result;
220217
}
221218

219+
static SDNode *selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT,
220+
int64_t Imm, const RISCVSubtarget &Subtarget) {
221+
RISCVMatInt::InstSeq Seq =
222+
RISCVMatInt::generateInstSeq(Imm, Subtarget.getFeatureBits());
223+
224+
return selectImmSeq(CurDAG, DL, VT, Seq);
225+
}
226+
222227
static SDValue createTuple(SelectionDAG &CurDAG, ArrayRef<SDValue> Regs,
223228
unsigned NF, RISCVII::VLMUL LMUL) {
224229
static const unsigned M1TupleRegClassIDs[] = {
@@ -667,6 +672,24 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
667672
if (isInt<12>(Offset / 2) && isInt<12>(Offset - Offset / 2))
668673
break;
669674

675+
RISCVMatInt::InstSeq Seq =
676+
RISCVMatInt::generateInstSeq(Offset, Subtarget->getFeatureBits());
677+
678+
Offset -= Lo12;
679+
// Restore sign bits for RV32.
680+
if (!Subtarget->is64Bit())
681+
Offset = SignExtend64<32>(Offset);
682+
683+
// We can fold if the last operation is an ADDI or its an ADDIW that could
684+
// be treated as an ADDI.
685+
if (Seq.back().Opc != RISCV::ADDI &&
686+
!(Seq.back().Opc == RISCV::ADDIW && isInt<32>(Offset)))
687+
break;
688+
assert(Seq.back().Imm == Lo12 && "Expected immediate to match Lo12");
689+
// Drop the last operation.
690+
Seq.pop_back();
691+
assert(!Seq.empty() && "Expected more instructions in sequence");
692+
670693
bool AllPointerUses = true;
671694
for (auto UI = Node->use_begin(), UE = Node->use_end(); UI != UE; ++UI) {
672695
SDNode *User = *UI;
@@ -695,13 +718,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
695718
if (!AllPointerUses)
696719
break;
697720

698-
Offset -= Lo12;
699-
// Restore sign bits for RV32.
700-
if (!Subtarget->is64Bit())
701-
Offset = SignExtend64<32>(Offset);
702-
703721
// Emit (ADDI (ADD X, Hi), Lo)
704-
SDNode *Imm = selectImm(CurDAG, DL, VT, Offset, *Subtarget);
722+
SDNode *Imm = selectImmSeq(CurDAG, DL, VT, Seq);
705723
SDNode *ADD = CurDAG->getMachineNode(RISCV::ADD, DL, VT,
706724
Node->getOperand(0), SDValue(Imm, 0));
707725
SDNode *ADDI =

llvm/test/CodeGen/RISCV/mem64.ll

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -307,10 +307,10 @@ define i64 @lw_sw_far_local(i64* %a, i64 %b) {
307307
define i64 @lw_really_far_local(i64* %a) {
308308
; RV64I-LABEL: lw_really_far_local:
309309
; RV64I: # %bb.0:
310-
; RV64I-NEXT: li a1, 1
311-
; RV64I-NEXT: slli a1, a1, 31
310+
; RV64I-NEXT: lui a1, 524288
311+
; RV64I-NEXT: addiw a1, a1, -2048
312312
; RV64I-NEXT: add a0, a0, a1
313-
; RV64I-NEXT: ld a0, -2048(a0)
313+
; RV64I-NEXT: ld a0, 0(a0)
314314
; RV64I-NEXT: ret
315315
%1 = getelementptr inbounds i64, i64* %a, i64 268435200
316316
%2 = load volatile i64, i64* %1
@@ -322,10 +322,10 @@ define i64 @lw_really_far_local(i64* %a) {
322322
define void @st_really_far_local(i64* %a, i64 %b) {
323323
; RV64I-LABEL: st_really_far_local:
324324
; RV64I: # %bb.0:
325-
; RV64I-NEXT: li a2, 1
326-
; RV64I-NEXT: slli a2, a2, 31
325+
; RV64I-NEXT: lui a2, 524288
326+
; RV64I-NEXT: addiw a2, a2, -2048
327327
; RV64I-NEXT: add a0, a0, a2
328-
; RV64I-NEXT: sd a1, -2048(a0)
328+
; RV64I-NEXT: sd a1, 0(a0)
329329
; RV64I-NEXT: ret
330330
%1 = getelementptr inbounds i64, i64* %a, i64 268435200
331331
store i64 %b, i64* %1
@@ -337,11 +337,11 @@ define void @st_really_far_local(i64* %a, i64 %b) {
337337
define i64 @lw_sw_really_far_local(i64* %a, i64 %b) {
338338
; RV64I-LABEL: lw_sw_really_far_local:
339339
; RV64I: # %bb.0:
340-
; RV64I-NEXT: li a2, 1
341-
; RV64I-NEXT: slli a2, a2, 31
340+
; RV64I-NEXT: lui a2, 524288
341+
; RV64I-NEXT: addiw a2, a2, -2048
342342
; RV64I-NEXT: add a2, a0, a2
343-
; RV64I-NEXT: ld a0, -2048(a2)
344-
; RV64I-NEXT: sd a1, -2048(a2)
343+
; RV64I-NEXT: ld a0, 0(a2)
344+
; RV64I-NEXT: sd a1, 0(a2)
345345
; RV64I-NEXT: ret
346346
%1 = getelementptr inbounds i64, i64* %a, i64 268435200
347347
%2 = load volatile i64, i64* %1

0 commit comments

Comments
 (0)