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