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