xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/ARC/ARCOptAddrMode.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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