xref: /llvm-project/llvm/lib/Target/Hexagon/HexagonGenMemAbsolute.cpp (revision 7e8bc5cf77bdda9e32b984b3fa91953361f24abb)
1 //===--- HexagonGenMemAbsolute.cpp - Generate Load/Store Set Absolute ---===//
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 pass traverses through all the basic blocks in a function and converts
10 // an indexed load/store with offset "0" to a absolute-set load/store
11 // instruction as long as the use of the register in the new instruction
12 // dominates the rest of the uses and there are more than 2 uses.
13 
14 #include "HexagonTargetMachine.h"
15 #include "llvm/ADT/Statistic.h"
16 #include "llvm/CodeGen/MachineDominators.h"
17 #include "llvm/CodeGen/MachineFunctionPass.h"
18 #include "llvm/CodeGen/MachineInstrBuilder.h"
19 #include "llvm/CodeGen/MachineRegisterInfo.h"
20 #include "llvm/CodeGen/Passes.h"
21 #include "llvm/CodeGen/TargetInstrInfo.h"
22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 #define DEBUG_TYPE "hexagon-abs"
26 
27 using namespace llvm;
28 
29 STATISTIC(HexagonNumLoadAbsConversions,
30           "Number of Load instructions converted to absolute-set form");
31 STATISTIC(HexagonNumStoreAbsConversions,
32           "Number of Store instructions converted to absolute-set form");
33 
34 namespace llvm {
35 FunctionPass *createHexagonGenMemAbsolute();
36 void initializeHexagonGenMemAbsolutePass(PassRegistry &Registry);
37 } // namespace llvm
38 
39 namespace {
40 
41 class HexagonGenMemAbsolute : public MachineFunctionPass {
42   const HexagonInstrInfo *TII;
43   MachineRegisterInfo *MRI;
44   const TargetRegisterInfo *TRI;
45 
46 public:
47   static char ID;
48   HexagonGenMemAbsolute() : MachineFunctionPass(ID), TII(0), MRI(0), TRI(0) {
49     initializeHexagonGenMemAbsolutePass(*PassRegistry::getPassRegistry());
50   }
51 
52   StringRef getPassName() const override {
53     return "Hexagon Generate Load/Store Set Absolute Address Instruction";
54   }
55 
56   void getAnalysisUsage(AnalysisUsage &AU) const override {
57     MachineFunctionPass::getAnalysisUsage(AU);
58     AU.addRequired<MachineDominatorTreeWrapperPass>();
59     AU.addPreserved<MachineDominatorTreeWrapperPass>();
60   }
61 
62   bool runOnMachineFunction(MachineFunction &Fn) override;
63 
64 private:
65   static bool isValidIndexedLoad(int &Opcode, int &NewOpcode);
66   static bool isValidIndexedStore(int &Opcode, int &NewOpcode);
67 };
68 } // namespace
69 
70 char HexagonGenMemAbsolute::ID = 0;
71 
72 INITIALIZE_PASS(HexagonGenMemAbsolute, "hexagon-gen-load-absolute",
73                 "Hexagon Generate Load/Store Set Absolute Address Instruction",
74                 false, false)
75 
76 bool HexagonGenMemAbsolute::runOnMachineFunction(MachineFunction &Fn) {
77   if (skipFunction(Fn.getFunction()))
78     return false;
79 
80   TII = Fn.getSubtarget<HexagonSubtarget>().getInstrInfo();
81   MRI = &Fn.getRegInfo();
82   TRI = Fn.getRegInfo().getTargetRegisterInfo();
83 
84   MachineDominatorTree &MDT =
85       getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
86 
87   // Loop over all of the basic blocks
88   for (MachineBasicBlock &MBB : Fn) {
89     // Traverse the basic block
90     for (MachineBasicBlock::iterator MII = MBB.begin(); MII != MBB.end();
91          ++MII) {
92       MachineInstr *MI = &*MII;
93       int Opc = MI->getOpcode();
94       if (Opc != Hexagon::CONST32 && Opc != Hexagon::A2_tfrsi)
95         continue;
96 
97       const MachineOperand &MO = MI->getOperand(0);
98       if (!MO.isReg() || !MO.isDef())
99         continue;
100 
101       unsigned DstReg = MO.getReg();
102       if (MRI->use_nodbg_empty(DstReg))
103         continue;
104 
105       typedef MachineRegisterInfo::use_nodbg_iterator use_iterator;
106       use_iterator NextUseMI = MRI->use_nodbg_begin(DstReg);
107 
108       MachineInstr *NextMI = NextUseMI->getParent();
109       int NextOpc = NextMI->getOpcode();
110       int NewOpc;
111       bool IsLoad = isValidIndexedLoad(NextOpc, NewOpc);
112 
113       if (!IsLoad && !isValidIndexedStore(NextOpc, NewOpc))
114         continue;
115 
116       // Base and Offset positions for load and store instructions
117       // Load R(dest), R(base), Imm -> R(dest) = mem(R(base) + Imm)
118       // Store R(base), Imm, R (src) -> mem(R(base) + Imm) = R(src)
119       unsigned BaseRegPos, ImmPos, RegPos;
120       if (!TII->getBaseAndOffsetPosition(*NextMI, BaseRegPos, ImmPos))
121         continue;
122       RegPos = IsLoad ? 0 : 2;
123 
124       bool IsGlobal = MI->getOperand(1).isGlobal();
125       if (!MI->getOperand(1).isImm() && !IsGlobal)
126         continue;
127 
128       const MachineOperand *BaseOp = nullptr;
129       int64_t Offset;
130       bool Scalable;
131       TII->getMemOperandWithOffset(*NextMI, BaseOp, Offset, Scalable, TRI);
132 
133       // Ensure BaseOp is non-null and register type.
134       if (!BaseOp || !BaseOp->isReg())
135         continue;
136 
137       if (Scalable)
138         continue;
139 
140       unsigned BaseReg = BaseOp->getReg();
141       if ((DstReg != BaseReg) || (Offset != 0))
142         continue;
143 
144       const MachineOperand &MO0 = NextMI->getOperand(RegPos);
145 
146       if (!MO0.isReg())
147         continue;
148 
149       unsigned LoadStoreReg = MO0.getReg();
150 
151       // Store: Bail out if the src and base are same (def and use on same
152       // register).
153       if (LoadStoreReg == BaseReg)
154         continue;
155 
156       // Insert the absolute-set instruction "I" only if the use of the
157       // BaseReg in "I" dominates the rest of the uses of BaseReg and if
158       // there are more than 2 uses of this BaseReg.
159       bool Dominates = true;
160       unsigned Counter = 0;
161       for (use_iterator I = NextUseMI, E = MRI->use_nodbg_end(); I != E; ++I) {
162         Counter++;
163         if (!MDT.dominates(NextMI, I->getParent()))
164           Dominates = false;
165       }
166 
167       if ((!Dominates) || (Counter < 3))
168         continue;
169 
170       // If we reach here, we have met all the conditions required for the
171       // replacement of the absolute instruction.
172       LLVM_DEBUG({
173         dbgs() << "Found a pair of instructions for absolute-set "
174                << (IsLoad ? "load" : "store") << "\n";
175         dbgs() << *MI;
176         dbgs() << *NextMI;
177       });
178       MachineBasicBlock *ParentBlock = NextMI->getParent();
179       MachineInstrBuilder MIB;
180       if (IsLoad) { // Insert absolute-set load instruction
181         ++HexagonNumLoadAbsConversions;
182         MIB = BuildMI(*ParentBlock, NextMI, NextMI->getDebugLoc(),
183                       TII->get(NewOpc), LoadStoreReg)
184                   .addReg(DstReg, RegState::Define);
185       } else { // Insert absolute-set store instruction
186         ++HexagonNumStoreAbsConversions;
187         MIB = BuildMI(*ParentBlock, NextMI, NextMI->getDebugLoc(),
188                       TII->get(NewOpc), DstReg);
189       }
190 
191       MachineOperand ImmOperand = MI->getOperand(1);
192       if (IsGlobal)
193         MIB.addGlobalAddress(ImmOperand.getGlobal(), ImmOperand.getOffset(),
194                              ImmOperand.getTargetFlags());
195       else
196         MIB.addImm(ImmOperand.getImm());
197 
198       if (IsLoad)
199         MIB->getOperand(0).setSubReg(MO0.getSubReg());
200       else
201         MIB.addReg(LoadStoreReg, 0, MO0.getSubReg());
202 
203       LLVM_DEBUG(dbgs() << "Replaced with " << *MIB << "\n");
204       // Erase the instructions that got replaced.
205       MII = MBB.erase(MI);
206       --MII;
207       NextMI->getParent()->erase(NextMI);
208     }
209   }
210 
211   return true;
212 }
213 
214 bool HexagonGenMemAbsolute::isValidIndexedLoad(int &Opc, int &NewOpc) {
215 
216   bool Result = true;
217   switch (Opc) {
218   case Hexagon::L2_loadrb_io:
219     NewOpc = Hexagon::L4_loadrb_ap;
220     break;
221   case Hexagon::L2_loadrh_io:
222     NewOpc = Hexagon::L4_loadrh_ap;
223     break;
224   case Hexagon::L2_loadri_io:
225     NewOpc = Hexagon::L4_loadri_ap;
226     break;
227   case Hexagon::L2_loadrd_io:
228     NewOpc = Hexagon::L4_loadrd_ap;
229     break;
230   case Hexagon::L2_loadruh_io:
231     NewOpc = Hexagon::L4_loadruh_ap;
232     break;
233   case Hexagon::L2_loadrub_io:
234     NewOpc = Hexagon::L4_loadrub_ap;
235     break;
236   default:
237     Result = false;
238   }
239 
240   return Result;
241 }
242 
243 bool HexagonGenMemAbsolute::isValidIndexedStore(int &Opc, int &NewOpc) {
244 
245   bool Result = true;
246   switch (Opc) {
247   case Hexagon::S2_storerd_io:
248     NewOpc = Hexagon::S4_storerd_ap;
249     break;
250   case Hexagon::S2_storeri_io:
251     NewOpc = Hexagon::S4_storeri_ap;
252     break;
253   case Hexagon::S2_storerh_io:
254     NewOpc = Hexagon::S4_storerh_ap;
255     break;
256   case Hexagon::S2_storerb_io:
257     NewOpc = Hexagon::S4_storerb_ap;
258     break;
259   default:
260     Result = false;
261   }
262 
263   return Result;
264 }
265 
266 //===----------------------------------------------------------------------===//
267 //                         Public Constructor Functions
268 //===----------------------------------------------------------------------===//
269 
270 FunctionPass *llvm::createHexagonGenMemAbsolute() {
271   return new HexagonGenMemAbsolute();
272 }
273