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 isCandidateToMergeMVA01S(const DestSourcePair &RegPair);
37 bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair);
38 // Merge the two instructions indicated into a single pair instruction.
39 MachineBasicBlock::iterator
40 mergePairedInsns(MachineBasicBlock::iterator I,
41 MachineBasicBlock::iterator Paired, bool MoveFromSToA);
42
43 // Look for C.MV instruction that can be combined with
44 // the given instruction into CM.MVA01S or CM.MVSA01. Return the matching
45 // instruction if one exists.
46 MachineBasicBlock::iterator
47 findMatchingInst(MachineBasicBlock::iterator &MBBI, bool MoveFromSToA,
48 const DestSourcePair &RegPair);
49 bool mergeMoveSARegPair(MachineBasicBlock &MBB);
50 bool runOnMachineFunction(MachineFunction &Fn) override;
51
52 StringRef getPassName() const override { return RISCV_MOVE_MERGE_NAME; }
53};
54
55char RISCVMoveMerge::ID = 0;
56
57} // end of anonymous namespace
58
59INITIALIZE_PASS(RISCVMoveMerge, "riscv-move-merge", RISCV_MOVE_MERGE_NAME,
60 false, false)
61
62static unsigned getMoveFromSToAOpcode(const RISCVSubtarget &ST) {
63 if (ST.hasStdExtZcmp())
64 return RISCV::CM_MVA01S;
65
66 if (ST.hasVendorXqccmp())
67 return RISCV::QC_CM_MVA01S;
68
69 llvm_unreachable("Unhandled subtarget with paired A to S move.");
70}
71
72static unsigned getMoveFromAToSOpcode(const RISCVSubtarget &ST) {
73 if (ST.hasStdExtZcmp())
74 return RISCV::CM_MVSA01;
75
76 if (ST.hasVendorXqccmp())
77 return RISCV::QC_CM_MVSA01;
78
79 llvm_unreachable("Unhandled subtarget with paired S to A move");
80}
81
82// Check if registers meet CM.MVA01S constraints.
83bool RISCVMoveMerge::isCandidateToMergeMVA01S(const DestSourcePair &RegPair) {
84 Register Destination = RegPair.Destination->getReg();
85 Register Source = RegPair.Source->getReg();
86 // If destination is not a0 or a1.
87 if ((Destination == RISCV::X10 || Destination == RISCV::X11) &&
88 RISCV::SR07RegClass.contains(Reg: Source))
89 return true;
90 return false;
91}
92
93// Check if registers meet CM.MVSA01 constraints.
94bool RISCVMoveMerge::isCandidateToMergeMVSA01(const DestSourcePair &RegPair) {
95 Register Destination = RegPair.Destination->getReg();
96 Register Source = RegPair.Source->getReg();
97 // If Source is s0 - s7.
98 if ((Source == RISCV::X10 || Source == RISCV::X11) &&
99 RISCV::SR07RegClass.contains(Reg: Destination))
100 return true;
101 return false;
102}
103
104MachineBasicBlock::iterator
105RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
106 MachineBasicBlock::iterator Paired,
107 bool MoveFromSToA) {
108 const MachineOperand *Sreg1, *Sreg2;
109 MachineBasicBlock::iterator E = I->getParent()->end();
110 MachineBasicBlock::iterator NextI = next_nodbg(It: I, End: E);
111 DestSourcePair FirstPair = TII->isCopyInstrImpl(MI: *I).value();
112 DestSourcePair PairedRegs = TII->isCopyInstrImpl(MI: *Paired).value();
113
114 if (NextI == Paired)
115 NextI = next_nodbg(It: NextI, End: E);
116 DebugLoc DL = I->getDebugLoc();
117
118 // Make a copy so we can update the kill flag in the MoveFromSToA case. The
119 // copied operand needs to be scoped outside the if since we make a pointer
120 // to it.
121 MachineOperand PairedSource = *PairedRegs.Source;
122
123 // The order of S-reg depends on which instruction holds A0, instead of
124 // the order of register pair.
125 // e,g.
126 // mv a1, s1
127 // mv a0, s2 => cm.mva01s s2,s1
128 //
129 // mv a0, s2
130 // mv a1, s1 => cm.mva01s s2,s1
131 unsigned Opcode;
132 if (MoveFromSToA) {
133 // We are moving one of the copies earlier so its kill flag may become
134 // invalid. Clear the copied kill flag if there are any reads of the
135 // register between the new location and the old location.
136 for (auto It = std::next(x: I); It != Paired && PairedSource.isKill(); ++It)
137 if (It->readsRegister(Reg: PairedSource.getReg(), TRI))
138 PairedSource.setIsKill(false);
139
140 Opcode = getMoveFromSToAOpcode(ST: *ST);
141 Sreg1 = FirstPair.Source;
142 Sreg2 = &PairedSource;
143 if (FirstPair.Destination->getReg() != RISCV::X10)
144 std::swap(a&: Sreg1, b&: Sreg2);
145 } else {
146 Opcode = getMoveFromAToSOpcode(ST: *ST);
147 Sreg1 = FirstPair.Destination;
148 Sreg2 = PairedRegs.Destination;
149 if (FirstPair.Source->getReg() != RISCV::X10)
150 std::swap(a&: Sreg1, b&: Sreg2);
151 }
152
153 BuildMI(BB&: *I->getParent(), I, MIMD: DL, MCID: TII->get(Opcode)).add(MO: *Sreg1).add(MO: *Sreg2);
154
155 I->eraseFromParent();
156 Paired->eraseFromParent();
157 return NextI;
158}
159
160MachineBasicBlock::iterator
161RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
162 bool MoveFromSToA,
163 const DestSourcePair &RegPair) {
164 MachineBasicBlock::iterator E = MBBI->getParent()->end();
165
166 // Track which register units have been modified and used between the first
167 // insn and the second insn.
168 ModifiedRegUnits.clear();
169 UsedRegUnits.clear();
170
171 for (MachineBasicBlock::iterator I = next_nodbg(It: MBBI, End: E); I != E;
172 I = next_nodbg(It: I, End: E)) {
173
174 MachineInstr &MI = *I;
175
176 if (auto SecondPair = TII->isCopyInstrImpl(MI)) {
177 Register SourceReg = SecondPair->Source->getReg();
178 Register DestReg = SecondPair->Destination->getReg();
179
180 bool IsCandidate = MoveFromSToA ? isCandidateToMergeMVA01S(RegPair: *SecondPair)
181 : isCandidateToMergeMVSA01(RegPair: *SecondPair);
182 if (IsCandidate) {
183 // Second destination must be different.
184 if (RegPair.Destination->getReg() == DestReg)
185 return E;
186
187 // For AtoS the source must also be different.
188 if (!MoveFromSToA && RegPair.Source->getReg() == SourceReg)
189 return E;
190
191 // If paired destination register was modified or used, the source reg
192 // was modified, there is no possibility of finding matching
193 // instruction so exit early.
194 if (!ModifiedRegUnits.available(Reg: DestReg) ||
195 !UsedRegUnits.available(Reg: DestReg) ||
196 !ModifiedRegUnits.available(Reg: SourceReg))
197 return E;
198
199 return I;
200 }
201 }
202 // Update modified / used register units.
203 LiveRegUnits::accumulateUsedDefed(MI, ModifiedRegUnits, UsedRegUnits, TRI);
204 }
205 return E;
206}
207
208// Finds instructions, which could be represented as C.MV instructions and
209// merged into CM.MVA01S or CM.MVSA01.
210bool RISCVMoveMerge::mergeMoveSARegPair(MachineBasicBlock &MBB) {
211 bool Modified = false;
212
213 for (MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
214 MBBI != E;) {
215 // Check if the instruction can be compressed to C.MV instruction. If it
216 // can, return Dest/Src register pair.
217 auto RegPair = TII->isCopyInstrImpl(MI: *MBBI);
218 if (RegPair.has_value()) {
219 bool MoveFromSToA = isCandidateToMergeMVA01S(RegPair: *RegPair);
220 if (!MoveFromSToA && !isCandidateToMergeMVSA01(RegPair: *RegPair)) {
221 ++MBBI;
222 continue;
223 }
224
225 MachineBasicBlock::iterator Paired =
226 findMatchingInst(MBBI, MoveFromSToA, RegPair: RegPair.value());
227 // If matching instruction can be found merge them.
228 if (Paired != E) {
229 MBBI = mergePairedInsns(I: MBBI, Paired, MoveFromSToA);
230 Modified = true;
231 continue;
232 }
233 }
234 ++MBBI;
235 }
236 return Modified;
237}
238
239bool RISCVMoveMerge::runOnMachineFunction(MachineFunction &Fn) {
240 if (skipFunction(F: Fn.getFunction()))
241 return false;
242
243 ST = &Fn.getSubtarget<RISCVSubtarget>();
244 if (!ST->hasStdExtZcmp() && !ST->hasVendorXqccmp())
245 return false;
246
247 TII = ST->getInstrInfo();
248 TRI = ST->getRegisterInfo();
249 // Resize the modified and used register unit trackers. We do this once
250 // per function and then clear the register units each time we optimize a
251 // move.
252 ModifiedRegUnits.init(TRI: *TRI);
253 UsedRegUnits.init(TRI: *TRI);
254 bool Modified = false;
255 for (auto &MBB : Fn)
256 Modified |= mergeMoveSARegPair(MBB);
257 return Modified;
258}
259
260/// createRISCVMoveMergePass - returns an instance of the
261/// move merge pass.
262FunctionPass *llvm::createRISCVMoveMergePass() { return new RISCVMoveMerge(); }
263