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