LLVM 20.0.0git
HexagonTfrCleanup.cpp
Go to the documentation of this file.
1//===------- HexagonTfrCleanup.cpp - Hexagon Transfer Cleanup 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// This pass is to address a situation that appears after register allocaion
9// evey now and then, namely a register copy from a source that was defined
10// as an immediate value in the same block (usually just before the copy).
11//
12// Here is an example of actual code emitted that shows this problem:
13//
14// .LBB0_5:
15// {
16// r5 = zxtb(r8)
17// r6 = or(r6, ##12345)
18// }
19// {
20// r3 = xor(r1, r2)
21// r1 = #0 <-- r1 set to #0
22// }
23// {
24// r7 = r1 <-- r7 set to r1
25// r0 = zxtb(r3)
26// }
27
28#define DEBUG_TYPE "tfr-cleanup"
30
36#include "llvm/CodeGen/Passes.h"
40#include "llvm/Support/Debug.h"
43
44using namespace llvm;
45
46namespace llvm {
49} // namespace llvm
50
51namespace {
52class HexagonTfrCleanup : public MachineFunctionPass {
53public:
54 static char ID;
55 HexagonTfrCleanup() : MachineFunctionPass(ID), HII(0), TRI(0) {
58 }
59 StringRef getPassName() const override { return "Hexagon TFR Cleanup"; }
60 void getAnalysisUsage(AnalysisUsage &AU) const override {
61 AU.setPreservesAll();
63 }
64 bool runOnMachineFunction(MachineFunction &MF) override;
65
66private:
67 const HexagonInstrInfo *HII;
69
70 typedef DenseMap<unsigned, uint64_t> ImmediateMap;
71
72 bool isIntReg(unsigned Reg, bool &Is32);
73 void setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap);
74 bool getReg(unsigned Reg, uint64_t &Val, ImmediateMap &IMap);
75 bool updateImmMap(MachineInstr *MI, ImmediateMap &IMap);
76 bool rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, SlotIndexes *Indexes);
77 bool eraseIfRedundant(MachineInstr *MI, SlotIndexes *Indexes);
78};
79} // namespace
80
81char HexagonTfrCleanup::ID = 0;
82
83namespace llvm {
84char &HexagonTfrCleanupID = HexagonTfrCleanup::ID;
85}
86
87bool HexagonTfrCleanup::isIntReg(unsigned Reg, bool &Is32) {
88 Is32 = Hexagon::IntRegsRegClass.contains(Reg);
89 return Is32 || Hexagon::DoubleRegsRegClass.contains(Reg);
90}
91
92// Assign given value V32 to the specified the register R32 in the map. Only
93// 32-bit registers are valid arguments.
94void HexagonTfrCleanup::setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap) {
95 ImmediateMap::iterator F = IMap.find(R32);
96 if (F == IMap.end())
97 IMap.insert(std::make_pair(R32, V32));
98 else
99 F->second = V32;
100}
101
102// Retrieve a value of the provided register Reg and store it into Val.
103// Return "true" if a value was found, "false" otherwise.
104bool HexagonTfrCleanup::getReg(unsigned Reg, uint64_t &Val,
105 ImmediateMap &IMap) {
106 bool Is32;
107 if (!isIntReg(Reg, Is32))
108 return false;
109
110 if (Is32) {
111 ImmediateMap::iterator F = IMap.find(Reg);
112 if (F == IMap.end())
113 return false;
114 Val = F->second;
115 return true;
116 }
117
118 // For 64-bit registers, compose the value from the values of its
119 // subregisters.
120 unsigned SubL = TRI->getSubReg(Reg, Hexagon::isub_lo);
121 unsigned SubH = TRI->getSubReg(Reg, Hexagon::isub_hi);
122 ImmediateMap::iterator FL = IMap.find(SubL), FH = IMap.find(SubH);
123 if (FL == IMap.end() || FH == IMap.end())
124 return false;
125 Val = (FH->second << 32) | FL->second;
126 return true;
127}
128
129// Process an instruction and record the relevant information in the imme-
130// diate map.
131bool HexagonTfrCleanup::updateImmMap(MachineInstr *MI, ImmediateMap &IMap) {
132 using namespace Hexagon;
133
134 if (MI->isCall()) {
135 IMap.clear();
136 return true;
137 }
138
139 // If this is an instruction that loads a constant into a register,
140 // record this information in IMap.
141 unsigned Opc = MI->getOpcode();
142 if (Opc == A2_tfrsi || Opc == A2_tfrpi) {
143 unsigned DefR = MI->getOperand(0).getReg();
144 bool Is32;
145 if (!isIntReg(DefR, Is32))
146 return false;
147 if (!MI->getOperand(1).isImm()) {
148 if (!Is32) {
149 IMap.erase(TRI->getSubReg(DefR, isub_lo));
150 IMap.erase(TRI->getSubReg(DefR, isub_hi));
151 } else {
152 IMap.erase(DefR);
153 }
154 return false;
155 }
156 uint64_t Val = MI->getOperand(1).getImm();
157 // If it's a 64-bit register, break it up into subregisters.
158 if (!Is32) {
159 uint32_t VH = (Val >> 32), VL = (Val & 0xFFFFFFFFU);
160 setReg(TRI->getSubReg(DefR, isub_lo), VL, IMap);
161 setReg(TRI->getSubReg(DefR, isub_hi), VH, IMap);
162 } else {
163 setReg(DefR, Val, IMap);
164 }
165 return true;
166 }
167
168 // Not a A2_tfr[sp]i. Invalidate all modified registers in IMap.
169 for (MachineInstr::mop_iterator Mo = MI->operands_begin(),
170 E = MI->operands_end();
171 Mo != E; ++Mo) {
172 if (Mo->isRegMask()) {
173 IMap.clear();
174 return true;
175 }
176 if (!Mo->isReg() || !Mo->isDef())
177 continue;
178 unsigned R = Mo->getReg();
179 for (MCRegAliasIterator AR(R, TRI, true); AR.isValid(); ++AR) {
180 ImmediateMap::iterator F = IMap.find(*AR);
181 if (F != IMap.end())
182 IMap.erase(F);
183 }
184 }
185 return true;
186}
187
188// Rewrite the instruction as A2_tfrsi/A2_tfrpi, it is a copy of a source that
189// has a known constant value.
190bool HexagonTfrCleanup::rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap,
191 SlotIndexes *Indexes) {
192 using namespace Hexagon;
193 unsigned Opc = MI->getOpcode();
194 switch (Opc) {
195 case A2_tfr:
196 case A2_tfrp:
197 case COPY:
198 break;
199 default:
200 return false;
201 }
202
203 unsigned DstR = MI->getOperand(0).getReg();
204 unsigned SrcR = MI->getOperand(1).getReg();
205 bool Tmp, Is32;
206 if (!isIntReg(DstR, Is32) || !isIntReg(SrcR, Tmp))
207 return false;
208 assert(Tmp == Is32 && "Register size mismatch");
209 uint64_t Val;
210 bool Found = getReg(SrcR, Val, IMap);
211 if (!Found)
212 return false;
213
214 MachineBasicBlock &B = *MI->getParent();
215 DebugLoc DL = MI->getDebugLoc();
216 int64_t SVal = Is32 ? int32_t(Val) : Val;
217 auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>();
218 MachineInstr *NewMI;
219 if (Is32)
220 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrsi), DstR).addImm(SVal);
221 else if (isInt<8>(SVal))
222 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrpi), DstR).addImm(SVal);
223 else if (isInt<8>(SVal >> 32) && isInt<8>(int32_t(Val & 0xFFFFFFFFLL)))
224 NewMI = BuildMI(B, MI, DL, HII->get(A2_combineii), DstR)
225 .addImm(int32_t(SVal >> 32))
226 .addImm(int32_t(Val & 0xFFFFFFFFLL));
227 else if (HST.isTinyCore())
228 // Disable generating CONST64 since it requires load resource.
229 return false;
230 else
231 NewMI = BuildMI(B, MI, DL, HII->get(CONST64), DstR).addImm(Val);
232
233 // Replace the MI to reuse the same slot index
234 if (Indexes)
235 Indexes->replaceMachineInstrInMaps(*MI, *NewMI);
236 MI->eraseFromParent();
237 return true;
238}
239
240// Remove the instruction if it is a self-assignment.
241bool HexagonTfrCleanup::eraseIfRedundant(MachineInstr *MI,
242 SlotIndexes *Indexes) {
243 unsigned Opc = MI->getOpcode();
244 unsigned DefR, SrcR;
245 bool IsUndef = false;
246 switch (Opc) {
247 case Hexagon::A2_tfr:
248 // Rd = Rd
249 DefR = MI->getOperand(0).getReg();
250 SrcR = MI->getOperand(1).getReg();
251 IsUndef = MI->getOperand(1).isUndef();
252 break;
253 case Hexagon::A2_tfrt:
254 case Hexagon::A2_tfrf:
255 // if ([!]Pu) Rd = Rd
256 DefR = MI->getOperand(0).getReg();
257 SrcR = MI->getOperand(2).getReg();
258 IsUndef = MI->getOperand(2).isUndef();
259 break;
260 default:
261 return false;
262 }
263 if (DefR != SrcR)
264 return false;
265 if (IsUndef) {
266 MachineBasicBlock &B = *MI->getParent();
267 DebugLoc DL = MI->getDebugLoc();
268 auto DefI = BuildMI(B, MI, DL, HII->get(TargetOpcode::IMPLICIT_DEF), DefR);
269 for (auto &Op : MI->operands())
270 if (Op.isReg() && Op.isDef() && Op.isImplicit())
271 DefI->addOperand(Op);
272 }
273
274 if (Indexes)
276 MI->eraseFromParent();
277 return true;
278}
279
280bool HexagonTfrCleanup::runOnMachineFunction(MachineFunction &MF) {
281 bool Changed = false;
282 // Map: 32-bit register -> immediate value.
283 // 64-bit registers are stored through their subregisters.
284 ImmediateMap IMap;
285 auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>();
286 SlotIndexes *Indexes = SIWrapper ? &SIWrapper->getSI() : nullptr;
287
288 auto &HST = MF.getSubtarget<HexagonSubtarget>();
289 HII = HST.getInstrInfo();
290 TRI = HST.getRegisterInfo();
291
292 for (MachineBasicBlock &B : MF) {
294 IMap.clear();
295 bool Inserted = false, Erased = false;
296 for (J = B.begin(), F = B.end(); J != F; J = NextJ) {
297 NextJ = std::next(J);
298 MachineInstr *MI = &*J;
299 bool E = eraseIfRedundant(MI, Indexes);
300 Erased |= E;
301 if (E)
302 continue;
303 Inserted |= rewriteIfImm(MI, IMap, Indexes);
304 MachineBasicBlock::iterator NewJ = std::prev(NextJ);
305 updateImmMap(&*NewJ, IMap);
306 }
307 bool BlockC = Inserted | Erased;
308 Changed |= BlockC;
309 if (BlockC && Indexes)
310 Indexes->repairIndexesInRange(&B, B.begin(), B.end());
311 }
312
313 return Changed;
314}
315
316//===----------------------------------------------------------------------===//
317// Public Constructor Functions
318//===----------------------------------------------------------------------===//
319INITIALIZE_PASS(HexagonTfrCleanup, "tfr-cleanup", "Hexagon TFR Cleanup", false,
320 false)
321
323 return new HexagonTfrCleanup();
324}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
unsigned const TargetRegisterInfo * TRI
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Represent the analysis usage information of a pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
This class represents an Operation in the Expression.
A debug info location.
Definition: DebugLoc.h:33
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
const HexagonInstrInfo * getInstrInfo() const override
MCRegAliasIterator enumerates all registers aliasing Reg.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
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.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Representation of each machine instruction.
Definition: MachineInstr.h:69
MachineOperand class - Representation of each machine instruction operand.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
Definition: PassRegistry.h:37
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
SlotIndexes pass.
Definition: SlotIndexes.h:297
void removeMachineInstrFromMaps(MachineInstr &MI, bool AllowBundled=false)
Removes machine instruction (bundle) MI from the mapping.
void repairIndexesInRange(MachineBasicBlock *MBB, MachineBasicBlock::iterator Begin, MachineBasicBlock::iterator End)
Repair indexes after adding and removing instructions.
SlotIndex replaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI)
ReplaceMachineInstrInMaps - Replacing a machine instr with a new one in maps used by register allocat...
Definition: SlotIndexes.h:588
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
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
char & HexagonTfrCleanupID
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
void initializeHexagonTfrCleanupPass(PassRegistry &)
FunctionPass * createHexagonTfrCleanup()