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