LLVM API Documentation

ARMLoadStoreOptimizer.cpp

Go to the documentation of this file.
00001 //===-- ARMLoadStoreOptimizer.cpp - ARM load / store opt. pass ----*- C++ -*-=//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file contains a pass that performs load / store related peephole
00011 // optimizations. This pass should be run after register allocation.
00012 //
00013 //===----------------------------------------------------------------------===//
00014 
00015 #define DEBUG_TYPE "arm-ldst-opt"
00016 #include "ARM.h"
00017 #include "ARMAddressingModes.h"
00018 #include "ARMMachineFunctionInfo.h"
00019 #include "ARMRegisterInfo.h"
00020 #include "llvm/ADT/STLExtras.h"
00021 #include "llvm/ADT/SmallVector.h"
00022 #include "llvm/ADT/Statistic.h"
00023 #include "llvm/CodeGen/MachineBasicBlock.h"
00024 #include "llvm/CodeGen/MachineFunctionPass.h"
00025 #include "llvm/CodeGen/MachineInstr.h"
00026 #include "llvm/CodeGen/MachineInstrBuilder.h"
00027 #include "llvm/CodeGen/RegisterScavenging.h"
00028 #include "llvm/Support/Compiler.h"
00029 #include "llvm/Target/TargetRegisterInfo.h"
00030 #include "llvm/Target/TargetInstrInfo.h"
00031 #include "llvm/Target/TargetMachine.h"
00032 using namespace llvm;
00033 
00034 STATISTIC(NumLDMGened , "Number of ldm instructions generated");
00035 STATISTIC(NumSTMGened , "Number of stm instructions generated");
00036 STATISTIC(NumFLDMGened, "Number of fldm instructions generated");
00037 STATISTIC(NumFSTMGened, "Number of fstm instructions generated");
00038 
00039 namespace {
00040   struct VISIBILITY_HIDDEN ARMLoadStoreOpt : public MachineFunctionPass {
00041     static char ID;
00042     ARMLoadStoreOpt() : MachineFunctionPass(&ID) {}
00043 
00044     const TargetInstrInfo *TII;
00045     const TargetRegisterInfo *TRI;
00046     ARMFunctionInfo *AFI;
00047     RegScavenger *RS;
00048 
00049     virtual bool runOnMachineFunction(MachineFunction &Fn);
00050 
00051     virtual const char *getPassName() const {
00052       return "ARM load / store optimization pass";
00053     }
00054 
00055   private:
00056     struct MemOpQueueEntry {
00057       int Offset;
00058       unsigned Position;
00059       MachineBasicBlock::iterator MBBI;
00060       bool Merged;
00061       MemOpQueueEntry(int o, int p, MachineBasicBlock::iterator i)
00062         : Offset(o), Position(p), MBBI(i), Merged(false) {};
00063     };
00064     typedef SmallVector<MemOpQueueEntry,8> MemOpQueue;
00065     typedef MemOpQueue::iterator MemOpQueueIter;
00066 
00067     SmallVector<MachineBasicBlock::iterator, 4>
00068     MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, unsigned Base,
00069                  int Opcode, unsigned Size,
00070                  ARMCC::CondCodes Pred, unsigned PredReg,
00071                  unsigned Scratch, MemOpQueue &MemOps);
00072 
00073     void AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps);
00074     bool LoadStoreMultipleOpti(MachineBasicBlock &MBB);
00075     bool MergeReturnIntoLDM(MachineBasicBlock &MBB);
00076   };
00077   char ARMLoadStoreOpt::ID = 0;
00078 }
00079 
00080 /// createARMLoadStoreOptimizationPass - returns an instance of the load / store
00081 /// optimization pass.
00082 FunctionPass *llvm::createARMLoadStoreOptimizationPass() {
00083   return new ARMLoadStoreOpt();
00084 }
00085 
00086 static int getLoadStoreMultipleOpcode(int Opcode) {
00087   switch (Opcode) {
00088   case ARM::LDR:
00089     NumLDMGened++;
00090     return ARM::LDM;
00091   case ARM::STR:
00092     NumSTMGened++;
00093     return ARM::STM;
00094   case ARM::FLDS:
00095     NumFLDMGened++;
00096     return ARM::FLDMS;
00097   case ARM::FSTS:
00098     NumFSTMGened++;
00099     return ARM::FSTMS;
00100   case ARM::FLDD:
00101     NumFLDMGened++;
00102     return ARM::FLDMD;
00103   case ARM::FSTD:
00104     NumFSTMGened++;
00105     return ARM::FSTMD;
00106   default: abort();
00107   }
00108   return 0;
00109 }
00110 
00111 /// mergeOps - Create and insert a LDM or STM with Base as base register and
00112 /// registers in Regs as the register operands that would be loaded / stored.
00113 /// It returns true if the transformation is done. 
00114 static bool mergeOps(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
00115                      int Offset, unsigned Base, bool BaseKill, int Opcode,
00116                      ARMCC::CondCodes Pred, unsigned PredReg, unsigned Scratch,
00117                      SmallVector<std::pair<unsigned, bool>, 8> &Regs,
00118                      const TargetInstrInfo *TII) {
00119   // Only a single register to load / store. Don't bother.
00120   unsigned NumRegs = Regs.size();
00121   if (NumRegs <= 1)
00122     return false;
00123 
00124   ARM_AM::AMSubMode Mode = ARM_AM::ia;
00125   bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR;
00126   if (isAM4 && Offset == 4)
00127     Mode = ARM_AM::ib;
00128   else if (isAM4 && Offset == -4 * (int)NumRegs + 4)
00129     Mode = ARM_AM::da;
00130   else if (isAM4 && Offset == -4 * (int)NumRegs)
00131     Mode = ARM_AM::db;
00132   else if (Offset != 0) {
00133     // If starting offset isn't zero, insert a MI to materialize a new base.
00134     // But only do so if it is cost effective, i.e. merging more than two
00135     // loads / stores.
00136     if (NumRegs <= 2)
00137       return false;
00138 
00139     unsigned NewBase;
00140     if (Opcode == ARM::LDR)
00141       // If it is a load, then just use one of the destination register to
00142       // use as the new base.
00143       NewBase = Regs[NumRegs-1].first;
00144     else {
00145       // Use the scratch register to use as a new base.
00146       NewBase = Scratch;
00147       if (NewBase == 0)
00148         return false;
00149     }
00150     int BaseOpc = ARM::ADDri;
00151     if (Offset < 0) {
00152       BaseOpc = ARM::SUBri;
00153       Offset = - Offset;
00154     }
00155     int ImmedOffset = ARM_AM::getSOImmVal(Offset);
00156     if (ImmedOffset == -1)
00157       return false;  // Probably not worth it then.
00158 
00159     BuildMI(MBB, MBBI, TII->get(BaseOpc), NewBase)
00160       .addReg(Base, false, false, BaseKill).addImm(ImmedOffset)
00161       .addImm(Pred).addReg(PredReg).addReg(0);
00162     Base = NewBase;
00163     BaseKill = true;  // New base is always killed right its use.
00164   }
00165 
00166   bool isDPR = Opcode == ARM::FLDD || Opcode == ARM::FSTD;
00167   bool isDef = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
00168   Opcode = getLoadStoreMultipleOpcode(Opcode);
00169   MachineInstrBuilder MIB = (isAM4)
00170     ? BuildMI(MBB, MBBI, TII->get(Opcode)).addReg(Base, false, false, BaseKill)
00171         .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg)
00172     : BuildMI(MBB, MBBI, TII->get(Opcode)).addReg(Base, false, false, BaseKill)
00173         .addImm(ARM_AM::getAM5Opc(Mode, false, isDPR ? NumRegs<<1 : NumRegs))
00174         .addImm(Pred).addReg(PredReg);
00175   for (unsigned i = 0; i != NumRegs; ++i)
00176     MIB = MIB.addReg(Regs[i].first, isDef, false, Regs[i].second);
00177 
00178   return true;
00179 }
00180 
00181 /// MergeLDR_STR - Merge a number of load / store instructions into one or more
00182 /// load / store multiple instructions.
00183 SmallVector<MachineBasicBlock::iterator, 4>
00184 ARMLoadStoreOpt::MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex,
00185                               unsigned Base, int Opcode, unsigned Size,
00186                               ARMCC::CondCodes Pred, unsigned PredReg,
00187                               unsigned Scratch, MemOpQueue &MemOps) {
00188   SmallVector<MachineBasicBlock::iterator, 4> Merges;
00189   bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR;
00190   int Offset = MemOps[SIndex].Offset;
00191   int SOffset = Offset;
00192   unsigned Pos = MemOps[SIndex].Position;
00193   MachineBasicBlock::iterator Loc = MemOps[SIndex].MBBI;
00194   unsigned PReg = MemOps[SIndex].MBBI->getOperand(0).getReg();
00195   unsigned PRegNum = ARMRegisterInfo::getRegisterNumbering(PReg);
00196   bool isKill = MemOps[SIndex].MBBI->getOperand(0).isKill();
00197 
00198   SmallVector<std::pair<unsigned,bool>, 8> Regs;
00199   Regs.push_back(std::make_pair(PReg, isKill));
00200   for (unsigned i = SIndex+1, e = MemOps.size(); i != e; ++i) {
00201     int NewOffset = MemOps[i].Offset;
00202     unsigned Reg = MemOps[i].MBBI->getOperand(0).getReg();
00203     unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg);
00204     isKill = MemOps[i].MBBI->getOperand(0).isKill();
00205     // AM4 - register numbers in ascending order.
00206     // AM5 - consecutive register numbers in ascending order.
00207     if (NewOffset == Offset + (int)Size &&
00208         ((isAM4 && RegNum > PRegNum) || RegNum == PRegNum+1)) {
00209       Offset += Size;
00210       Regs.push_back(std::make_pair(Reg, isKill));
00211       PRegNum = RegNum;
00212     } else {
00213       // Can't merge this in. Try merge the earlier ones first.
00214       if (mergeOps(MBB, ++Loc, SOffset, Base, false, Opcode, Pred, PredReg,
00215                    Scratch, Regs, TII)) {
00216         Merges.push_back(prior(Loc));
00217         for (unsigned j = SIndex; j < i; ++j) {
00218           MBB.erase(MemOps[j].MBBI);
00219           MemOps[j].Merged = true;
00220         }
00221       }
00222       SmallVector<MachineBasicBlock::iterator, 4> Merges2 =
00223         MergeLDR_STR(MBB, i, Base, Opcode, Size, Pred, PredReg, Scratch,MemOps);
00224       Merges.append(Merges2.begin(), Merges2.end());
00225       return Merges;
00226     }
00227 
00228     if (MemOps[i].Position > Pos) {
00229       Pos = MemOps[i].Position;
00230       Loc = MemOps[i].MBBI;
00231     }
00232   }
00233 
00234   bool BaseKill = Loc->findRegisterUseOperandIdx(Base, true) != -1;
00235   if (mergeOps(MBB, ++Loc, SOffset, Base, BaseKill, Opcode, Pred, PredReg,
00236                Scratch, Regs, TII)) {
00237     Merges.push_back(prior(Loc));
00238     for (unsigned i = SIndex, e = MemOps.size(); i != e; ++i) {
00239       MBB.erase(MemOps[i].MBBI);
00240       MemOps[i].Merged = true;
00241     }
00242   }
00243 
00244   return Merges;
00245 }
00246 
00247 /// getInstrPredicate - If instruction is predicated, returns its predicate
00248 /// condition, otherwise returns AL. It also returns the condition code
00249 /// register by reference.
00250 static ARMCC::CondCodes getInstrPredicate(MachineInstr *MI, unsigned &PredReg) {
00251   int PIdx = MI->findFirstPredOperandIdx();
00252   if (PIdx == -1) {
00253     PredReg = 0;
00254     return ARMCC::AL;
00255   }
00256 
00257   PredReg = MI->getOperand(PIdx+1).getReg();
00258   return (ARMCC::CondCodes)MI->getOperand(PIdx).getImm();
00259 }
00260 
00261 static inline bool isMatchingDecrement(MachineInstr *MI, unsigned Base,
00262                                        unsigned Bytes, ARMCC::CondCodes Pred,
00263                                        unsigned PredReg) {
00264   unsigned MyPredReg = 0;
00265   return (MI && MI->getOpcode() == ARM::SUBri &&
00266           MI->getOperand(0).getReg() == Base &&
00267           MI->getOperand(1).getReg() == Base &&
00268           ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes &&
00269           getInstrPredicate(MI, MyPredReg) == Pred &&
00270           MyPredReg == PredReg);
00271 }
00272 
00273 static inline bool isMatchingIncrement(MachineInstr *MI, unsigned Base,
00274                                        unsigned Bytes, ARMCC::CondCodes Pred,
00275                                        unsigned PredReg) {
00276   unsigned MyPredReg = 0;
00277   return (MI && MI->getOpcode() == ARM::ADDri &&
00278           MI->getOperand(0).getReg() == Base &&
00279           MI->getOperand(1).getReg() == Base &&
00280           ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes &&
00281           getInstrPredicate(MI, MyPredReg) == Pred &&
00282           MyPredReg == PredReg);
00283 }
00284 
00285 static inline unsigned getLSMultipleTransferSize(MachineInstr *MI) {
00286   switch (MI->getOpcode()) {
00287   default: return 0;
00288   case ARM::LDR:
00289   case ARM::STR:
00290   case ARM::FLDS:
00291   case ARM::FSTS:
00292     return 4;
00293   case ARM::FLDD:
00294   case ARM::FSTD:
00295     return 8;
00296   case ARM::LDM:
00297   case ARM::STM:
00298     return (MI->getNumOperands() - 4) * 4;
00299   case ARM::FLDMS:
00300   case ARM::FSTMS:
00301   case ARM::FLDMD:
00302   case ARM::FSTMD:
00303     return ARM_AM::getAM5Offset(MI->getOperand(1).getImm()) * 4;
00304   }
00305 }
00306 
00307 /// mergeBaseUpdateLSMultiple - Fold proceeding/trailing inc/dec of base
00308 /// register into the LDM/STM/FLDM{D|S}/FSTM{D|S} op when possible:
00309 ///
00310 /// stmia rn, <ra, rb, rc>
00311 /// rn := rn + 4 * 3;
00312 /// =>
00313 /// stmia rn!, <ra, rb, rc>
00314 ///
00315 /// rn := rn - 4 * 3;
00316 /// ldmia rn, <ra, rb, rc>
00317 /// =>
00318 /// ldmdb rn!, <ra, rb, rc>
00319 static bool mergeBaseUpdateLSMultiple(MachineBasicBlock &MBB,
00320                                       MachineBasicBlock::iterator MBBI,
00321                                       bool &Advance,
00322                                       MachineBasicBlock::iterator &I) {
00323   MachineInstr *MI = MBBI;
00324   unsigned Base = MI->getOperand(0).getReg();
00325   unsigned Bytes = getLSMultipleTransferSize(MI);
00326   unsigned PredReg = 0;
00327   ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
00328   int Opcode = MI->getOpcode();
00329   bool isAM4 = Opcode == ARM::LDM || Opcode == ARM::STM;
00330 
00331   if (isAM4) {
00332     if (ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm()))
00333       return false;
00334 
00335     // Can't use the updating AM4 sub-mode if the base register is also a dest
00336     // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined.
00337     for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) {
00338       if (MI->getOperand(i).getReg() == Base)
00339         return false;
00340     }
00341 
00342     ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm());
00343     if (MBBI != MBB.begin()) {
00344       MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
00345       if (Mode == ARM_AM::ia &&
00346           isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
00347         MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::db, true));
00348         MBB.erase(PrevMBBI);
00349         return true;
00350       } else if (Mode == ARM_AM::ib &&
00351                  isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
00352         MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::da, true));
00353         MBB.erase(PrevMBBI);
00354         return true;
00355       }
00356     }
00357 
00358     if (MBBI != MBB.end()) {
00359       MachineBasicBlock::iterator NextMBBI = next(MBBI);
00360       if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) &&
00361           isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
00362         MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
00363         if (NextMBBI == I) {
00364           Advance = true;
00365           ++I;
00366         }
00367         MBB.erase(NextMBBI);
00368         return true;
00369       } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) &&
00370                  isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
00371         MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
00372         if (NextMBBI == I) {
00373           Advance = true;
00374           ++I;
00375         }
00376         MBB.erase(NextMBBI);
00377         return true;
00378       }
00379     }
00380   } else {
00381     // FLDM{D|S}, FSTM{D|S} addressing mode 5 ops.
00382     if (ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm()))
00383       return false;
00384 
00385     ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm());
00386     unsigned Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm());
00387     if (MBBI != MBB.begin()) {
00388       MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
00389       if (Mode == ARM_AM::ia &&
00390           isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
00391         MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::db, true, Offset));
00392         MBB.erase(PrevMBBI);
00393         return true;
00394       }
00395     }
00396 
00397     if (MBBI != MBB.end()) {
00398       MachineBasicBlock::iterator NextMBBI = next(MBBI);
00399       if (Mode == ARM_AM::ia &&
00400           isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
00401         MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::ia, true, Offset));
00402         if (NextMBBI == I) {
00403           Advance = true;
00404           ++I;
00405         }
00406         MBB.erase(NextMBBI);
00407       }
00408       return true;
00409     }
00410   }
00411 
00412   return false;
00413 }
00414 
00415 static unsigned getPreIndexedLoadStoreOpcode(unsigned Opc) {
00416   switch (Opc) {
00417   case ARM::LDR: return ARM::LDR_PRE;
00418   case ARM::STR: return ARM::STR_PRE;
00419   case ARM::FLDS: return ARM::FLDMS;
00420   case ARM::FLDD: return ARM::FLDMD;
00421   case ARM::FSTS: return ARM::FSTMS;
00422   case ARM::FSTD: return ARM::FSTMD;
00423   default: abort();
00424   }
00425   return 0;
00426 }
00427 
00428 static unsigned getPostIndexedLoadStoreOpcode(unsigned Opc) {
00429   switch (Opc) {
00430   case ARM::LDR: return ARM::LDR_POST;
00431   case ARM::STR: return ARM::STR_POST;
00432   case ARM::FLDS: return ARM::FLDMS;
00433   case ARM::FLDD: return ARM::FLDMD;
00434   case ARM::FSTS: return ARM::FSTMS;
00435   case ARM::FSTD: return ARM::FSTMD;
00436   default: abort();
00437   }
00438   return 0;
00439 }
00440 
00441 /// mergeBaseUpdateLoadStore - Fold proceeding/trailing inc/dec of base
00442 /// register into the LDR/STR/FLD{D|S}/FST{D|S} op when possible:
00443 static bool mergeBaseUpdateLoadStore(MachineBasicBlock &MBB,
00444                                      MachineBasicBlock::iterator MBBI,
00445                                      const TargetInstrInfo *TII,
00446                                      bool &Advance,
00447                                      MachineBasicBlock::iterator &I) {
00448   MachineInstr *MI = MBBI;
00449   unsigned Base = MI->getOperand(1).getReg();
00450   bool BaseKill = MI->getOperand(1).isKill();
00451   unsigned Bytes = getLSMultipleTransferSize(MI);
00452   int Opcode = MI->getOpcode();
00453   bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
00454   if ((isAM2 && ARM_AM::getAM2Offset(MI->getOperand(3).getImm()) != 0) ||
00455       (!isAM2 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0))
00456     return false;
00457 
00458   bool isLd = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
00459   // Can't do the merge if the destination register is the same as the would-be
00460   // writeback register.
00461   if (isLd && MI->getOperand(0).getReg() == Base)
00462     return false;
00463 
00464   unsigned PredReg = 0;
00465   ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
00466   bool DoMerge = false;
00467   ARM_AM::AddrOpc AddSub = ARM_AM::add;
00468   unsigned NewOpc = 0;
00469   if (MBBI != MBB.begin()) {
00470     MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
00471     if (isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
00472       DoMerge = true;
00473       AddSub = ARM_AM::sub;
00474       NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
00475     } else if (isAM2 && isMatchingIncrement(PrevMBBI, Base, Bytes,
00476                                             Pred, PredReg)) {
00477       DoMerge = true;
00478       NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
00479     }
00480     if (DoMerge)
00481       MBB.erase(PrevMBBI);
00482   }
00483 
00484   if (!DoMerge && MBBI != MBB.end()) {
00485     MachineBasicBlock::iterator NextMBBI = next(MBBI);
00486     if (isAM2 && isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
00487       DoMerge = true;
00488       AddSub = ARM_AM::sub;
00489       NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
00490     } else if (isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
00491       DoMerge = true;
00492       NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
00493     }
00494     if (DoMerge) {
00495       if (NextMBBI == I) {
00496         Advance = true;
00497         ++I;
00498       }
00499       MBB.erase(NextMBBI);
00500     }
00501   }
00502 
00503   if (!DoMerge)
00504     return false;
00505 
00506   bool isDPR = NewOpc == ARM::FLDMD || NewOpc == ARM::FSTMD;
00507   unsigned Offset = isAM2 ? ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift)
00508     : ARM_AM::getAM5Opc((AddSub == ARM_AM::sub) ? ARM_AM::db : ARM_AM::ia,
00509                         true, isDPR ? 2 : 1);
00510   if (isLd) {
00511     if (isAM2)
00512       // LDR_PRE, LDR_POST;
00513       BuildMI(MBB, MBBI, TII->get(NewOpc), MI->getOperand(0).getReg())
00514         .addReg(Base, true)
00515         .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
00516     else
00517       // FLDMS, FLDMD
00518       BuildMI(MBB, MBBI, TII->get(NewOpc)).addReg(Base, false, false, BaseKill)
00519         .addImm(Offset).addImm(Pred).addReg(PredReg)
00520         .addReg(MI->getOperand(0).getReg(), true);
00521   } else {
00522     MachineOperand &MO = MI->getOperand(0);
00523     if (isAM2)
00524       // STR_PRE, STR_POST;
00525       BuildMI(MBB, MBBI, TII->get(NewOpc), Base)
00526         .addReg(MO.getReg(), false, false, MO.isKill())
00527         .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
00528     else
00529       // FSTMS, FSTMD
00530       BuildMI(MBB, MBBI, TII->get(NewOpc)).addReg(Base).addImm(Offset)
00531         .addImm(Pred).addReg(PredReg)
00532         .addReg(MO.getReg(), false, false, MO.isKill());
00533   }
00534   MBB.erase(MBBI);
00535 
00536   return true;
00537 }
00538 
00539 /// isMemoryOp - Returns true if instruction is a memory operations (that this
00540 /// pass is capable of operating on).
00541 static bool isMemoryOp(MachineInstr *MI) {
00542   int Opcode = MI->getOpcode();
00543   switch (Opcode) {
00544   default: break;
00545   case ARM::LDR:
00546   case ARM::STR:
00547     return MI->getOperand(1).isReg() && MI->getOperand(2).getReg() == 0;
00548   case ARM::FLDS:
00549   case ARM::FSTS:
00550     return MI->getOperand(1).isReg();
00551   case ARM::FLDD:
00552   case ARM::FSTD:
00553     return MI->getOperand(1).isReg();
00554   }
00555   return false;
00556 }
00557 
00558 /// AdvanceRS - Advance register scavenger to just before the earliest memory
00559 /// op that is being merged.
00560 void ARMLoadStoreOpt::AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps) {
00561   MachineBasicBlock::iterator Loc = MemOps[0].MBBI;
00562   unsigned Position = MemOps[0].Position;
00563   for (unsigned i = 1, e = MemOps.size(); i != e; ++i) {
00564     if (MemOps[i].Position < Position) {
00565       Position = MemOps[i].Position;
00566       Loc = MemOps[i].MBBI;
00567     }
00568   }
00569 
00570   if (Loc != MBB.begin())
00571     RS->forward(prior(Loc));
00572 }
00573 
00574 /// LoadStoreMultipleOpti - An optimization pass to turn multiple LDR / STR
00575 /// ops of the same base and incrementing offset into LDM / STM ops.
00576 bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) {
00577   unsigned NumMerges = 0;
00578   unsigned NumMemOps = 0;
00579   MemOpQueue MemOps;
00580   unsigned CurrBase = 0;
00581   int CurrOpc = -1;
00582   unsigned CurrSize = 0;
00583   ARMCC::CondCodes CurrPred = ARMCC::AL;
00584   unsigned CurrPredReg = 0;
00585   unsigned Position = 0;
00586 
00587   RS->enterBasicBlock(&MBB);
00588   MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
00589   while (MBBI != E) {
00590     bool Advance  = false;
00591     bool TryMerge = false;
00592     bool Clobber  = false;
00593 
00594     bool isMemOp = isMemoryOp(MBBI);
00595     if (isMemOp) {
00596       int Opcode = MBBI->getOpcode();
00597       bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
00598       unsigned Size = getLSMultipleTransferSize(MBBI);
00599       unsigned Base = MBBI->getOperand(1).getReg();
00600       unsigned PredReg = 0;
00601       ARMCC::CondCodes Pred = getInstrPredicate(MBBI, PredReg);
00602       unsigned NumOperands = MBBI->getDesc().getNumOperands();
00603       unsigned OffField = MBBI->getOperand(NumOperands-3).getImm();
00604       int Offset = isAM2
00605         ? ARM_AM::getAM2Offset(OffField) : ARM_AM::getAM5Offset(OffField) * 4;
00606       if (isAM2) {
00607         if (ARM_AM::getAM2Op(OffField) == ARM_AM::sub)
00608           Offset = -Offset;
00609       } else {
00610         if (ARM_AM::getAM5Op(OffField) == ARM_AM::sub)
00611           Offset = -Offset;
00612       }
00613       // Watch out for:
00614       // r4 := ldr [r5]
00615       // r5 := ldr [r5, #4]
00616       // r6 := ldr [r5, #8]
00617       //
00618       // The second ldr has effectively broken the chain even though it
00619       // looks like the later ldr(s) use the same base register. Try to
00620       // merge the ldr's so far, including this one. But don't try to
00621       // combine the following ldr(s).
00622       Clobber = (Opcode == ARM::LDR && Base == MBBI->getOperand(0).getReg());
00623       if (CurrBase == 0 && !Clobber) {
00624         // Start of a new chain.
00625         CurrBase = Base;
00626         CurrOpc  = Opcode;
00627         CurrSize = Size;
00628         CurrPred = Pred;
00629         CurrPredReg = PredReg;
00630         MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
00631         NumMemOps++;
00632         Advance = true;
00633       } else {
00634         if (Clobber) {
00635           TryMerge = true;
00636           Advance = true;
00637         }
00638 
00639         if (CurrOpc == Opcode && CurrBase == Base && CurrPred == Pred) {
00640           // No need to match PredReg.
00641           // Continue adding to the queue.
00642           if (Offset > MemOps.back().Offset) {
00643             MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
00644             NumMemOps++;
00645             Advance = true;
00646           } else {
00647             for (MemOpQueueIter I = MemOps.begin(), E = MemOps.end();
00648                  I != E; ++I) {
00649               if (Offset < I->Offset) {
00650                 MemOps.insert(I, MemOpQueueEntry(Offset, Position, MBBI));
00651                 NumMemOps++;
00652                 Advance = true;
00653                 break;
00654               } else if (Offset == I->Offset) {
00655                 // Collision! This can't be merged!
00656                 break;
00657               }
00658             }
00659           }
00660         }
00661       }
00662     }
00663 
00664     if (Advance) {
00665       ++Position;
00666       ++MBBI;
00667     } else
00668       TryMerge = true;
00669 
00670     if (TryMerge) {
00671       if (NumMemOps > 1) {
00672         // Try to find a free register to use as a new base in case it's needed.
00673         // First advance to the instruction just before the start of the chain.
00674         AdvanceRS(MBB, MemOps);
00675         // Find a scratch register. Make sure it's a call clobbered register or
00676         // a spilled callee-saved register.
00677         unsigned Scratch = RS->FindUnusedReg(&ARM::GPRRegClass, true);
00678         if (!Scratch)
00679           Scratch = RS->FindUnusedReg(&ARM::GPRRegClass,
00680                                       AFI->getSpilledCSRegisters());
00681         // Process the load / store instructions.
00682         RS->forward(prior(MBBI));
00683 
00684         // Merge ops.
00685         SmallVector<MachineBasicBlock::iterator,4> MBBII =
00686           MergeLDR_STR(MBB, 0, CurrBase, CurrOpc, CurrSize,
00687                        CurrPred, CurrPredReg, Scratch, MemOps);
00688 
00689         // Try folding preceeding/trailing base inc/dec into the generated
00690         // LDM/STM ops.
00691         for (unsigned i = 0, e = MBBII.size(); i < e; ++i)
00692           if (mergeBaseUpdateLSMultiple(MBB, MBBII[i], Advance, MBBI))
00693             NumMerges++;
00694         NumMerges += MBBII.size();
00695 
00696         // Try folding preceeding/trailing base inc/dec into those load/store
00697         // that were not merged to form LDM/STM ops.
00698         for (unsigned i = 0; i != NumMemOps; ++i)
00699           if (!MemOps[i].Merged)
00700             if (mergeBaseUpdateLoadStore(MBB, MemOps[i].MBBI, TII,Advance,MBBI))
00701               NumMerges++;
00702 
00703         // RS may be pointing to an instruction that's deleted. 
00704         RS->skipTo(prior(MBBI));
00705       }
00706 
00707       CurrBase = 0;
00708       CurrOpc = -1;
00709       CurrSize = 0;
00710       CurrPred = ARMCC::AL;
00711       CurrPredReg = 0;
00712       if (NumMemOps) {
00713         MemOps.clear();
00714         NumMemOps = 0;
00715       }
00716 
00717       // If iterator hasn't been advanced and this is not a memory op, skip it.
00718       // It can't start a new chain anyway.
00719       if (!Advance && !isMemOp && MBBI != E) {
00720         ++Position;
00721         ++MBBI;
00722       }
00723     }
00724   }
00725   return NumMerges > 0;
00726 }
00727 
00728 /// MergeReturnIntoLDM - If this is a exit BB, try merging the return op
00729 /// (bx lr) into the preceeding stack restore so it directly restore the value
00730 /// of LR into pc.
00731 ///   ldmfd sp!, {r7, lr}
00732 ///   bx lr
00733 /// =>
00734 ///   ldmfd sp!, {r7, pc}
00735 bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
00736   if (MBB.empty()) return false;
00737 
00738   MachineBasicBlock::iterator MBBI = prior(MBB.end());
00739   if (MBBI->getOpcode() == ARM::BX_RET && MBBI != MBB.begin()) {
00740     MachineInstr *PrevMI = prior(MBBI);
00741     if (PrevMI->getOpcode() == ARM::LDM) {
00742       MachineOperand &MO = PrevMI->getOperand(PrevMI->getNumOperands()-1);
00743       if (MO.getReg() == ARM::LR) {
00744         PrevMI->setDesc(TII->get(ARM::LDM_RET));
00745         MO.setReg(ARM::PC);
00746         MBB.erase(MBBI);
00747         return true;
00748       }
00749     }
00750   }
00751   return false;
00752 }
00753 
00754 bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
00755   const TargetMachine &TM = Fn.getTarget();
00756   AFI = Fn.getInfo<ARMFunctionInfo>();
00757   TII = TM.getInstrInfo();
00758   TRI = TM.getRegisterInfo();
00759   RS = new RegScavenger();
00760 
00761   bool Modified = false;
00762   for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
00763        ++MFI) {
00764     MachineBasicBlock &MBB = *MFI;
00765     Modified |= LoadStoreMultipleOpti(MBB);
00766     Modified |= MergeReturnIntoLDM(MBB);
00767   }
00768 
00769   delete RS;
00770   return Modified;
00771 }