10b57cec5SDimitry Andric //===- ARCOptAddrMode.cpp ---------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric /// \file 100b57cec5SDimitry Andric /// This pass folds LD/ST + ADD pairs into Pre/Post-increment form of 110b57cec5SDimitry Andric /// load/store instructions. 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "ARC.h" 150b57cec5SDimitry Andric #define GET_INSTRMAP_INFO 160b57cec5SDimitry Andric #include "ARCInstrInfo.h" 170b57cec5SDimitry Andric #include "ARCTargetMachine.h" 180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h" 190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineDominators.h" 200b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 210b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 220b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 230b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 240b57cec5SDimitry Andric #include "llvm/IR/Function.h" 25480093f4SDimitry Andric #include "llvm/InitializePasses.h" 26349cc55cSDimitry Andric #include "llvm/Support/CommandLine.h" 270b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 280b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric using namespace llvm; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric #define OPTADDRMODE_DESC "ARC load/store address mode" 330b57cec5SDimitry Andric #define OPTADDRMODE_NAME "arc-addr-mode" 340b57cec5SDimitry Andric #define DEBUG_TYPE "arc-addr-mode" 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric namespace llvm { 37349cc55cSDimitry Andric 38349cc55cSDimitry Andric static cl::opt<unsigned> ArcKillAddrMode("arc-kill-addr-mode", cl::init(0), 3981ad6265SDimitry Andric cl::ReallyHidden); 40349cc55cSDimitry Andric 41349cc55cSDimitry Andric #define DUMP_BEFORE() ((ArcKillAddrMode & 0x0001) != 0) 42349cc55cSDimitry Andric #define DUMP_AFTER() ((ArcKillAddrMode & 0x0002) != 0) 43349cc55cSDimitry Andric #define VIEW_BEFORE() ((ArcKillAddrMode & 0x0004) != 0) 44349cc55cSDimitry Andric #define VIEW_AFTER() ((ArcKillAddrMode & 0x0008) != 0) 45349cc55cSDimitry Andric #define KILL_PASS() ((ArcKillAddrMode & 0x0010) != 0) 46349cc55cSDimitry Andric 470b57cec5SDimitry Andric FunctionPass *createARCOptAddrMode(); 480b57cec5SDimitry Andric void initializeARCOptAddrModePass(PassRegistry &); 490b57cec5SDimitry Andric } // end namespace llvm 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric namespace { 520b57cec5SDimitry Andric class ARCOptAddrMode : public MachineFunctionPass { 530b57cec5SDimitry Andric public: 540b57cec5SDimitry Andric static char ID; 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric ARCOptAddrMode() : MachineFunctionPass(ID) {} 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric StringRef getPassName() const override { return OPTADDRMODE_DESC; } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 610b57cec5SDimitry Andric AU.setPreservesCFG(); 620b57cec5SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 63*0fca6ea1SDimitry Andric AU.addRequired<MachineDominatorTreeWrapperPass>(); 64*0fca6ea1SDimitry Andric AU.addPreserved<MachineDominatorTreeWrapperPass>(); 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric private: 700b57cec5SDimitry Andric const ARCSubtarget *AST = nullptr; 710b57cec5SDimitry Andric const ARCInstrInfo *AII = nullptr; 720b57cec5SDimitry Andric MachineRegisterInfo *MRI = nullptr; 730b57cec5SDimitry Andric MachineDominatorTree *MDT = nullptr; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric // Tries to combine \p Ldst with increment of its base register to form 760b57cec5SDimitry Andric // single post-increment instruction. 770b57cec5SDimitry Andric MachineInstr *tryToCombine(MachineInstr &Ldst); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric // Returns true if result of \p Add is not used before \p Ldst 800b57cec5SDimitry Andric bool noUseOfAddBeforeLoadOrStore(const MachineInstr *Add, 810b57cec5SDimitry Andric const MachineInstr *Ldst); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // Returns true if load/store instruction \p Ldst can be hoisted up to 840b57cec5SDimitry Andric // instruction \p To 850b57cec5SDimitry Andric bool canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To); 860b57cec5SDimitry Andric 87349cc55cSDimitry Andric // // Returns true if load/store instruction \p Ldst can be sunk down 88349cc55cSDimitry Andric // // to instruction \p To 89349cc55cSDimitry Andric // bool canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric // Check if instructions \p Ldst and \p Add can be moved to become adjacent 920b57cec5SDimitry Andric // If they can return instruction which need not to move. 930b57cec5SDimitry Andric // If \p Uses is not null, fill it with instructions after \p Ldst which use 940b57cec5SDimitry Andric // \p Ldst's base register 950b57cec5SDimitry Andric MachineInstr *canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add, 960b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> *Uses); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // Returns true if all instruction in \p Uses array can be adjusted 990b57cec5SDimitry Andric // to accomodate increment of register \p BaseReg by \p Incr 1000b57cec5SDimitry Andric bool canFixPastUses(const ArrayRef<MachineInstr *> &Uses, 1010b57cec5SDimitry Andric MachineOperand &Incr, unsigned BaseReg); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric // Update all instructions in \p Uses to accomodate increment 1040b57cec5SDimitry Andric // of \p BaseReg by \p Offset 1050b57cec5SDimitry Andric void fixPastUses(ArrayRef<MachineInstr *> Uses, unsigned BaseReg, 1060b57cec5SDimitry Andric int64_t Offset); 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // Change instruction \p Ldst to postincrement form. 1090b57cec5SDimitry Andric // \p NewBase is register to hold update base value 1100b57cec5SDimitry Andric // \p NewOffset is instruction's new offset 1110b57cec5SDimitry Andric void changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode, 1120b57cec5SDimitry Andric unsigned NewBase, MachineOperand &NewOffset); 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric bool processBasicBlock(MachineBasicBlock &MBB); 1150b57cec5SDimitry Andric }; 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric } // end anonymous namespace 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric char ARCOptAddrMode::ID = 0; 1200b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false, 1210b57cec5SDimitry Andric false) 122*0fca6ea1SDimitry Andric INITIALIZE_PASS_DEPENDENCY(MachineDominatorTreeWrapperPass) 1230b57cec5SDimitry Andric INITIALIZE_PASS_END(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false, 1240b57cec5SDimitry Andric false) 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric // Return true if \p Off can be used as immediate offset 1270b57cec5SDimitry Andric // operand of load/store instruction (S9 literal) 1280b57cec5SDimitry Andric static bool isValidLoadStoreOffset(int64_t Off) { return isInt<9>(Off); } 1290b57cec5SDimitry Andric 1300b57cec5SDimitry Andric // Return true if \p Off can be used as immediate operand of 1310b57cec5SDimitry Andric // ADD/SUB instruction (U6 literal) 1320b57cec5SDimitry Andric static bool isValidIncrementOffset(int64_t Off) { return isUInt<6>(Off); } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric static bool isAddConstantOp(const MachineInstr &MI, int64_t &Amount) { 1350b57cec5SDimitry Andric int64_t Sign = 1; 1360b57cec5SDimitry Andric switch (MI.getOpcode()) { 1370b57cec5SDimitry Andric case ARC::SUB_rru6: 1380b57cec5SDimitry Andric Sign = -1; 139bdd1243dSDimitry Andric [[fallthrough]]; 1400b57cec5SDimitry Andric case ARC::ADD_rru6: 1410b57cec5SDimitry Andric assert(MI.getOperand(2).isImm() && "Expected immediate operand"); 1420b57cec5SDimitry Andric Amount = Sign * MI.getOperand(2).getImm(); 1430b57cec5SDimitry Andric return true; 1440b57cec5SDimitry Andric default: 1450b57cec5SDimitry Andric return false; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // Return true if \p MI dominates of uses of virtual register \p VReg 1500b57cec5SDimitry Andric static bool dominatesAllUsesOf(const MachineInstr *MI, unsigned VReg, 1510b57cec5SDimitry Andric MachineDominatorTree *MDT, 1520b57cec5SDimitry Andric MachineRegisterInfo *MRI) { 1530b57cec5SDimitry Andric 1548bcb0991SDimitry Andric assert(Register::isVirtualRegister(VReg) && "Expected virtual register!"); 1550b57cec5SDimitry Andric 15606c3fb27SDimitry Andric for (const MachineOperand &Use : MRI->use_nodbg_operands(VReg)) { 15706c3fb27SDimitry Andric const MachineInstr *User = Use.getParent(); 1580b57cec5SDimitry Andric if (User->isPHI()) { 15906c3fb27SDimitry Andric unsigned BBOperandIdx = Use.getOperandNo() + 1; 1600b57cec5SDimitry Andric MachineBasicBlock *MBB = User->getOperand(BBOperandIdx).getMBB(); 1610b57cec5SDimitry Andric if (MBB->empty()) { 1620b57cec5SDimitry Andric const MachineBasicBlock *InstBB = MI->getParent(); 1630b57cec5SDimitry Andric assert(InstBB != MBB && "Instruction found in empty MBB"); 1640b57cec5SDimitry Andric if (!MDT->dominates(InstBB, MBB)) 1650b57cec5SDimitry Andric return false; 1660b57cec5SDimitry Andric continue; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric User = &*MBB->rbegin(); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric if (!MDT->dominates(MI, User)) 1720b57cec5SDimitry Andric return false; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric return true; 1750b57cec5SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric // Return true if \p MI is load/store instruction with immediate offset 1780b57cec5SDimitry Andric // which can be adjusted by \p Disp 1790b57cec5SDimitry Andric static bool isLoadStoreThatCanHandleDisplacement(const TargetInstrInfo *TII, 1800b57cec5SDimitry Andric const MachineInstr &MI, 1810b57cec5SDimitry Andric int64_t Disp) { 1820b57cec5SDimitry Andric unsigned BasePos, OffPos; 1830b57cec5SDimitry Andric if (!TII->getBaseAndOffsetPosition(MI, BasePos, OffPos)) 1840b57cec5SDimitry Andric return false; 1850b57cec5SDimitry Andric const MachineOperand &MO = MI.getOperand(OffPos); 1860b57cec5SDimitry Andric if (!MO.isImm()) 1870b57cec5SDimitry Andric return false; 1880b57cec5SDimitry Andric int64_t Offset = MO.getImm() + Disp; 1890b57cec5SDimitry Andric return isValidLoadStoreOffset(Offset); 1900b57cec5SDimitry Andric } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric bool ARCOptAddrMode::noUseOfAddBeforeLoadOrStore(const MachineInstr *Add, 1930b57cec5SDimitry Andric const MachineInstr *Ldst) { 1948bcb0991SDimitry Andric Register R = Add->getOperand(0).getReg(); 1950b57cec5SDimitry Andric return dominatesAllUsesOf(Ldst, R, MDT, MRI); 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric MachineInstr *ARCOptAddrMode::tryToCombine(MachineInstr &Ldst) { 199480093f4SDimitry Andric assert(Ldst.mayLoadOrStore() && "LD/ST instruction expected"); 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric unsigned BasePos, OffsetPos; 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[ABAW] tryToCombine " << Ldst); 2040b57cec5SDimitry Andric if (!AII->getBaseAndOffsetPosition(Ldst, BasePos, OffsetPos)) { 2050b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[ABAW] Not a recognized load/store\n"); 2060b57cec5SDimitry Andric return nullptr; 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric MachineOperand &Base = Ldst.getOperand(BasePos); 2100b57cec5SDimitry Andric MachineOperand &Offset = Ldst.getOperand(OffsetPos); 2110b57cec5SDimitry Andric 2120b57cec5SDimitry Andric assert(Base.isReg() && "Base operand must be register"); 2130b57cec5SDimitry Andric if (!Offset.isImm()) { 2140b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[ABAW] Offset is not immediate\n"); 2150b57cec5SDimitry Andric return nullptr; 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 2188bcb0991SDimitry Andric Register B = Base.getReg(); 2198bcb0991SDimitry Andric if (Register::isStackSlot(B) || !Register::isVirtualRegister(B)) { 2200b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[ABAW] Base is not VReg\n"); 2210b57cec5SDimitry Andric return nullptr; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric // TODO: try to generate address preincrement 2250b57cec5SDimitry Andric if (Offset.getImm() != 0) { 2260b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[ABAW] Non-zero offset\n"); 2270b57cec5SDimitry Andric return nullptr; 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric for (auto &Add : MRI->use_nodbg_instructions(B)) { 2310b57cec5SDimitry Andric int64_t Incr; 2320b57cec5SDimitry Andric if (!isAddConstantOp(Add, Incr)) 2330b57cec5SDimitry Andric continue; 2340b57cec5SDimitry Andric if (!isValidLoadStoreOffset(Incr)) 2350b57cec5SDimitry Andric continue; 2360b57cec5SDimitry Andric 2370b57cec5SDimitry Andric SmallVector<MachineInstr *, 8> Uses; 2380b57cec5SDimitry Andric MachineInstr *MoveTo = canJoinInstructions(&Ldst, &Add, &Uses); 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric if (!MoveTo) 2410b57cec5SDimitry Andric continue; 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric if (!canFixPastUses(Uses, Add.getOperand(2), B)) 2440b57cec5SDimitry Andric continue; 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric LLVM_DEBUG(MachineInstr *First = &Ldst; MachineInstr *Last = &Add; 2470b57cec5SDimitry Andric if (MDT->dominates(Last, First)) std::swap(First, Last); 2480b57cec5SDimitry Andric dbgs() << "[ABAW] Instructions " << *First << " and " << *Last 2490b57cec5SDimitry Andric << " combined\n"; 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric ); 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric MachineInstr *Result = Ldst.getNextNode(); 2540b57cec5SDimitry Andric if (MoveTo == &Add) { 2550b57cec5SDimitry Andric Ldst.removeFromParent(); 2560b57cec5SDimitry Andric Add.getParent()->insertAfter(Add.getIterator(), &Ldst); 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric if (Result == &Add) 2590b57cec5SDimitry Andric Result = Result->getNextNode(); 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric fixPastUses(Uses, B, Incr); 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric int NewOpcode = ARC::getPostIncOpcode(Ldst.getOpcode()); 2640b57cec5SDimitry Andric assert(NewOpcode > 0 && "No postincrement form found"); 2650b57cec5SDimitry Andric unsigned NewBaseReg = Add.getOperand(0).getReg(); 2660b57cec5SDimitry Andric changeToAddrMode(Ldst, NewOpcode, NewBaseReg, Add.getOperand(2)); 2670b57cec5SDimitry Andric Add.eraseFromParent(); 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric return Result; 2700b57cec5SDimitry Andric } 2710b57cec5SDimitry Andric return nullptr; 2720b57cec5SDimitry Andric } 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric MachineInstr * 2750b57cec5SDimitry Andric ARCOptAddrMode::canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add, 2760b57cec5SDimitry Andric SmallVectorImpl<MachineInstr *> *Uses) { 2770b57cec5SDimitry Andric assert(Ldst && Add && "NULL instruction passed"); 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric MachineInstr *First = Add; 2800b57cec5SDimitry Andric MachineInstr *Last = Ldst; 2810b57cec5SDimitry Andric if (MDT->dominates(Ldst, Add)) 2820b57cec5SDimitry Andric std::swap(First, Last); 2830b57cec5SDimitry Andric else if (!MDT->dominates(Add, Ldst)) 2840b57cec5SDimitry Andric return nullptr; 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "canJoinInstructions: " << *First << *Last); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric unsigned BasePos, OffPos; 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric if (!AII->getBaseAndOffsetPosition(*Ldst, BasePos, OffPos)) { 2910b57cec5SDimitry Andric LLVM_DEBUG( 2920b57cec5SDimitry Andric dbgs() 2930b57cec5SDimitry Andric << "[canJoinInstructions] Cannot determine base/offset position\n"); 2940b57cec5SDimitry Andric return nullptr; 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2978bcb0991SDimitry Andric Register BaseReg = Ldst->getOperand(BasePos).getReg(); 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric // prohibit this: 3000b57cec5SDimitry Andric // v1 = add v0, c 3010b57cec5SDimitry Andric // st v1, [v0, 0] 3020b57cec5SDimitry Andric // and this 3030b57cec5SDimitry Andric // st v0, [v0, 0] 3040b57cec5SDimitry Andric // v1 = add v0, c 3050b57cec5SDimitry Andric if (Ldst->mayStore() && Ldst->getOperand(0).isReg()) { 3068bcb0991SDimitry Andric Register StReg = Ldst->getOperand(0).getReg(); 3070b57cec5SDimitry Andric if (Add->getOperand(0).getReg() == StReg || BaseReg == StReg) { 3080b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[canJoinInstructions] Store uses result of Add\n"); 3090b57cec5SDimitry Andric return nullptr; 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric 3130b57cec5SDimitry Andric SmallVector<MachineInstr *, 4> UsesAfterLdst; 3140b57cec5SDimitry Andric SmallVector<MachineInstr *, 4> UsesAfterAdd; 3150b57cec5SDimitry Andric for (MachineInstr &MI : MRI->use_nodbg_instructions(BaseReg)) { 3160b57cec5SDimitry Andric if (&MI == Ldst || &MI == Add) 3170b57cec5SDimitry Andric continue; 3180b57cec5SDimitry Andric if (&MI != Add && MDT->dominates(Ldst, &MI)) 3190b57cec5SDimitry Andric UsesAfterLdst.push_back(&MI); 3200b57cec5SDimitry Andric else if (!MDT->dominates(&MI, Ldst)) 3210b57cec5SDimitry Andric return nullptr; 3220b57cec5SDimitry Andric if (MDT->dominates(Add, &MI)) 3230b57cec5SDimitry Andric UsesAfterAdd.push_back(&MI); 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric 3260b57cec5SDimitry Andric MachineInstr *Result = nullptr; 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric if (First == Add) { 3290b57cec5SDimitry Andric // n = add b, i 3300b57cec5SDimitry Andric // ... 3310b57cec5SDimitry Andric // x = ld [b, o] or x = ld [n, o] 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric if (noUseOfAddBeforeLoadOrStore(First, Last)) { 3340b57cec5SDimitry Andric Result = Last; 3350b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can sink Add down to Ldst\n"); 3360b57cec5SDimitry Andric } else if (canHoistLoadStoreTo(Ldst, Add)) { 3370b57cec5SDimitry Andric Result = First; 3380b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Ldst to Add\n"); 3390b57cec5SDimitry Andric } 3400b57cec5SDimitry Andric } else { 3410b57cec5SDimitry Andric // x = ld [b, o] 3420b57cec5SDimitry Andric // ... 3430b57cec5SDimitry Andric // n = add b, i 3440b57cec5SDimitry Andric Result = First; 3450b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Add to Ldst\n"); 3460b57cec5SDimitry Andric } 3470b57cec5SDimitry Andric if (Result && Uses) 3480b57cec5SDimitry Andric *Uses = (Result == Ldst) ? UsesAfterLdst : UsesAfterAdd; 3490b57cec5SDimitry Andric return Result; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric bool ARCOptAddrMode::canFixPastUses(const ArrayRef<MachineInstr *> &Uses, 3530b57cec5SDimitry Andric MachineOperand &Incr, unsigned BaseReg) { 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric assert(Incr.isImm() && "Expected immediate increment"); 3560b57cec5SDimitry Andric int64_t NewOffset = Incr.getImm(); 3570b57cec5SDimitry Andric for (MachineInstr *MI : Uses) { 3580b57cec5SDimitry Andric int64_t Dummy; 3590b57cec5SDimitry Andric if (isAddConstantOp(*MI, Dummy)) { 3600b57cec5SDimitry Andric if (isValidIncrementOffset(Dummy + NewOffset)) 3610b57cec5SDimitry Andric continue; 3620b57cec5SDimitry Andric return false; 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric if (isLoadStoreThatCanHandleDisplacement(AII, *MI, -NewOffset)) 3650b57cec5SDimitry Andric continue; 3660b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Instruction cannot handle displacement " << -NewOffset 3670b57cec5SDimitry Andric << ": " << *MI); 3680b57cec5SDimitry Andric return false; 3690b57cec5SDimitry Andric } 3700b57cec5SDimitry Andric return true; 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric void ARCOptAddrMode::fixPastUses(ArrayRef<MachineInstr *> Uses, 3740b57cec5SDimitry Andric unsigned NewBase, int64_t NewOffset) { 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric for (MachineInstr *MI : Uses) { 3770b57cec5SDimitry Andric int64_t Amount; 3780b57cec5SDimitry Andric unsigned BasePos, OffPos; 3790b57cec5SDimitry Andric if (isAddConstantOp(*MI, Amount)) { 3800b57cec5SDimitry Andric NewOffset += Amount; 3810b57cec5SDimitry Andric assert(isValidIncrementOffset(NewOffset) && 3820b57cec5SDimitry Andric "New offset won't fit into ADD instr"); 3830b57cec5SDimitry Andric BasePos = 1; 3840b57cec5SDimitry Andric OffPos = 2; 3850b57cec5SDimitry Andric } else if (AII->getBaseAndOffsetPosition(*MI, BasePos, OffPos)) { 3860b57cec5SDimitry Andric MachineOperand &MO = MI->getOperand(OffPos); 3870b57cec5SDimitry Andric assert(MO.isImm() && "expected immediate operand"); 3880b57cec5SDimitry Andric NewOffset += MO.getImm(); 3890b57cec5SDimitry Andric assert(isValidLoadStoreOffset(NewOffset) && 3900b57cec5SDimitry Andric "New offset won't fit into LD/ST"); 3910b57cec5SDimitry Andric } else 3920b57cec5SDimitry Andric llvm_unreachable("unexpected instruction"); 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric MI->getOperand(BasePos).setReg(NewBase); 3950b57cec5SDimitry Andric MI->getOperand(OffPos).setImm(NewOffset); 3960b57cec5SDimitry Andric } 3970b57cec5SDimitry Andric } 3980b57cec5SDimitry Andric 3990b57cec5SDimitry Andric bool ARCOptAddrMode::canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) { 4000b57cec5SDimitry Andric if (Ldst->getParent() != To->getParent()) 4010b57cec5SDimitry Andric return false; 4020b57cec5SDimitry Andric MachineBasicBlock::const_iterator MI(To), ME(Ldst), 4030b57cec5SDimitry Andric End(Ldst->getParent()->end()); 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric bool IsStore = Ldst->mayStore(); 4060b57cec5SDimitry Andric for (; MI != ME && MI != End; ++MI) { 4070b57cec5SDimitry Andric if (MI->isDebugValue()) 4080b57cec5SDimitry Andric continue; 4090b57cec5SDimitry Andric if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() || 4100b57cec5SDimitry Andric MI->hasUnmodeledSideEffects()) 4110b57cec5SDimitry Andric return false; 4120b57cec5SDimitry Andric if (IsStore && MI->mayLoad()) 4130b57cec5SDimitry Andric return false; 4140b57cec5SDimitry Andric } 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric for (auto &O : Ldst->explicit_operands()) { 4170b57cec5SDimitry Andric if (!O.isReg() || !O.isUse()) 4180b57cec5SDimitry Andric continue; 4190b57cec5SDimitry Andric MachineInstr *OpDef = MRI->getVRegDef(O.getReg()); 4200b57cec5SDimitry Andric if (!OpDef || !MDT->dominates(OpDef, To)) 4210b57cec5SDimitry Andric return false; 4220b57cec5SDimitry Andric } 4230b57cec5SDimitry Andric return true; 4240b57cec5SDimitry Andric } 4250b57cec5SDimitry Andric 426349cc55cSDimitry Andric // bool ARCOptAddrMode::canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) { 427349cc55cSDimitry Andric // // Can only sink load/store within same BB 428349cc55cSDimitry Andric // if (Ldst->getParent() != To->getParent()) 429349cc55cSDimitry Andric // return false; 430349cc55cSDimitry Andric // MachineBasicBlock::const_iterator MI(Ldst), ME(To), 431349cc55cSDimitry Andric // End(Ldst->getParent()->end()); 4320b57cec5SDimitry Andric 433349cc55cSDimitry Andric // bool IsStore = Ldst->mayStore(); 434349cc55cSDimitry Andric // bool IsLoad = Ldst->mayLoad(); 4350b57cec5SDimitry Andric 436349cc55cSDimitry Andric // Register ValReg = IsLoad ? Ldst->getOperand(0).getReg() : Register(); 437349cc55cSDimitry Andric // for (; MI != ME && MI != End; ++MI) { 438349cc55cSDimitry Andric // if (MI->isDebugValue()) 439349cc55cSDimitry Andric // continue; 440349cc55cSDimitry Andric // if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() || 441349cc55cSDimitry Andric // MI->hasUnmodeledSideEffects()) 442349cc55cSDimitry Andric // return false; 443349cc55cSDimitry Andric // if (IsStore && MI->mayLoad()) 444349cc55cSDimitry Andric // return false; 445349cc55cSDimitry Andric // if (ValReg && MI->readsVirtualRegister(ValReg)) 446349cc55cSDimitry Andric // return false; 447349cc55cSDimitry Andric // } 448349cc55cSDimitry Andric // return true; 449349cc55cSDimitry Andric // } 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric void ARCOptAddrMode::changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode, 4520b57cec5SDimitry Andric unsigned NewBase, 4530b57cec5SDimitry Andric MachineOperand &NewOffset) { 4540b57cec5SDimitry Andric bool IsStore = Ldst.mayStore(); 4550b57cec5SDimitry Andric unsigned BasePos, OffPos; 4560b57cec5SDimitry Andric MachineOperand Src = MachineOperand::CreateImm(0xDEADBEEF); 4570b57cec5SDimitry Andric AII->getBaseAndOffsetPosition(Ldst, BasePos, OffPos); 4580b57cec5SDimitry Andric 4598bcb0991SDimitry Andric Register BaseReg = Ldst.getOperand(BasePos).getReg(); 4600b57cec5SDimitry Andric 46181ad6265SDimitry Andric Ldst.removeOperand(OffPos); 46281ad6265SDimitry Andric Ldst.removeOperand(BasePos); 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric if (IsStore) { 4650b57cec5SDimitry Andric Src = Ldst.getOperand(BasePos - 1); 46681ad6265SDimitry Andric Ldst.removeOperand(BasePos - 1); 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric Ldst.setDesc(AST->getInstrInfo()->get(NewOpcode)); 4700b57cec5SDimitry Andric Ldst.addOperand(MachineOperand::CreateReg(NewBase, true)); 4710b57cec5SDimitry Andric if (IsStore) 4720b57cec5SDimitry Andric Ldst.addOperand(Src); 4730b57cec5SDimitry Andric Ldst.addOperand(MachineOperand::CreateReg(BaseReg, false)); 4740b57cec5SDimitry Andric Ldst.addOperand(NewOffset); 4750b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[ABAW] New Ldst: " << Ldst); 4760b57cec5SDimitry Andric } 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric bool ARCOptAddrMode::processBasicBlock(MachineBasicBlock &MBB) { 4790b57cec5SDimitry Andric bool Changed = false; 4800b57cec5SDimitry Andric for (auto MI = MBB.begin(), ME = MBB.end(); MI != ME; ++MI) { 4810b57cec5SDimitry Andric if (MI->isDebugValue()) 4820b57cec5SDimitry Andric continue; 4830b57cec5SDimitry Andric if (!MI->mayLoad() && !MI->mayStore()) 4840b57cec5SDimitry Andric continue; 4850b57cec5SDimitry Andric if (ARC::getPostIncOpcode(MI->getOpcode()) < 0) 4860b57cec5SDimitry Andric continue; 4870b57cec5SDimitry Andric MachineInstr *Res = tryToCombine(*MI); 4880b57cec5SDimitry Andric if (Res) { 4890b57cec5SDimitry Andric Changed = true; 4900b57cec5SDimitry Andric // Res points to the next instruction. Rewind to process it 4910b57cec5SDimitry Andric MI = std::prev(Res->getIterator()); 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric return Changed; 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric bool ARCOptAddrMode::runOnMachineFunction(MachineFunction &MF) { 498349cc55cSDimitry Andric if (skipFunction(MF.getFunction()) || KILL_PASS()) 4990b57cec5SDimitry Andric return false; 5000b57cec5SDimitry Andric 501349cc55cSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 502349cc55cSDimitry Andric if (DUMP_BEFORE()) 503349cc55cSDimitry Andric MF.dump(); 504349cc55cSDimitry Andric #endif 505349cc55cSDimitry Andric if (VIEW_BEFORE()) 506349cc55cSDimitry Andric MF.viewCFG(); 507349cc55cSDimitry Andric 5080b57cec5SDimitry Andric AST = &MF.getSubtarget<ARCSubtarget>(); 5090b57cec5SDimitry Andric AII = AST->getInstrInfo(); 5100b57cec5SDimitry Andric MRI = &MF.getRegInfo(); 511*0fca6ea1SDimitry Andric MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric bool Changed = false; 5140b57cec5SDimitry Andric for (auto &MBB : MF) 5150b57cec5SDimitry Andric Changed |= processBasicBlock(MBB); 516349cc55cSDimitry Andric 517349cc55cSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 518349cc55cSDimitry Andric if (DUMP_AFTER()) 519349cc55cSDimitry Andric MF.dump(); 520349cc55cSDimitry Andric #endif 521349cc55cSDimitry Andric if (VIEW_AFTER()) 522349cc55cSDimitry Andric MF.viewCFG(); 5230b57cec5SDimitry Andric return Changed; 5240b57cec5SDimitry Andric } 5250b57cec5SDimitry Andric 5260b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5270b57cec5SDimitry Andric // Public Constructor Functions 5280b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric FunctionPass *llvm::createARCOptAddrMode() { return new ARCOptAddrMode(); } 531