LLVM 23.0.0git
RISCVMoveMerger.cpp
Go to the documentation of this file.
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;
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.
43 mergeGPRPairInsns(MachineBasicBlock::iterator I,
44 MachineBasicBlock::iterator Paired, bool RegPairIsEven);
46 mergePairedInsns(MachineBasicBlock::iterator I,
47 MachineBasicBlock::iterator Paired, bool MoveFromSToA);
48
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.
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(Source, RISCV::sub_gpr_even,
99 &RISCV::GPRPairRegClass);
100 Register DestPair = TRI->getMatchingSuperReg(Destination, RISCV::sub_gpr_even,
101 &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(Source, RISCV::sub_gpr_odd,
114 &RISCV::GPRPairRegClass);
115 Register DestPair = TRI->getMatchingSuperReg(Destination, RISCV::sub_gpr_odd,
116 &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(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(Destination))
141 return true;
142 return false;
143}
144
146RISCVMoveMerge::mergeGPRPairInsns(MachineBasicBlock::iterator I,
148 bool RegPairIsEven) {
149 MachineBasicBlock::iterator E = I->getParent()->end();
151 DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
152 DestSourcePair SecondPair = TII->isCopyInstrImpl(*Paired).value();
153
154 if (NextI == Paired)
155 NextI = next_nodbg(NextI, 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);
163 for (auto It = std::next(I); It != Paired && PairedSource.isKill(); ++It)
164 if (It->readsRegister(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(FirstPair.Source->getReg(), GPRPairIdx,
171 &RISCV::GPRPairRegClass);
172 SrcReg2 = ST->hasStdExtZdinx() ? SrcReg1 : Register(RISCV::X0_Pair);
173 DestReg = TRI->getMatchingSuperReg(FirstPair.Destination->getReg(),
174 GPRPairIdx, &RISCV::GPRPairRegClass);
175
176 BuildMI(*I->getParent(), I, DL, TII->get(Opcode), DestReg)
177 .addReg(SrcReg1, getKillRegState(PairedSource.isKill() &&
178 FirstPair.Source->isKill()))
179 .addReg(SrcReg2, getKillRegState(PairedSource.isKill() &&
180 FirstPair.Source->isKill()));
181
183 Paired->eraseFromParent();
184 return NextI;
185}
186
188RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
190 bool MoveFromSToA) {
191 const MachineOperand *Sreg1, *Sreg2;
192 MachineBasicBlock::iterator E = I->getParent()->end();
194 DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
195 DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
196
197 if (NextI == Paired)
198 NextI = next_nodbg(NextI, 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, 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(I); It != Paired && PairedSource.isKill(); ++It)
220 if (It->readsRegister(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(Sreg1, Sreg2);
227 } else {
228 Sreg1 = FirstPair.Destination;
229 Sreg2 = PairedRegs.Destination;
230 if (FirstPair.Source->getReg() != RISCV::X10)
231 std::swap(Sreg1, Sreg2);
232 }
233
234 BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
235
237 Paired->eraseFromParent();
238 return NextI;
239}
240
242RISCVMoveMerge::findMatchingInstPair(MachineBasicBlock::iterator &MBBI,
243 bool EvenRegPair,
244 const DestSourcePair &RegPair) {
246 ModifiedRegUnits.clear();
247 UsedRegUnits.clear();
248
250 I = next_nodbg(I, 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 RegPair.Source->getReg(), RegPairIdx, &RISCV::GPRPairRegClass);
270
271 Register DestGPRPair = TRI->getMatchingSuperReg(
272 RegPair.Destination->getReg(), RegPairIdx, &RISCV::GPRPairRegClass);
273
274 // Check if the second pair's registers match the other lane of the
275 // GPRPairs.
276 if (SourceReg != TRI->getSubReg(SrcGPRPair, SecondPairIdx) ||
277 DestReg != TRI->getSubReg(DestGPRPair, SecondPairIdx))
278 return E;
279
280 if (!ModifiedRegUnits.available(DestReg) ||
281 !UsedRegUnits.available(DestReg) ||
282 !ModifiedRegUnits.available(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
294RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
295 bool MoveFromSToA,
296 const DestSourcePair &RegPair) {
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
305 I = next_nodbg(I, 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(*SecondPair)
314 : isCandidateToMergeMVSA01(*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(DestReg) ||
328 !UsedRegUnits.available(DestReg) ||
329 !ModifiedRegUnits.available(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
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(*MBBI);
351 if (RegPair.has_value()) {
352 bool MoveFromSToA = isCandidateToMergeMVA01S(*RegPair);
353 bool IsEven = isEvenRegisterCopy(*RegPair);
354 bool IsOdd = isOddRegisterCopy(*RegPair);
355 if (!MoveFromSToA && !isCandidateToMergeMVSA01(*RegPair) && !IsEven &&
356 !IsOdd) {
357 ++MBBI;
358 continue;
359 }
360
362 if (ST->hasStdExtZcmp() || ST->hasVendorXqccmp()) {
363 Paired = findMatchingInst(MBBI, MoveFromSToA, RegPair.value());
364 if (Paired != E) {
365 MBBI = mergePairedInsns(MBBI, Paired, MoveFromSToA);
366 Modified = true;
367 continue;
368 }
369 }
370 if (IsEven != IsOdd) {
371 Paired = findMatchingInstPair(MBBI, IsEven, RegPair.value());
372 if (Paired != E) {
373 MBBI = mergeGPRPairInsns(MBBI, Paired, 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(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);
400 UsedRegUnits.init(*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(); }
aarch64 promote const
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
MachineBasicBlock MachineBasicBlock::iterator MBBI
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
if(PassOpts->AAPipeline)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static unsigned getCM_MVOpcode(const RISCVSubtarget &ST, bool MoveFromSToA)
#define RISCV_MOVE_MERGE_NAME
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
A set of register units used to track register liveness.
static void accumulateUsedDefed(const MachineInstr &MI, LiveRegUnits &ModifiedRegUnits, LiveRegUnits &UsedRegUnits, const TargetRegisterInfo *TRI)
For a machine instruction MI, adds all register units used in UsedRegUnits and defined or clobbered i...
bool available(MCRegister Reg) const
Returns true if no part of physical register Reg is live.
void init(const TargetRegisterInfo &TRI)
Initialize and clear the set.
void clear()
Clears the set.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineInstrBundleIterator< MachineInstr > iterator
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
const RISCVRegisterInfo * getRegisterInfo() const override
const RISCVInstrInfo * getInstrInfo() const override
constexpr bool isValid() const
Definition Register.h:112
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
FunctionPass * createRISCVMoveMergePass()
createRISCVMoveMergePass - returns an instance of the move merge pass.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:872
const MachineOperand * Source
const MachineOperand * Destination