xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonOptAddrMode.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- HexagonOptAddrMode.cpp ---------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric // This implements a Hexagon-specific pass to optimize addressing mode for
9*0b57cec5SDimitry Andric // load/store instructions.
10*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
11*0b57cec5SDimitry Andric 
12*0b57cec5SDimitry Andric #include "HexagonInstrInfo.h"
13*0b57cec5SDimitry Andric #include "HexagonSubtarget.h"
14*0b57cec5SDimitry Andric #include "MCTargetDesc/HexagonBaseInfo.h"
15*0b57cec5SDimitry Andric #include "RDFGraph.h"
16*0b57cec5SDimitry Andric #include "RDFLiveness.h"
17*0b57cec5SDimitry Andric #include "RDFRegisters.h"
18*0b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
19*0b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h"
20*0b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominanceFrontier.h"
23*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
24*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
25*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
26*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
27*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
28*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOperand.h"
29*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
30*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
31*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
32*0b57cec5SDimitry Andric #include "llvm/Pass.h"
33*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
34*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
35*0b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
36*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
37*0b57cec5SDimitry Andric #include <cassert>
38*0b57cec5SDimitry Andric #include <cstdint>
39*0b57cec5SDimitry Andric 
40*0b57cec5SDimitry Andric #define DEBUG_TYPE "opt-addr-mode"
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric using namespace llvm;
43*0b57cec5SDimitry Andric using namespace rdf;
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric static cl::opt<int> CodeGrowthLimit("hexagon-amode-growth-limit",
46*0b57cec5SDimitry Andric   cl::Hidden, cl::init(0), cl::desc("Code growth limit for address mode "
47*0b57cec5SDimitry Andric   "optimization"));
48*0b57cec5SDimitry Andric 
49*0b57cec5SDimitry Andric namespace llvm {
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric   FunctionPass *createHexagonOptAddrMode();
52*0b57cec5SDimitry Andric   void initializeHexagonOptAddrModePass(PassRegistry&);
53*0b57cec5SDimitry Andric 
54*0b57cec5SDimitry Andric } // end namespace llvm
55*0b57cec5SDimitry Andric 
56*0b57cec5SDimitry Andric namespace {
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric class HexagonOptAddrMode : public MachineFunctionPass {
59*0b57cec5SDimitry Andric public:
60*0b57cec5SDimitry Andric   static char ID;
61*0b57cec5SDimitry Andric 
62*0b57cec5SDimitry Andric   HexagonOptAddrMode() : MachineFunctionPass(ID) {}
63*0b57cec5SDimitry Andric 
64*0b57cec5SDimitry Andric   StringRef getPassName() const override {
65*0b57cec5SDimitry Andric     return "Optimize addressing mode of load/store";
66*0b57cec5SDimitry Andric   }
67*0b57cec5SDimitry Andric 
68*0b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
69*0b57cec5SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
70*0b57cec5SDimitry Andric     AU.addRequired<MachineDominatorTree>();
71*0b57cec5SDimitry Andric     AU.addRequired<MachineDominanceFrontier>();
72*0b57cec5SDimitry Andric     AU.setPreservesAll();
73*0b57cec5SDimitry Andric   }
74*0b57cec5SDimitry Andric 
75*0b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric private:
78*0b57cec5SDimitry Andric   using MISetType = DenseSet<MachineInstr *>;
79*0b57cec5SDimitry Andric   using InstrEvalMap = DenseMap<MachineInstr *, bool>;
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric   MachineRegisterInfo *MRI = nullptr;
82*0b57cec5SDimitry Andric   const HexagonInstrInfo *HII = nullptr;
83*0b57cec5SDimitry Andric   const HexagonRegisterInfo *HRI = nullptr;
84*0b57cec5SDimitry Andric   MachineDominatorTree *MDT = nullptr;
85*0b57cec5SDimitry Andric   DataFlowGraph *DFG = nullptr;
86*0b57cec5SDimitry Andric   DataFlowGraph::DefStackMap DefM;
87*0b57cec5SDimitry Andric   Liveness *LV = nullptr;
88*0b57cec5SDimitry Andric   MISetType Deleted;
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric   bool processBlock(NodeAddr<BlockNode *> BA);
91*0b57cec5SDimitry Andric   bool xformUseMI(MachineInstr *TfrMI, MachineInstr *UseMI,
92*0b57cec5SDimitry Andric                   NodeAddr<UseNode *> UseN, unsigned UseMOnum);
93*0b57cec5SDimitry Andric   bool processAddUses(NodeAddr<StmtNode *> AddSN, MachineInstr *AddMI,
94*0b57cec5SDimitry Andric                       const NodeList &UNodeList);
95*0b57cec5SDimitry Andric   bool updateAddUses(MachineInstr *AddMI, MachineInstr *UseMI);
96*0b57cec5SDimitry Andric   bool analyzeUses(unsigned DefR, const NodeList &UNodeList,
97*0b57cec5SDimitry Andric                    InstrEvalMap &InstrEvalResult, short &SizeInc);
98*0b57cec5SDimitry Andric   bool hasRepForm(MachineInstr &MI, unsigned TfrDefR);
99*0b57cec5SDimitry Andric   bool canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN, MachineInstr &MI,
100*0b57cec5SDimitry Andric                        const NodeList &UNodeList);
101*0b57cec5SDimitry Andric   bool isSafeToExtLR(NodeAddr<StmtNode *> SN, MachineInstr *MI,
102*0b57cec5SDimitry Andric                      unsigned LRExtReg, const NodeList &UNodeList);
103*0b57cec5SDimitry Andric   void getAllRealUses(NodeAddr<StmtNode *> SN, NodeList &UNodeList);
104*0b57cec5SDimitry Andric   bool allValidCandidates(NodeAddr<StmtNode *> SA, NodeList &UNodeList);
105*0b57cec5SDimitry Andric   short getBaseWithLongOffset(const MachineInstr &MI) const;
106*0b57cec5SDimitry Andric   bool changeStore(MachineInstr *OldMI, MachineOperand ImmOp,
107*0b57cec5SDimitry Andric                    unsigned ImmOpNum);
108*0b57cec5SDimitry Andric   bool changeLoad(MachineInstr *OldMI, MachineOperand ImmOp, unsigned ImmOpNum);
109*0b57cec5SDimitry Andric   bool changeAddAsl(NodeAddr<UseNode *> AddAslUN, MachineInstr *AddAslMI,
110*0b57cec5SDimitry Andric                     const MachineOperand &ImmOp, unsigned ImmOpNum);
111*0b57cec5SDimitry Andric   bool isValidOffset(MachineInstr *MI, int Offset);
112*0b57cec5SDimitry Andric };
113*0b57cec5SDimitry Andric 
114*0b57cec5SDimitry Andric } // end anonymous namespace
115*0b57cec5SDimitry Andric 
116*0b57cec5SDimitry Andric char HexagonOptAddrMode::ID = 0;
117*0b57cec5SDimitry Andric 
118*0b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(HexagonOptAddrMode, "amode-opt",
119*0b57cec5SDimitry Andric                       "Optimize addressing mode", false, false)
120*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
121*0b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominanceFrontier)
122*0b57cec5SDimitry Andric INITIALIZE_PASS_END(HexagonOptAddrMode, "amode-opt", "Optimize addressing mode",
123*0b57cec5SDimitry Andric                     false, false)
124*0b57cec5SDimitry Andric 
125*0b57cec5SDimitry Andric bool HexagonOptAddrMode::hasRepForm(MachineInstr &MI, unsigned TfrDefR) {
126*0b57cec5SDimitry Andric   const MCInstrDesc &MID = MI.getDesc();
127*0b57cec5SDimitry Andric 
128*0b57cec5SDimitry Andric   if ((!MID.mayStore() && !MID.mayLoad()) || HII->isPredicated(MI))
129*0b57cec5SDimitry Andric     return false;
130*0b57cec5SDimitry Andric 
131*0b57cec5SDimitry Andric   if (MID.mayStore()) {
132*0b57cec5SDimitry Andric     MachineOperand StOp = MI.getOperand(MI.getNumOperands() - 1);
133*0b57cec5SDimitry Andric     if (StOp.isReg() && StOp.getReg() == TfrDefR)
134*0b57cec5SDimitry Andric       return false;
135*0b57cec5SDimitry Andric   }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric   if (HII->getAddrMode(MI) == HexagonII::BaseRegOffset)
138*0b57cec5SDimitry Andric     // Tranform to Absolute plus register offset.
139*0b57cec5SDimitry Andric     return (HII->changeAddrMode_rr_ur(MI) >= 0);
140*0b57cec5SDimitry Andric   else if (HII->getAddrMode(MI) == HexagonII::BaseImmOffset)
141*0b57cec5SDimitry Andric     // Tranform to absolute addressing mode.
142*0b57cec5SDimitry Andric     return (HII->changeAddrMode_io_abs(MI) >= 0);
143*0b57cec5SDimitry Andric 
144*0b57cec5SDimitry Andric   return false;
145*0b57cec5SDimitry Andric }
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric // Check if addasl instruction can be removed. This is possible only
148*0b57cec5SDimitry Andric // if it's feeding to only load/store instructions with base + register
149*0b57cec5SDimitry Andric // offset as these instruction can be tranformed to use 'absolute plus
150*0b57cec5SDimitry Andric // shifted register offset'.
151*0b57cec5SDimitry Andric // ex:
152*0b57cec5SDimitry Andric // Rs = ##foo
153*0b57cec5SDimitry Andric // Rx = addasl(Rs, Rt, #2)
154*0b57cec5SDimitry Andric // Rd = memw(Rx + #28)
155*0b57cec5SDimitry Andric // Above three instructions can be replaced with Rd = memw(Rt<<#2 + ##foo+28)
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric bool HexagonOptAddrMode::canRemoveAddasl(NodeAddr<StmtNode *> AddAslSN,
158*0b57cec5SDimitry Andric                                          MachineInstr &MI,
159*0b57cec5SDimitry Andric                                          const NodeList &UNodeList) {
160*0b57cec5SDimitry Andric   // check offset size in addasl. if 'offset > 3' return false
161*0b57cec5SDimitry Andric   const MachineOperand &OffsetOp = MI.getOperand(3);
162*0b57cec5SDimitry Andric   if (!OffsetOp.isImm() || OffsetOp.getImm() > 3)
163*0b57cec5SDimitry Andric     return false;
164*0b57cec5SDimitry Andric 
165*0b57cec5SDimitry Andric   unsigned OffsetReg = MI.getOperand(2).getReg();
166*0b57cec5SDimitry Andric   RegisterRef OffsetRR;
167*0b57cec5SDimitry Andric   NodeId OffsetRegRD = 0;
168*0b57cec5SDimitry Andric   for (NodeAddr<UseNode *> UA : AddAslSN.Addr->members_if(DFG->IsUse, *DFG)) {
169*0b57cec5SDimitry Andric     RegisterRef RR = UA.Addr->getRegRef(*DFG);
170*0b57cec5SDimitry Andric     if (OffsetReg == RR.Reg) {
171*0b57cec5SDimitry Andric       OffsetRR = RR;
172*0b57cec5SDimitry Andric       OffsetRegRD = UA.Addr->getReachingDef();
173*0b57cec5SDimitry Andric     }
174*0b57cec5SDimitry Andric   }
175*0b57cec5SDimitry Andric 
176*0b57cec5SDimitry Andric   for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
177*0b57cec5SDimitry Andric     NodeAddr<UseNode *> UA = *I;
178*0b57cec5SDimitry Andric     NodeAddr<InstrNode *> IA = UA.Addr->getOwner(*DFG);
179*0b57cec5SDimitry Andric     if (UA.Addr->getFlags() & NodeAttrs::PhiRef)
180*0b57cec5SDimitry Andric       return false;
181*0b57cec5SDimitry Andric     NodeAddr<RefNode*> AA = LV->getNearestAliasedRef(OffsetRR, IA);
182*0b57cec5SDimitry Andric     if ((DFG->IsDef(AA) && AA.Id != OffsetRegRD) ||
183*0b57cec5SDimitry Andric          AA.Addr->getReachingDef() != OffsetRegRD)
184*0b57cec5SDimitry Andric       return false;
185*0b57cec5SDimitry Andric 
186*0b57cec5SDimitry Andric     MachineInstr &UseMI = *NodeAddr<StmtNode *>(IA).Addr->getCode();
187*0b57cec5SDimitry Andric     NodeAddr<DefNode *> OffsetRegDN = DFG->addr<DefNode *>(OffsetRegRD);
188*0b57cec5SDimitry Andric     // Reaching Def to an offset register can't be a phi.
189*0b57cec5SDimitry Andric     if ((OffsetRegDN.Addr->getFlags() & NodeAttrs::PhiRef) &&
190*0b57cec5SDimitry Andric         MI.getParent() != UseMI.getParent())
191*0b57cec5SDimitry Andric     return false;
192*0b57cec5SDimitry Andric 
193*0b57cec5SDimitry Andric     const MCInstrDesc &UseMID = UseMI.getDesc();
194*0b57cec5SDimitry Andric     if ((!UseMID.mayLoad() && !UseMID.mayStore()) ||
195*0b57cec5SDimitry Andric         HII->getAddrMode(UseMI) != HexagonII::BaseImmOffset ||
196*0b57cec5SDimitry Andric         getBaseWithLongOffset(UseMI) < 0)
197*0b57cec5SDimitry Andric       return false;
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric     // Addasl output can't be a store value.
200*0b57cec5SDimitry Andric     if (UseMID.mayStore() && UseMI.getOperand(2).isReg() &&
201*0b57cec5SDimitry Andric         UseMI.getOperand(2).getReg() == MI.getOperand(0).getReg())
202*0b57cec5SDimitry Andric       return false;
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric     for (auto &Mo : UseMI.operands())
205*0b57cec5SDimitry Andric       if (Mo.isFI())
206*0b57cec5SDimitry Andric         return false;
207*0b57cec5SDimitry Andric   }
208*0b57cec5SDimitry Andric   return true;
209*0b57cec5SDimitry Andric }
210*0b57cec5SDimitry Andric 
211*0b57cec5SDimitry Andric bool HexagonOptAddrMode::allValidCandidates(NodeAddr<StmtNode *> SA,
212*0b57cec5SDimitry Andric                                             NodeList &UNodeList) {
213*0b57cec5SDimitry Andric   for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
214*0b57cec5SDimitry Andric     NodeAddr<UseNode *> UN = *I;
215*0b57cec5SDimitry Andric     RegisterRef UR = UN.Addr->getRegRef(*DFG);
216*0b57cec5SDimitry Andric     NodeSet Visited, Defs;
217*0b57cec5SDimitry Andric     const auto &P = LV->getAllReachingDefsRec(UR, UN, Visited, Defs);
218*0b57cec5SDimitry Andric     if (!P.second) {
219*0b57cec5SDimitry Andric       LLVM_DEBUG({
220*0b57cec5SDimitry Andric         dbgs() << "*** Unable to collect all reaching defs for use ***\n"
221*0b57cec5SDimitry Andric                << PrintNode<UseNode*>(UN, *DFG) << '\n'
222*0b57cec5SDimitry Andric                << "The program's complexity may exceed the limits.\n";
223*0b57cec5SDimitry Andric       });
224*0b57cec5SDimitry Andric       return false;
225*0b57cec5SDimitry Andric     }
226*0b57cec5SDimitry Andric     const auto &ReachingDefs = P.first;
227*0b57cec5SDimitry Andric     if (ReachingDefs.size() > 1) {
228*0b57cec5SDimitry Andric       LLVM_DEBUG({
229*0b57cec5SDimitry Andric         dbgs() << "*** Multiple Reaching Defs found!!! ***\n";
230*0b57cec5SDimitry Andric         for (auto DI : ReachingDefs) {
231*0b57cec5SDimitry Andric           NodeAddr<UseNode *> DA = DFG->addr<UseNode *>(DI);
232*0b57cec5SDimitry Andric           NodeAddr<StmtNode *> TempIA = DA.Addr->getOwner(*DFG);
233*0b57cec5SDimitry Andric           dbgs() << "\t\t[Reaching Def]: "
234*0b57cec5SDimitry Andric                  << Print<NodeAddr<InstrNode *>>(TempIA, *DFG) << "\n";
235*0b57cec5SDimitry Andric         }
236*0b57cec5SDimitry Andric       });
237*0b57cec5SDimitry Andric       return false;
238*0b57cec5SDimitry Andric     }
239*0b57cec5SDimitry Andric   }
240*0b57cec5SDimitry Andric   return true;
241*0b57cec5SDimitry Andric }
242*0b57cec5SDimitry Andric 
243*0b57cec5SDimitry Andric void HexagonOptAddrMode::getAllRealUses(NodeAddr<StmtNode *> SA,
244*0b57cec5SDimitry Andric                                         NodeList &UNodeList) {
245*0b57cec5SDimitry Andric   for (NodeAddr<DefNode *> DA : SA.Addr->members_if(DFG->IsDef, *DFG)) {
246*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\t\t[DefNode]: "
247*0b57cec5SDimitry Andric                       << Print<NodeAddr<DefNode *>>(DA, *DFG) << "\n");
248*0b57cec5SDimitry Andric     RegisterRef DR = DFG->getPRI().normalize(DA.Addr->getRegRef(*DFG));
249*0b57cec5SDimitry Andric 
250*0b57cec5SDimitry Andric     auto UseSet = LV->getAllReachedUses(DR, DA);
251*0b57cec5SDimitry Andric 
252*0b57cec5SDimitry Andric     for (auto UI : UseSet) {
253*0b57cec5SDimitry Andric       NodeAddr<UseNode *> UA = DFG->addr<UseNode *>(UI);
254*0b57cec5SDimitry Andric       LLVM_DEBUG({
255*0b57cec5SDimitry Andric         NodeAddr<StmtNode *> TempIA = UA.Addr->getOwner(*DFG);
256*0b57cec5SDimitry Andric         dbgs() << "\t\t\t[Reached Use]: "
257*0b57cec5SDimitry Andric                << Print<NodeAddr<InstrNode *>>(TempIA, *DFG) << "\n";
258*0b57cec5SDimitry Andric       });
259*0b57cec5SDimitry Andric 
260*0b57cec5SDimitry Andric       if (UA.Addr->getFlags() & NodeAttrs::PhiRef) {
261*0b57cec5SDimitry Andric         NodeAddr<PhiNode *> PA = UA.Addr->getOwner(*DFG);
262*0b57cec5SDimitry Andric         NodeId id = PA.Id;
263*0b57cec5SDimitry Andric         const Liveness::RefMap &phiUse = LV->getRealUses(id);
264*0b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "\t\t\t\tphi real Uses"
265*0b57cec5SDimitry Andric                           << Print<Liveness::RefMap>(phiUse, *DFG) << "\n");
266*0b57cec5SDimitry Andric         if (!phiUse.empty()) {
267*0b57cec5SDimitry Andric           for (auto I : phiUse) {
268*0b57cec5SDimitry Andric             if (!DFG->getPRI().alias(RegisterRef(I.first), DR))
269*0b57cec5SDimitry Andric               continue;
270*0b57cec5SDimitry Andric             auto phiUseSet = I.second;
271*0b57cec5SDimitry Andric             for (auto phiUI : phiUseSet) {
272*0b57cec5SDimitry Andric               NodeAddr<UseNode *> phiUA = DFG->addr<UseNode *>(phiUI.first);
273*0b57cec5SDimitry Andric               UNodeList.push_back(phiUA);
274*0b57cec5SDimitry Andric             }
275*0b57cec5SDimitry Andric           }
276*0b57cec5SDimitry Andric         }
277*0b57cec5SDimitry Andric       } else
278*0b57cec5SDimitry Andric         UNodeList.push_back(UA);
279*0b57cec5SDimitry Andric     }
280*0b57cec5SDimitry Andric   }
281*0b57cec5SDimitry Andric }
282*0b57cec5SDimitry Andric 
283*0b57cec5SDimitry Andric bool HexagonOptAddrMode::isSafeToExtLR(NodeAddr<StmtNode *> SN,
284*0b57cec5SDimitry Andric                                        MachineInstr *MI, unsigned LRExtReg,
285*0b57cec5SDimitry Andric                                        const NodeList &UNodeList) {
286*0b57cec5SDimitry Andric   RegisterRef LRExtRR;
287*0b57cec5SDimitry Andric   NodeId LRExtRegRD = 0;
288*0b57cec5SDimitry Andric   // Iterate through all the UseNodes in SN and find the reaching def
289*0b57cec5SDimitry Andric   // for the LRExtReg.
290*0b57cec5SDimitry Andric   for (NodeAddr<UseNode *> UA : SN.Addr->members_if(DFG->IsUse, *DFG)) {
291*0b57cec5SDimitry Andric     RegisterRef RR = UA.Addr->getRegRef(*DFG);
292*0b57cec5SDimitry Andric     if (LRExtReg == RR.Reg) {
293*0b57cec5SDimitry Andric       LRExtRR = RR;
294*0b57cec5SDimitry Andric       LRExtRegRD = UA.Addr->getReachingDef();
295*0b57cec5SDimitry Andric     }
296*0b57cec5SDimitry Andric   }
297*0b57cec5SDimitry Andric 
298*0b57cec5SDimitry Andric   for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
299*0b57cec5SDimitry Andric     NodeAddr<UseNode *> UA = *I;
300*0b57cec5SDimitry Andric     NodeAddr<InstrNode *> IA = UA.Addr->getOwner(*DFG);
301*0b57cec5SDimitry Andric     // The reaching def of LRExtRR at load/store node should be same as the
302*0b57cec5SDimitry Andric     // one reaching at the SN.
303*0b57cec5SDimitry Andric     if (UA.Addr->getFlags() & NodeAttrs::PhiRef)
304*0b57cec5SDimitry Andric       return false;
305*0b57cec5SDimitry Andric     NodeAddr<RefNode*> AA = LV->getNearestAliasedRef(LRExtRR, IA);
306*0b57cec5SDimitry Andric     if ((DFG->IsDef(AA) && AA.Id != LRExtRegRD) ||
307*0b57cec5SDimitry Andric         AA.Addr->getReachingDef() != LRExtRegRD) {
308*0b57cec5SDimitry Andric       LLVM_DEBUG(
309*0b57cec5SDimitry Andric           dbgs() << "isSafeToExtLR: Returning false; another reaching def\n");
310*0b57cec5SDimitry Andric       return false;
311*0b57cec5SDimitry Andric     }
312*0b57cec5SDimitry Andric 
313*0b57cec5SDimitry Andric     MachineInstr *UseMI = NodeAddr<StmtNode *>(IA).Addr->getCode();
314*0b57cec5SDimitry Andric     NodeAddr<DefNode *> LRExtRegDN = DFG->addr<DefNode *>(LRExtRegRD);
315*0b57cec5SDimitry Andric     // Reaching Def to LRExtReg can't be a phi.
316*0b57cec5SDimitry Andric     if ((LRExtRegDN.Addr->getFlags() & NodeAttrs::PhiRef) &&
317*0b57cec5SDimitry Andric         MI->getParent() != UseMI->getParent())
318*0b57cec5SDimitry Andric     return false;
319*0b57cec5SDimitry Andric   }
320*0b57cec5SDimitry Andric   return true;
321*0b57cec5SDimitry Andric }
322*0b57cec5SDimitry Andric 
323*0b57cec5SDimitry Andric bool HexagonOptAddrMode::isValidOffset(MachineInstr *MI, int Offset) {
324*0b57cec5SDimitry Andric   unsigned AlignMask = 0;
325*0b57cec5SDimitry Andric   switch (HII->getMemAccessSize(*MI)) {
326*0b57cec5SDimitry Andric   case HexagonII::MemAccessSize::DoubleWordAccess:
327*0b57cec5SDimitry Andric     AlignMask = 0x7;
328*0b57cec5SDimitry Andric     break;
329*0b57cec5SDimitry Andric   case HexagonII::MemAccessSize::WordAccess:
330*0b57cec5SDimitry Andric     AlignMask = 0x3;
331*0b57cec5SDimitry Andric     break;
332*0b57cec5SDimitry Andric   case HexagonII::MemAccessSize::HalfWordAccess:
333*0b57cec5SDimitry Andric     AlignMask = 0x1;
334*0b57cec5SDimitry Andric     break;
335*0b57cec5SDimitry Andric   case HexagonII::MemAccessSize::ByteAccess:
336*0b57cec5SDimitry Andric     AlignMask = 0x0;
337*0b57cec5SDimitry Andric     break;
338*0b57cec5SDimitry Andric   default:
339*0b57cec5SDimitry Andric     return false;
340*0b57cec5SDimitry Andric   }
341*0b57cec5SDimitry Andric 
342*0b57cec5SDimitry Andric   if ((AlignMask & Offset) != 0)
343*0b57cec5SDimitry Andric     return false;
344*0b57cec5SDimitry Andric   return HII->isValidOffset(MI->getOpcode(), Offset, HRI, false);
345*0b57cec5SDimitry Andric }
346*0b57cec5SDimitry Andric 
347*0b57cec5SDimitry Andric bool HexagonOptAddrMode::processAddUses(NodeAddr<StmtNode *> AddSN,
348*0b57cec5SDimitry Andric                                         MachineInstr *AddMI,
349*0b57cec5SDimitry Andric                                         const NodeList &UNodeList) {
350*0b57cec5SDimitry Andric 
351*0b57cec5SDimitry Andric   unsigned AddDefR = AddMI->getOperand(0).getReg();
352*0b57cec5SDimitry Andric   for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
353*0b57cec5SDimitry Andric     NodeAddr<UseNode *> UN = *I;
354*0b57cec5SDimitry Andric     NodeAddr<StmtNode *> SN = UN.Addr->getOwner(*DFG);
355*0b57cec5SDimitry Andric     MachineInstr *MI = SN.Addr->getCode();
356*0b57cec5SDimitry Andric     const MCInstrDesc &MID = MI->getDesc();
357*0b57cec5SDimitry Andric     if ((!MID.mayLoad() && !MID.mayStore()) ||
358*0b57cec5SDimitry Andric         HII->getAddrMode(*MI) != HexagonII::BaseImmOffset ||
359*0b57cec5SDimitry Andric         HII->isHVXVec(*MI))
360*0b57cec5SDimitry Andric       return false;
361*0b57cec5SDimitry Andric 
362*0b57cec5SDimitry Andric     MachineOperand BaseOp = MID.mayLoad() ? MI->getOperand(1)
363*0b57cec5SDimitry Andric                                           : MI->getOperand(0);
364*0b57cec5SDimitry Andric 
365*0b57cec5SDimitry Andric     if (!BaseOp.isReg() || BaseOp.getReg() != AddDefR)
366*0b57cec5SDimitry Andric       return false;
367*0b57cec5SDimitry Andric 
368*0b57cec5SDimitry Andric     MachineOperand OffsetOp = MID.mayLoad() ? MI->getOperand(2)
369*0b57cec5SDimitry Andric                                             : MI->getOperand(1);
370*0b57cec5SDimitry Andric     if (!OffsetOp.isImm())
371*0b57cec5SDimitry Andric       return false;
372*0b57cec5SDimitry Andric 
373*0b57cec5SDimitry Andric     int64_t newOffset = OffsetOp.getImm() + AddMI->getOperand(2).getImm();
374*0b57cec5SDimitry Andric     if (!isValidOffset(MI, newOffset))
375*0b57cec5SDimitry Andric       return false;
376*0b57cec5SDimitry Andric 
377*0b57cec5SDimitry Andric     // Since we'll be extending the live range of Rt in the following example,
378*0b57cec5SDimitry Andric     // make sure that is safe. another definition of Rt doesn't exist between 'add'
379*0b57cec5SDimitry Andric     // and load/store instruction.
380*0b57cec5SDimitry Andric     //
381*0b57cec5SDimitry Andric     // Ex: Rx= add(Rt,#10)
382*0b57cec5SDimitry Andric     //     memw(Rx+#0) = Rs
383*0b57cec5SDimitry Andric     // will be replaced with =>  memw(Rt+#10) = Rs
384*0b57cec5SDimitry Andric     unsigned BaseReg = AddMI->getOperand(1).getReg();
385*0b57cec5SDimitry Andric     if (!isSafeToExtLR(AddSN, AddMI, BaseReg, UNodeList))
386*0b57cec5SDimitry Andric       return false;
387*0b57cec5SDimitry Andric   }
388*0b57cec5SDimitry Andric 
389*0b57cec5SDimitry Andric   // Update all the uses of 'add' with the appropriate base and offset
390*0b57cec5SDimitry Andric   // values.
391*0b57cec5SDimitry Andric   bool Changed = false;
392*0b57cec5SDimitry Andric   for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
393*0b57cec5SDimitry Andric     NodeAddr<UseNode *> UseN = *I;
394*0b57cec5SDimitry Andric     assert(!(UseN.Addr->getFlags() & NodeAttrs::PhiRef) &&
395*0b57cec5SDimitry Andric            "Found a PhiRef node as a real reached use!!");
396*0b57cec5SDimitry Andric 
397*0b57cec5SDimitry Andric     NodeAddr<StmtNode *> OwnerN = UseN.Addr->getOwner(*DFG);
398*0b57cec5SDimitry Andric     MachineInstr *UseMI = OwnerN.Addr->getCode();
399*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\t\t[MI <BB#" << UseMI->getParent()->getNumber()
400*0b57cec5SDimitry Andric                       << ">]: " << *UseMI << "\n");
401*0b57cec5SDimitry Andric     Changed |= updateAddUses(AddMI, UseMI);
402*0b57cec5SDimitry Andric   }
403*0b57cec5SDimitry Andric 
404*0b57cec5SDimitry Andric   if (Changed)
405*0b57cec5SDimitry Andric     Deleted.insert(AddMI);
406*0b57cec5SDimitry Andric 
407*0b57cec5SDimitry Andric   return Changed;
408*0b57cec5SDimitry Andric }
409*0b57cec5SDimitry Andric 
410*0b57cec5SDimitry Andric bool HexagonOptAddrMode::updateAddUses(MachineInstr *AddMI,
411*0b57cec5SDimitry Andric                                         MachineInstr *UseMI) {
412*0b57cec5SDimitry Andric   const MachineOperand ImmOp = AddMI->getOperand(2);
413*0b57cec5SDimitry Andric   const MachineOperand AddRegOp = AddMI->getOperand(1);
414*0b57cec5SDimitry Andric   unsigned newReg = AddRegOp.getReg();
415*0b57cec5SDimitry Andric   const MCInstrDesc &MID = UseMI->getDesc();
416*0b57cec5SDimitry Andric 
417*0b57cec5SDimitry Andric   MachineOperand &BaseOp = MID.mayLoad() ? UseMI->getOperand(1)
418*0b57cec5SDimitry Andric                                          : UseMI->getOperand(0);
419*0b57cec5SDimitry Andric   MachineOperand &OffsetOp = MID.mayLoad() ? UseMI->getOperand(2)
420*0b57cec5SDimitry Andric                                            : UseMI->getOperand(1);
421*0b57cec5SDimitry Andric   BaseOp.setReg(newReg);
422*0b57cec5SDimitry Andric   BaseOp.setIsUndef(AddRegOp.isUndef());
423*0b57cec5SDimitry Andric   BaseOp.setImplicit(AddRegOp.isImplicit());
424*0b57cec5SDimitry Andric   OffsetOp.setImm(ImmOp.getImm() + OffsetOp.getImm());
425*0b57cec5SDimitry Andric   MRI->clearKillFlags(newReg);
426*0b57cec5SDimitry Andric 
427*0b57cec5SDimitry Andric   return true;
428*0b57cec5SDimitry Andric }
429*0b57cec5SDimitry Andric 
430*0b57cec5SDimitry Andric bool HexagonOptAddrMode::analyzeUses(unsigned tfrDefR,
431*0b57cec5SDimitry Andric                                      const NodeList &UNodeList,
432*0b57cec5SDimitry Andric                                      InstrEvalMap &InstrEvalResult,
433*0b57cec5SDimitry Andric                                      short &SizeInc) {
434*0b57cec5SDimitry Andric   bool KeepTfr = false;
435*0b57cec5SDimitry Andric   bool HasRepInstr = false;
436*0b57cec5SDimitry Andric   InstrEvalResult.clear();
437*0b57cec5SDimitry Andric 
438*0b57cec5SDimitry Andric   for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
439*0b57cec5SDimitry Andric     bool CanBeReplaced = false;
440*0b57cec5SDimitry Andric     NodeAddr<UseNode *> UN = *I;
441*0b57cec5SDimitry Andric     NodeAddr<StmtNode *> SN = UN.Addr->getOwner(*DFG);
442*0b57cec5SDimitry Andric     MachineInstr &MI = *SN.Addr->getCode();
443*0b57cec5SDimitry Andric     const MCInstrDesc &MID = MI.getDesc();
444*0b57cec5SDimitry Andric     if ((MID.mayLoad() || MID.mayStore())) {
445*0b57cec5SDimitry Andric       if (!hasRepForm(MI, tfrDefR)) {
446*0b57cec5SDimitry Andric         KeepTfr = true;
447*0b57cec5SDimitry Andric         continue;
448*0b57cec5SDimitry Andric       }
449*0b57cec5SDimitry Andric       SizeInc++;
450*0b57cec5SDimitry Andric       CanBeReplaced = true;
451*0b57cec5SDimitry Andric     } else if (MI.getOpcode() == Hexagon::S2_addasl_rrri) {
452*0b57cec5SDimitry Andric       NodeList AddaslUseList;
453*0b57cec5SDimitry Andric 
454*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\nGetting ReachedUses for === " << MI << "\n");
455*0b57cec5SDimitry Andric       getAllRealUses(SN, AddaslUseList);
456*0b57cec5SDimitry Andric       // Process phi nodes.
457*0b57cec5SDimitry Andric       if (allValidCandidates(SN, AddaslUseList) &&
458*0b57cec5SDimitry Andric           canRemoveAddasl(SN, MI, AddaslUseList)) {
459*0b57cec5SDimitry Andric         SizeInc += AddaslUseList.size();
460*0b57cec5SDimitry Andric         SizeInc -= 1; // Reduce size by 1 as addasl itself can be removed.
461*0b57cec5SDimitry Andric         CanBeReplaced = true;
462*0b57cec5SDimitry Andric       } else
463*0b57cec5SDimitry Andric         SizeInc++;
464*0b57cec5SDimitry Andric     } else
465*0b57cec5SDimitry Andric       // Currently, only load/store and addasl are handled.
466*0b57cec5SDimitry Andric       // Some other instructions to consider -
467*0b57cec5SDimitry Andric       // A2_add -> A2_addi
468*0b57cec5SDimitry Andric       // M4_mpyrr_addr -> M4_mpyrr_addi
469*0b57cec5SDimitry Andric       KeepTfr = true;
470*0b57cec5SDimitry Andric 
471*0b57cec5SDimitry Andric     InstrEvalResult[&MI] = CanBeReplaced;
472*0b57cec5SDimitry Andric     HasRepInstr |= CanBeReplaced;
473*0b57cec5SDimitry Andric   }
474*0b57cec5SDimitry Andric 
475*0b57cec5SDimitry Andric   // Reduce total size by 2 if original tfr can be deleted.
476*0b57cec5SDimitry Andric   if (!KeepTfr)
477*0b57cec5SDimitry Andric     SizeInc -= 2;
478*0b57cec5SDimitry Andric 
479*0b57cec5SDimitry Andric   return HasRepInstr;
480*0b57cec5SDimitry Andric }
481*0b57cec5SDimitry Andric 
482*0b57cec5SDimitry Andric bool HexagonOptAddrMode::changeLoad(MachineInstr *OldMI, MachineOperand ImmOp,
483*0b57cec5SDimitry Andric                                     unsigned ImmOpNum) {
484*0b57cec5SDimitry Andric   bool Changed = false;
485*0b57cec5SDimitry Andric   MachineBasicBlock *BB = OldMI->getParent();
486*0b57cec5SDimitry Andric   auto UsePos = MachineBasicBlock::iterator(OldMI);
487*0b57cec5SDimitry Andric   MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator();
488*0b57cec5SDimitry Andric   ++InsertPt;
489*0b57cec5SDimitry Andric   unsigned OpStart;
490*0b57cec5SDimitry Andric   unsigned OpEnd = OldMI->getNumOperands();
491*0b57cec5SDimitry Andric   MachineInstrBuilder MIB;
492*0b57cec5SDimitry Andric 
493*0b57cec5SDimitry Andric   if (ImmOpNum == 1) {
494*0b57cec5SDimitry Andric     if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset) {
495*0b57cec5SDimitry Andric       short NewOpCode = HII->changeAddrMode_rr_ur(*OldMI);
496*0b57cec5SDimitry Andric       assert(NewOpCode >= 0 && "Invalid New opcode\n");
497*0b57cec5SDimitry Andric       MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
498*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(0));
499*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(2));
500*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(3));
501*0b57cec5SDimitry Andric       MIB.add(ImmOp);
502*0b57cec5SDimitry Andric       OpStart = 4;
503*0b57cec5SDimitry Andric       Changed = true;
504*0b57cec5SDimitry Andric     } else if (HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset &&
505*0b57cec5SDimitry Andric                OldMI->getOperand(2).isImm()) {
506*0b57cec5SDimitry Andric       short NewOpCode = HII->changeAddrMode_io_abs(*OldMI);
507*0b57cec5SDimitry Andric       assert(NewOpCode >= 0 && "Invalid New opcode\n");
508*0b57cec5SDimitry Andric       MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode))
509*0b57cec5SDimitry Andric                 .add(OldMI->getOperand(0));
510*0b57cec5SDimitry Andric       const GlobalValue *GV = ImmOp.getGlobal();
511*0b57cec5SDimitry Andric       int64_t Offset = ImmOp.getOffset() + OldMI->getOperand(2).getImm();
512*0b57cec5SDimitry Andric 
513*0b57cec5SDimitry Andric       MIB.addGlobalAddress(GV, Offset, ImmOp.getTargetFlags());
514*0b57cec5SDimitry Andric       OpStart = 3;
515*0b57cec5SDimitry Andric       Changed = true;
516*0b57cec5SDimitry Andric     } else
517*0b57cec5SDimitry Andric       Changed = false;
518*0b57cec5SDimitry Andric 
519*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n");
520*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[TO]: " << *MIB << "\n");
521*0b57cec5SDimitry Andric   } else if (ImmOpNum == 2) {
522*0b57cec5SDimitry Andric     if (OldMI->getOperand(3).isImm() && OldMI->getOperand(3).getImm() == 0) {
523*0b57cec5SDimitry Andric       short NewOpCode = HII->changeAddrMode_rr_io(*OldMI);
524*0b57cec5SDimitry Andric       assert(NewOpCode >= 0 && "Invalid New opcode\n");
525*0b57cec5SDimitry Andric       MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
526*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(0));
527*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(1));
528*0b57cec5SDimitry Andric       MIB.add(ImmOp);
529*0b57cec5SDimitry Andric       OpStart = 4;
530*0b57cec5SDimitry Andric       Changed = true;
531*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n");
532*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "[TO]: " << *MIB << "\n");
533*0b57cec5SDimitry Andric     }
534*0b57cec5SDimitry Andric   }
535*0b57cec5SDimitry Andric 
536*0b57cec5SDimitry Andric   if (Changed)
537*0b57cec5SDimitry Andric     for (unsigned i = OpStart; i < OpEnd; ++i)
538*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(i));
539*0b57cec5SDimitry Andric 
540*0b57cec5SDimitry Andric   return Changed;
541*0b57cec5SDimitry Andric }
542*0b57cec5SDimitry Andric 
543*0b57cec5SDimitry Andric bool HexagonOptAddrMode::changeStore(MachineInstr *OldMI, MachineOperand ImmOp,
544*0b57cec5SDimitry Andric                                      unsigned ImmOpNum) {
545*0b57cec5SDimitry Andric   bool Changed = false;
546*0b57cec5SDimitry Andric   unsigned OpStart;
547*0b57cec5SDimitry Andric   unsigned OpEnd = OldMI->getNumOperands();
548*0b57cec5SDimitry Andric   MachineBasicBlock *BB = OldMI->getParent();
549*0b57cec5SDimitry Andric   auto UsePos = MachineBasicBlock::iterator(OldMI);
550*0b57cec5SDimitry Andric   MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator();
551*0b57cec5SDimitry Andric   ++InsertPt;
552*0b57cec5SDimitry Andric   MachineInstrBuilder MIB;
553*0b57cec5SDimitry Andric   if (ImmOpNum == 0) {
554*0b57cec5SDimitry Andric     if (HII->getAddrMode(*OldMI) == HexagonII::BaseRegOffset) {
555*0b57cec5SDimitry Andric       short NewOpCode = HII->changeAddrMode_rr_ur(*OldMI);
556*0b57cec5SDimitry Andric       assert(NewOpCode >= 0 && "Invalid New opcode\n");
557*0b57cec5SDimitry Andric       MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
558*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(1));
559*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(2));
560*0b57cec5SDimitry Andric       MIB.add(ImmOp);
561*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(3));
562*0b57cec5SDimitry Andric       OpStart = 4;
563*0b57cec5SDimitry Andric     } else if (HII->getAddrMode(*OldMI) == HexagonII::BaseImmOffset) {
564*0b57cec5SDimitry Andric       short NewOpCode = HII->changeAddrMode_io_abs(*OldMI);
565*0b57cec5SDimitry Andric       assert(NewOpCode >= 0 && "Invalid New opcode\n");
566*0b57cec5SDimitry Andric       MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
567*0b57cec5SDimitry Andric       const GlobalValue *GV = ImmOp.getGlobal();
568*0b57cec5SDimitry Andric       int64_t Offset = ImmOp.getOffset() + OldMI->getOperand(1).getImm();
569*0b57cec5SDimitry Andric       MIB.addGlobalAddress(GV, Offset, ImmOp.getTargetFlags());
570*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(2));
571*0b57cec5SDimitry Andric       OpStart = 3;
572*0b57cec5SDimitry Andric     }
573*0b57cec5SDimitry Andric     Changed = true;
574*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n");
575*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[TO]: " << *MIB << "\n");
576*0b57cec5SDimitry Andric   } else if (ImmOpNum == 1 && OldMI->getOperand(2).getImm() == 0) {
577*0b57cec5SDimitry Andric     short NewOpCode = HII->changeAddrMode_rr_io(*OldMI);
578*0b57cec5SDimitry Andric     assert(NewOpCode >= 0 && "Invalid New opcode\n");
579*0b57cec5SDimitry Andric     MIB = BuildMI(*BB, InsertPt, OldMI->getDebugLoc(), HII->get(NewOpCode));
580*0b57cec5SDimitry Andric     MIB.add(OldMI->getOperand(0));
581*0b57cec5SDimitry Andric     MIB.add(ImmOp);
582*0b57cec5SDimitry Andric     OpStart = 3;
583*0b57cec5SDimitry Andric     Changed = true;
584*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[Changing]: " << *OldMI << "\n");
585*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[TO]: " << *MIB << "\n");
586*0b57cec5SDimitry Andric   }
587*0b57cec5SDimitry Andric   if (Changed)
588*0b57cec5SDimitry Andric     for (unsigned i = OpStart; i < OpEnd; ++i)
589*0b57cec5SDimitry Andric       MIB.add(OldMI->getOperand(i));
590*0b57cec5SDimitry Andric 
591*0b57cec5SDimitry Andric   return Changed;
592*0b57cec5SDimitry Andric }
593*0b57cec5SDimitry Andric 
594*0b57cec5SDimitry Andric short HexagonOptAddrMode::getBaseWithLongOffset(const MachineInstr &MI) const {
595*0b57cec5SDimitry Andric   if (HII->getAddrMode(MI) == HexagonII::BaseImmOffset) {
596*0b57cec5SDimitry Andric     short TempOpCode = HII->changeAddrMode_io_rr(MI);
597*0b57cec5SDimitry Andric     return HII->changeAddrMode_rr_ur(TempOpCode);
598*0b57cec5SDimitry Andric   }
599*0b57cec5SDimitry Andric   return HII->changeAddrMode_rr_ur(MI);
600*0b57cec5SDimitry Andric }
601*0b57cec5SDimitry Andric 
602*0b57cec5SDimitry Andric bool HexagonOptAddrMode::changeAddAsl(NodeAddr<UseNode *> AddAslUN,
603*0b57cec5SDimitry Andric                                       MachineInstr *AddAslMI,
604*0b57cec5SDimitry Andric                                       const MachineOperand &ImmOp,
605*0b57cec5SDimitry Andric                                       unsigned ImmOpNum) {
606*0b57cec5SDimitry Andric   NodeAddr<StmtNode *> SA = AddAslUN.Addr->getOwner(*DFG);
607*0b57cec5SDimitry Andric 
608*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Processing addasl :" << *AddAslMI << "\n");
609*0b57cec5SDimitry Andric 
610*0b57cec5SDimitry Andric   NodeList UNodeList;
611*0b57cec5SDimitry Andric   getAllRealUses(SA, UNodeList);
612*0b57cec5SDimitry Andric 
613*0b57cec5SDimitry Andric   for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
614*0b57cec5SDimitry Andric     NodeAddr<UseNode *> UseUN = *I;
615*0b57cec5SDimitry Andric     assert(!(UseUN.Addr->getFlags() & NodeAttrs::PhiRef) &&
616*0b57cec5SDimitry Andric            "Can't transform this 'AddAsl' instruction!");
617*0b57cec5SDimitry Andric 
618*0b57cec5SDimitry Andric     NodeAddr<StmtNode *> UseIA = UseUN.Addr->getOwner(*DFG);
619*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[InstrNode]: "
620*0b57cec5SDimitry Andric                       << Print<NodeAddr<InstrNode *>>(UseIA, *DFG) << "\n");
621*0b57cec5SDimitry Andric     MachineInstr *UseMI = UseIA.Addr->getCode();
622*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[MI <" << printMBBReference(*UseMI->getParent())
623*0b57cec5SDimitry Andric                       << ">]: " << *UseMI << "\n");
624*0b57cec5SDimitry Andric     const MCInstrDesc &UseMID = UseMI->getDesc();
625*0b57cec5SDimitry Andric     assert(HII->getAddrMode(*UseMI) == HexagonII::BaseImmOffset);
626*0b57cec5SDimitry Andric 
627*0b57cec5SDimitry Andric     auto UsePos = MachineBasicBlock::iterator(UseMI);
628*0b57cec5SDimitry Andric     MachineBasicBlock::instr_iterator InsertPt = UsePos.getInstrIterator();
629*0b57cec5SDimitry Andric     short NewOpCode = getBaseWithLongOffset(*UseMI);
630*0b57cec5SDimitry Andric     assert(NewOpCode >= 0 && "Invalid New opcode\n");
631*0b57cec5SDimitry Andric 
632*0b57cec5SDimitry Andric     unsigned OpStart;
633*0b57cec5SDimitry Andric     unsigned OpEnd = UseMI->getNumOperands();
634*0b57cec5SDimitry Andric 
635*0b57cec5SDimitry Andric     MachineBasicBlock *BB = UseMI->getParent();
636*0b57cec5SDimitry Andric     MachineInstrBuilder MIB =
637*0b57cec5SDimitry Andric         BuildMI(*BB, InsertPt, UseMI->getDebugLoc(), HII->get(NewOpCode));
638*0b57cec5SDimitry Andric     // change mem(Rs + # ) -> mem(Rt << # + ##)
639*0b57cec5SDimitry Andric     if (UseMID.mayLoad()) {
640*0b57cec5SDimitry Andric       MIB.add(UseMI->getOperand(0));
641*0b57cec5SDimitry Andric       MIB.add(AddAslMI->getOperand(2));
642*0b57cec5SDimitry Andric       MIB.add(AddAslMI->getOperand(3));
643*0b57cec5SDimitry Andric       const GlobalValue *GV = ImmOp.getGlobal();
644*0b57cec5SDimitry Andric       MIB.addGlobalAddress(GV, UseMI->getOperand(2).getImm()+ImmOp.getOffset(),
645*0b57cec5SDimitry Andric                            ImmOp.getTargetFlags());
646*0b57cec5SDimitry Andric       OpStart = 3;
647*0b57cec5SDimitry Andric     } else if (UseMID.mayStore()) {
648*0b57cec5SDimitry Andric       MIB.add(AddAslMI->getOperand(2));
649*0b57cec5SDimitry Andric       MIB.add(AddAslMI->getOperand(3));
650*0b57cec5SDimitry Andric       const GlobalValue *GV = ImmOp.getGlobal();
651*0b57cec5SDimitry Andric       MIB.addGlobalAddress(GV, UseMI->getOperand(1).getImm()+ImmOp.getOffset(),
652*0b57cec5SDimitry Andric                            ImmOp.getTargetFlags());
653*0b57cec5SDimitry Andric       MIB.add(UseMI->getOperand(2));
654*0b57cec5SDimitry Andric       OpStart = 3;
655*0b57cec5SDimitry Andric     } else
656*0b57cec5SDimitry Andric       llvm_unreachable("Unhandled instruction");
657*0b57cec5SDimitry Andric 
658*0b57cec5SDimitry Andric     for (unsigned i = OpStart; i < OpEnd; ++i)
659*0b57cec5SDimitry Andric       MIB.add(UseMI->getOperand(i));
660*0b57cec5SDimitry Andric 
661*0b57cec5SDimitry Andric     Deleted.insert(UseMI);
662*0b57cec5SDimitry Andric   }
663*0b57cec5SDimitry Andric 
664*0b57cec5SDimitry Andric   return true;
665*0b57cec5SDimitry Andric }
666*0b57cec5SDimitry Andric 
667*0b57cec5SDimitry Andric bool HexagonOptAddrMode::xformUseMI(MachineInstr *TfrMI, MachineInstr *UseMI,
668*0b57cec5SDimitry Andric                                     NodeAddr<UseNode *> UseN,
669*0b57cec5SDimitry Andric                                     unsigned UseMOnum) {
670*0b57cec5SDimitry Andric   const MachineOperand ImmOp = TfrMI->getOperand(1);
671*0b57cec5SDimitry Andric   const MCInstrDesc &MID = UseMI->getDesc();
672*0b57cec5SDimitry Andric   unsigned Changed = false;
673*0b57cec5SDimitry Andric   if (MID.mayLoad())
674*0b57cec5SDimitry Andric     Changed = changeLoad(UseMI, ImmOp, UseMOnum);
675*0b57cec5SDimitry Andric   else if (MID.mayStore())
676*0b57cec5SDimitry Andric     Changed = changeStore(UseMI, ImmOp, UseMOnum);
677*0b57cec5SDimitry Andric   else if (UseMI->getOpcode() == Hexagon::S2_addasl_rrri)
678*0b57cec5SDimitry Andric     Changed = changeAddAsl(UseN, UseMI, ImmOp, UseMOnum);
679*0b57cec5SDimitry Andric 
680*0b57cec5SDimitry Andric   if (Changed)
681*0b57cec5SDimitry Andric     Deleted.insert(UseMI);
682*0b57cec5SDimitry Andric 
683*0b57cec5SDimitry Andric   return Changed;
684*0b57cec5SDimitry Andric }
685*0b57cec5SDimitry Andric 
686*0b57cec5SDimitry Andric bool HexagonOptAddrMode::processBlock(NodeAddr<BlockNode *> BA) {
687*0b57cec5SDimitry Andric   bool Changed = false;
688*0b57cec5SDimitry Andric 
689*0b57cec5SDimitry Andric   for (auto IA : BA.Addr->members(*DFG)) {
690*0b57cec5SDimitry Andric     if (!DFG->IsCode<NodeAttrs::Stmt>(IA))
691*0b57cec5SDimitry Andric       continue;
692*0b57cec5SDimitry Andric 
693*0b57cec5SDimitry Andric     NodeAddr<StmtNode *> SA = IA;
694*0b57cec5SDimitry Andric     MachineInstr *MI = SA.Addr->getCode();
695*0b57cec5SDimitry Andric     if ((MI->getOpcode() != Hexagon::A2_tfrsi ||
696*0b57cec5SDimitry Andric          !MI->getOperand(1).isGlobal()) &&
697*0b57cec5SDimitry Andric         (MI->getOpcode() != Hexagon::A2_addi ||
698*0b57cec5SDimitry Andric          !MI->getOperand(2).isImm() || HII->isConstExtended(*MI)))
699*0b57cec5SDimitry Andric     continue;
700*0b57cec5SDimitry Andric 
701*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[Analyzing " << HII->getName(MI->getOpcode())
702*0b57cec5SDimitry Andric                       << "]: " << *MI << "\n\t[InstrNode]: "
703*0b57cec5SDimitry Andric                       << Print<NodeAddr<InstrNode *>>(IA, *DFG) << '\n');
704*0b57cec5SDimitry Andric 
705*0b57cec5SDimitry Andric     NodeList UNodeList;
706*0b57cec5SDimitry Andric     getAllRealUses(SA, UNodeList);
707*0b57cec5SDimitry Andric 
708*0b57cec5SDimitry Andric     if (!allValidCandidates(SA, UNodeList))
709*0b57cec5SDimitry Andric       continue;
710*0b57cec5SDimitry Andric 
711*0b57cec5SDimitry Andric     // Analyze all uses of 'add'. If the output of 'add' is used as an address
712*0b57cec5SDimitry Andric     // in the base+immediate addressing mode load/store instructions, see if
713*0b57cec5SDimitry Andric     // they can be updated to use the immediate value as an offet. Thus,
714*0b57cec5SDimitry Andric     // providing us the opportunity to eliminate 'add'.
715*0b57cec5SDimitry Andric     // Ex: Rx= add(Rt,#12)
716*0b57cec5SDimitry Andric     //     memw(Rx+#0) = Rs
717*0b57cec5SDimitry Andric     // This can be replaced with memw(Rt+#12) = Rs
718*0b57cec5SDimitry Andric     //
719*0b57cec5SDimitry Andric     // This transformation is only performed if all uses can be updated and
720*0b57cec5SDimitry Andric     // the offset isn't required to be constant extended.
721*0b57cec5SDimitry Andric     if (MI->getOpcode() == Hexagon::A2_addi) {
722*0b57cec5SDimitry Andric       Changed |= processAddUses(SA, MI, UNodeList);
723*0b57cec5SDimitry Andric       continue;
724*0b57cec5SDimitry Andric     }
725*0b57cec5SDimitry Andric 
726*0b57cec5SDimitry Andric     short SizeInc = 0;
727*0b57cec5SDimitry Andric     unsigned DefR = MI->getOperand(0).getReg();
728*0b57cec5SDimitry Andric     InstrEvalMap InstrEvalResult;
729*0b57cec5SDimitry Andric 
730*0b57cec5SDimitry Andric     // Analyze all uses and calculate increase in size. Perform the optimization
731*0b57cec5SDimitry Andric     // only if there is no increase in size.
732*0b57cec5SDimitry Andric     if (!analyzeUses(DefR, UNodeList, InstrEvalResult, SizeInc))
733*0b57cec5SDimitry Andric       continue;
734*0b57cec5SDimitry Andric     if (SizeInc > CodeGrowthLimit)
735*0b57cec5SDimitry Andric       continue;
736*0b57cec5SDimitry Andric 
737*0b57cec5SDimitry Andric     bool KeepTfr = false;
738*0b57cec5SDimitry Andric 
739*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\t[Total reached uses] : " << UNodeList.size()
740*0b57cec5SDimitry Andric                       << "\n");
741*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\t[Processing Reached Uses] ===\n");
742*0b57cec5SDimitry Andric     for (auto I = UNodeList.rbegin(), E = UNodeList.rend(); I != E; ++I) {
743*0b57cec5SDimitry Andric       NodeAddr<UseNode *> UseN = *I;
744*0b57cec5SDimitry Andric       assert(!(UseN.Addr->getFlags() & NodeAttrs::PhiRef) &&
745*0b57cec5SDimitry Andric              "Found a PhiRef node as a real reached use!!");
746*0b57cec5SDimitry Andric 
747*0b57cec5SDimitry Andric       NodeAddr<StmtNode *> OwnerN = UseN.Addr->getOwner(*DFG);
748*0b57cec5SDimitry Andric       MachineInstr *UseMI = OwnerN.Addr->getCode();
749*0b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\t[MI <" << printMBBReference(*UseMI->getParent())
750*0b57cec5SDimitry Andric                         << ">]: " << *UseMI << "\n");
751*0b57cec5SDimitry Andric 
752*0b57cec5SDimitry Andric       int UseMOnum = -1;
753*0b57cec5SDimitry Andric       unsigned NumOperands = UseMI->getNumOperands();
754*0b57cec5SDimitry Andric       for (unsigned j = 0; j < NumOperands - 1; ++j) {
755*0b57cec5SDimitry Andric         const MachineOperand &op = UseMI->getOperand(j);
756*0b57cec5SDimitry Andric         if (op.isReg() && op.isUse() && DefR == op.getReg())
757*0b57cec5SDimitry Andric           UseMOnum = j;
758*0b57cec5SDimitry Andric       }
759*0b57cec5SDimitry Andric       // It is possible that the register will not be found in any operand.
760*0b57cec5SDimitry Andric       // This could happen, for example, when DefR = R4, but the used
761*0b57cec5SDimitry Andric       // register is D2.
762*0b57cec5SDimitry Andric 
763*0b57cec5SDimitry Andric       // Change UseMI if replacement is possible. If any replacement failed,
764*0b57cec5SDimitry Andric       // or wasn't attempted, make sure to keep the TFR.
765*0b57cec5SDimitry Andric       bool Xformed = false;
766*0b57cec5SDimitry Andric       if (UseMOnum >= 0 && InstrEvalResult[UseMI])
767*0b57cec5SDimitry Andric         Xformed = xformUseMI(MI, UseMI, UseN, UseMOnum);
768*0b57cec5SDimitry Andric       Changed |=  Xformed;
769*0b57cec5SDimitry Andric       KeepTfr |= !Xformed;
770*0b57cec5SDimitry Andric     }
771*0b57cec5SDimitry Andric     if (!KeepTfr)
772*0b57cec5SDimitry Andric       Deleted.insert(MI);
773*0b57cec5SDimitry Andric   }
774*0b57cec5SDimitry Andric   return Changed;
775*0b57cec5SDimitry Andric }
776*0b57cec5SDimitry Andric 
777*0b57cec5SDimitry Andric bool HexagonOptAddrMode::runOnMachineFunction(MachineFunction &MF) {
778*0b57cec5SDimitry Andric   if (skipFunction(MF.getFunction()))
779*0b57cec5SDimitry Andric     return false;
780*0b57cec5SDimitry Andric 
781*0b57cec5SDimitry Andric   bool Changed = false;
782*0b57cec5SDimitry Andric   auto &HST = MF.getSubtarget<HexagonSubtarget>();
783*0b57cec5SDimitry Andric   MRI = &MF.getRegInfo();
784*0b57cec5SDimitry Andric   HII = HST.getInstrInfo();
785*0b57cec5SDimitry Andric   HRI = HST.getRegisterInfo();
786*0b57cec5SDimitry Andric   const auto &MDF = getAnalysis<MachineDominanceFrontier>();
787*0b57cec5SDimitry Andric   MDT = &getAnalysis<MachineDominatorTree>();
788*0b57cec5SDimitry Andric   const TargetOperandInfo TOI(*HII);
789*0b57cec5SDimitry Andric 
790*0b57cec5SDimitry Andric   DataFlowGraph G(MF, *HII, *HRI, *MDT, MDF, TOI);
791*0b57cec5SDimitry Andric   // Need to keep dead phis because we can propagate uses of registers into
792*0b57cec5SDimitry Andric   // nodes dominated by those would-be phis.
793*0b57cec5SDimitry Andric   G.build(BuildOptions::KeepDeadPhis);
794*0b57cec5SDimitry Andric   DFG = &G;
795*0b57cec5SDimitry Andric 
796*0b57cec5SDimitry Andric   Liveness L(*MRI, *DFG);
797*0b57cec5SDimitry Andric   L.computePhiInfo();
798*0b57cec5SDimitry Andric   LV = &L;
799*0b57cec5SDimitry Andric 
800*0b57cec5SDimitry Andric   Deleted.clear();
801*0b57cec5SDimitry Andric   NodeAddr<FuncNode *> FA = DFG->getFunc();
802*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "==== [RefMap#]=====:\n "
803*0b57cec5SDimitry Andric                     << Print<NodeAddr<FuncNode *>>(FA, *DFG) << "\n");
804*0b57cec5SDimitry Andric 
805*0b57cec5SDimitry Andric   for (NodeAddr<BlockNode *> BA : FA.Addr->members(*DFG))
806*0b57cec5SDimitry Andric     Changed |= processBlock(BA);
807*0b57cec5SDimitry Andric 
808*0b57cec5SDimitry Andric   for (auto MI : Deleted)
809*0b57cec5SDimitry Andric     MI->eraseFromParent();
810*0b57cec5SDimitry Andric 
811*0b57cec5SDimitry Andric   if (Changed) {
812*0b57cec5SDimitry Andric     G.build();
813*0b57cec5SDimitry Andric     L.computeLiveIns();
814*0b57cec5SDimitry Andric     L.resetLiveIns();
815*0b57cec5SDimitry Andric     L.resetKills();
816*0b57cec5SDimitry Andric   }
817*0b57cec5SDimitry Andric 
818*0b57cec5SDimitry Andric   return Changed;
819*0b57cec5SDimitry Andric }
820*0b57cec5SDimitry Andric 
821*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
822*0b57cec5SDimitry Andric //                         Public Constructor Functions
823*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
824*0b57cec5SDimitry Andric 
825*0b57cec5SDimitry Andric FunctionPass *llvm::createHexagonOptAddrMode() {
826*0b57cec5SDimitry Andric   return new HexagonOptAddrMode();
827*0b57cec5SDimitry Andric }
828