1 //===-- RISCVMoveMerger.cpp - RISC-V 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 // This pass also supports Xqccmp, which has identical instructions.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #include "RISCVInstrInfo.h"
17 #include "RISCVSubtarget.h"
18
19 using namespace llvm;
20
21 #define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass"
22
23 namespace {
24 struct RISCVMoveMerge : public MachineFunctionPass {
25 static char ID;
26
RISCVMoveMerge__anone75dfb3c0111::RISCVMoveMerge27 RISCVMoveMerge() : MachineFunctionPass(ID) {}
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(const RISCVSubtarget &STI, MachineBasicBlock &MBB);
49 bool runOnMachineFunction(MachineFunction &Fn) override;
50
getPassName__anone75dfb3c0111::RISCVMoveMerge51 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
isMoveFromAToS(unsigned Opcode)61 static bool isMoveFromAToS(unsigned Opcode) {
62 switch (Opcode) {
63 case RISCV::CM_MVA01S:
64 case RISCV::QC_CM_MVA01S:
65 return true;
66 default:
67 return false;
68 }
69 }
70
getMoveFromAToSOpcode(const RISCVSubtarget & STI)71 static unsigned getMoveFromAToSOpcode(const RISCVSubtarget &STI) {
72 if (STI.hasStdExtZcmp())
73 return RISCV::CM_MVA01S;
74
75 if (STI.hasVendorXqccmp())
76 return RISCV::QC_CM_MVA01S;
77
78 llvm_unreachable("Unhandled subtarget with paired A to S move.");
79 }
80
isMoveFromSToA(unsigned Opcode)81 static bool isMoveFromSToA(unsigned Opcode) {
82 switch (Opcode) {
83 case RISCV::CM_MVSA01:
84 case RISCV::QC_CM_MVSA01:
85 return true;
86 default:
87 return false;
88 }
89 }
90
getMoveFromSToAOpcode(const RISCVSubtarget & STI)91 static unsigned getMoveFromSToAOpcode(const RISCVSubtarget &STI) {
92 if (STI.hasStdExtZcmp())
93 return RISCV::CM_MVSA01;
94
95 if (STI.hasVendorXqccmp())
96 return RISCV::QC_CM_MVSA01;
97
98 llvm_unreachable("Unhandled subtarget with paired S to A move");
99 }
100
101 // Check if registers meet CM.MVA01S constraints.
isCandidateToMergeMVA01S(const DestSourcePair & RegPair)102 bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
103 Register Destination = RegPair.Destination->getReg();
104 Register Source = RegPair.Source->getReg();
105 // If destination is not a0 or a1.
106 if ((Destination == RISCV::X10 || Destination == RISCV::X11) &&
107 RISCV::SR07RegClass.contains(Source))
108 return true;
109 return false;
110 }
111
112 // Check if registers meet CM.MVSA01 constraints.
isCandidateToMergeMVSA01(const DestSourcePair & RegPair)113 bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) {
114 Register Destination = RegPair.Destination->getReg();
115 Register Source = RegPair.Source->getReg();
116 // If Source is s0 - s7.
117 if ((Source == RISCV::X10 || Source == RISCV::X11) &&
118 RISCV::SR07RegClass.contains(Destination))
119 return true;
120 return false;
121 }
122
123 MachineBasicBlock::iterator
mergePairedInsns(MachineBasicBlock::iterator I,MachineBasicBlock::iterator Paired,unsigned Opcode)124 RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
125 MachineBasicBlock::iterator Paired,
126 unsigned Opcode) {
127 const MachineOperand *Sreg1, *Sreg2;
128 MachineBasicBlock::iterator E = I->getParent()->end();
129 MachineBasicBlock::iterator NextI = next_nodbg(I, E);
130 DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
131 DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
132 Register ARegInFirstPair = isMoveFromAToS(Opcode)
133 ? FirstPair.Destination->getReg()
134 : FirstPair.Source->getReg();
135
136 if (NextI == Paired)
137 NextI = next_nodbg(NextI, E);
138 DebugLoc DL = I->getDebugLoc();
139
140 // Make a copy so we can update the kill flag in the MoveFromAToS case. The
141 // copied operand needs to be scoped outside the if since we make a pointer
142 // to it.
143 MachineOperand PairedSource = *PairedRegs.Source;
144
145 // The order of S-reg depends on which instruction holds A0, instead of
146 // the order of register pair.
147 // e,g.
148 // mv a1, s1
149 // mv a0, s2 => cm.mva01s s2,s1
150 //
151 // mv a0, s2
152 // mv a1, s1 => cm.mva01s s2,s1
153 bool StartWithX10 = ARegInFirstPair == RISCV::X10;
154 if (isMoveFromAToS(Opcode)) {
155 // We are moving one of the copies earlier so its kill flag may become
156 // invalid. Clear the copied kill flag if there are any reads of the
157 // register between the new location and the old location.
158 for (auto It = std::next(I); It != Paired && PairedSource.isKill(); ++It)
159 if (It->readsRegister(PairedSource.getReg(), TRI))
160 PairedSource.setIsKill(false);
161
162 Sreg1 = StartWithX10 ? FirstPair.Source : &PairedSource;
163 Sreg2 = StartWithX10 ? &PairedSource : FirstPair.Source;
164 } else {
165 Sreg1 = StartWithX10 ? FirstPair.Destination : PairedRegs.Destination;
166 Sreg2 = StartWithX10 ? PairedRegs.Destination : FirstPair.Destination;
167 }
168
169 BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
170
171 I->eraseFromParent();
172 Paired->eraseFromParent();
173 return NextI;
174 }
175
176 MachineBasicBlock::iterator
findMatchingInst(MachineBasicBlock::iterator & MBBI,unsigned InstOpcode,const DestSourcePair & RegPair)177 RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
178 unsigned InstOpcode,
179 const DestSourcePair &RegPair) {
180 MachineBasicBlock::iterator E = MBBI->getParent()->end();
181
182 // Track which register units have been modified and used between the first
183 // insn and the second insn.
184 ModifiedRegUnits.clear();
185 UsedRegUnits.clear();
186
187 for (MachineBasicBlock::iterator I = next_nodbg(MBBI, E); I != E;
188 I = next_nodbg(I, E)) {
189
190 MachineInstr &MI = *I;
191
192 if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
193 Register SourceReg = SecondPair->Source->getReg();
194 Register DestReg = SecondPair->Destination->getReg();
195
196 if (isMoveFromAToS(InstOpcode) && isCandidateToMergeMVA01S(*SecondPair)) {
197 // If register pair is valid and destination registers are different.
198 if ((RegPair.Destination->getReg() == DestReg))
199 return E;
200
201 // If paired destination register was modified or used, the source reg
202 // was modified, there is no possibility of finding matching
203 // instruction so exit early.
204 if (!ModifiedRegUnits.available(DestReg) ||
205 !UsedRegUnits.available(DestReg) ||
206 !ModifiedRegUnits.available(SourceReg))
207 return E;
208
209 return I;
210 } else if (isMoveFromSToA(InstOpcode) &&
211 isCandidateToMergeMVSA01(*SecondPair)) {
212 if ((RegPair.Source->getReg() == SourceReg) ||
213 (RegPair.Destination->getReg() == DestReg))
214 return E;
215
216 if (!ModifiedRegUnits.available(DestReg) ||
217 !UsedRegUnits.available(DestReg) ||
218 !ModifiedRegUnits.available(SourceReg))
219 return E;
220
221 return I;
222 }
223 }
224 // Update modified / used register units.
225 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
226 }
227 return E;
228 }
229
230 // Finds instructions, which could be represented as C.MV instructions and
231 // merged into CM.MVA01S or CM.MVSA01.
mergeMoveSARegPair(const RISCVSubtarget & STI,MachineBasicBlock & MBB)232 bool RISCVMoveMerge::mergeMoveSARegPair(const RISCVSubtarget &STI,
233 MachineBasicBlock &MBB) {
234 bool Modified = false;
235
236 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
237 MBBI != E;) {
238 // Check if the instruction can be compressed to C.MV instruction. If it
239 // can, return Dest/Src register pair.
240 auto RegPair = TII->isCopyInstrImpl(*MBBI);
241 if (RegPair.has_value()) {
242 unsigned Opcode = 0;
243
244 if (isCandidateToMergeMVA01S(*RegPair))
245 Opcode = getMoveFromAToSOpcode(STI);
246 else if (isCandidateToMergeMVSA01(*RegPair))
247 Opcode = getMoveFromSToAOpcode(STI);
248 else {
249 ++MBBI;
250 continue;
251 }
252
253 MachineBasicBlock::iterator Paired =
254 findMatchingInst(MBBI, Opcode, RegPair.value());
255 // If matching instruction can be found merge them.
256 if (Paired != E) {
257 MBBI = mergePairedInsns(MBBI, Paired, Opcode);
258 Modified = true;
259 continue;
260 }
261 }
262 ++MBBI;
263 }
264 return Modified;
265 }
266
runOnMachineFunction(MachineFunction & Fn)267 bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
268 if (skipFunction(Fn.getFunction()))
269 return false;
270
271 const RISCVSubtarget *Subtarget = &Fn.getSubtarget<RISCVSubtarget>();
272 if (!(Subtarget->hasStdExtZcmp() || Subtarget->hasVendorXqccmp()))
273 return false;
274
275 TII = Subtarget->getInstrInfo();
276 TRI = Subtarget->getRegisterInfo();
277 // Resize the modified and used register unit trackers. We do this once
278 // per function and then clear the register units each time we optimize a
279 // move.
280 ModifiedRegUnits.init(*TRI);
281 UsedRegUnits.init(*TRI);
282 bool Modified = false;
283 for (auto &MBB : Fn)
284 Modified |= mergeMoveSARegPair(*Subtarget, MBB);
285 return Modified;
286 }
287
288 /// createRISCVMoveMergePass - returns an instance of the
289 /// move merge pass.
createRISCVMoveMergePass()290 FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }
291