xref: /llvm-project/llvm/lib/Target/Hexagon/HexagonTfrCleanup.cpp (revision 7e8bc5cf77bdda9e32b984b3fa91953361f24abb)
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/LiveIntervals.h"
32 #include "llvm/CodeGen/MachineFunction.h"
33 #include "llvm/CodeGen/MachineInstrBuilder.h"
34 #include "llvm/CodeGen/Passes.h"
35 #include "llvm/CodeGen/TargetInstrInfo.h"
36 #include "llvm/CodeGen/TargetRegisterInfo.h"
37 
38 using namespace llvm;
39 
40 namespace llvm {
41 FunctionPass *createHexagonTfrCleanup();
42 void initializeHexagonTfrCleanupPass(PassRegistry &);
43 } // namespace llvm
44 
45 namespace {
46 class HexagonTfrCleanup : public MachineFunctionPass {
47 public:
48   static char ID;
49   HexagonTfrCleanup() : MachineFunctionPass(ID), HII(0), TRI(0) {
50     PassRegistry &R = *PassRegistry::getPassRegistry();
51     initializeHexagonTfrCleanupPass(R);
52   }
53   StringRef getPassName() const override { return "Hexagon TFR Cleanup"; }
54   void getAnalysisUsage(AnalysisUsage &AU) const override {
55     AU.setPreservesAll();
56     MachineFunctionPass::getAnalysisUsage(AU);
57   }
58   bool runOnMachineFunction(MachineFunction &MF) override;
59 
60 private:
61   const HexagonInstrInfo *HII;
62   const TargetRegisterInfo *TRI;
63 
64   typedef DenseMap<unsigned, uint64_t> ImmediateMap;
65 
66   bool isIntReg(unsigned Reg, bool &Is32);
67   void setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap);
68   bool getReg(unsigned Reg, uint64_t &Val, ImmediateMap &IMap);
69   bool updateImmMap(MachineInstr *MI, ImmediateMap &IMap);
70   bool rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, SlotIndexes *Indexes);
71   bool eraseIfRedundant(MachineInstr *MI, SlotIndexes *Indexes);
72 };
73 } // namespace
74 
75 char HexagonTfrCleanup::ID = 0;
76 
77 namespace llvm {
78 char &HexagonTfrCleanupID = HexagonTfrCleanup::ID;
79 }
80 
81 bool HexagonTfrCleanup::isIntReg(unsigned Reg, bool &Is32) {
82   Is32 = Hexagon::IntRegsRegClass.contains(Reg);
83   return Is32 || Hexagon::DoubleRegsRegClass.contains(Reg);
84 }
85 
86 // Assign given value V32 to the specified the register R32 in the map. Only
87 // 32-bit registers are valid arguments.
88 void HexagonTfrCleanup::setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap) {
89   IMap[R32] = V32;
90 }
91 
92 // Retrieve a value of the provided register Reg and store it into Val.
93 // Return "true" if a value was found, "false" otherwise.
94 bool HexagonTfrCleanup::getReg(unsigned Reg, uint64_t &Val,
95                                ImmediateMap &IMap) {
96   bool Is32;
97   if (!isIntReg(Reg, Is32))
98     return false;
99 
100   if (Is32) {
101     ImmediateMap::iterator F = IMap.find(Reg);
102     if (F == IMap.end())
103       return false;
104     Val = F->second;
105     return true;
106   }
107 
108   // For 64-bit registers, compose the value from the values of its
109   // subregisters.
110   unsigned SubL = TRI->getSubReg(Reg, Hexagon::isub_lo);
111   unsigned SubH = TRI->getSubReg(Reg, Hexagon::isub_hi);
112   ImmediateMap::iterator FL = IMap.find(SubL), FH = IMap.find(SubH);
113   if (FL == IMap.end() || FH == IMap.end())
114     return false;
115   Val = (FH->second << 32) | FL->second;
116   return true;
117 }
118 
119 // Process an instruction and record the relevant information in the imme-
120 // diate map.
121 bool HexagonTfrCleanup::updateImmMap(MachineInstr *MI, ImmediateMap &IMap) {
122   using namespace Hexagon;
123 
124   if (MI->isCall()) {
125     IMap.clear();
126     return true;
127   }
128 
129   // If this is an instruction that loads a constant into a register,
130   // record this information in IMap.
131   unsigned Opc = MI->getOpcode();
132   if (Opc == A2_tfrsi || Opc == A2_tfrpi) {
133     unsigned DefR = MI->getOperand(0).getReg();
134     bool Is32;
135     if (!isIntReg(DefR, Is32))
136       return false;
137     if (!MI->getOperand(1).isImm()) {
138       if (!Is32) {
139         IMap.erase(TRI->getSubReg(DefR, isub_lo));
140         IMap.erase(TRI->getSubReg(DefR, isub_hi));
141       } else {
142         IMap.erase(DefR);
143       }
144       return false;
145     }
146     uint64_t Val = MI->getOperand(1).getImm();
147     // If it's a 64-bit register, break it up into subregisters.
148     if (!Is32) {
149       uint32_t VH = (Val >> 32), VL = (Val & 0xFFFFFFFFU);
150       setReg(TRI->getSubReg(DefR, isub_lo), VL, IMap);
151       setReg(TRI->getSubReg(DefR, isub_hi), VH, IMap);
152     } else {
153       setReg(DefR, Val, IMap);
154     }
155     return true;
156   }
157 
158   // Not a A2_tfr[sp]i. Invalidate all modified registers in IMap.
159   for (MachineInstr::mop_iterator Mo = MI->operands_begin(),
160                                   E = MI->operands_end();
161        Mo != E; ++Mo) {
162     if (Mo->isRegMask()) {
163       IMap.clear();
164       return true;
165     }
166     if (!Mo->isReg() || !Mo->isDef())
167       continue;
168     unsigned R = Mo->getReg();
169     for (MCRegAliasIterator AR(R, TRI, true); AR.isValid(); ++AR) {
170       ImmediateMap::iterator F = IMap.find(*AR);
171       if (F != IMap.end())
172         IMap.erase(F);
173     }
174   }
175   return true;
176 }
177 
178 // Rewrite the instruction as A2_tfrsi/A2_tfrpi, it is a copy of a source that
179 // has a known constant value.
180 bool HexagonTfrCleanup::rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap,
181                                      SlotIndexes *Indexes) {
182   using namespace Hexagon;
183   unsigned Opc = MI->getOpcode();
184   switch (Opc) {
185   case A2_tfr:
186   case A2_tfrp:
187   case COPY:
188     break;
189   default:
190     return false;
191   }
192 
193   unsigned DstR = MI->getOperand(0).getReg();
194   unsigned SrcR = MI->getOperand(1).getReg();
195   bool Tmp, Is32;
196   if (!isIntReg(DstR, Is32) || !isIntReg(SrcR, Tmp))
197     return false;
198   assert(Tmp == Is32 && "Register size mismatch");
199   uint64_t Val;
200   bool Found = getReg(SrcR, Val, IMap);
201   if (!Found)
202     return false;
203 
204   MachineBasicBlock &B = *MI->getParent();
205   DebugLoc DL = MI->getDebugLoc();
206   int64_t SVal = Is32 ? int32_t(Val) : Val;
207   auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>();
208   MachineInstr *NewMI;
209   if (Is32)
210     NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrsi), DstR).addImm(SVal);
211   else if (isInt<8>(SVal))
212     NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrpi), DstR).addImm(SVal);
213   else if (isInt<8>(SVal >> 32) && isInt<8>(int32_t(Val & 0xFFFFFFFFLL)))
214     NewMI = BuildMI(B, MI, DL, HII->get(A2_combineii), DstR)
215                 .addImm(int32_t(SVal >> 32))
216                 .addImm(int32_t(Val & 0xFFFFFFFFLL));
217   else if (HST.isTinyCore())
218     // Disable generating CONST64 since it requires load resource.
219     return false;
220   else
221     NewMI = BuildMI(B, MI, DL, HII->get(CONST64), DstR).addImm(Val);
222 
223   // Replace the MI to reuse the same slot index
224   if (Indexes)
225     Indexes->replaceMachineInstrInMaps(*MI, *NewMI);
226   MI->eraseFromParent();
227   return true;
228 }
229 
230 // Remove the instruction if it is a self-assignment.
231 bool HexagonTfrCleanup::eraseIfRedundant(MachineInstr *MI,
232                                          SlotIndexes *Indexes) {
233   unsigned Opc = MI->getOpcode();
234   unsigned DefR, SrcR;
235   bool IsUndef = false;
236   switch (Opc) {
237   case Hexagon::A2_tfr:
238     // Rd = Rd
239     DefR = MI->getOperand(0).getReg();
240     SrcR = MI->getOperand(1).getReg();
241     IsUndef = MI->getOperand(1).isUndef();
242     break;
243   case Hexagon::A2_tfrt:
244   case Hexagon::A2_tfrf:
245     // if ([!]Pu) Rd = Rd
246     DefR = MI->getOperand(0).getReg();
247     SrcR = MI->getOperand(2).getReg();
248     IsUndef = MI->getOperand(2).isUndef();
249     break;
250   default:
251     return false;
252   }
253   if (DefR != SrcR)
254     return false;
255   if (IsUndef) {
256     MachineBasicBlock &B = *MI->getParent();
257     DebugLoc DL = MI->getDebugLoc();
258     auto DefI = BuildMI(B, MI, DL, HII->get(TargetOpcode::IMPLICIT_DEF), DefR);
259     for (auto &Op : MI->operands())
260       if (Op.isReg() && Op.isDef() && Op.isImplicit())
261         DefI->addOperand(Op);
262   }
263 
264   if (Indexes)
265     Indexes->removeMachineInstrFromMaps(*MI);
266   MI->eraseFromParent();
267   return true;
268 }
269 
270 bool HexagonTfrCleanup::runOnMachineFunction(MachineFunction &MF) {
271   bool Changed = false;
272   // Map: 32-bit register -> immediate value.
273   // 64-bit registers are stored through their subregisters.
274   ImmediateMap IMap;
275   auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>();
276   SlotIndexes *Indexes = SIWrapper ? &SIWrapper->getSI() : nullptr;
277 
278   auto &HST = MF.getSubtarget<HexagonSubtarget>();
279   HII = HST.getInstrInfo();
280   TRI = HST.getRegisterInfo();
281 
282   for (MachineBasicBlock &B : MF) {
283     MachineBasicBlock::iterator J, F, NextJ;
284     IMap.clear();
285     bool Inserted = false, Erased = false;
286     for (J = B.begin(), F = B.end(); J != F; J = NextJ) {
287       NextJ = std::next(J);
288       MachineInstr *MI = &*J;
289       bool E = eraseIfRedundant(MI, Indexes);
290       Erased |= E;
291       if (E)
292         continue;
293       Inserted |= rewriteIfImm(MI, IMap, Indexes);
294       MachineBasicBlock::iterator NewJ = std::prev(NextJ);
295       updateImmMap(&*NewJ, IMap);
296     }
297     bool BlockC = Inserted | Erased;
298     Changed |= BlockC;
299     if (BlockC && Indexes)
300       Indexes->repairIndexesInRange(&B, B.begin(), B.end());
301   }
302 
303   return Changed;
304 }
305 
306 //===----------------------------------------------------------------------===//
307 //                         Public Constructor Functions
308 //===----------------------------------------------------------------------===//
309 INITIALIZE_PASS(HexagonTfrCleanup, "tfr-cleanup", "Hexagon TFR Cleanup", false,
310                 false)
311 
312 FunctionPass *llvm::createHexagonTfrCleanup() {
313   return new HexagonTfrCleanup();
314 }
315