508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			508 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- ARCOptAddrMode.cpp ---------------------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| /// \file
 | |
| /// This pass folds LD/ST + ADD pairs into Pre/Post-increment form  of
 | |
| /// load/store instructions.
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "ARC.h"
 | |
| #define GET_INSTRMAP_INFO
 | |
| #include "ARCInstrInfo.h"
 | |
| #include "ARCTargetMachine.h"
 | |
| #include "llvm/CodeGen/MachineBasicBlock.h"
 | |
| #include "llvm/CodeGen/MachineDominators.h"
 | |
| #include "llvm/CodeGen/MachineFunctionPass.h"
 | |
| #include "llvm/CodeGen/MachineInstr.h"
 | |
| #include "llvm/CodeGen/MachineInstrBuilder.h"
 | |
| #include "llvm/CodeGen/TargetRegisterInfo.h"
 | |
| #include "llvm/IR/Function.h"
 | |
| #include "llvm/Support/Debug.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| #define OPTADDRMODE_DESC "ARC load/store address mode"
 | |
| #define OPTADDRMODE_NAME "arc-addr-mode"
 | |
| #define DEBUG_TYPE "arc-addr-mode"
 | |
| 
 | |
| namespace llvm {
 | |
| FunctionPass *createARCOptAddrMode();
 | |
| void initializeARCOptAddrModePass(PassRegistry &);
 | |
| } // end namespace llvm
 | |
| 
 | |
| namespace {
 | |
| class ARCOptAddrMode : public MachineFunctionPass {
 | |
| public:
 | |
|   static char ID;
 | |
| 
 | |
|   ARCOptAddrMode() : MachineFunctionPass(ID) {}
 | |
| 
 | |
|   StringRef getPassName() const override { return OPTADDRMODE_DESC; }
 | |
| 
 | |
|   void getAnalysisUsage(AnalysisUsage &AU) const override {
 | |
|     AU.setPreservesCFG();
 | |
|     MachineFunctionPass::getAnalysisUsage(AU);
 | |
|     AU.addRequired<MachineDominatorTree>();
 | |
|     AU.addPreserved<MachineDominatorTree>();
 | |
|   }
 | |
| 
 | |
|   bool runOnMachineFunction(MachineFunction &MF) override;
 | |
| 
 | |
| private:
 | |
|   const ARCSubtarget *AST = nullptr;
 | |
|   const ARCInstrInfo *AII = nullptr;
 | |
|   MachineRegisterInfo *MRI = nullptr;
 | |
|   MachineDominatorTree *MDT = nullptr;
 | |
| 
 | |
|   // Tries to combine \p Ldst with increment of its base register to form
 | |
|   // single post-increment instruction.
 | |
|   MachineInstr *tryToCombine(MachineInstr &Ldst);
 | |
| 
 | |
|   // Returns true if result of \p Add is not used before \p Ldst
 | |
|   bool noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
 | |
|                                    const MachineInstr *Ldst);
 | |
| 
 | |
|   // Returns true if load/store instruction \p Ldst can be hoisted up to
 | |
|   // instruction \p To
 | |
|   bool canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);
 | |
| 
 | |
|   // Returns true if load/store instruction \p Ldst can be sunk down
 | |
|   // to instruction \p To
 | |
|   bool canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To);
 | |
| 
 | |
|   // Check if instructions \p Ldst and \p Add can be moved to become adjacent
 | |
|   // If they can return instruction which need not to move.
 | |
|   // If \p Uses is not null, fill it with instructions after \p Ldst which use
 | |
|   // \p Ldst's base register
 | |
|   MachineInstr *canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
 | |
|                                     SmallVectorImpl<MachineInstr *> *Uses);
 | |
| 
 | |
|   // Returns true if all instruction in \p Uses array can be adjusted
 | |
|   // to accomodate increment of register \p BaseReg by \p Incr
 | |
|   bool canFixPastUses(const ArrayRef<MachineInstr *> &Uses,
 | |
|                       MachineOperand &Incr, unsigned BaseReg);
 | |
| 
 | |
|   // Update all instructions in \p Uses to accomodate increment
 | |
|   // of \p BaseReg by \p Offset
 | |
|   void fixPastUses(ArrayRef<MachineInstr *> Uses, unsigned BaseReg,
 | |
|                    int64_t Offset);
 | |
| 
 | |
|   // Change instruction \p Ldst to postincrement form.
 | |
|   // \p NewBase is register to hold update base value
 | |
|   // \p NewOffset is instruction's new offset
 | |
|   void changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
 | |
|                         unsigned NewBase, MachineOperand &NewOffset);
 | |
| 
 | |
|   bool processBasicBlock(MachineBasicBlock &MBB);
 | |
| };
 | |
| 
 | |
| } // end anonymous namespace
 | |
| 
 | |
| char ARCOptAddrMode::ID = 0;
 | |
| INITIALIZE_PASS_BEGIN(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,
 | |
|                       false)
 | |
| INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
 | |
| INITIALIZE_PASS_END(ARCOptAddrMode, OPTADDRMODE_NAME, OPTADDRMODE_DESC, false,
 | |
|                     false)
 | |
| 
 | |
| // Return true if \p Off can be used as immediate offset
 | |
| // operand of load/store instruction (S9 literal)
 | |
| static bool isValidLoadStoreOffset(int64_t Off) { return isInt<9>(Off); }
 | |
| 
 | |
| // Return true if \p Off can be used as immediate operand of
 | |
| // ADD/SUB instruction (U6 literal)
 | |
| static bool isValidIncrementOffset(int64_t Off) { return isUInt<6>(Off); }
 | |
| 
 | |
| static bool isAddConstantOp(const MachineInstr &MI, int64_t &Amount) {
 | |
|   int64_t Sign = 1;
 | |
|   switch (MI.getOpcode()) {
 | |
|   case ARC::SUB_rru6:
 | |
|     Sign = -1;
 | |
|     LLVM_FALLTHROUGH;
 | |
|   case ARC::ADD_rru6:
 | |
|     assert(MI.getOperand(2).isImm() && "Expected immediate operand");
 | |
|     Amount = Sign * MI.getOperand(2).getImm();
 | |
|     return true;
 | |
|   default:
 | |
|     return false;
 | |
|   }
 | |
| }
 | |
| 
 | |
| // Return true if \p MI dominates of uses of virtual register \p VReg
 | |
| static bool dominatesAllUsesOf(const MachineInstr *MI, unsigned VReg,
 | |
|                                MachineDominatorTree *MDT,
 | |
|                                MachineRegisterInfo *MRI) {
 | |
| 
 | |
|   assert(TargetRegisterInfo::isVirtualRegister(VReg) &&
 | |
|          "Expected virtual register!");
 | |
| 
 | |
|   for (auto it = MRI->use_nodbg_begin(VReg), end = MRI->use_nodbg_end();
 | |
|        it != end; ++it) {
 | |
|     MachineInstr *User = it->getParent();
 | |
|     if (User->isPHI()) {
 | |
|       unsigned BBOperandIdx = User->getOperandNo(&*it) + 1;
 | |
|       MachineBasicBlock *MBB = User->getOperand(BBOperandIdx).getMBB();
 | |
|       if (MBB->empty()) {
 | |
|         const MachineBasicBlock *InstBB = MI->getParent();
 | |
|         assert(InstBB != MBB && "Instruction found in empty MBB");
 | |
|         if (!MDT->dominates(InstBB, MBB))
 | |
|           return false;
 | |
|         continue;
 | |
|       }
 | |
|       User = &*MBB->rbegin();
 | |
|     }
 | |
| 
 | |
|     if (!MDT->dominates(MI, User))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // Return true if \p MI is load/store instruction with immediate offset
 | |
| // which can be adjusted by \p Disp
 | |
| static bool isLoadStoreThatCanHandleDisplacement(const TargetInstrInfo *TII,
 | |
|                                                  const MachineInstr &MI,
 | |
|                                                  int64_t Disp) {
 | |
|   unsigned BasePos, OffPos;
 | |
|   if (!TII->getBaseAndOffsetPosition(MI, BasePos, OffPos))
 | |
|     return false;
 | |
|   const MachineOperand &MO = MI.getOperand(OffPos);
 | |
|   if (!MO.isImm())
 | |
|     return false;
 | |
|   int64_t Offset = MO.getImm() + Disp;
 | |
|   return isValidLoadStoreOffset(Offset);
 | |
| }
 | |
| 
 | |
| bool ARCOptAddrMode::noUseOfAddBeforeLoadOrStore(const MachineInstr *Add,
 | |
|                                                  const MachineInstr *Ldst) {
 | |
|   unsigned R = Add->getOperand(0).getReg();
 | |
|   return dominatesAllUsesOf(Ldst, R, MDT, MRI);
 | |
| }
 | |
| 
 | |
| MachineInstr *ARCOptAddrMode::tryToCombine(MachineInstr &Ldst) {
 | |
|   assert((Ldst.mayLoad() || Ldst.mayStore()) && "LD/ST instruction expected");
 | |
| 
 | |
|   unsigned BasePos, OffsetPos;
 | |
| 
 | |
|   LLVM_DEBUG(dbgs() << "[ABAW] tryToCombine " << Ldst);
 | |
|   if (!AII->getBaseAndOffsetPosition(Ldst, BasePos, OffsetPos)) {
 | |
|     LLVM_DEBUG(dbgs() << "[ABAW] Not a recognized load/store\n");
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   MachineOperand &Base = Ldst.getOperand(BasePos);
 | |
|   MachineOperand &Offset = Ldst.getOperand(OffsetPos);
 | |
| 
 | |
|   assert(Base.isReg() && "Base operand must be register");
 | |
|   if (!Offset.isImm()) {
 | |
|     LLVM_DEBUG(dbgs() << "[ABAW] Offset is not immediate\n");
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   unsigned B = Base.getReg();
 | |
|   if (TargetRegisterInfo::isStackSlot(B) ||
 | |
|       !TargetRegisterInfo::isVirtualRegister(B)) {
 | |
|     LLVM_DEBUG(dbgs() << "[ABAW] Base is not VReg\n");
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   // TODO: try to generate address preincrement
 | |
|   if (Offset.getImm() != 0) {
 | |
|     LLVM_DEBUG(dbgs() << "[ABAW] Non-zero offset\n");
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   for (auto &Add : MRI->use_nodbg_instructions(B)) {
 | |
|     int64_t Incr;
 | |
|     if (!isAddConstantOp(Add, Incr))
 | |
|       continue;
 | |
|     if (!isValidLoadStoreOffset(Incr))
 | |
|       continue;
 | |
| 
 | |
|     SmallVector<MachineInstr *, 8> Uses;
 | |
|     MachineInstr *MoveTo = canJoinInstructions(&Ldst, &Add, &Uses);
 | |
| 
 | |
|     if (!MoveTo)
 | |
|       continue;
 | |
| 
 | |
|     if (!canFixPastUses(Uses, Add.getOperand(2), B))
 | |
|       continue;
 | |
| 
 | |
|     LLVM_DEBUG(MachineInstr *First = &Ldst; MachineInstr *Last = &Add;
 | |
|                if (MDT->dominates(Last, First)) std::swap(First, Last);
 | |
|                dbgs() << "[ABAW] Instructions " << *First << " and " << *Last
 | |
|                       << " combined\n";
 | |
| 
 | |
|     );
 | |
| 
 | |
|     MachineInstr *Result = Ldst.getNextNode();
 | |
|     if (MoveTo == &Add) {
 | |
|       Ldst.removeFromParent();
 | |
|       Add.getParent()->insertAfter(Add.getIterator(), &Ldst);
 | |
|     }
 | |
|     if (Result == &Add)
 | |
|       Result = Result->getNextNode();
 | |
| 
 | |
|     fixPastUses(Uses, B, Incr);
 | |
| 
 | |
|     int NewOpcode = ARC::getPostIncOpcode(Ldst.getOpcode());
 | |
|     assert(NewOpcode > 0 && "No postincrement form found");
 | |
|     unsigned NewBaseReg = Add.getOperand(0).getReg();
 | |
|     changeToAddrMode(Ldst, NewOpcode, NewBaseReg, Add.getOperand(2));
 | |
|     Add.eraseFromParent();
 | |
| 
 | |
|     return Result;
 | |
|   }
 | |
|   return nullptr;
 | |
| }
 | |
| 
 | |
| MachineInstr *
 | |
| ARCOptAddrMode::canJoinInstructions(MachineInstr *Ldst, MachineInstr *Add,
 | |
|                                     SmallVectorImpl<MachineInstr *> *Uses) {
 | |
|   assert(Ldst && Add && "NULL instruction passed");
 | |
| 
 | |
|   MachineInstr *First = Add;
 | |
|   MachineInstr *Last = Ldst;
 | |
|   if (MDT->dominates(Ldst, Add))
 | |
|     std::swap(First, Last);
 | |
|   else if (!MDT->dominates(Add, Ldst))
 | |
|     return nullptr;
 | |
| 
 | |
|   LLVM_DEBUG(dbgs() << "canJoinInstructions: " << *First << *Last);
 | |
| 
 | |
|   unsigned BasePos, OffPos;
 | |
| 
 | |
|   if (!AII->getBaseAndOffsetPosition(*Ldst, BasePos, OffPos)) {
 | |
|     LLVM_DEBUG(
 | |
|         dbgs()
 | |
|         << "[canJoinInstructions] Cannot determine base/offset position\n");
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   unsigned BaseReg = Ldst->getOperand(BasePos).getReg();
 | |
| 
 | |
|   // prohibit this:
 | |
|   //   v1 = add v0, c
 | |
|   //   st v1, [v0, 0]
 | |
|   // and this
 | |
|   //   st v0, [v0, 0]
 | |
|   //   v1 = add v0, c
 | |
|   if (Ldst->mayStore() && Ldst->getOperand(0).isReg()) {
 | |
|     unsigned StReg = Ldst->getOperand(0).getReg();
 | |
|     if (Add->getOperand(0).getReg() == StReg || BaseReg == StReg) {
 | |
|       LLVM_DEBUG(dbgs() << "[canJoinInstructions] Store uses result of Add\n");
 | |
|       return nullptr;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   SmallVector<MachineInstr *, 4> UsesAfterLdst;
 | |
|   SmallVector<MachineInstr *, 4> UsesAfterAdd;
 | |
|   for (MachineInstr &MI : MRI->use_nodbg_instructions(BaseReg)) {
 | |
|     if (&MI == Ldst || &MI == Add)
 | |
|       continue;
 | |
|     if (&MI != Add && MDT->dominates(Ldst, &MI))
 | |
|       UsesAfterLdst.push_back(&MI);
 | |
|     else if (!MDT->dominates(&MI, Ldst))
 | |
|       return nullptr;
 | |
|     if (MDT->dominates(Add, &MI))
 | |
|       UsesAfterAdd.push_back(&MI);
 | |
|   }
 | |
| 
 | |
|   MachineInstr *Result = nullptr;
 | |
| 
 | |
|   if (First == Add) {
 | |
|     //  n = add b, i
 | |
|     //  ...
 | |
|     //  x = ld [b, o] or x = ld [n, o]
 | |
| 
 | |
|     if (noUseOfAddBeforeLoadOrStore(First, Last)) {
 | |
|       Result = Last;
 | |
|       LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can sink Add down to Ldst\n");
 | |
|     } else if (canHoistLoadStoreTo(Ldst, Add)) {
 | |
|       Result = First;
 | |
|       LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Ldst to Add\n");
 | |
|     }
 | |
|   } else {
 | |
|     // x = ld [b, o]
 | |
|     // ...
 | |
|     // n = add b, i
 | |
|     Result = First;
 | |
|     LLVM_DEBUG(dbgs() << "[canJoinInstructions] Can hoist Add to Ldst\n");
 | |
|   }
 | |
|   if (Result && Uses)
 | |
|     *Uses = (Result == Ldst) ? UsesAfterLdst : UsesAfterAdd;
 | |
|   return Result;
 | |
| }
 | |
| 
 | |
| bool ARCOptAddrMode::canFixPastUses(const ArrayRef<MachineInstr *> &Uses,
 | |
|                                     MachineOperand &Incr, unsigned BaseReg) {
 | |
| 
 | |
|   assert(Incr.isImm() && "Expected immediate increment");
 | |
|   int64_t NewOffset = Incr.getImm();
 | |
|   for (MachineInstr *MI : Uses) {
 | |
|     int64_t Dummy;
 | |
|     if (isAddConstantOp(*MI, Dummy)) {
 | |
|       if (isValidIncrementOffset(Dummy + NewOffset))
 | |
|         continue;
 | |
|       return false;
 | |
|     }
 | |
|     if (isLoadStoreThatCanHandleDisplacement(AII, *MI, -NewOffset))
 | |
|       continue;
 | |
|     LLVM_DEBUG(dbgs() << "Instruction cannot handle displacement " << -NewOffset
 | |
|                       << ": " << *MI);
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void ARCOptAddrMode::fixPastUses(ArrayRef<MachineInstr *> Uses,
 | |
|                                  unsigned NewBase, int64_t NewOffset) {
 | |
| 
 | |
|   for (MachineInstr *MI : Uses) {
 | |
|     int64_t Amount;
 | |
|     unsigned BasePos, OffPos;
 | |
|     if (isAddConstantOp(*MI, Amount)) {
 | |
|       NewOffset += Amount;
 | |
|       assert(isValidIncrementOffset(NewOffset) &&
 | |
|              "New offset won't fit into ADD instr");
 | |
|       BasePos = 1;
 | |
|       OffPos = 2;
 | |
|     } else if (AII->getBaseAndOffsetPosition(*MI, BasePos, OffPos)) {
 | |
|       MachineOperand &MO = MI->getOperand(OffPos);
 | |
|       assert(MO.isImm() && "expected immediate operand");
 | |
|       NewOffset += MO.getImm();
 | |
|       assert(isValidLoadStoreOffset(NewOffset) &&
 | |
|              "New offset won't fit into LD/ST");
 | |
|     } else
 | |
|       llvm_unreachable("unexpected instruction");
 | |
| 
 | |
|     MI->getOperand(BasePos).setReg(NewBase);
 | |
|     MI->getOperand(OffPos).setImm(NewOffset);
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool ARCOptAddrMode::canHoistLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {
 | |
|   if (Ldst->getParent() != To->getParent())
 | |
|     return false;
 | |
|   MachineBasicBlock::const_iterator MI(To), ME(Ldst),
 | |
|       End(Ldst->getParent()->end());
 | |
| 
 | |
|   bool IsStore = Ldst->mayStore();
 | |
|   for (; MI != ME && MI != End; ++MI) {
 | |
|     if (MI->isDebugValue())
 | |
|       continue;
 | |
|     if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||
 | |
|         MI->hasUnmodeledSideEffects())
 | |
|       return false;
 | |
|     if (IsStore && MI->mayLoad())
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   for (auto &O : Ldst->explicit_operands()) {
 | |
|     if (!O.isReg() || !O.isUse())
 | |
|       continue;
 | |
|     MachineInstr *OpDef = MRI->getVRegDef(O.getReg());
 | |
|     if (!OpDef || !MDT->dominates(OpDef, To))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool ARCOptAddrMode::canSinkLoadStoreTo(MachineInstr *Ldst, MachineInstr *To) {
 | |
|   // Can only sink load/store within same BB
 | |
|   if (Ldst->getParent() != To->getParent())
 | |
|     return false;
 | |
|   MachineBasicBlock::const_iterator MI(Ldst), ME(To),
 | |
|       End(Ldst->getParent()->end());
 | |
| 
 | |
|   bool IsStore = Ldst->mayStore();
 | |
|   bool IsLoad = Ldst->mayLoad();
 | |
| 
 | |
|   unsigned ValReg = IsLoad ? Ldst->getOperand(0).getReg() : 0;
 | |
|   for (; MI != ME && MI != End; ++MI) {
 | |
|     if (MI->isDebugValue())
 | |
|       continue;
 | |
|     if (MI->mayStore() || MI->isCall() || MI->isInlineAsm() ||
 | |
|         MI->hasUnmodeledSideEffects())
 | |
|       return false;
 | |
|     if (IsStore && MI->mayLoad())
 | |
|       return false;
 | |
|     if (ValReg && MI->readsVirtualRegister(ValReg))
 | |
|       return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void ARCOptAddrMode::changeToAddrMode(MachineInstr &Ldst, unsigned NewOpcode,
 | |
|                                       unsigned NewBase,
 | |
|                                       MachineOperand &NewOffset) {
 | |
|   bool IsStore = Ldst.mayStore();
 | |
|   unsigned BasePos, OffPos;
 | |
|   MachineOperand Src = MachineOperand::CreateImm(0xDEADBEEF);
 | |
|   AII->getBaseAndOffsetPosition(Ldst, BasePos, OffPos);
 | |
| 
 | |
|   unsigned BaseReg = Ldst.getOperand(BasePos).getReg();
 | |
| 
 | |
|   Ldst.RemoveOperand(OffPos);
 | |
|   Ldst.RemoveOperand(BasePos);
 | |
| 
 | |
|   if (IsStore) {
 | |
|     Src = Ldst.getOperand(BasePos - 1);
 | |
|     Ldst.RemoveOperand(BasePos - 1);
 | |
|   }
 | |
| 
 | |
|   Ldst.setDesc(AST->getInstrInfo()->get(NewOpcode));
 | |
|   Ldst.addOperand(MachineOperand::CreateReg(NewBase, true));
 | |
|   if (IsStore)
 | |
|     Ldst.addOperand(Src);
 | |
|   Ldst.addOperand(MachineOperand::CreateReg(BaseReg, false));
 | |
|   Ldst.addOperand(NewOffset);
 | |
|   LLVM_DEBUG(dbgs() << "[ABAW] New Ldst: " << Ldst);
 | |
| }
 | |
| 
 | |
| bool ARCOptAddrMode::processBasicBlock(MachineBasicBlock &MBB) {
 | |
|   bool Changed = false;
 | |
|   for (auto MI = MBB.begin(), ME = MBB.end(); MI != ME; ++MI) {
 | |
|     if (MI->isDebugValue())
 | |
|       continue;
 | |
|     if (!MI->mayLoad() && !MI->mayStore())
 | |
|       continue;
 | |
|     if (ARC::getPostIncOpcode(MI->getOpcode()) < 0)
 | |
|       continue;
 | |
|     MachineInstr *Res = tryToCombine(*MI);
 | |
|     if (Res) {
 | |
|       Changed = true;
 | |
|       // Res points to the next instruction. Rewind to process it
 | |
|       MI = std::prev(Res->getIterator());
 | |
|     }
 | |
|   }
 | |
|   return Changed;
 | |
| }
 | |
| 
 | |
| bool ARCOptAddrMode::runOnMachineFunction(MachineFunction &MF) {
 | |
|   if (skipFunction(MF.getFunction()))
 | |
|     return false;
 | |
| 
 | |
|   AST = &MF.getSubtarget<ARCSubtarget>();
 | |
|   AII = AST->getInstrInfo();
 | |
|   MRI = &MF.getRegInfo();
 | |
|   MDT = &getAnalysis<MachineDominatorTree>();
 | |
| 
 | |
|   bool Changed = false;
 | |
|   for (auto &MBB : MF)
 | |
|     Changed |= processBasicBlock(MBB);
 | |
|   return Changed;
 | |
| }
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| //                         Public Constructor Functions
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| FunctionPass *llvm::createARCOptAddrMode() { return new ARCOptAddrMode(); }
 |