ARMLoadStoreOptimizer.cpp revision 675860758ec8926f9803840615366931aca7f8d8
18e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//===-- ARMLoadStoreOptimizer.cpp - ARM load / store opt. pass ----*- C++ -*-=//
28e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//
38e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//                     The LLVM Compiler Infrastructure
48e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//
54ee451de366474b9c228b4e5fa573795a715216dChris Lattner// This file is distributed under the University of Illinois Open Source
64ee451de366474b9c228b4e5fa573795a715216dChris Lattner// License. See LICENSE.TXT for details.
78e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//
88e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//===----------------------------------------------------------------------===//
98e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//
108e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner// This file contains a pass that performs load / store related peephole
118e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner// optimizations. This pass should be run after register allocation.
128e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//
138e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner//===----------------------------------------------------------------------===//
148e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
157336f7febb5170b374a4cbffee273ad82ff8a1a3Jordan Rose#define DEBUG_TYPE "arm-ldst-opt"
16d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "ARM.h"
17d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "ARMAddressingModes.h"
180b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "ARMMachineFunctionInfo.h"
190b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "ARMRegisterInfo.h"
200b8c9a80f20772c3793201ab5b251d3520b9cea3Chandler Carruth#include "llvm/DerivedTypes.h"
21c25e7581b9b8088910da31702d4ca21c4734c6d7Torok Edwin#include "llvm/CodeGen/MachineBasicBlock.h"
22d185f64f828ce1f8b476807a4a1345c0c53d8213Chris Lattner#include "llvm/CodeGen/MachineFunctionPass.h"
23d04a8d4b33ff316ca4cf961e06c9e312eff8e64fChandler Carruth#include "llvm/CodeGen/MachineInstr.h"
2492bcb426c3e4503c99324afd4ed0a73521711a56Chris Lattner#include "llvm/CodeGen/MachineInstrBuilder.h"
25df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner#include "llvm/CodeGen/MachineRegisterInfo.h"
26476b242fe7a61e5f9ac6214b0bc5c680d24f152eNick Lewycky#include "llvm/CodeGen/RegisterScavenging.h"
27bcef7df6ec9aba7c5009a4d33944f80227563665Duncan Sands#include "llvm/Target/TargetData.h"
28a896176973d59d8e22514b363d31e8d1becf185eChris Lattner#include "llvm/Target/TargetInstrInfo.h"
295679d18c54ef46170e46f51bf471bb334f2b6525Misha Brukman#include "llvm/Target/TargetMachine.h"
308e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner#include "llvm/Target/TargetRegisterInfo.h"
318e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner#include "llvm/Support/Compiler.h"
32d1e1703c39742f3c9fc3d27a442ff59bbdbfb5aaBenjamin Kramer#include "llvm/ADT/DenseMap.h"
333f2d5f60b31fd057c10f77b2e607b23a8c94f6d3Chris Lattner#include "llvm/ADT/STLExtras.h"
34df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner#include "llvm/ADT/SmallPtrSet.h"
35df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner#include "llvm/ADT/SmallVector.h"
36df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner#include "llvm/ADT/Statistic.h"
378e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnerusing namespace llvm;
388e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
398e3a8e0452695643d04c21e15c94b802aef81baeChris LattnerSTATISTIC(NumLDMGened , "Number of ldm instructions generated");
408e3a8e0452695643d04c21e15c94b802aef81baeChris LattnerSTATISTIC(NumSTMGened , "Number of stm instructions generated");
418e3a8e0452695643d04c21e15c94b802aef81baeChris LattnerSTATISTIC(NumFLDMGened, "Number of fldm instructions generated");
428e3a8e0452695643d04c21e15c94b802aef81baeChris LattnerSTATISTIC(NumFSTMGened, "Number of fstm instructions generated");
438e3a8e0452695643d04c21e15c94b802aef81baeChris LattnerSTATISTIC(NumLdStMoved, "Number of load / store instructions moved");
448e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
45df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner/// ARMAllocLoadStoreOpt - Post- register allocation pass the combine
468e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner/// load / store instructions to form ldm / stm instructions.
478e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
488e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnernamespace {
498e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  struct VISIBILITY_HIDDEN ARMLoadStoreOpt : public MachineFunctionPass {
508e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    static char ID;
518e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    ARMLoadStoreOpt() : MachineFunctionPass(&ID) {}
52df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
538e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    const TargetInstrInfo *TII;
548e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    const TargetRegisterInfo *TRI;
558e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    ARMFunctionInfo *AFI;
568e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    RegScavenger *RS;
578e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
588e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    virtual bool runOnMachineFunction(MachineFunction &Fn);
59df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
608e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    virtual const char *getPassName() const {
618e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      return "ARM load / store optimization pass";
628e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    }
638e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
647336f7febb5170b374a4cbffee273ad82ff8a1a3Jordan Rose  private:
652c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    struct MemOpQueueEntry {
668e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      int Offset;
67df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      unsigned Position;
688e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      MachineBasicBlock::iterator MBBI;
698e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      bool Merged;
708e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      MemOpQueueEntry(int o, int p, MachineBasicBlock::iterator i)
718e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        : Offset(o), Position(p), MBBI(i), Merged(false) {};
728e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    };
738e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    typedef SmallVector<MemOpQueueEntry,8> MemOpQueue;
74df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    typedef MemOpQueue::iterator MemOpQueueIter;
75df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
768e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    bool MergeOps(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
778e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                  int Offset, unsigned Base, bool BaseKill, int Opcode,
788e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                  ARMCC::CondCodes Pred, unsigned PredReg, unsigned Scratch,
798e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                  DebugLoc dl, SmallVector<std::pair<unsigned, bool>, 8> &Regs);
807336f7febb5170b374a4cbffee273ad82ff8a1a3Jordan Rose    void MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, unsigned Base,
818e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                      int Opcode, unsigned Size,
828e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                      ARMCC::CondCodes Pred, unsigned PredReg,
838e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                      unsigned Scratch, MemOpQueue &MemOps,
848e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                      SmallVector<MachineBasicBlock::iterator, 4> &Merges);
857336f7febb5170b374a4cbffee273ad82ff8a1a3Jordan Rose
868e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    void AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps);
87d343c6b70ec03b357d42e47ce7c00b3c3cb78efdChris Lattner    bool FixInvalidRegPairOp(MachineBasicBlock &MBB,
88df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                             MachineBasicBlock::iterator &MBBI);
898e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    bool LoadStoreMultipleOpti(MachineBasicBlock &MBB);
908e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    bool MergeReturnIntoLDM(MachineBasicBlock &MBB);
911b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  };
921b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  char ARMLoadStoreOpt::ID = 0;
931b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen}
941b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen
951b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesenstatic int getLoadStoreMultipleOpcode(int Opcode) {
961b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  switch (Opcode) {
971b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  case ARM::LDR:
981b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen    NumLDMGened++;
997336f7febb5170b374a4cbffee273ad82ff8a1a3Jordan Rose    return ARM::LDM;
1001b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  case ARM::STR:
1011b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen    NumSTMGened++;
1021b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen    return ARM::STM;
1031b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  case ARM::FLDS:
1047336f7febb5170b374a4cbffee273ad82ff8a1a3Jordan Rose    NumFLDMGened++;
1051b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen    return ARM::FLDMS;
1061b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  case ARM::FSTS:
1071b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen    NumFSTMGened++;
1081b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen    return ARM::FSTMS;
1091b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen  case ARM::FLDD:
1108e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    NumFLDMGened++;
1118e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    return ARM::FLDMD;
1128e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  case ARM::FSTD:
1138e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    NumFSTMGened++;
1142c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    return ARM::FSTMD;
1158e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  default: abort();
1168e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
1178e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  return 0;
1188e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner}
1198e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
1208e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner/// MergeOps - Create and insert a LDM or STM with Base as base register and
1218e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner/// registers in Regs as the register operands that would be loaded / stored.
12287d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei/// It returns true if the transformation is done.
12387d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyeibool
12487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy BenyeiARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB,
1257336f7febb5170b374a4cbffee273ad82ff8a1a3Jordan Rose                          MachineBasicBlock::iterator MBBI,
1268e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          int Offset, unsigned Base, bool BaseKill,
1278e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          int Opcode, ARMCC::CondCodes Pred,
1288e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          unsigned PredReg, unsigned Scratch, DebugLoc dl,
1298e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          SmallVector<std::pair<unsigned, bool>, 8> &Regs) {
1308e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  // Only a single register to load / store. Don't bother.
1318e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned NumRegs = Regs.size();
1328e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  if (NumRegs <= 1)
1338e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    return false;
1348e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
1358e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  ARM_AM::AMSubMode Mode = ARM_AM::ia;
1368e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR;
1378e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  if (isAM4 && Offset == 4)
1388e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    Mode = ARM_AM::ib;
1398e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  else if (isAM4 && Offset == -4 * (int)NumRegs + 4)
14087d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei    Mode = ARM_AM::da;
14187d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  else if (isAM4 && Offset == -4 * (int)NumRegs)
1428e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    Mode = ARM_AM::db;
1438e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  else if (Offset != 0) {
1448e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    // If starting offset isn't zero, insert a MI to materialize a new base.
1458e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    // But only do so if it is cost effective, i.e. merging more than two
1468e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    // loads / stores.
1478e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    if (NumRegs <= 2)
1488e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      return false;
1498e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
1508e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    unsigned NewBase;
1518e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    if (Opcode == ARM::LDR)
1528e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      // If it is a load, then just use one of the destination register to
1538e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      // use as the new base.
1548e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      NewBase = Regs[NumRegs-1].first;
1558e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    else {
1568e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      // Use the scratch register to use as a new base.
1578e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      NewBase = Scratch;
1588e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (NewBase == 0)
1598e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        return false;
160ff6c91efcf62d1cb99343fdcb2de6271520a1981Owen Anderson    }
161ff6c91efcf62d1cb99343fdcb2de6271520a1981Owen Anderson    int BaseOpc = ARM::ADDri;
162ff6c91efcf62d1cb99343fdcb2de6271520a1981Owen Anderson    if (Offset < 0) {
1638e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      BaseOpc = ARM::SUBri;
1648e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      Offset = - Offset;
1658e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    }
1668e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    int ImmedOffset = ARM_AM::getSOImmVal(Offset);
1678e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    if (ImmedOffset == -1)
1688e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      return false;  // Probably not worth it then.
1698e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
1708e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    BuildMI(MBB, MBBI, dl, TII->get(BaseOpc), NewBase)
1718e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      .addReg(Base, getKillRegState(BaseKill)).addImm(ImmedOffset)
1728e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      .addImm(Pred).addReg(PredReg).addReg(0);
1738e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    Base = NewBase;
1748e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    BaseKill = true;  // New base is always killed right its use.
1758e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
1768e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
1778e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  bool isDPR = Opcode == ARM::FLDD || Opcode == ARM::FSTD;
1788e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  bool isDef = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
1792c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  Opcode = getLoadStoreMultipleOpcode(Opcode);
1808e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  MachineInstrBuilder MIB = (isAM4)
1812c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    ? BuildMI(MBB, MBBI, dl, TII->get(Opcode))
1828e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        .addReg(Base, getKillRegState(BaseKill))
1832c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg)
1848e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    : BuildMI(MBB, MBBI, dl, TII->get(Opcode))
1858e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        .addReg(Base, getKillRegState(BaseKill))
1868e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        .addImm(ARM_AM::getAM5Opc(Mode, false, isDPR ? NumRegs<<1 : NumRegs))
187df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addImm(Pred).addReg(PredReg);
1888e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  for (unsigned i = 0; i != NumRegs; ++i)
1892c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef)
1908e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                     | getKillRegState(Regs[i].second));
1918e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
1928e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  return true;
1938e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner}
19487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei
1958e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner/// MergeLDR_STR - Merge a number of load / store instructions into one or more
1962c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling/// load / store multiple instructions.
197df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattnervoid
198df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris LattnerARMLoadStoreOpt::MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex,
1998e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          unsigned Base, int Opcode, unsigned Size,
2008e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          ARMCC::CondCodes Pred, unsigned PredReg,
2018e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          unsigned Scratch, MemOpQueue &MemOps,
2028e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          SmallVector<MachineBasicBlock::iterator, 4> &Merges) {
2038e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR;
2048e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  int Offset = MemOps[SIndex].Offset;
2058e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  int SOffset = Offset;
2068e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned Pos = MemOps[SIndex].Position;
2078e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  MachineBasicBlock::iterator Loc = MemOps[SIndex].MBBI;
2088e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  DebugLoc dl = Loc->getDebugLoc();
2098e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned PReg = Loc->getOperand(0).getReg();
2108e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned PRegNum = ARMRegisterInfo::getRegisterNumbering(PReg);
2118e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  bool isKill = Loc->getOperand(0).isKill();
2128e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
213df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  SmallVector<std::pair<unsigned,bool>, 8> Regs;
214df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  Regs.push_back(std::make_pair(PReg, isKill));
2158e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  for (unsigned i = SIndex+1, e = MemOps.size(); i != e; ++i) {
2168e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    int NewOffset = MemOps[i].Offset;
2178e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    unsigned Reg = MemOps[i].MBBI->getOperand(0).getReg();
218df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg);
2198e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    isKill = MemOps[i].MBBI->getOperand(0).isKill();
220df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    // AM4 - register numbers in ascending order.
2218e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    // AM5 - consecutive register numbers in ascending order.
2228e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    if (NewOffset == Offset + (int)Size &&
2238e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        ((isAM4 && RegNum > PRegNum) || RegNum == PRegNum+1)) {
224df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      Offset += Size;
225df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      Regs.push_back(std::make_pair(Reg, isKill));
2268e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      PRegNum = RegNum;
227df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    } else {
2288e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      // Can't merge this in. Try merge the earlier ones first.
2298e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (MergeOps(MBB, ++Loc, SOffset, Base, false, Opcode, Pred, PredReg,
2308e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                   Scratch, dl, Regs)) {
231e434d277ca5183eeb6f881000732dcf4c8edd52eChris Lattner        Merges.push_back(prior(Loc));
23295ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        for (unsigned j = SIndex; j < i; ++j) {
2338e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          MBB.erase(MemOps[j].MBBI);
2348e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          MemOps[j].Merged = true;
2352c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        }
2368e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      }
237df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      MergeLDR_STR(MBB, i, Base, Opcode, Size, Pred, PredReg, Scratch,
238df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                   MemOps, Merges);
239df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      return;
240df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    }
241df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
242df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (MemOps[i].Position > Pos) {
243df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      Pos = MemOps[i].Position;
244df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      Loc = MemOps[i].MBBI;
245df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    }
246df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  }
247df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
248df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  bool BaseKill = Loc->findRegisterUseOperandIdx(Base, true) != -1;
2498e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  if (MergeOps(MBB, ++Loc, SOffset, Base, BaseKill, Opcode, Pred, PredReg,
2508e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner               Scratch, dl, Regs)) {
2518e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    Merges.push_back(prior(Loc));
2528e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    for (unsigned i = SIndex, e = MemOps.size(); i != e; ++i) {
2538e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      MBB.erase(MemOps[i].MBBI);
2548e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      MemOps[i].Merged = true;
2558e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    }
2568e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
2578e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
2588e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  return;
2598e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner}
260df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
261df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner/// getInstrPredicate - If instruction is predicated, returns its predicate
262df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner/// condition, otherwise returns AL. It also returns the condition code
263df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner/// register by reference.
2648e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnerstatic ARMCC::CondCodes getInstrPredicate(MachineInstr *MI, unsigned &PredReg) {
2658e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  int PIdx = MI->findFirstPredOperandIdx();
2668e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  if (PIdx == -1) {
2672c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    PredReg = 0;
2688e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    return ARMCC::AL;
2698e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
2702c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
2712c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  PredReg = MI->getOperand(PIdx+1).getReg();
272df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  return (ARMCC::CondCodes)MI->getOperand(PIdx).getImm();
273df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner}
2748e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
2758e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnerstatic inline bool isMatchingDecrement(MachineInstr *MI, unsigned Base,
276df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                                       unsigned Bytes, ARMCC::CondCodes Pred,
277df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                                       unsigned PredReg) {
278df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  unsigned MyPredReg = 0;
2798e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  return (MI && MI->getOpcode() == ARM::SUBri &&
2808e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          MI->getOperand(0).getReg() == Base &&
2818e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          MI->getOperand(1).getReg() == Base &&
2822c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling          ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes &&
2838e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          getInstrPredicate(MI, MyPredReg) == Pred &&
2849fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky          MyPredReg == PredReg);
285df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner}
2862c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
2878e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnerstatic inline bool isMatchingIncrement(MachineInstr *MI, unsigned Base,
28887d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei                                       unsigned Bytes, ARMCC::CondCodes Pred,
28987d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei                                       unsigned PredReg) {
2902c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  unsigned MyPredReg = 0;
2912c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  return (MI && MI->getOpcode() == ARM::ADDri &&
2928e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          MI->getOperand(0).getReg() == Base &&
2938e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          MI->getOperand(1).getReg() == Base &&
294df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes &&
295df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          getInstrPredicate(MI, MyPredReg) == Pred &&
296df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          MyPredReg == PredReg);
2978e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner}
2982c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
299df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattnerstatic inline unsigned getLSMultipleTransferSize(MachineInstr *MI) {
3008e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  switch (MI->getOpcode()) {
3018e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  default: return 0;
3029fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::LDR:
3039fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::STR:
3049fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FLDS:
3059fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FSTS:
3069fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky    return 4;
3079fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FLDD:
3089fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FSTD:
3099fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky    return 8;
3109fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::LDM:
3119fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::STM:
3129fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky    return (MI->getNumOperands() - 4) * 4;
3139fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FLDMS:
3149fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FSTMS:
3159fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FLDMD:
3169fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  case ARM::FSTMD:
3179fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky    return ARM_AM::getAM5Offset(MI->getOperand(1).getImm()) * 4;
3189fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky  }
3199fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky}
3209fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky
3219fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// mergeBaseUpdateLSMultiple - Fold proceeding/trailing inc/dec of base
3229fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// register into the LDM/STM/FLDM{D|S}/FSTM{D|S} op when possible:
32387d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei///
32487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei/// stmia rn, <ra, rb, rc>
3259fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// rn := rn + 4 * 3;
3269fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// =>
32787d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei/// stmia rn!, <ra, rb, rc>
32887d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei///
3299fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// rn := rn - 4 * 3;
3309fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// ldmia rn, <ra, rb, rc>
3319fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// =>
3329fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky/// ldmdb rn!, <ra, rb, rc>
3339fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewyckystatic bool mergeBaseUpdateLSMultiple(MachineBasicBlock &MBB,
3349fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky                                      MachineBasicBlock::iterator MBBI,
3359fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky                                      bool &Advance,
3369fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky                                      MachineBasicBlock::iterator &I) {
3378e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  MachineInstr *MI = MBBI;
3388e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned Base = MI->getOperand(0).getReg();
339df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  unsigned Bytes = getLSMultipleTransferSize(MI);
340df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  unsigned PredReg = 0;
341df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
342df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  int Opcode = MI->getOpcode();
343df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  bool isAM4 = Opcode == ARM::LDM || Opcode == ARM::STM;
3448e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
3458e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  if (isAM4) {
3469fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky    if (ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm()))
3478e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      return false;
3482c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
3498e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    // Can't use the updating AM4 sub-mode if the base register is also a dest
3509fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky    // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined.
351df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) {
3522c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling      if (MI->getOperand(i).getReg() == Base)
3538e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        return false;
35487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei    }
35587d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei
3562c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm());
3572c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    if (MBBI != MBB.begin()) {
3588e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
3598e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (Mode == ARM_AM::ia &&
360df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
361df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::db, true));
362df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        MBB.erase(PrevMBBI);
3638e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        return true;
3642c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling      } else if (Mode == ARM_AM::ib &&
365df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                 isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
3668e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::da, true));
3678e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        MBB.erase(PrevMBBI);
3688e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        return true;
3698e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      }
3708e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    }
371df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
3729fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky    if (MBBI != MBB.end()) {
3739fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky      MachineBasicBlock::iterator NextMBBI = next(MBBI);
3749fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky      if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) &&
3752c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling          isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
3769fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky        MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
3778e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        if (NextMBBI == I) {
3789fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky          Advance = true;
3798e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          ++I;
3809fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky        }
3819fa89334f1045b56e8ae409004e119d47ef17ec7Nick Lewycky        MBB.erase(NextMBBI);
3828e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        return true;
3838e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) &&
384e434d277ca5183eeb6f881000732dcf4c8edd52eChris Lattner                 isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
385eff2ab61b5d411fe64ba601d402b7c549644b590Devang Patel        MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
3861d92831759620a2e5ce4f5a3088c0a1a77a48c8fChris Lattner        if (NextMBBI == I) {
387e434d277ca5183eeb6f881000732dcf4c8edd52eChris Lattner          Advance = true;
3881d92831759620a2e5ce4f5a3088c0a1a77a48c8fChris Lattner          ++I;
38987d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei        }
39087d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei        MBB.erase(NextMBBI);
3919100a78bce4e1d34d8ffd5efa2cc79ed864dd1c0Nick Lewycky        return true;
392eff2ab61b5d411fe64ba601d402b7c549644b590Devang Patel      }
39387d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei    }
39487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  } else {
3959100a78bce4e1d34d8ffd5efa2cc79ed864dd1c0Nick Lewycky    // FLDM{D|S}, FSTM{D|S} addressing mode 5 ops.
396eff2ab61b5d411fe64ba601d402b7c549644b590Devang Patel    if (ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm()))
3978e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      return false;
398eff2ab61b5d411fe64ba601d402b7c549644b590Devang Patel
3999100a78bce4e1d34d8ffd5efa2cc79ed864dd1c0Nick Lewycky    ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm());
4001d92831759620a2e5ce4f5a3088c0a1a77a48c8fChris Lattner    unsigned Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm());
401eff2ab61b5d411fe64ba601d402b7c549644b590Devang Patel    if (MBBI != MBB.begin()) {
402e434d277ca5183eeb6f881000732dcf4c8edd52eChris Lattner      MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
403eff2ab61b5d411fe64ba601d402b7c549644b590Devang Patel      if (Mode == ARM_AM::ia &&
40415c13d3e63d7745bccad74d547af4e3482193eaaMichael Ilseman          isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
40595ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::db, true, Offset));
40695ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        MBB.erase(PrevMBBI);
40795ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        return true;
40895ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling      }
40987d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei    }
41087d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei
41195ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling    if (MBBI != MBB.end()) {
41295ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling      MachineBasicBlock::iterator NextMBBI = next(MBBI);
41395ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling      if (Mode == ARM_AM::ia &&
41495ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling          isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
41595ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::ia, true, Offset));
41695ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        if (NextMBBI == I) {
41795ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling          Advance = true;
41895ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling          ++I;
41995ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        }
42095ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling        MBB.erase(NextMBBI);
42195ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling      }
42295ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling      return true;
4238e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    }
4248e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
4258e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
4268e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  return false;
4278e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner}
428df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
4298e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnerstatic unsigned getPreIndexedLoadStoreOpcode(unsigned Opc) {
4308e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  switch (Opc) {
4318e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  case ARM::LDR: return ARM::LDR_PRE;
4322c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  case ARM::STR: return ARM::STR_PRE;
4338e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  case ARM::FLDS: return ARM::FLDMS;
4348e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  case ARM::FLDD: return ARM::FLDMD;
43587d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  case ARM::FSTS: return ARM::FSTMS;
43687d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  case ARM::FSTD: return ARM::FSTMD;
43787d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  default: abort();
43887d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  }
43987d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  return 0;
4408e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner}
4412c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
4428e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnerstatic unsigned getPostIndexedLoadStoreOpcode(unsigned Opc) {
4438e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  switch (Opc) {
444df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  case ARM::LDR: return ARM::LDR_POST;
445df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  case ARM::STR: return ARM::STR_POST;
4468e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  case ARM::FLDS: return ARM::FLDMS;
4472c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  case ARM::FLDD: return ARM::FLDMD;
4488e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  case ARM::FSTS: return ARM::FSTMS;
4498e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  case ARM::FSTD: return ARM::FSTMD;
4508e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  default: abort();
4518e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
4528e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  return 0;
4538e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner}
4542c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
4558e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner/// mergeBaseUpdateLoadStore - Fold proceeding/trailing inc/dec of base
456df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner/// register into the LDR/STR/FLD{D|S}/FST{D|S} op when possible:
457df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattnerstatic bool mergeBaseUpdateLoadStore(MachineBasicBlock &MBB,
4588e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                                     MachineBasicBlock::iterator MBBI,
4591d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson                                     const TargetInstrInfo *TII,
460df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                                     bool &Advance,
4618e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                                     MachineBasicBlock::iterator &I) {
4622c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  MachineInstr *MI = MBBI;
4638e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned Base = MI->getOperand(1).getReg();
4648e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  bool BaseKill = MI->getOperand(1).isKill();
4658e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned Bytes = getLSMultipleTransferSize(MI);
4668e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  int Opcode = MI->getOpcode();
4678e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  DebugLoc dl = MI->getDebugLoc();
468ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling  bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
469ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling  if ((isAM2 && ARM_AM::getAM2Offset(MI->getOperand(3).getImm()) != 0) ||
470ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling      (!isAM2 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0))
471ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling    return false;
472ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling
473df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  bool isLd = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
474df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  // Can't do the merge if the destination register is the same as the would-be
475df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  // writeback register.
476df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  if (isLd && MI->getOperand(0).getReg() == Base)
477df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    return false;
478bb46f52027416598a662dc1c58f48d9d56b1a65bRafael Espindola
4793d10a5a75794356a0a568ce283713adc3a963200Bill Wendling  unsigned PredReg = 0;
4805e721d768254a920b78b9129d79a84c0163cb3f4Bill Wendling  ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
48132811bef956e0fae4329e6515420d85f7e510660Bill Wendling  bool DoMerge = false;
482df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  ARM_AM::AddrOpc AddSub = ARM_AM::add;
483266c7bbbbcc4b326dea82e577de1a415d6acc23eChris Lattner  unsigned NewOpc = 0;
484df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  if (MBBI != MBB.begin()) {
485667d4b8de6dea70195ff12ef39a4deebffa2f5c7Duncan Sands    MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
48632811bef956e0fae4329e6515420d85f7e510660Bill Wendling    if (isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
487df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      DoMerge = true;
488667d4b8de6dea70195ff12ef39a4deebffa2f5c7Duncan Sands      AddSub = ARM_AM::sub;
489df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
490df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    } else if (isAM2 && isMatchingIncrement(PrevMBBI, Base, Bytes,
491df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                                            Pred, PredReg)) {
492df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      DoMerge = true;
493df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
494df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    }
495df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (DoMerge)
496bea4626f93c830e31f82cc947df28fdae583cd09Rafael Espindola      MBB.erase(PrevMBBI);
497a2de37c897556fbd1f94a3ed84ad27accd8f8debMichael Gottesman  }
498df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
499df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  if (!DoMerge && MBBI != MBB.end()) {
500df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    MachineBasicBlock::iterator NextMBBI = next(MBBI);
501ce718ff9f42c7da092eaa01dd0242e8d5ba84713Hans Wennborg    if (isAM2 && isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
502ce718ff9f42c7da092eaa01dd0242e8d5ba84713Hans Wennborg      DoMerge = true;
503ce718ff9f42c7da092eaa01dd0242e8d5ba84713Hans Wennborg      AddSub = ARM_AM::sub;
504df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
505df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    } else if (isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
506df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      DoMerge = true;
507df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
508df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    }
509df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (DoMerge) {
510df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      if (NextMBBI == I) {
5110f96817d010c4d2abbb0e1c1cfc56ff537010081Bill Wendling        Advance = true;
5123defc0bfa600cc253f0cba0fe781aa49435d968aBill Wendling        ++I;
513df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      }
514df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      MBB.erase(NextMBBI);
51547f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman    }
51647f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman  }
51747f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman
51847f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman  if (!DoMerge)
51947f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman    return false;
52047f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman
52147f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman  bool isDPR = NewOpc == ARM::FLDMD || NewOpc == ARM::FSTMD;
52247f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman  unsigned Offset = isAM2 ? ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift)
52347f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman    : ARM_AM::getAM5Opc((AddSub == ARM_AM::sub) ? ARM_AM::db : ARM_AM::ia,
524ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling                        true, isDPR ? 2 : 1);
525ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling  if (isLd) {
526ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling    if (isAM2)
527ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling      // LDR_PRE, LDR_POST;
528ae510f3936f2510cebff86ea38536b30fdf2a30cBill Wendling      BuildMI(MBB, MBBI, dl, TII->get(NewOpc), MI->getOperand(0).getReg())
52908d012eba490c4906ec773c39db9f2a18a78c997Dan Gohman        .addReg(Base, RegState::Define)
53008d012eba490c4906ec773c39db9f2a18a78c997Dan Gohman        .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
5311224c386981f7948f298ed9ad444c40609570f2eDan Gohman    else
532dd8004dc73d091ccb3927dbbc3b41639a3738ae3Dan Gohman      // FLDMS, FLDMD
533df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      BuildMI(MBB, MBBI, dl, TII->get(NewOpc))
534df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(Base, getKillRegState(BaseKill))
535df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addImm(Offset).addImm(Pred).addReg(PredReg)
536df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(MI->getOperand(0).getReg(), RegState::Define);
537df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  } else {
538df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    MachineOperand &MO = MI->getOperand(0);
539df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (isAM2)
5408ba2d5befc05ca73d3bac8708819bbbe759e2cf9Dale Johannesen      // STR_PRE, STR_POST;
541581600bfc3060ee13afb278cd87e25da5b5f7db2Chad Rosier      BuildMI(MBB, MBBI, dl, TII->get(NewOpc), Base)
542df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(MO.getReg(), getKillRegState(MO.isKill()))
543df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
544df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    else
545df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      // FSTMS, FSTMD
546df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      BuildMI(MBB, MBBI, dl, TII->get(NewOpc)).addReg(Base).addImm(Offset)
547df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addImm(Pred).addReg(PredReg)
548df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(MO.getReg(), getKillRegState(MO.isKill()));
549ded05e34b65dc42998e9db6ca1abd513e7a9d120Anton Korobeynikov  }
550385f5a99ecc7fee48a7539bc63d3e1d3b5089c0dAnton Korobeynikov  MBB.erase(MBBI);
551385f5a99ecc7fee48a7539bc63d3e1d3b5089c0dAnton Korobeynikov
552385f5a99ecc7fee48a7539bc63d3e1d3b5089c0dAnton Korobeynikov  return true;
553211a14e476abc9b864ab6a5d5e0bbb86d288b650Anton Korobeynikov}
554f9930da2ef72350c6c805af09e754e4e6e13d47bChe-Liang Chiou
555f9930da2ef72350c6c805af09e754e4e6e13d47bChe-Liang Chiou/// isMemoryOp - Returns true if instruction is a memory operations (that this
556e53d6051b7e173722351a5647bfd71eebee3d837Micah Villmow/// pass is capable of operating on).
557e53d6051b7e173722351a5647bfd71eebee3d837Micah Villmowstatic bool isMemoryOp(MachineInstr *MI) {
5583575222175b4982f380ff291bb17be67aadc0966Elena Demikhovsky  int Opcode = MI->getOpcode();
559385f5a99ecc7fee48a7539bc63d3e1d3b5089c0dAnton Korobeynikov  switch (Opcode) {
560df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  default: break;
561df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  case ARM::LDR:
562df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  case ARM::STR:
56395ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling    return MI->getOperand(1).isReg() && MI->getOperand(2).getReg() == 0;
56495ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  case ARM::FLDS:
56595ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  case ARM::FSTS:
5662253a2f52f3c46ae75cd05f5885acb987bd1d6b6Michael Gottesman    return MI->getOperand(1).isReg();
56795ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  case ARM::FLDD:
56877226a03dca98e6237c1068f2652fe41bea7b687Diego Novillo  case ARM::FSTD:
56995ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling    return MI->getOperand(1).isReg();
570df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  }
57195ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  return false;
57295ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling}
57395ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling
574df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner/// AdvanceRS - Advance register scavenger to just before the earliest memory
575143d46476cdcf5b88b9ee18ebd799e5820a2db0eBill Wendling/// op that is being merged.
576df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattnervoid ARMLoadStoreOpt::AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps) {
57795ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  MachineBasicBlock::iterator Loc = MemOps[0].MBBI;
57895ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  unsigned Position = MemOps[0].Position;
57995ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  for (unsigned i = 1, e = MemOps.size(); i != e; ++i) {
58095ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling    if (MemOps[i].Position < Position) {
58195ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling      Position = MemOps[i].Position;
58295ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling      Loc = MemOps[i].MBBI;
58395ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling    }
58495ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling  }
585df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
586df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  if (Loc != MBB.begin())
587456ca048af35163b9f52187e92a23ee0a9f059e8Stephen Lin    RS->forward(prior(Loc));
58825456ef74ca7ac9bf46451f28d995f785e2596deRafael Espindola}
58995ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling
59095ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendlingstatic int getMemoryOpOffset(const MachineInstr *MI) {
591df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  int Opcode = MI->getOpcode();
592df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
593114baee1fa017daefad2339c77b45b9ca3d79a41Bill Wendling  bool isAM3 = Opcode == ARM::LDRD || Opcode == ARM::STRD;
5948eec41fc778e99d42172a7f6de76faa43a6d8847Kostya Serebryany  unsigned NumOperands = MI->getDesc().getNumOperands();
5958eec41fc778e99d42172a7f6de76faa43a6d8847Kostya Serebryany  unsigned OffField = MI->getOperand(NumOperands-3).getImm();
5968eec41fc778e99d42172a7f6de76faa43a6d8847Kostya Serebryany  int Offset = isAM2
59795ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling    ? ARM_AM::getAM2Offset(OffField)
59895ce4c2ffb0ff31a79b060fb112659322a5be3bfBill Wendling    : (isAM3 ? ARM_AM::getAM3Offset(OffField)
599df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner             : ARM_AM::getAM5Offset(OffField) * 4);
600df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  if (isAM2) {
601df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (ARM_AM::getAM2Op(OffField) == ARM_AM::sub)
602df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      Offset = -Offset;
603df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  } else if (isAM3) {
604df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (ARM_AM::getAM3Op(OffField) == ARM_AM::sub)
605df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      Offset = -Offset;
606df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  } else {
6079ea4034e007a83c778cd306ea66481be1317a51bMisha Brukman    if (ARM_AM::getAM5Op(OffField) == ARM_AM::sub)
608ff03048c1350fcc4fda1ef6d6c57252f3a950854Eli Friedman      Offset = -Offset;
609ff03048c1350fcc4fda1ef6d6c57252f3a950854Eli Friedman  }
610ff03048c1350fcc4fda1ef6d6c57252f3a950854Eli Friedman  return Offset;
611df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner}
61209d9ef4122414a1a2ec95f52d660d6500f2819d0Chris Lattner
613e6e8826870bee3facb04f950f0bd725f8a88623dBill Wendlingstatic void InsertLDR_STR(MachineBasicBlock &MBB,
614e6e8826870bee3facb04f950f0bd725f8a88623dBill Wendling                          MachineBasicBlock::iterator &MBBI,
615e6e8826870bee3facb04f950f0bd725f8a88623dBill Wendling                          int OffImm, bool isDef,
616e6e8826870bee3facb04f950f0bd725f8a88623dBill Wendling                          DebugLoc dl, unsigned NewOpc,
617e6e8826870bee3facb04f950f0bd725f8a88623dBill Wendling                          unsigned Reg, bool RegKill,
6188e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          unsigned BaseReg, bool BaseKill,
6198e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          unsigned OffReg, bool OffKill,
6208e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                          ARMCC::CondCodes Pred, unsigned PredReg,
621df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner                          const TargetInstrInfo *TII) {
6228e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned Offset;
623df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  if (OffImm < 0)
6241d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson    Offset = ARM_AM::getAM2Opc(ARM_AM::sub, -OffImm, ARM_AM::no_shift);
625ce16339930a2b03e53b4e6399ef59c092a7f2cfaDan Gohman  else
6261d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson    Offset = ARM_AM::getAM2Opc(ARM_AM::add, OffImm, ARM_AM::no_shift);
6271d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson  if (isDef)
6281d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson    BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc), Reg)
6291d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson      .addReg(BaseReg, getKillRegState(BaseKill))
6301d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson      .addReg(OffReg,  getKillRegState(OffKill))
6311d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson      .addImm(Offset)
6321d0be15f89cb5056e20e2d24faa8d6afb1573bcaOwen Anderson      .addImm(Pred).addReg(PredReg);
633bb811a244567aa8a1522203f15588f4d001b7353Dale Johannesen  else
6348e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
6358e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      .addReg(Reg, getKillRegState(RegKill))
6368e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      .addReg(BaseReg, getKillRegState(BaseKill))
637df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      .addReg(OffReg,  getKillRegState(OffKill))
638df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      .addImm(Offset)
639df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      .addImm(Pred).addReg(PredReg);
640df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner}
641ae3a0be92e33bc716722aa600983fc1535acb122Dan Gohman
642ae3a0be92e33bc716722aa600983fc1535acb122Dan Gohmanbool ARMLoadStoreOpt::FixInvalidRegPairOp(MachineBasicBlock &MBB,
643ae3a0be92e33bc716722aa600983fc1535acb122Dan Gohman                                          MachineBasicBlock::iterator &MBBI) {
644df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  MachineInstr *MI = &*MBBI;
645df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  unsigned Opcode = MI->getOpcode();
646df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  if (Opcode == ARM::LDRD || Opcode == ARM::STRD) {
647df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned EvenReg = MI->getOperand(0).getReg();
648df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned OddReg  = MI->getOperand(1).getReg();
649df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned EvenRegNum = TRI->getDwarfRegNum(EvenReg, false);
650df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned OddRegNum  = TRI->getDwarfRegNum(OddReg, false);
651df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if ((EvenRegNum & 1) == 0 && (EvenRegNum + 1) == OddRegNum)
652df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      return false;
653df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
654df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    bool isDef = Opcode == ARM::LDRD;
655df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    bool EvenKill = isDef ? false : MI->getOperand(0).isKill();
656df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    bool OddKill  = isDef ? false : MI->getOperand(1).isKill();
657df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    const MachineOperand &BaseOp = MI->getOperand(2);
658df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned BaseReg = BaseOp.getReg();
659df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    bool BaseKill = BaseOp.isKill();
660df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    const MachineOperand &OffOp = MI->getOperand(3);
661df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned OffReg = OffOp.getReg();
662df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    bool OffKill = OffOp.isKill();
663df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    int OffImm = getMemoryOpOffset(MI);
664df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    unsigned PredReg = 0;
665df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
666df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner
667df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (OddRegNum > EvenRegNum && OffReg == 0 && OffImm == 0) {
668df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      // Ascending register numbers and no offset. It's safe to change it to a
669ab21db79ef1d2530880ad11f21f0b87ffca02dd4Chris Lattner      // ldm or stm.
670df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      unsigned NewOpc = (Opcode == ARM::LDRD) ? ARM::LDM : ARM::STM;
671dccc03b2423fe65efb5963ae816b99c24fc53374Bill Wendling      BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
672df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(BaseReg, getKillRegState(BaseKill))
673df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))
674df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addImm(Pred).addReg(PredReg)
675df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(EvenReg, getDefRegState(isDef))
676df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        .addReg(OddReg, getDefRegState(isDef));
677ff03048c1350fcc4fda1ef6d6c57252f3a950854Eli Friedman    } else {
678ff03048c1350fcc4fda1ef6d6c57252f3a950854Eli Friedman      // Split into two instructions.
67947f3513dd574535aeb40c9eb11134f0899e92269Eli Friedman      unsigned NewOpc = (Opcode == ARM::LDRD) ? ARM::LDR : ARM::STR;
680df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      DebugLoc dl = MBBI->getDebugLoc();
681df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      // If this is a load and base register is killed, it may have been
682df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      // re-defed by the load, make sure the first load does not clobber it.
683df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      if (isDef &&
684df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          (BaseKill || OffKill) &&
685df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          (TRI->regsOverlap(EvenReg, BaseReg) ||
686df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner           (OffReg && TRI->regsOverlap(EvenReg, OffReg)))) {
687e6e8826870bee3facb04f950f0bd725f8a88623dBill Wendling        assert(!TRI->regsOverlap(OddReg, BaseReg) &&
6882c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling               (!OffReg || !TRI->regsOverlap(OddReg, OffReg)));
6892c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        InsertLDR_STR(MBB, MBBI, OffImm+4, isDef, dl, NewOpc, OddReg, OddKill,
6908e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                      BaseReg, false, OffReg, false, Pred, PredReg, TII);
6918e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        InsertLDR_STR(MBB, MBBI, OffImm, isDef, dl, NewOpc, EvenReg, EvenKill,
6928e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                      BaseReg, BaseKill, OffReg, OffKill, Pred, PredReg, TII);
69387d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei      } else {
69487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei        InsertLDR_STR(MBB, MBBI, OffImm, isDef, dl, NewOpc, EvenReg, EvenKill,
6958e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                      BaseReg, false, OffReg, false, Pred, PredReg, TII);
6968e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        InsertLDR_STR(MBB, MBBI, OffImm+4, isDef, dl, NewOpc, OddReg, OddKill,
697689ad6ef3fd2e89394f1e8860dfebfe56b73c3daDaniel Dunbar                      BaseReg, BaseKill, OffReg, OffKill, Pred, PredReg, TII);
6988e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      }
6998e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    }
70040f8f6264d5af2c38e797e0dc59827cd231e8ff7Jay Foad
701df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    MBBI = prior(MBBI);
702df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    MBB.erase(MI);
7038e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
7042c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  return false;
7054ce0df610879e82d9853c6a38a75b1883feaee06Chris Lattner}
7068e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
7078e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner/// LoadStoreMultipleOpti - An optimization pass to turn multiple LDR / STR
708df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner/// ops of the same base and incrementing offset into LDM / STM ops.
7098e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnerbool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) {
7102c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling  unsigned NumMerges = 0;
711df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  unsigned NumMemOps = 0;
7128e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  MemOpQueue MemOps;
713df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner  unsigned CurrBase = 0;
7148e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  int CurrOpc = -1;
7158e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned CurrSize = 0;
71610c6d12a9fd4dab411091f64db4db69670b88850Bill Wendling  ARMCC::CondCodes CurrPred = ARMCC::AL;
7178e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned CurrPredReg = 0;
7188e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  unsigned Position = 0;
7198e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  SmallVector<MachineBasicBlock::iterator,4> Merges;
7208e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
7218e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  RS->enterBasicBlock(&MBB);
7228e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
723057beb8d4fe8d5dad98ad80a49a649730c3a3eb0Tobias Grosser  while (MBBI != E) {
724df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (FixInvalidRegPairOp(MBB, MBBI))
7258e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      continue;
7262c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
7278e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    bool Advance  = false;
7288d2a004822f9cc5bf38d5ef14494e2f0faa82b8cDavid Blaikie    bool TryMerge = false;
7298e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    bool Clobber  = false;
7308e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
7318e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    bool isMemOp = isMemoryOp(MBBI);
7328e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    if (isMemOp) {
7338e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      int Opcode = MBBI->getOpcode();
73487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei      unsigned Size = getLSMultipleTransferSize(MBBI);
735df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      unsigned Base = MBBI->getOperand(1).getReg();
7368e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      unsigned PredReg = 0;
737df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      ARMCC::CondCodes Pred = getInstrPredicate(MBBI, PredReg);
7388e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      int Offset = getMemoryOpOffset(MBBI);
7392c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling      // Watch out for:
74087d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei      // r4 := ldr [r5]
7418e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      // r5 := ldr [r5, #4]
7422c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling      // r6 := ldr [r5, #8]
7438e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      //
7448e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      // The second ldr has effectively broken the chain even though it
7458e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      // looks like the later ldr(s) use the same base register. Try to
746ce16339930a2b03e53b4e6399ef59c092a7f2cfaDan Gohman      // merge the ldr's so far, including this one. But don't try to
747df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      // combine the following ldr(s).
748df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      Clobber = (Opcode == ARM::LDR && Base == MBBI->getOperand(0).getReg());
7498e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (CurrBase == 0 && !Clobber) {
7502c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        // Start of a new chain.
7518e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        CurrBase = Base;
7528e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        CurrOpc  = Opcode;
753c23197a26f34f559ea9797de51e187087c039c42Torok Edwin        CurrSize = Size;
7548e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        CurrPred = Pred;
7558e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        CurrPredReg = PredReg;
7561b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen        MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
7570a29cb045444c13160e90fe7942a9d7c720185edTim Northover        NumMemOps++;
758df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        Advance = true;
7598e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      } else {
7608e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        if (Clobber) {
7611b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen          TryMerge = true;
7620a29cb045444c13160e90fe7942a9d7c720185edTim Northover          Advance = true;
763df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        }
7648e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
7658e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        if (CurrOpc == Opcode && CurrBase == Base && CurrPred == Pred) {
7661b25cb2416c46a6cebf2a6c52235e9fe46a10d11Dale Johannesen          // No need to match PredReg.
7670a29cb045444c13160e90fe7942a9d7c720185edTim Northover          // Continue adding to the queue.
768df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          if (Offset > MemOps.back().Offset) {
769057beb8d4fe8d5dad98ad80a49a649730c3a3eb0Tobias Grosser            MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
7700a29cb045444c13160e90fe7942a9d7c720185edTim Northover            NumMemOps++;
7710a29cb045444c13160e90fe7942a9d7c720185edTim Northover            Advance = true;
772057beb8d4fe8d5dad98ad80a49a649730c3a3eb0Tobias Grosser          } else {
7738e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner            for (MemOpQueueIter I = MemOps.begin(), E = MemOps.end();
7748e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                 I != E; ++I) {
7758e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner              if (Offset < I->Offset) {
7768e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                MemOps.insert(I, MemOpQueueEntry(Offset, Position, MBBI));
7778e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                NumMemOps++;
7788e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                Advance = true;
7798e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                break;
7808e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner              } else if (Offset == I->Offset) {
7818e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                // Collision! This can't be merged!
7828e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                break;
7838e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner              }
7848e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner            }
785df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner          }
78606be8b8a698b3d71aa93f30456b197ca6d54b1d0Craig Topper        }
78787d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei      }
78887d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei    }
7898e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
7908e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    if (Advance) {
791df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      ++Position;
7928e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      ++MBBI;
793df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    } else
7948e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      TryMerge = true;
7952c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
796df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    if (TryMerge) {
7978e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (NumMemOps > 1) {
7982c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        // Try to find a free register to use as a new base in case it's needed.
7998e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // First advance to the instruction just before the start of the chain.
8002c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        AdvanceRS(MBB, MemOps);
8018e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // Find a scratch register. Make sure it's a call clobbered register or
80287d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei        // a spilled callee-saved register.
8032c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        unsigned Scratch = RS->FindUnusedReg(&ARM::GPRRegClass, true);
8042c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        if (!Scratch)
8058e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          Scratch = RS->FindUnusedReg(&ARM::GPRRegClass,
8068e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner                                      AFI->getSpilledCSRegisters());
8078e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // Process the load / store instructions.
808df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        RS->forward(prior(MBBI));
8098e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
810df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        // Merge ops.
8118e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        Merges.clear();
8128e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        MergeLDR_STR(MBB, 0, CurrBase, CurrOpc, CurrSize,
8132c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling                     CurrPred, CurrPredReg, Scratch, MemOps, Merges);
8148e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
8158e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // Try folding preceeding/trailing base inc/dec into the generated
8168e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // LDM/STM ops.
8178e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        for (unsigned i = 0, e = Merges.size(); i < e; ++i)
8188e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          if (mergeBaseUpdateLSMultiple(MBB, Merges[i], Advance, MBBI))
8198e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner            ++NumMerges;
8208e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        NumMerges += Merges.size();
821689ad6ef3fd2e89394f1e8860dfebfe56b73c3daDaniel Dunbar
8228e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // Try folding preceeding/trailing base inc/dec into those load/store
8238e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // that were not merged to form LDM/STM ops.
8248e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        for (unsigned i = 0; i != NumMemOps; ++i)
82540f8f6264d5af2c38e797e0dc59827cd231e8ff7Jay Foad          if (!MemOps[i].Merged)
826df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner            if (mergeBaseUpdateLoadStore(MBB, MemOps[i].MBBI, TII,Advance,MBBI))
8278e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner              ++NumMerges;
8288e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
8298e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // RS may be pointing to an instruction that's deleted.
83040f8f6264d5af2c38e797e0dc59827cd231e8ff7Jay Foad        RS->skipTo(prior(MBBI));
831df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      } else if (NumMemOps == 1) {
8328e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        // Try folding preceeding/trailing base inc/dec into the single
833df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner        // load/store.
8348e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        if (mergeBaseUpdateLoadStore(MBB, MemOps[0].MBBI, TII, Advance, MBBI)) {
8358e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          ++NumMerges;
8368e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner          RS->forward(prior(MBBI));
8372c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling        }
8388e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      }
83987d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei
8402c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling      CurrBase = 0;
8418e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      CurrOpc = -1;
84287d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei      CurrSize = 0;
84387d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei      CurrPred = ARMCC::AL;
84487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei      CurrPredReg = 0;
8458e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (NumMemOps) {
84687d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei        MemOps.clear();
8478e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        NumMemOps = 0;
8488e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      }
8492c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
8502402123413080aee8e9418e4f08b8613ef5cc360Nick Lewycky      // If iterator hasn't been advanced and this is not a memory op, skip it.
851df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      // It can't start a new chain anyway.
8528e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (!Advance && !isMemOp && MBBI != E) {
8538e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        ++Position;
8548e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner        ++MBBI;
855df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      }
8568e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner    }
8578e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  }
85887d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  return NumMerges > 0;
859df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner}
8602c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling
8618e3a8e0452695643d04c21e15c94b802aef81baeChris Lattnernamespace {
86287d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei  struct OffsetCompare {
8632c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    bool operator()(const MachineInstr *LHS, const MachineInstr *RHS) const {
8648e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      int LOffset = getMemoryOpOffset(LHS);
8658e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      int ROffset = getMemoryOpOffset(RHS);
8668e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      assert(LHS == RHS || LOffset != ROffset);
8678e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      return LOffset > ROffset;
868df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner    }
8698e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  };
8702c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling}
8718e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner
8722c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling/// MergeReturnIntoLDM - If this is a exit BB, try merging the return op
8738e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner/// (bx lr) into the preceeding stack restore so it directly restore the value
87487d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei/// of LR into pc.
8752c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling///   ldmfd sp!, {r7, lr}
8768e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner///   bx lr
87787d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei/// =>
87887d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei///   ldmfd sp!, {r7, pc}
87987d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyeibool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
8808e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  if (MBB.empty()) return false;
88187d0b9ed1462705dd9bf1cb7f67d0bf03af776c8Guy Benyei
8828e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  MachineBasicBlock::iterator MBBI = prior(MBB.end());
8838e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner  if (MBBI->getOpcode() == ARM::BX_RET && MBBI != MBB.begin()) {
8842c6fd8c7ceea0392635ce21038d2b7fc215d9116Bill Wendling    MachineInstr *PrevMI = prior(MBBI);
8852402123413080aee8e9418e4f08b8613ef5cc360Nick Lewycky    if (PrevMI->getOpcode() == ARM::LDM) {
886df98617b23315e427cc4fad8ccfdd50d68bec2f9Chris Lattner      MachineOperand &MO = PrevMI->getOperand(PrevMI->getNumOperands()-1);
8878e3a8e0452695643d04c21e15c94b802aef81baeChris Lattner      if (MO.getReg() == ARM::LR) {
888        PrevMI->setDesc(TII->get(ARM::LDM_RET));
889        MO.setReg(ARM::PC);
890        MBB.erase(MBBI);
891        return true;
892      }
893    }
894  }
895  return false;
896}
897
898bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
899  const TargetMachine &TM = Fn.getTarget();
900  AFI = Fn.getInfo<ARMFunctionInfo>();
901  TII = TM.getInstrInfo();
902  TRI = TM.getRegisterInfo();
903  RS = new RegScavenger();
904
905  bool Modified = false;
906  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
907       ++MFI) {
908    MachineBasicBlock &MBB = *MFI;
909    Modified |= LoadStoreMultipleOpti(MBB);
910    Modified |= MergeReturnIntoLDM(MBB);
911  }
912
913  delete RS;
914  return Modified;
915}
916
917
918/// ARMPreAllocLoadStoreOpt - Pre- register allocation pass that move
919/// load / stores from consecutive locations close to make it more
920/// likely they will be combined later.
921
922namespace {
923  struct VISIBILITY_HIDDEN ARMPreAllocLoadStoreOpt : public MachineFunctionPass{
924    static char ID;
925    ARMPreAllocLoadStoreOpt() : MachineFunctionPass(&ID) {}
926
927    const TargetData *TD;
928    const TargetInstrInfo *TII;
929    const TargetRegisterInfo *TRI;
930    const ARMSubtarget *STI;
931    MachineRegisterInfo *MRI;
932
933    virtual bool runOnMachineFunction(MachineFunction &Fn);
934
935    virtual const char *getPassName() const {
936      return "ARM pre- register allocation load / store optimization pass";
937    }
938
939  private:
940    bool CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1, DebugLoc &dl,
941                          unsigned &NewOpc, unsigned &EvenReg,
942                          unsigned &OddReg, unsigned &BaseReg,
943                          unsigned &OffReg, unsigned &Offset,
944                          unsigned &PredReg, ARMCC::CondCodes &Pred);
945    bool RescheduleOps(MachineBasicBlock *MBB,
946                       SmallVector<MachineInstr*, 4> &Ops,
947                       unsigned Base, bool isLd,
948                       DenseMap<MachineInstr*, unsigned> &MI2LocMap);
949    bool RescheduleLoadStoreInstrs(MachineBasicBlock *MBB);
950  };
951  char ARMPreAllocLoadStoreOpt::ID = 0;
952}
953
954bool ARMPreAllocLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
955  TD  = Fn.getTarget().getTargetData();
956  TII = Fn.getTarget().getInstrInfo();
957  TRI = Fn.getTarget().getRegisterInfo();
958  STI = &Fn.getTarget().getSubtarget<ARMSubtarget>();
959  MRI = &Fn.getRegInfo();
960
961  bool Modified = false;
962  for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
963       ++MFI)
964    Modified |= RescheduleLoadStoreInstrs(MFI);
965
966  return Modified;
967}
968
969static bool IsSafeToMove(bool isLd, unsigned Base,
970                         MachineBasicBlock::iterator I,
971                         MachineBasicBlock::iterator E,
972                         SmallPtrSet<MachineInstr*, 4> MoveOps,
973                         const TargetRegisterInfo *TRI) {
974  // Are there stores / loads / calls between them?
975  // FIXME: This is overly conservative. We should make use of alias information
976  // some day.
977  while (++I != E) {
978    const TargetInstrDesc &TID = I->getDesc();
979    if (TID.isCall() || TID.isTerminator() || TID.hasUnmodeledSideEffects())
980      return false;
981    if (isLd && TID.mayStore())
982      return false;
983    if (!isLd) {
984      if (TID.mayLoad())
985        return false;
986      // It's not safe to move the first 'str' down.
987      // str r1, [r0]
988      // strh r5, [r0]
989      // str r4, [r0, #+4]
990      if (TID.mayStore() && !MoveOps.count(&*I))
991        return false;
992    }
993    for (unsigned j = 0, NumOps = I->getNumOperands(); j != NumOps; ++j) {
994      MachineOperand &MO = I->getOperand(j);
995      if (MO.isReg() && MO.isDef() && TRI->regsOverlap(MO.getReg(), Base))
996        return false;
997    }
998  }
999  return true;
1000}
1001
1002bool
1003ARMPreAllocLoadStoreOpt::CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1,
1004                                          DebugLoc &dl,
1005                                          unsigned &NewOpc, unsigned &EvenReg,
1006                                          unsigned &OddReg, unsigned &BaseReg,
1007                                          unsigned &OffReg, unsigned &Offset,
1008                                          unsigned &PredReg,
1009                                          ARMCC::CondCodes &Pred) {
1010  // FIXME: FLDS / FSTS -> FLDD / FSTD
1011  unsigned Opcode = Op0->getOpcode();
1012  if (Opcode == ARM::LDR)
1013    NewOpc = ARM::LDRD;
1014  else if (Opcode == ARM::STR)
1015    NewOpc = ARM::STRD;
1016  else
1017    return 0;
1018
1019  // Must sure the base address satisfies i64 ld / st alignment requirement.
1020  if (!Op0->hasOneMemOperand() ||
1021      !Op0->memoperands_begin()->getValue() ||
1022      Op0->memoperands_begin()->isVolatile())
1023    return false;
1024
1025  unsigned Align = Op0->memoperands_begin()->getAlignment();
1026  unsigned ReqAlign = STI->hasV6Ops()
1027    ? TD->getPrefTypeAlignment(Type::Int64Ty) : 8; // Pre-v6 need 8-byte align
1028  if (Align < ReqAlign)
1029    return false;
1030
1031  // Then make sure the immediate offset fits.
1032  int OffImm = getMemoryOpOffset(Op0);
1033  ARM_AM::AddrOpc AddSub = ARM_AM::add;
1034  if (OffImm < 0) {
1035    AddSub = ARM_AM::sub;
1036    OffImm = - OffImm;
1037  }
1038  if (OffImm >= 256) // 8 bits
1039    return false;
1040  Offset = ARM_AM::getAM3Opc(AddSub, OffImm);
1041
1042  EvenReg = Op0->getOperand(0).getReg();
1043  OddReg  = Op1->getOperand(0).getReg();
1044  if (EvenReg == OddReg)
1045    return false;
1046  BaseReg = Op0->getOperand(1).getReg();
1047  OffReg = Op0->getOperand(2).getReg();
1048  Pred = getInstrPredicate(Op0, PredReg);
1049  dl = Op0->getDebugLoc();
1050  return true;
1051}
1052
1053bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
1054                                 SmallVector<MachineInstr*, 4> &Ops,
1055                                 unsigned Base, bool isLd,
1056                                 DenseMap<MachineInstr*, unsigned> &MI2LocMap) {
1057  bool RetVal = false;
1058
1059  // Sort by offset (in reverse order).
1060  std::sort(Ops.begin(), Ops.end(), OffsetCompare());
1061
1062  // The loads / stores of the same base are in order. Scan them from first to
1063  // last and check for the followins:
1064  // 1. Any def of base.
1065  // 2. Any gaps.
1066  while (Ops.size() > 1) {
1067    unsigned FirstLoc = ~0U;
1068    unsigned LastLoc = 0;
1069    MachineInstr *FirstOp = 0;
1070    MachineInstr *LastOp = 0;
1071    int LastOffset = 0;
1072    unsigned LastBytes = 0;
1073    unsigned NumMove = 0;
1074    for (int i = Ops.size() - 1; i >= 0; --i) {
1075      MachineInstr *Op = Ops[i];
1076      unsigned Loc = MI2LocMap[Op];
1077      if (Loc <= FirstLoc) {
1078        FirstLoc = Loc;
1079        FirstOp = Op;
1080      }
1081      if (Loc >= LastLoc) {
1082        LastLoc = Loc;
1083        LastOp = Op;
1084      }
1085
1086      int Offset = getMemoryOpOffset(Op);
1087      unsigned Bytes = getLSMultipleTransferSize(Op);
1088      if (LastBytes) {
1089        if (Bytes != LastBytes || Offset != (LastOffset + (int)Bytes))
1090          break;
1091      }
1092      LastOffset = Offset;
1093      LastBytes = Bytes;
1094      if (++NumMove == 4)
1095        break;
1096    }
1097
1098    if (NumMove <= 1)
1099      Ops.pop_back();
1100    else {
1101      SmallPtrSet<MachineInstr*, 4> MoveOps;
1102      for (int i = NumMove-1; i >= 0; --i)
1103        MoveOps.insert(Ops[i]);
1104
1105      // Be conservative, if the instructions are too far apart, don't
1106      // move them. We want to limit the increase of register pressure.
1107      bool DoMove = (LastLoc - FirstLoc) < NumMove*4;
1108      if (DoMove)
1109        DoMove = IsSafeToMove(isLd, Base, FirstOp, LastOp, MoveOps, TRI);
1110      if (!DoMove) {
1111        for (unsigned i = 0; i != NumMove; ++i)
1112          Ops.pop_back();
1113      } else {
1114        // This is the new location for the loads / stores.
1115        MachineBasicBlock::iterator InsertPos = isLd ? FirstOp : LastOp;
1116        while (InsertPos != MBB->end() && MoveOps.count(InsertPos))
1117          ++InsertPos;
1118
1119        // If we are moving a pair of loads / stores, see if it makes sense
1120        // to try to allocate a pair of registers that can form register pairs.
1121        MachineInstr *Op0 = Ops.back();
1122        MachineInstr *Op1 = Ops[Ops.size()-2];
1123        unsigned EvenReg = 0, OddReg = 0;
1124        unsigned BaseReg = 0, OffReg = 0, PredReg = 0;
1125        ARMCC::CondCodes Pred = ARMCC::AL;
1126        unsigned NewOpc = 0;
1127        unsigned Offset = 0;
1128        DebugLoc dl;
1129        if (NumMove == 2 && CanFormLdStDWord(Op0, Op1, dl, NewOpc,
1130                                             EvenReg, OddReg, BaseReg, OffReg,
1131                                             Offset, PredReg, Pred)) {
1132          Ops.pop_back();
1133          Ops.pop_back();
1134          MBB->erase(Op0);
1135          MBB->erase(Op1);
1136
1137          // Form the pair instruction.
1138          if (isLd)
1139            BuildMI(*MBB, InsertPos, dl, TII->get(NewOpc))
1140              .addReg(EvenReg, RegState::Define)
1141              .addReg(OddReg, RegState::Define)
1142              .addReg(BaseReg).addReg(0).addImm(Offset)
1143              .addImm(Pred).addReg(PredReg);
1144          else
1145            BuildMI(*MBB, InsertPos, dl, TII->get(NewOpc))
1146              .addReg(EvenReg)
1147              .addReg(OddReg)
1148              .addReg(BaseReg).addReg(0).addImm(Offset)
1149              .addImm(Pred).addReg(PredReg);
1150
1151          // Add register allocation hints to form register pairs.
1152          MRI->setRegAllocationHint(EvenReg, ARMRI::RegPairEven, OddReg);
1153          MRI->setRegAllocationHint(OddReg,  ARMRI::RegPairOdd, EvenReg);
1154        } else {
1155          for (unsigned i = 0; i != NumMove; ++i) {
1156            MachineInstr *Op = Ops.back();
1157            Ops.pop_back();
1158            MBB->splice(InsertPos, MBB, Op);
1159          }
1160        }
1161
1162        NumLdStMoved += NumMove;
1163        RetVal = true;
1164      }
1165    }
1166  }
1167
1168  return RetVal;
1169}
1170
1171bool
1172ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
1173  bool RetVal = false;
1174
1175  DenseMap<MachineInstr*, unsigned> MI2LocMap;
1176  DenseMap<unsigned, SmallVector<MachineInstr*, 4> > Base2LdsMap;
1177  DenseMap<unsigned, SmallVector<MachineInstr*, 4> > Base2StsMap;
1178  SmallVector<unsigned, 4> LdBases;
1179  SmallVector<unsigned, 4> StBases;
1180
1181  unsigned Loc = 0;
1182  MachineBasicBlock::iterator MBBI = MBB->begin();
1183  MachineBasicBlock::iterator E = MBB->end();
1184  while (MBBI != E) {
1185    for (; MBBI != E; ++MBBI) {
1186      MachineInstr *MI = MBBI;
1187      const TargetInstrDesc &TID = MI->getDesc();
1188      if (TID.isCall() || TID.isTerminator()) {
1189        // Stop at barriers.
1190        ++MBBI;
1191        break;
1192      }
1193
1194      MI2LocMap[MI] = Loc++;
1195      if (!isMemoryOp(MI))
1196        continue;
1197      unsigned PredReg = 0;
1198      if (getInstrPredicate(MI, PredReg) != ARMCC::AL)
1199        continue;
1200
1201      int Opcode = MI->getOpcode();
1202      bool isLd = Opcode == ARM::LDR ||
1203        Opcode == ARM::FLDS || Opcode == ARM::FLDD;
1204      unsigned Base = MI->getOperand(1).getReg();
1205      int Offset = getMemoryOpOffset(MI);
1206
1207      bool StopHere = false;
1208      if (isLd) {
1209        DenseMap<unsigned, SmallVector<MachineInstr*, 4> >::iterator BI =
1210          Base2LdsMap.find(Base);
1211        if (BI != Base2LdsMap.end()) {
1212          for (unsigned i = 0, e = BI->second.size(); i != e; ++i) {
1213            if (Offset == getMemoryOpOffset(BI->second[i])) {
1214              StopHere = true;
1215              break;
1216            }
1217          }
1218          if (!StopHere)
1219            BI->second.push_back(MI);
1220        } else {
1221          SmallVector<MachineInstr*, 4> MIs;
1222          MIs.push_back(MI);
1223          Base2LdsMap[Base] = MIs;
1224          LdBases.push_back(Base);
1225        }
1226      } else {
1227        DenseMap<unsigned, SmallVector<MachineInstr*, 4> >::iterator BI =
1228          Base2StsMap.find(Base);
1229        if (BI != Base2StsMap.end()) {
1230          for (unsigned i = 0, e = BI->second.size(); i != e; ++i) {
1231            if (Offset == getMemoryOpOffset(BI->second[i])) {
1232              StopHere = true;
1233              break;
1234            }
1235          }
1236          if (!StopHere)
1237            BI->second.push_back(MI);
1238        } else {
1239          SmallVector<MachineInstr*, 4> MIs;
1240          MIs.push_back(MI);
1241          Base2StsMap[Base] = MIs;
1242          StBases.push_back(Base);
1243        }
1244      }
1245
1246      if (StopHere) {
1247        // Found a duplicate (a base+offset combination that's seen earlier). Backtrack.
1248        --Loc;
1249        break;
1250      }
1251    }
1252
1253    // Re-schedule loads.
1254    for (unsigned i = 0, e = LdBases.size(); i != e; ++i) {
1255      unsigned Base = LdBases[i];
1256      SmallVector<MachineInstr*, 4> &Lds = Base2LdsMap[Base];
1257      if (Lds.size() > 1)
1258        RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap);
1259    }
1260
1261    // Re-schedule stores.
1262    for (unsigned i = 0, e = StBases.size(); i != e; ++i) {
1263      unsigned Base = StBases[i];
1264      SmallVector<MachineInstr*, 4> &Sts = Base2StsMap[Base];
1265      if (Sts.size() > 1)
1266        RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap);
1267    }
1268
1269    if (MBBI != E) {
1270      Base2LdsMap.clear();
1271      Base2StsMap.clear();
1272      LdBases.clear();
1273      StBases.clear();
1274    }
1275  }
1276
1277  return RetVal;
1278}
1279
1280
1281/// createARMLoadStoreOptimizationPass - returns an instance of the load / store
1282/// optimization pass.
1283FunctionPass *llvm::createARMLoadStoreOptimizationPass(bool PreAlloc) {
1284  if (PreAlloc)
1285    return new ARMPreAllocLoadStoreOpt();
1286  return new ARMLoadStoreOpt();
1287}
1288