Skip to content

Commit c9e08fa

Browse files
committed
[RISCV] Add a pass to merge moving parameter registers instructions for Zcmp
This patch adds a pass to generate `cm.mvsa01` & `cm.mva01s`. RISCVMoveOptimizer.cpp which combines two mv inst into one cm.mva01s or cm.mva01s. Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D150415
1 parent 42a82b1 commit c9e08fa

File tree

6 files changed

+443
-0
lines changed

6 files changed

+443
-0
lines changed

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ add_llvm_target(RISCVCodeGen
3636
RISCVMergeBaseOffset.cpp
3737
RISCVOptWInstrs.cpp
3838
RISCVRedundantCopyElimination.cpp
39+
RISCVMoveMerger.cpp
3940
RISCVRegisterInfo.cpp
4041
RISCVRVVInitUndef.cpp
4142
RISCVSubtarget.cpp

llvm/lib/Target/RISCV/RISCV.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ FunctionPass *createRISCVInitUndefPass();
7070
void initializeRISCVInitUndefPass(PassRegistry &);
7171
extern char &RISCVInitUndefID;
7272

73+
FunctionPass *createRISCVMoveMergePass();
74+
void initializeRISCVMoveMergePass(PassRegistry &);
75+
7376
InstructionSelector *createRISCVInstructionSelector(const RISCVTargetMachine &,
7477
RISCVSubtarget &,
7578
RISCVRegisterBankInfo &);
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
//===---------- RISCVMoveMerge.cpp - RISCV move merge pass -------------===//
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 performs move related peephole optimizations
10+
// as Zcmp has specified. This pass should be run after register allocation.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "RISCVInstrInfo.h"
15+
#include "RISCVMachineFunctionInfo.h"
16+
17+
using namespace llvm;
18+
19+
#define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass"
20+
21+
namespace {
22+
struct RISCVMoveMerge : public MachineFunctionPass {
23+
static char ID;
24+
25+
RISCVMoveMerge() : MachineFunctionPass(ID) {
26+
initializeRISCVMoveMergePass(*PassRegistry::getPassRegistry());
27+
}
28+
29+
const RISCVInstrInfo *TII;
30+
const TargetRegisterInfo *TRI;
31+
32+
// Track which register units have been modified and used.
33+
LiveRegUnits ModifiedRegUnits, UsedRegUnits;
34+
35+
bool isCandidateToMergeMVA01S(const DestSourcePair &RegPair);
36+
bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair);
37+
// Merge the two instructions indicated into a single pair instruction.
38+
MachineBasicBlock::iterator
39+
mergePairedInsns(MachineBasicBlock::iterator I,
40+
MachineBasicBlock::iterator Paired, unsigned Opcode);
41+
42+
// Look for C.MV instruction that can be combined with
43+
// the given instruction into CM.MVA01S or CM.MVSA01. Return the matching
44+
// instruction if one exists.
45+
MachineBasicBlock::iterator
46+
findMatchingInst(MachineBasicBlock::iterator &MBBI, unsigned InstOpcode,
47+
const DestSourcePair &RegPair);
48+
bool mergeMoveSARegPair(MachineBasicBlock &MBB);
49+
bool runOnMachineFunction(MachineFunction &Fn) override;
50+
51+
StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
52+
};
53+
54+
char RISCVMoveMerge::ID = 0;
55+
56+
} // end of anonymous namespace
57+
58+
INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
59+
false, false)
60+
61+
// Check if registers meet CM.MVA01S constraints.
62+
bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
63+
Register Destination = RegPair.Destination->getReg();
64+
Register Source = RegPair.Source->getReg();
65+
// If destination is not a0 or a1.
66+
if ((Destination == RISCV::X10 || Destination == RISCV::X11) &&
67+
RISCV::SR07RegClass.contains(Source))
68+
return true;
69+
return false;
70+
}
71+
72+
// Check if registers meet CM.MVSA01 constraints.
73+
bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) {
74+
Register Destination = RegPair.Destination->getReg();
75+
Register Source = RegPair.Source->getReg();
76+
// If Source is s0 - s7.
77+
if ((Source == RISCV::X10 || Source == RISCV::X11) &&
78+
RISCV::SR07RegClass.contains(Destination))
79+
return true;
80+
return false;
81+
}
82+
83+
MachineBasicBlock::iterator
84+
RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
85+
MachineBasicBlock::iterator Paired,
86+
unsigned Opcode) {
87+
const MachineOperand *Sreg1, *Sreg2;
88+
MachineBasicBlock::iterator E = I->getParent()->end();
89+
MachineBasicBlock::iterator NextI = next_nodbg(I, E);
90+
DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
91+
DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
92+
Register ARegInFirstPair = Opcode == RISCV::CM_MVA01S
93+
? FirstPair.Destination->getReg()
94+
: FirstPair.Source->getReg();
95+
96+
if (NextI == Paired)
97+
NextI = next_nodbg(NextI, E);
98+
DebugLoc DL = I->getDebugLoc();
99+
100+
// The order of S-reg depends on which instruction holds A0, instead of
101+
// the order of register pair.
102+
// e,g.
103+
// mv a1, s1
104+
// mv a0, s2 => cm.mva01s s2,s1
105+
//
106+
// mv a0, s2
107+
// mv a1, s1 => cm.mva01s s2,s1
108+
bool StartWithX10 = ARegInFirstPair == RISCV::X10;
109+
if (Opcode == RISCV::CM_MVA01S) {
110+
Sreg1 = StartWithX10 ? FirstPair.Source : PairedRegs.Source;
111+
Sreg2 = StartWithX10 ? PairedRegs.Source : FirstPair.Source;
112+
} else {
113+
Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination;
114+
Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination;
115+
}
116+
117+
BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
118+
119+
I->eraseFromParent();
120+
Paired->eraseFromParent();
121+
return NextI;
122+
}
123+
124+
MachineBasicBlock::iterator
125+
RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
126+
unsigned InstOpcode,
127+
const DestSourcePair &RegPair) {
128+
MachineBasicBlock::iterator E = MBBI->getParent()->end();
129+
130+
// Track which register units have been modified and used between the first
131+
// insn and the second insn.
132+
ModifiedRegUnits.clear();
133+
UsedRegUnits.clear();
134+
135+
for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E;
136+
I = next_nodbg(I, E)) {
137+
138+
MachineInstr &MI = *I;
139+
140+
if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
141+
Register SourceReg = SecondPair->Source->getReg();
142+
Register DestReg = SecondPair->Destination->getReg();
143+
144+
if (InstOpcode == RISCV::CM_MVA01S &&
145+
isCandidateToMergeMVA01S(*SecondPair)) {
146+
// If register pair is valid and destination registers are different.
147+
if ((RegPair.Destination->getReg() == DestReg))
148+
return E;
149+
150+
// If paired destination register was modified or used, the source reg
151+
// was modified, there is no possibility of finding matching
152+
// instruction so exit early.
153+
if (!ModifiedRegUnits.available(DestReg) ||
154+
!UsedRegUnits.available(DestReg) ||
155+
!ModifiedRegUnits.available(SourceReg))
156+
return E;
157+
158+
return I;
159+
} else if (InstOpcode == RISCV::CM_MVSA01 &&
160+
isCandidateToMergeMVSA01(*SecondPair)) {
161+
if ((RegPair.Source->getReg() == SourceReg) ||
162+
(RegPair.Destination->getReg() == DestReg))
163+
return E;
164+
165+
if (!ModifiedRegUnits.available(DestReg) ||
166+
!UsedRegUnits.available(DestReg) ||
167+
!ModifiedRegUnits.available(SourceReg))
168+
return E;
169+
170+
return I;
171+
}
172+
}
173+
// Update modified / used register units.
174+
LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
175+
}
176+
return E;
177+
}
178+
179+
// Finds instructions, which could be represented as C.MV instructions and
180+
// merged into CM.MVA01S or CM.MVSA01.
181+
bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
182+
bool Modified = false;
183+
184+
for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
185+
MBBI != E;) {
186+
// Check if the instruction can be compressed to C.MV instruction. If it
187+
// can, return Dest/Src register pair.
188+
auto RegPair = TII->isCopyInstrImpl(*MBBI);
189+
if (RegPair.has_value()) {
190+
unsigned Opcode = 0;
191+
192+
if (isCandidateToMergeMVA01S(*RegPair))
193+
Opcode = RISCV::CM_MVA01S;
194+
else if (isCandidateToMergeMVSA01(*RegPair))
195+
Opcode = RISCV::CM_MVSA01;
196+
else {
197+
++MBBI;
198+
continue;
199+
}
200+
201+
MachineBasicBlock::iterator Paired =
202+
findMatchingInst(MBBI, Opcode, RegPair.value());
203+
// If matching instruction can be found merge them.
204+
if (Paired != E) {
205+
MBBI = mergePairedInsns(MBBI, Paired, Opcode);
206+
Modified = true;
207+
continue;
208+
}
209+
}
210+
++MBBI;
211+
}
212+
return Modified;
213+
}
214+
215+
bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
216+
if (skipFunction(Fn.getFunction()))
217+
return false;
218+
219+
const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
220+
if (!Subtarget->hasStdExtZcmp())
221+
return false;
222+
223+
TII = Subtarget->getInstrInfo();
224+
TRI = Subtarget->getRegisterInfo();
225+
// Resize the modified and used register unit trackers. We do this once
226+
// per function and then clear the register units each time we optimize a
227+
// move.
228+
ModifiedRegUnits.init(*TRI);
229+
UsedRegUnits.init(*TRI);
230+
bool Modified = false;
231+
for (auto &MBB : Fn)
232+
Modified |= mergeMoveSARegPair(MBB);
233+
return Modified;
234+
}
235+
236+
/// createRISCVMoveMergePass - returns an instance of the
237+
/// move merge pass.
238+
FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
8787
initializeRISCVInsertReadWriteCSRPass(*PR);
8888
initializeRISCVDAGToDAGISelPass(*PR);
8989
initializeRISCVInitUndefPass(*PR);
90+
initializeRISCVMoveMergePass(*PR);
9091
}
9192

9293
static StringRef computeDataLayout(const Triple &TT) {
@@ -348,6 +349,8 @@ void RISCVPassConfig::addPreEmitPass() {
348349
}
349350

350351
void RISCVPassConfig::addPreEmitPass2() {
352+
if (TM->getOptLevel() != CodeGenOpt::None)
353+
addPass(createRISCVMoveMergePass());
351354
addPass(createRISCVExpandPseudoPass());
352355

353356
// Schedule the expansion of AMOs at the last possible moment, avoiding the

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@
177177
; CHECK-NEXT: Lazy Machine Block Frequency Analysis
178178
; CHECK-NEXT: Machine Optimization Remark Emitter
179179
; CHECK-NEXT: Stack Frame Layout Analysis
180+
; CHECK-NEXT: RISC-V Zcmp move merging pass
180181
; CHECK-NEXT: RISC-V pseudo instruction expansion pass
181182
; CHECK-NEXT: RISC-V atomic pseudo instruction expansion pass
182183
; CHECK-NEXT: Lazy Machine Block Frequency Analysis

0 commit comments

Comments
 (0)