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"
29 #include "HexagonTargetMachine.h"
30
31 #include "llvm/CodeGen/LiveInterval.h"
32 #include "llvm/CodeGen/LiveIntervals.h"
33 #include "llvm/CodeGen/MachineFunction.h"
34 #include "llvm/CodeGen/MachineInstrBuilder.h"
35 #include "llvm/CodeGen/MachineRegisterInfo.h"
36 #include "llvm/CodeGen/Passes.h"
37 #include "llvm/CodeGen/TargetInstrInfo.h"
38 #include "llvm/CodeGen/TargetRegisterInfo.h"
39 #include "llvm/Support/CommandLine.h"
40 #include "llvm/Support/Debug.h"
41 #include "llvm/Support/raw_ostream.h"
42 #include "llvm/Target/TargetMachine.h"
43
44 using namespace llvm;
45
46 namespace llvm {
47 FunctionPass *createHexagonTfrCleanup();
48 void initializeHexagonTfrCleanupPass(PassRegistry &);
49 } // namespace llvm
50
51 namespace {
52 class HexagonTfrCleanup : public MachineFunctionPass {
53 public:
54 static char ID;
HexagonTfrCleanup()55 HexagonTfrCleanup() : MachineFunctionPass(ID), HII(0), TRI(0) {
56 PassRegistry &R = *PassRegistry::getPassRegistry();
57 initializeHexagonTfrCleanupPass(R);
58 }
getPassName() const59 StringRef getPassName() const override { return "Hexagon TFR Cleanup"; }
getAnalysisUsage(AnalysisUsage & AU) const60 void getAnalysisUsage(AnalysisUsage &AU) const override {
61 AU.setPreservesAll();
62 MachineFunctionPass::getAnalysisUsage(AU);
63 }
64 bool runOnMachineFunction(MachineFunction &MF) override;
65
66 private:
67 const HexagonInstrInfo *HII;
68 const TargetRegisterInfo *TRI;
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
81 char HexagonTfrCleanup::ID = 0;
82
83 namespace llvm {
84 char &HexagonTfrCleanupID = HexagonTfrCleanup::ID;
85 }
86
isIntReg(unsigned Reg,bool & Is32)87 bool 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.
setReg(unsigned R32,uint32_t V32,ImmediateMap & IMap)94 void 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.
getReg(unsigned Reg,uint64_t & Val,ImmediateMap & IMap)104 bool 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.
updateImmMap(MachineInstr * MI,ImmediateMap & IMap)131 bool 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.
rewriteIfImm(MachineInstr * MI,ImmediateMap & IMap,SlotIndexes * Indexes)190 bool 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.
eraseIfRedundant(MachineInstr * MI,SlotIndexes * Indexes)241 bool 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)
275 Indexes->removeMachineInstrFromMaps(*MI);
276 MI->eraseFromParent();
277 return true;
278 }
279
runOnMachineFunction(MachineFunction & MF)280 bool 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) {
293 MachineBasicBlock::iterator J, F, NextJ;
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 //===----------------------------------------------------------------------===//
319 INITIALIZE_PASS(HexagonTfrCleanup, "tfr-cleanup", "Hexagon TFR Cleanup", false,
320 false)
321
createHexagonTfrCleanup()322 FunctionPass *llvm::createHexagonTfrCleanup() {
323 return new HexagonTfrCleanup();
324 }
325