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
19using namespace llvm;
20
21#define RISCV_MOVE_MERGE_NAME "RISC-V Zcmp move merging pass"
22
23namespace {
24struct RISCVMoveMerge : public MachineFunctionPass {
25 static char ID;
26
27 RISCVMoveMerge() : MachineFunctionPass(ID) {}
28
29 const RISCVSubtarget *ST;
30 const RISCVInstrInfo *TII;
31 const TargetRegisterInfo *TRI;
32
33 // Track which register units have been modified and used.
34 LiveRegUnits ModifiedRegUnits, UsedRegUnits;
35
36 bool isEvenRegisterCopy(const DestSourcePair &RegPair);
37 bool isOddRegisterCopy(const DestSourcePair &RegPair);
38
39 bool isCandidateToMergeMVA01S(const DestSourcePair &RegPair);
40 bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair);
41 // Merge the two instructions indicated into a single pair instruction.
42 MachineBasicBlock::iterator
43 mergeGPRPairInsns(MachineBasicBlock::iterator I,
44 MachineBasicBlock::iterator Paired, bool RegPairIsEven);
45 MachineBasicBlock::iterator
46 mergePairedInsns(MachineBasicBlock::iterator I,
47 MachineBasicBlock::iterator Paired, bool MoveFromSToA);
48
49 MachineBasicBlock::iterator
50 findMatchingInstPair(MachineBasicBlock::iterator &MBBI, bool EvenRegPair,
51 const DestSourcePair &RegPair);
52 // Look for C.MV instruction that can be combined with
53 // the given instruction into CM.MVA01S or CM.MVSA01. Return the matching
54 // instruction if one exists.
55 MachineBasicBlock::iterator
56 findMatchingInst(MachineBasicBlock::iterator &MBBI, bool MoveFromSToA,
57 const DestSourcePair &RegPair);
58 bool mergeMoveSARegPair(MachineBasicBlock &MBB);
59 bool runOnMachineFunction(MachineFunction &Fn) override;
60
61 StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
62};
63
64char RISCVMoveMerge::ID = 0;
65
66} // end of anonymous namespace
67
68INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
69 false, false)
70
71static unsigned getGPRPairCopyOpcode(const RISCVSubtarget &ST) {
72 if (ST.hasStdExtZdinx())
73 return RISCV::FSGNJ_D_IN32X;
74
75 if (ST.hasStdExtP())
76 return RISCV::PADD_DW;
77
78 llvm_unreachable("Unhandled subtarget with paired move.");
79}
80
81static unsigned getCM_MVOpcode(const RISCVSubtarget &ST, bool MoveFromSToA) {
82 if (ST.hasStdExtZcmp())
83 return MoveFromSToA ? RISCV::CM_MVA01S : RISCV::CM_MVSA01;
84
85 if (ST.hasVendorXqccmp())
86 return MoveFromSToA ? RISCV::QC_CM_MVA01S : RISCV::QC_CM_MVSA01;
87
88 llvm_unreachable("Unhandled subtarget with paired move.");
89}
90
91bool RISCVMoveMerge::isEvenRegisterCopy(const DestSourcePair &RegPair) {
92 Register Destination = RegPair.Destination->getReg();
93 Register Source = RegPair.Source->getReg();
94
95 if (Source == Destination)
96 return false;
97
98 Register SrcPair = TRI->getMatchingSuperReg(Reg: Source, SubIdx: RISCV::sub_gpr_even,
99 RC: &RISCV::GPRPairRegClass);
100 Register DestPair = TRI->getMatchingSuperReg(Reg: Destination, SubIdx: RISCV::sub_gpr_even,
101 RC: &RISCV::GPRPairRegClass);
102
103 return SrcPair.isValid() && DestPair.isValid();
104}
105
106bool RISCVMoveMerge::isOddRegisterCopy(const DestSourcePair &RegPair) {
107 Register Destination = RegPair.Destination->getReg();
108 Register Source = RegPair.Source->getReg();
109
110 if (Source == Destination)
111 return false;
112
113 Register SrcPair = TRI->getMatchingSuperReg(Reg: Source, SubIdx: RISCV::sub_gpr_odd,
114 RC: &RISCV::GPRPairRegClass);
115 Register DestPair = TRI->getMatchingSuperReg(Reg: Destination, SubIdx: RISCV::sub_gpr_odd,
116 RC: &RISCV::GPRPairRegClass);
117
118 return SrcPair.isValid() && DestPair.isValid();
119}
120
121// Check if registers meet CM.MVA01S constraints.
122bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
123 Register Destination = RegPair.Destination->getReg();
124 Register Source = RegPair.Source->getReg();
125 // If destination is not a0 or a1.
126 if ((ST->hasStdExtZcmp() || ST->hasVendorXqccmp()) &&
127 (Destination == RISCV::X10 || Destination == RISCV::X11) &&
128 RISCV::SR07RegClass.contains(Reg: Source))
129 return true;
130 return false;
131}
132
133// Check if registers meet CM.MVSA01 constraints.
134bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) {
135 Register Destination = RegPair.Destination->getReg();
136 Register Source = RegPair.Source->getReg();
137 // If Source is s0 - s7.
138 if ((ST->hasStdExtZcmp() || ST->hasVendorXqccmp()) &&
139 (Source == RISCV::X10 || Source == RISCV::X11) &&
140 RISCV::SR07RegClass.contains(Reg: Destination))
141 return true;
142 return false;
143}
144
145MachineBasicBlock::iterator
146RISCVMoveMerge::mergeGPRPairInsns(MachineBasicBlock::iterator I,
147 MachineBasicBlock::iterator Paired,
148 bool RegPairIsEven) {
149 MachineBasicBlock::iterator E = I->getParent()->end();
150 MachineBasicBlock::iterator NextI = next_nodbg(It: I, End: E);
151 DestSourcePair FirstPair = TII->isCopyInstrImpl(MI: *I).value();
152 DestSourcePair SecondPair = TII->isCopyInstrImpl(MI: *Paired).value();
153
154 if (NextI == Paired)
155 NextI = next_nodbg(It: NextI, End: E);
156 DebugLoc DL = I->getDebugLoc();
157
158 // Make a copy of the second instruction to update the kill
159 // flag.
160 MachineOperand PairedSource = *SecondPair.Source;
161
162 unsigned Opcode = getGPRPairCopyOpcode(ST: *ST);
163 for (auto It = std::next(x: I); It != Paired && PairedSource.isKill(); ++It)
164 if (It->readsRegister(Reg: PairedSource.getReg(), TRI))
165 PairedSource.setIsKill(false);
166
167 Register SrcReg1, SrcReg2, DestReg;
168 unsigned GPRPairIdx =
169 RegPairIsEven ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
170 SrcReg1 = TRI->getMatchingSuperReg(Reg: FirstPair.Source->getReg(), SubIdx: GPRPairIdx,
171 RC: &RISCV::GPRPairRegClass);
172 SrcReg2 = ST->hasStdExtZdinx() ? SrcReg1 : Register(RISCV::X0_Pair);
173 DestReg = TRI->getMatchingSuperReg(Reg: FirstPair.Destination->getReg(),
174 SubIdx: GPRPairIdx, RC: &RISCV::GPRPairRegClass);
175
176 BuildMI(BB&: *I->getParent(), I, MIMD: DL, MCID: TII->get(Opcode), DestReg)
177 .addReg(RegNo: SrcReg1, Flags: getKillRegState(B: PairedSource.isKill() &&
178 FirstPair.Source->isKill()))
179 .addReg(RegNo: SrcReg2, Flags: getKillRegState(B: PairedSource.isKill() &&
180 FirstPair.Source->isKill()));
181
182 I->eraseFromParent();
183 Paired->eraseFromParent();
184 return NextI;
185}
186
187MachineBasicBlock::iterator
188RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
189 MachineBasicBlock::iterator Paired,
190 bool MoveFromSToA) {
191 const MachineOperand *Sreg1, *Sreg2;
192 MachineBasicBlock::iterator E = I->getParent()->end();
193 MachineBasicBlock::iterator NextI = next_nodbg(It: I, End: E);
194 DestSourcePair FirstPair = TII->isCopyInstrImpl(MI: *I).value();
195 DestSourcePair PairedRegs = TII->isCopyInstrImpl(MI: *Paired).value();
196
197 if (NextI == Paired)
198 NextI = next_nodbg(It: NextI, End: E);
199 DebugLoc DL = I->getDebugLoc();
200
201 // Make a copy so we can update the kill flag in the MoveFromSToA case. The
202 // copied operand needs to be scoped outside the if since we make a pointer
203 // to it.
204 MachineOperand PairedSource = *PairedRegs.Source;
205
206 // The order of S-reg depends on which instruction holds A0, instead of
207 // the order of register pair.
208 // e,g.
209 // mv a1, s1
210 // mv a0, s2 => cm.mva01s s2,s1
211 //
212 // mv a0, s2
213 // mv a1, s1 => cm.mva01s s2,s1
214 unsigned Opcode = getCM_MVOpcode(ST: *ST, MoveFromSToA);
215 if (MoveFromSToA) {
216 // We are moving one of the copies earlier so its kill flag may become
217 // invalid. Clear the copied kill flag if there are any reads of the
218 // register between the new location and the old location.
219 for (auto It = std::next(x: I); It != Paired && PairedSource.isKill(); ++It)
220 if (It->readsRegister(Reg: PairedSource.getReg(), TRI))
221 PairedSource.setIsKill(false);
222
223 Sreg1 = FirstPair.Source;
224 Sreg2 = &PairedSource;
225 if (FirstPair.Destination->getReg() != RISCV::X10)
226 std::swap(a&: Sreg1, b&: Sreg2);
227 } else {
228 Sreg1 = FirstPair.Destination;
229 Sreg2 = PairedRegs.Destination;
230 if (FirstPair.Source->getReg() != RISCV::X10)
231 std::swap(a&: Sreg1, b&: Sreg2);
232 }
233
234 BuildMI(BB&: *I->getParent(), I, MIMD: DL, MCID: TII->get(Opcode)).add(MO: *Sreg1).add(MO: *Sreg2);
235
236 I->eraseFromParent();
237 Paired->eraseFromParent();
238 return NextI;
239}
240
241MachineBasicBlock::iterator
242RISCVMoveMerge::findMatchingInstPair(MachineBasicBlock::iterator &MBBI,
243 bool EvenRegPair,
244 const DestSourcePair &RegPair) {
245 MachineBasicBlock::iterator E = MBBI->getParent()->end();
246 ModifiedRegUnits.clear();
247 UsedRegUnits.clear();
248
249 for (MachineBasicBlock::iterator I = next_nodbg(It: MBBI, End: E); I != E;
250 I = next_nodbg(It: I, End: E)) {
251
252 MachineInstr &MI = *I;
253
254 if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
255 Register SourceReg = SecondPair->Source->getReg();
256 Register DestReg = SecondPair->Destination->getReg();
257
258 if (RegPair.Destination->getReg() == DestReg ||
259 RegPair.Source->getReg() == SourceReg)
260 return E;
261
262 unsigned RegPairIdx =
263 EvenRegPair ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
264 unsigned SecondPairIdx =
265 !EvenRegPair ? RISCV::sub_gpr_even : RISCV::sub_gpr_odd;
266
267 // Get the register GPRPair.
268 Register SrcGPRPair = TRI->getMatchingSuperReg(
269 Reg: RegPair.Source->getReg(), SubIdx: RegPairIdx, RC: &RISCV::GPRPairRegClass);
270
271 Register DestGPRPair = TRI->getMatchingSuperReg(
272 Reg: RegPair.Destination->getReg(), SubIdx: RegPairIdx, RC: &RISCV::GPRPairRegClass);
273
274 // Check if the second pair's registers match the other lane of the
275 // GPRPairs.
276 if (SourceReg != TRI->getSubReg(Reg: SrcGPRPair, Idx: SecondPairIdx) ||
277 DestReg != TRI->getSubReg(Reg: DestGPRPair, Idx: SecondPairIdx))
278 return E;
279
280 if (!ModifiedRegUnits.available(Reg: DestReg) ||
281 !UsedRegUnits.available(Reg: DestReg) ||
282 !ModifiedRegUnits.available(Reg: SourceReg))
283 return E;
284
285 return I;
286 }
287 // Update modified / used register units.
288 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
289 }
290 return E;
291}
292
293MachineBasicBlock::iterator
294RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
295 bool MoveFromSToA,
296 const DestSourcePair &RegPair) {
297 MachineBasicBlock::iterator E = MBBI->getParent()->end();
298
299 // Track which register units have been modified and used between the first
300 // insn and the second insn.
301 ModifiedRegUnits.clear();
302 UsedRegUnits.clear();
303
304 for (MachineBasicBlock::iterator I = next_nodbg(It: MBBI, End: E); I != E;
305 I = next_nodbg(It: I, End: E)) {
306
307 MachineInstr &MI = *I;
308
309 if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
310 Register SourceReg = SecondPair->Source->getReg();
311 Register DestReg = SecondPair->Destination->getReg();
312
313 bool IsCandidate = MoveFromSToA ? isCandidateToMergeMVA01S(RegPair: *SecondPair)
314 : isCandidateToMergeMVSA01(RegPair: *SecondPair);
315 if (IsCandidate) {
316 // Second destination must be different.
317 if (RegPair.Destination->getReg() == DestReg)
318 return E;
319
320 // For AtoS the source must also be different.
321 if (!MoveFromSToA && RegPair.Source->getReg() == SourceReg)
322 return E;
323
324 // If paired destination register was modified or used, the source reg
325 // was modified, there is no possibility of finding matching
326 // instruction so exit early.
327 if (!ModifiedRegUnits.available(Reg: DestReg) ||
328 !UsedRegUnits.available(Reg: DestReg) ||
329 !ModifiedRegUnits.available(Reg: SourceReg))
330 return E;
331
332 return I;
333 }
334 }
335 // Update modified / used register units.
336 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
337 }
338 return E;
339}
340
341// Finds instructions, which could be represented as C.MV instructions and
342// merged into CM.MVA01S or CM.MVSA01.
343bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
344 bool Modified = false;
345
346 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
347 MBBI != E;) {
348 // Check if the instruction can be compressed to C.MV instruction. If it
349 // can, return Dest/Src register pair.
350 auto RegPair = TII->isCopyInstrImpl(MI: *MBBI);
351 if (RegPair.has_value()) {
352 bool MoveFromSToA = isCandidateToMergeMVA01S(RegPair: *RegPair);
353 bool IsEven = isEvenRegisterCopy(RegPair: *RegPair);
354 bool IsOdd = isOddRegisterCopy(RegPair: *RegPair);
355 if (!MoveFromSToA && !isCandidateToMergeMVSA01(RegPair: *RegPair) && !IsEven &&
356 !IsOdd) {
357 ++MBBI;
358 continue;
359 }
360
361 MachineBasicBlock::iterator Paired = E;
362 if (ST->hasStdExtZcmp() || ST->hasVendorXqccmp()) {
363 Paired = findMatchingInst(MBBI, MoveFromSToA, RegPair: RegPair.value());
364 if (Paired != E) {
365 MBBI = mergePairedInsns(I: MBBI, Paired, MoveFromSToA);
366 Modified = true;
367 continue;
368 }
369 }
370 if (IsEven != IsOdd) {
371 Paired = findMatchingInstPair(MBBI, EvenRegPair: IsEven, RegPair: RegPair.value());
372 if (Paired != E) {
373 MBBI = mergeGPRPairInsns(I: MBBI, Paired, RegPairIsEven: IsEven);
374 Modified = true;
375 continue;
376 }
377 }
378 }
379 ++MBBI;
380 }
381 return Modified;
382}
383
384bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
385 if (skipFunction(F: Fn.getFunction()))
386 return false;
387
388 ST = &Fn.getSubtarget<RISCVSubtarget>();
389 bool HasGPRPairCopy =
390 !ST->is64Bit() && (ST->hasStdExtZdinx() || ST->hasStdExtP());
391 if (!ST->hasStdExtZcmp() && !ST->hasVendorXqccmp() && !HasGPRPairCopy)
392 return false;
393
394 TII = ST->getInstrInfo();
395 TRI = ST->getRegisterInfo();
396 // Resize the modified and used register unit trackers. We do this once
397 // per function and then clear the register units each time we optimize a
398 // move.
399 ModifiedRegUnits.init(TRI: *TRI);
400 UsedRegUnits.init(TRI: *TRI);
401 bool Modified = false;
402 for (auto &MBB : Fn)
403 Modified |= mergeMoveSARegPair(MBB);
404 return Modified;
405}
406
407/// createRISCVMoveMergePass - returns an instance of the
408/// move merge pass.
409FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }
410