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