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