LLVM 22.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 isCandidateToMergeMVA01S(const DestSourcePair &RegPair);
37 bool isCandidateToMergeMVSA01(const DestSourcePair &RegPair);
38 // Merge the two instructions indicated into a single pair instruction.
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.
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(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(Destination))
100 return true;
101 return false;
102}
103
105RISCVMoveMerge::mergePairedInsns(MachineBasicBlock::iterator I,
107 bool MoveFromSToA) {
108 const MachineOperand *Sreg1, *Sreg2;
109 MachineBasicBlock::iterator E = I->getParent()->end();
111 DestSourcePair FirstPair = TII->isCopyInstrImpl(*I).value();
112 DestSourcePair PairedRegs = TII->isCopyInstrImpl(*Paired).value();
113
114 if (NextI == Paired)
115 NextI = next_nodbg(NextI, 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(I); It != Paired && PairedSource.isKill(); ++It)
137 if (It->readsRegister(PairedSource.getReg(), TRI))
138 PairedSource.setIsKill(false);
139
140 Opcode = getMoveFromSToAOpcode(*ST);
141 Sreg1 = FirstPair.Source;
142 Sreg2 = &PairedSource;
143 if (FirstPair.Destination->getReg() != RISCV::X10)
144 std::swap(Sreg1, Sreg2);
145 } else {
146 Opcode = getMoveFromAToSOpcode(*ST);
147 Sreg1 = FirstPair.Destination;
148 Sreg2 = PairedRegs.Destination;
149 if (FirstPair.Source->getReg() != RISCV::X10)
150 std::swap(Sreg1, Sreg2);
151 }
152
153 BuildMI(*I->getParent(), I, DL, TII->get(Opcode)).add(*Sreg1).add(*Sreg2);
154
156 Paired->eraseFromParent();
157 return NextI;
158}
159
161RISCVMoveMerge::findMatchingInst(MachineBasicBlock::iterator &MBBI,
162 bool MoveFromSToA,
163 const DestSourcePair &RegPair) {
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
172 I = next_nodbg(I, 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(*SecondPair)
181 : isCandidateToMergeMVSA01(*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(DestReg) ||
195 !UsedRegUnits.available(DestReg) ||
196 !ModifiedRegUnits.available(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
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(*MBBI);
218 if (RegPair.has_value()) {
219 bool MoveFromSToA = isCandidateToMergeMVA01S(*RegPair);
220 if (!MoveFromSToA && !isCandidateToMergeMVSA01(*RegPair)) {
221 ++MBBI;
222 continue;
223 }
224
226 findMatchingInst(MBBI, MoveFromSToA, RegPair.value());
227 // If matching instruction can be found merge them.
228 if (Paired != E) {
229 MBBI = mergePairedInsns(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(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);
253 UsedRegUnits.init(*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(); }
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:58
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
#define RISCV_MOVE_MERGE_NAME
static unsigned getMoveFromAToSOpcode(const RISCVSubtarget &ST)
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:480
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 & 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
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.
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.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:853
const MachineOperand * Source
const MachineOperand * Destination