Skip to content

Commit 109aa58

Browse files
authored
[RISCV] Add an experimental pseudoinstruction to represent a rematerializable constant materialization sequence. (#69983)
Rematerialization during register allocation is currently limited to a single instruction with no inputs. This patch introduces a pseudoinstruction that represents the materialization of a constant. I've started with a sequence of 2 instructions for now, which covers at least the common LUI+ADDI(W) case. This instruction will be expanded into real instructions immediately after register allocation using a new pass. This gives the post-RA scheduler a chance to separate the 2 instructions to improve ILP. I believe this matches the approach used by AArch64. Unfortunately, this loses some CSE opportunies when an LUI value is used by multiple constants with different LSBs. This feature is off by default and a new backend command line option is added to enable it for testing. This avoids the spill and reloads reported in #69586.
1 parent 265ed68 commit 109aa58

File tree

10 files changed

+3093
-0
lines changed

10 files changed

+3093
-0
lines changed

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ add_llvm_target(RISCVCodeGen
4444
RISCVMacroFusion.cpp
4545
RISCVMergeBaseOffset.cpp
4646
RISCVOptWInstrs.cpp
47+
RISCVPostRAExpandPseudoInsts.cpp
4748
RISCVRedundantCopyElimination.cpp
4849
RISCVMoveMerger.cpp
4950
RISCVPushPopOptimizer.cpp

llvm/lib/Target/RISCV/RISCV.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ void initializeRISCVExpandAtomicPseudoPass(PassRegistry &);
6363
FunctionPass *createRISCVInsertVSETVLIPass();
6464
void initializeRISCVInsertVSETVLIPass(PassRegistry &);
6565

66+
FunctionPass *createRISCVPostRAExpandPseudoPass();
67+
void initializeRISCVPostRAExpandPseudoPass(PassRegistry &);
6668
FunctionPass *createRISCVInsertReadWriteCSRPass();
6769
void initializeRISCVInsertReadWriteCSRPass(PassRegistry &);
6870

llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ using namespace llvm;
2929
#define DEBUG_TYPE "riscv-isel"
3030
#define PASS_NAME "RISC-V DAG->DAG Pattern Instruction Selection"
3131

32+
static cl::opt<bool> UsePseudoMovImm(
33+
"riscv-use-rematerializable-movimm", cl::Hidden,
34+
cl::desc("Use a rematerializable pseudoinstruction for 2 instruction "
35+
"constant materialization"),
36+
cl::init(false));
37+
3238
namespace llvm::RISCV {
3339
#define GET_RISCVVSSEGTable_IMPL
3440
#define GET_RISCVVLSEGTable_IMPL
@@ -195,6 +201,13 @@ static SDValue selectImm(SelectionDAG *CurDAG, const SDLoc &DL, const MVT VT,
195201
RISCVMatInt::InstSeq Seq =
196202
RISCVMatInt::generateInstSeq(Imm, Subtarget.getFeatureBits());
197203

204+
// Use a rematerializable pseudo instruction for short sequences if enabled.
205+
if (Seq.size() == 2 && UsePseudoMovImm)
206+
return SDValue(
207+
CurDAG->getMachineNode(RISCV::PseudoMovImm, DL, VT,
208+
CurDAG->getTargetConstant(Imm, DL, VT)),
209+
0);
210+
198211
// See if we can create this constant as (ADD (SLLI X, C), X) where X is at
199212
// worst an LUI+ADDIW. This will require an extra register, but avoids a
200213
// constant pool.

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1664,6 +1664,16 @@ def PseudoJump : Pseudo<(outs GPR:$rd), (ins pseudo_jump_symbol:$target), [],
16641664
"jump", "$target, $rd">,
16651665
Sched<[WriteIALU, WriteJalr, ReadJalr]>;
16661666

1667+
// Pseudo for a rematerializable constant materialization sequence.
1668+
// This is an experimental feature enabled by
1669+
// -riscv-use-rematerializable-movimm in RISCVISelDAGToDAG.cpp
1670+
// It will be expanded after register allocation.
1671+
// FIXME: The scheduling information does not reflect the multiple instructions.
1672+
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, isCodeGenOnly = 1,
1673+
isPseudo = 1, isReMaterializable = 1, IsSignExtendingOpW = 1 in
1674+
def PseudoMovImm : Pseudo<(outs GPR:$dst), (ins i32imm:$imm), []>,
1675+
Sched<[WriteIALU]>;
1676+
16671677
let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8, isCodeGenOnly = 0,
16681678
isAsmParserOnly = 1 in
16691679
def PseudoLLA : Pseudo<(outs GPR:$dst), (ins bare_symbol:$src), [],
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//===-- RISCVPostRAExpandPseudoInsts.cpp - Expand pseudo instrs ----===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains a pass that expands the pseudo instruction pseudolisimm32
10+
// into target instructions. This pass should be run during the post-regalloc
11+
// passes, before post RA scheduling.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "MCTargetDesc/RISCVMatInt.h"
16+
#include "RISCV.h"
17+
#include "RISCVInstrInfo.h"
18+
#include "RISCVTargetMachine.h"
19+
#include "llvm/CodeGen/MachineFunctionPass.h"
20+
#include "llvm/CodeGen/MachineInstrBuilder.h"
21+
22+
using namespace llvm;
23+
24+
#define RISCV_POST_RA_EXPAND_PSEUDO_NAME \
25+
"RISC-V post-regalloc pseudo instruction expansion pass"
26+
27+
namespace {
28+
29+
class RISCVPostRAExpandPseudo : public MachineFunctionPass {
30+
public:
31+
const RISCVInstrInfo *TII;
32+
static char ID;
33+
34+
RISCVPostRAExpandPseudo() : MachineFunctionPass(ID) {
35+
initializeRISCVPostRAExpandPseudoPass(*PassRegistry::getPassRegistry());
36+
}
37+
38+
bool runOnMachineFunction(MachineFunction &MF) override;
39+
40+
StringRef getPassName() const override {
41+
return RISCV_POST_RA_EXPAND_PSEUDO_NAME;
42+
}
43+
44+
private:
45+
bool expandMBB(MachineBasicBlock &MBB);
46+
bool expandMI(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
47+
MachineBasicBlock::iterator &NextMBBI);
48+
bool expandMovImm(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI);
49+
};
50+
51+
char RISCVPostRAExpandPseudo::ID = 0;
52+
53+
bool RISCVPostRAExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
54+
TII = static_cast<const RISCVInstrInfo *>(MF.getSubtarget().getInstrInfo());
55+
bool Modified = false;
56+
for (auto &MBB : MF)
57+
Modified |= expandMBB(MBB);
58+
return Modified;
59+
}
60+
61+
bool RISCVPostRAExpandPseudo::expandMBB(MachineBasicBlock &MBB) {
62+
bool Modified = false;
63+
64+
MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
65+
while (MBBI != E) {
66+
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
67+
Modified |= expandMI(MBB, MBBI, NMBBI);
68+
MBBI = NMBBI;
69+
}
70+
71+
return Modified;
72+
}
73+
74+
bool RISCVPostRAExpandPseudo::expandMI(MachineBasicBlock &MBB,
75+
MachineBasicBlock::iterator MBBI,
76+
MachineBasicBlock::iterator &NextMBBI) {
77+
switch (MBBI->getOpcode()) {
78+
case RISCV::PseudoMovImm:
79+
return expandMovImm(MBB, MBBI);
80+
default:
81+
return false;
82+
}
83+
}
84+
85+
bool RISCVPostRAExpandPseudo::expandMovImm(MachineBasicBlock &MBB,
86+
MachineBasicBlock::iterator MBBI) {
87+
DebugLoc DL = MBBI->getDebugLoc();
88+
89+
int64_t Val = MBBI->getOperand(1).getImm();
90+
91+
RISCVMatInt::InstSeq Seq = RISCVMatInt::generateInstSeq(
92+
Val, MBB.getParent()->getSubtarget().getFeatureBits());
93+
assert(!Seq.empty());
94+
95+
Register SrcReg = RISCV::X0;
96+
Register DstReg = MBBI->getOperand(0).getReg();
97+
bool DstIsDead = MBBI->getOperand(0).isDead();
98+
bool Renamable = MBBI->getOperand(0).isRenamable();
99+
bool SrcRenamable = false;
100+
unsigned Num = 0;
101+
102+
for (RISCVMatInt::Inst &Inst : Seq) {
103+
bool LastItem = ++Num == Seq.size();
104+
switch (Inst.getOpndKind()) {
105+
case RISCVMatInt::Imm:
106+
BuildMI(MBB, MBBI, DL, TII->get(Inst.getOpcode()))
107+
.addReg(DstReg, RegState::Define |
108+
getDeadRegState(DstIsDead && LastItem) |
109+
getRenamableRegState(Renamable))
110+
.addImm(Inst.getImm());
111+
break;
112+
case RISCVMatInt::RegX0:
113+
BuildMI(MBB, MBBI, DL, TII->get(Inst.getOpcode()))
114+
.addReg(DstReg, RegState::Define |
115+
getDeadRegState(DstIsDead && LastItem) |
116+
getRenamableRegState(Renamable))
117+
.addReg(SrcReg, RegState::Kill | getRenamableRegState(SrcRenamable))
118+
.addReg(RISCV::X0);
119+
break;
120+
case RISCVMatInt::RegReg:
121+
BuildMI(MBB, MBBI, DL, TII->get(Inst.getOpcode()))
122+
.addReg(DstReg, RegState::Define |
123+
getDeadRegState(DstIsDead && LastItem) |
124+
getRenamableRegState(Renamable))
125+
.addReg(SrcReg, RegState::Kill | getRenamableRegState(SrcRenamable))
126+
.addReg(SrcReg, RegState::Kill | getRenamableRegState(SrcRenamable));
127+
break;
128+
case RISCVMatInt::RegImm:
129+
BuildMI(MBB, MBBI, DL, TII->get(Inst.getOpcode()))
130+
.addReg(DstReg, RegState::Define |
131+
getDeadRegState(DstIsDead && LastItem) |
132+
getRenamableRegState(Renamable))
133+
.addReg(SrcReg, RegState::Kill | getRenamableRegState(SrcRenamable))
134+
.addImm(Inst.getImm());
135+
break;
136+
}
137+
// Only the first instruction has X0 as its source.
138+
SrcReg = DstReg;
139+
SrcRenamable = Renamable;
140+
}
141+
MBBI->eraseFromParent();
142+
return true;
143+
}
144+
145+
} // end of anonymous namespace
146+
147+
INITIALIZE_PASS(RISCVPostRAExpandPseudo, "riscv-expand-pseudolisimm32",
148+
RISCV_POST_RA_EXPAND_PSEUDO_NAME, false, false)
149+
namespace llvm {
150+
151+
FunctionPass *createRISCVPostRAExpandPseudoPass() {
152+
return new RISCVPostRAExpandPseudo();
153+
}
154+
155+
} // end of namespace llvm

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
9696
initializeRISCVMakeCompressibleOptPass(*PR);
9797
initializeRISCVGatherScatterLoweringPass(*PR);
9898
initializeRISCVCodeGenPreparePass(*PR);
99+
initializeRISCVPostRAExpandPseudoPass(*PR);
99100
initializeRISCVMergeBaseOffsetOptPass(*PR);
100101
initializeRISCVOptWInstrsPass(*PR);
101102
initializeRISCVPreRAExpandPseudoPass(*PR);
@@ -372,6 +373,8 @@ bool RISCVPassConfig::addGlobalInstructionSelect() {
372373
}
373374

374375
void RISCVPassConfig::addPreSched2() {
376+
addPass(createRISCVPostRAExpandPseudoPass());
377+
375378
// Emit KCFI checks for indirect calls.
376379
addPass(createKCFIPass());
377380
}

llvm/test/CodeGen/RISCV/O0-pipeline.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
; CHECK-NEXT: Machine Optimization Remark Emitter
5353
; CHECK-NEXT: Prologue/Epilogue Insertion & Frame Finalization
5454
; CHECK-NEXT: Post-RA pseudo instruction expansion pass
55+
; CHECK-NEXT: RISC-V post-regalloc pseudo instruction expansion pass
5556
; CHECK-NEXT: Insert KCFI indirect call checks
5657
; CHECK-NEXT: Analyze Machine Code For Garbage Collection
5758
; CHECK-NEXT: Insert fentry calls

llvm/test/CodeGen/RISCV/O3-pipeline.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
; CHECK-NEXT: Tail Duplication
157157
; CHECK-NEXT: Machine Copy Propagation Pass
158158
; CHECK-NEXT: Post-RA pseudo instruction expansion pass
159+
; CHECK-NEXT: RISC-V post-regalloc pseudo instruction expansion pass
159160
; CHECK-NEXT: Insert KCFI indirect call checks
160161
; CHECK-NEXT: MachineDominator Tree Construction
161162
; CHECK-NEXT: Machine Natural Loop Construction

0 commit comments

Comments
 (0)