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