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
155 I->eraseFromParent();
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
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
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
Register const TargetRegisterInfo * TRI
#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
A debug info location.
Definition: DebugLoc.h:124
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.
Definition: LiveRegUnits.h:31
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...
Definition: LiveRegUnits.h:48
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
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
Representation of each machine instruction.
Definition: MachineInstr.h:72
MachineOperand class - Representation of each machine instruction operand.
void setIsKill(bool Val=true)
Register getReg() const
getReg - Returns the register number.
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:85
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
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: AddressRanges.h:18
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:858
const MachineOperand * Source
const MachineOperand * Destination