xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonTfrCleanup.cpp (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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;
55   HexagonTfrCleanup() : MachineFunctionPass(ID), HII(0), TRI(0) {
56     PassRegistry &R = *PassRegistry::getPassRegistry();
57     initializeHexagonTfrCleanupPass(R);
58   }
59   StringRef getPassName() const override { return "Hexagon TFR Cleanup"; }
60   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 
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.
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.
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.
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.
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.
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 
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 
322 FunctionPass *llvm::createHexagonTfrCleanup() {
323   return new HexagonTfrCleanup();
324 }
325