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 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.
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::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(Source, RISCV::sub_gpr_even,
101 &RISCV::GPRPairRegClass);
102 Register DestPair = TRI->getMatchingSuperReg(Destination, RISCV::sub_gpr_even,
103 &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(Source, RISCV::sub_gpr_odd,
118 &RISCV::GPRPairRegClass);
119 Register DestPair = TRI->getMatchingSuperReg(Destination, RISCV::sub_gpr_odd,
120 &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(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(Destination))
145 return true;
146 return false;
147}
148
150RISCVMoveMerge::mergeGPRPairInsns(MachineBasicBlock::iterator I,
152 bool RegPairIsEven) {
153 MachineBasicBlock::iterator E = I->getParent()->end();
155 DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
156 DestSourcePair SecondPair = TII->isCopyInstrImpl(*Paired).value();
157
158 if (NextI == Paired)
159 NextI = next_nodbg(NextI, 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);
167 for (auto It = std::next(I); It != Paired && PairedSource.isKill(); ++It)
168 if (It->readsRegister(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(FirstPair.Source->getReg(), GPRPairIdx,
175 &RISCV::GPRPairRegClass);
176 SrcReg2 = ST->hasStdExtZdinx() ? SrcReg1 : Register(RISCV::X0_Pair);
177 DestReg = TRI->getMatchingSuperReg(FirstPair.Destination->getReg(),
178 GPRPairIdx, &RISCV::GPRPairRegClass);
179
180 BuildMI(*I->getParent(), I, DL, TII->get(Opcode), DestReg)
181 .addReg(SrcReg1, getKillRegState(PairedSource.isKill() &&
182 FirstPair.Source->isKill()))
183 .addReg(SrcReg2, getKillRegState(PairedSource.isKill() &&
184 FirstPair.Source->isKill()));
185
187 Paired->eraseFromParent();
188 return NextI;
189}
190
192RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
194 bool MoveFromSToA) {
195 const MachineOperand *Sreg1, *Sreg2;
196 MachineBasicBlock::iterator E = I->getParent()->end();
198 DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
199 DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
200
201 if (NextI == Paired)
202 NextI = next_nodbg(NextI, 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, 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(I); It != Paired && PairedSource.isKill(); ++It)
224 if (It->readsRegister(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(Sreg1, Sreg2);
231 } else {
232 Sreg1 = FirstPair.Destination;
233 Sreg2 = PairedRegs.Destination;
234 if (FirstPair.Source->getReg() != RISCV::X10)
235 std::swap(Sreg1, Sreg2);
236 }
237
238 BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
239
241 Paired->eraseFromParent();
242 return NextI;
243}
244
246RISCVMoveMerge::findMatchingInstPair(MachineBasicBlock::iterator &MBBI,
247 bool EvenRegPair,
248 const DestSourcePair &RegPair) {
250 ModifiedRegUnits.clear();
251 UsedRegUnits.clear();
252
254 I = next_nodbg(I, 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 RegPair.Source->getReg(), RegPairIdx, &RISCV::GPRPairRegClass);
274
275 Register DestGPRPair = TRI->getMatchingSuperReg(
276 RegPair.Destination->getReg(), RegPairIdx, &RISCV::GPRPairRegClass);
277
278 // Check if the second pair's registers match the other lane of the
279 // GPRPairs.
280 if (SourceReg != TRI->getSubReg(SrcGPRPair, SecondPairIdx) ||
281 DestReg != TRI->getSubReg(DestGPRPair, SecondPairIdx))
282 return E;
283
284 if (!ModifiedRegUnits.available(DestReg) ||
285 !UsedRegUnits.available(DestReg) ||
286 !ModifiedRegUnits.available(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
298RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
299 bool MoveFromSToA,
300 const DestSourcePair &RegPair) {
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
309 I = next_nodbg(I, 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(*SecondPair)
318 : isCandidateToMergeMVSA01(*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(DestReg) ||
332 !UsedRegUnits.available(DestReg) ||
333 !ModifiedRegUnits.available(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
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(*MBBI);
355 if (RegPair.has_value()) {
356 bool MoveFromSToA = isCandidateToMergeMVA01S(*RegPair);
357 bool IsEven = isGPRPairCopyCandidateEven(*RegPair);
358 bool IsOdd = isGPRPairCopyCandidateOdd(*RegPair);
359 if (!MoveFromSToA && !isCandidateToMergeMVSA01(*RegPair) && !IsEven &&
360 !IsOdd) {
361 ++MBBI;
362 continue;
363 }
364
366 if (ST->hasStdExtZcmp() || ST->hasVendorXqccmp()) {
367 Paired = findMatchingInst(MBBI, MoveFromSToA, RegPair.value());
368 if (Paired != E) {
369 MBBI = mergePairedInsns(MBBI, Paired, MoveFromSToA);
370 Modified = true;
371 continue;
372 }
373 }
374 if (IsEven != IsOdd) {
375 Paired = findMatchingInstPair(MBBI, IsEven, RegPair.value());
376 if (Paired != E) {
377 MBBI = mergeGPRPairInsns(MBBI, Paired, 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(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);
404 UsedRegUnits.init(*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(); }
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 MachineInstrBundleIterator< MachineInstr > 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