1 //===-- ARMLoadStoreOptimizer.cpp - ARM load / store opt. pass ----*- C++ -*-=// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains a pass that performs load / store related peephole 11 // optimizations. This pass should be run after register allocation. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #define DEBUG_TYPE "arm-ldst-opt" 16 #include "ARM.h" 17 #include "ARMAddressingModes.h" 18 #include "ARMMachineFunctionInfo.h" 19 #include "ARMRegisterInfo.h" 20 #include "llvm/ADT/STLExtras.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/ADT/Statistic.h" 23 #include "llvm/CodeGen/MachineBasicBlock.h" 24 #include "llvm/CodeGen/MachineFunctionPass.h" 25 #include "llvm/CodeGen/MachineInstr.h" 26 #include "llvm/CodeGen/MachineInstrBuilder.h" 27 #include "llvm/CodeGen/RegisterScavenging.h" 28 #include "llvm/Support/Compiler.h" 29 #include "llvm/Target/TargetRegisterInfo.h" 30 #include "llvm/Target/TargetInstrInfo.h" 31 #include "llvm/Target/TargetMachine.h" 32 using namespace llvm; 33 34 STATISTIC(NumLDMGened , "Number of ldm instructions generated"); 35 STATISTIC(NumSTMGened , "Number of stm instructions generated"); 36 STATISTIC(NumFLDMGened, "Number of fldm instructions generated"); 37 STATISTIC(NumFSTMGened, "Number of fstm instructions generated"); 38 39 namespace { 40 struct VISIBILITY_HIDDEN ARMLoadStoreOpt : public MachineFunctionPass { 41 static char ID; 42 ARMLoadStoreOpt() : MachineFunctionPass(&ID) {} 43 44 const TargetInstrInfo *TII; 45 const TargetRegisterInfo *TRI; 46 ARMFunctionInfo *AFI; 47 RegScavenger *RS; 48 49 virtual bool runOnMachineFunction(MachineFunction &Fn); 50 51 virtual const char *getPassName() const { 52 return "ARM load / store optimization pass"; 53 } 54 55 private: 56 struct MemOpQueueEntry { 57 int Offset; 58 unsigned Position; 59 MachineBasicBlock::iterator MBBI; 60 bool Merged; 61 MemOpQueueEntry(int o, int p, MachineBasicBlock::iterator i) 62 : Offset(o), Position(p), MBBI(i), Merged(false) {}; 63 }; 64 typedef SmallVector<MemOpQueueEntry,8> MemOpQueue; 65 typedef MemOpQueue::iterator MemOpQueueIter; 66 67 bool MergeOps(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, 68 int Offset, unsigned Base, bool BaseKill, int Opcode, 69 ARMCC::CondCodes Pred, unsigned PredReg, unsigned Scratch, 70 DebugLoc dl, SmallVector<std::pair<unsigned, bool>, 8> &Regs); 71 void MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, unsigned Base, 72 int Opcode, unsigned Size, 73 ARMCC::CondCodes Pred, unsigned PredReg, 74 unsigned Scratch, MemOpQueue &MemOps, 75 SmallVector<MachineBasicBlock::iterator, 4> &Merges); 76 77 void AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps); 78 bool LoadStoreMultipleOpti(MachineBasicBlock &MBB); 79 bool MergeReturnIntoLDM(MachineBasicBlock &MBB); 80 }; 81 char ARMLoadStoreOpt::ID = 0; 82 } 83 84 /// createARMLoadStoreOptimizationPass - returns an instance of the load / store 85 /// optimization pass. 86 FunctionPass *llvm::createARMLoadStoreOptimizationPass() { 87 return new ARMLoadStoreOpt(); 88 } 89 90 static int getLoadStoreMultipleOpcode(int Opcode) { 91 switch (Opcode) { 92 case ARM::LDR: 93 NumLDMGened++; 94 return ARM::LDM; 95 case ARM::STR: 96 NumSTMGened++; 97 return ARM::STM; 98 case ARM::FLDS: 99 NumFLDMGened++; 100 return ARM::FLDMS; 101 case ARM::FSTS: 102 NumFSTMGened++; 103 return ARM::FSTMS; 104 case ARM::FLDD: 105 NumFLDMGened++; 106 return ARM::FLDMD; 107 case ARM::FSTD: 108 NumFSTMGened++; 109 return ARM::FSTMD; 110 default: abort(); 111 } 112 return 0; 113 } 114 115 /// MergeOps - Create and insert a LDM or STM with Base as base register and 116 /// registers in Regs as the register operands that would be loaded / stored. 117 /// It returns true if the transformation is done. 118 bool 119 ARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB, 120 MachineBasicBlock::iterator MBBI, 121 int Offset, unsigned Base, bool BaseKill, 122 int Opcode, ARMCC::CondCodes Pred, 123 unsigned PredReg, unsigned Scratch, DebugLoc dl, 124 SmallVector<std::pair<unsigned, bool>, 8> &Regs) { 125 // Only a single register to load / store. Don't bother. 126 unsigned NumRegs = Regs.size(); 127 if (NumRegs <= 1) 128 return false; 129 130 ARM_AM::AMSubMode Mode = ARM_AM::ia; 131 bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR; 132 if (isAM4 && Offset == 4) 133 Mode = ARM_AM::ib; 134 else if (isAM4 && Offset == -4 * (int)NumRegs + 4) 135 Mode = ARM_AM::da; 136 else if (isAM4 && Offset == -4 * (int)NumRegs) 137 Mode = ARM_AM::db; 138 else if (Offset != 0) { 139 // If starting offset isn't zero, insert a MI to materialize a new base. 140 // But only do so if it is cost effective, i.e. merging more than two 141 // loads / stores. 142 if (NumRegs <= 2) 143 return false; 144 145 unsigned NewBase; 146 if (Opcode == ARM::LDR) 147 // If it is a load, then just use one of the destination register to 148 // use as the new base. 149 NewBase = Regs[NumRegs-1].first; 150 else { 151 // Use the scratch register to use as a new base. 152 NewBase = Scratch; 153 if (NewBase == 0) 154 return false; 155 } 156 int BaseOpc = ARM::ADDri; 157 if (Offset < 0) { 158 BaseOpc = ARM::SUBri; 159 Offset = - Offset; 160 } 161 int ImmedOffset = ARM_AM::getSOImmVal(Offset); 162 if (ImmedOffset == -1) 163 return false; // Probably not worth it then. 164 165 BuildMI(MBB, MBBI, dl, TII->get(BaseOpc), NewBase) 166 .addReg(Base, getKillRegState(BaseKill)).addImm(ImmedOffset) 167 .addImm(Pred).addReg(PredReg).addReg(0); 168 Base = NewBase; 169 BaseKill = true; // New base is always killed right its use. 170 } 171 172 bool isDPR = Opcode == ARM::FLDD || Opcode == ARM::FSTD; 173 bool isDef = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD; 174 Opcode = getLoadStoreMultipleOpcode(Opcode); 175 MachineInstrBuilder MIB = (isAM4) 176 ? BuildMI(MBB, MBBI, dl, TII->get(Opcode)) 177 .addReg(Base, getKillRegState(BaseKill)) 178 .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg) 179 : BuildMI(MBB, MBBI, dl, TII->get(Opcode)) 180 .addReg(Base, getKillRegState(BaseKill)) 181 .addImm(ARM_AM::getAM5Opc(Mode, false, isDPR ? NumRegs<<1 : NumRegs)) 182 .addImm(Pred).addReg(PredReg); 183 for (unsigned i = 0; i != NumRegs; ++i) 184 MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef) 185 | getKillRegState(Regs[i].second)); 186 187 return true; 188 } 189 190 /// MergeLDR_STR - Merge a number of load / store instructions into one or more 191 /// load / store multiple instructions. 192 void 193 ARMLoadStoreOpt::MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, 194 unsigned Base, int Opcode, unsigned Size, 195 ARMCC::CondCodes Pred, unsigned PredReg, 196 unsigned Scratch, MemOpQueue &MemOps, 197 SmallVector<MachineBasicBlock::iterator, 4> &Merges) { 198 bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR; 199 int Offset = MemOps[SIndex].Offset; 200 int SOffset = Offset; 201 unsigned Pos = MemOps[SIndex].Position; 202 MachineBasicBlock::iterator Loc = MemOps[SIndex].MBBI; 203 DebugLoc dl = Loc->getDebugLoc(); 204 unsigned PReg = Loc->getOperand(0).getReg(); 205 unsigned PRegNum = ARMRegisterInfo::getRegisterNumbering(PReg); 206 bool isKill = Loc->getOperand(0).isKill(); 207 208 SmallVector<std::pair<unsigned,bool>, 8> Regs; 209 Regs.push_back(std::make_pair(PReg, isKill)); 210 for (unsigned i = SIndex+1, e = MemOps.size(); i != e; ++i) { 211 int NewOffset = MemOps[i].Offset; 212 unsigned Reg = MemOps[i].MBBI->getOperand(0).getReg(); 213 unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg); 214 isKill = MemOps[i].MBBI->getOperand(0).isKill(); 215 // AM4 - register numbers in ascending order. 216 // AM5 - consecutive register numbers in ascending order. 217 if (NewOffset == Offset + (int)Size && 218 ((isAM4 && RegNum > PRegNum) || RegNum == PRegNum+1)) { 219 Offset += Size; 220 Regs.push_back(std::make_pair(Reg, isKill)); 221 PRegNum = RegNum; 222 } else { 223 // Can't merge this in. Try merge the earlier ones first. 224 if (MergeOps(MBB, ++Loc, SOffset, Base, false, Opcode, Pred, PredReg, 225 Scratch, dl, Regs)) { 226 Merges.push_back(prior(Loc)); 227 for (unsigned j = SIndex; j < i; ++j) { 228 MBB.erase(MemOps[j].MBBI); 229 MemOps[j].Merged = true; 230 } 231 } 232 MergeLDR_STR(MBB, i, Base, Opcode, Size, Pred, PredReg, Scratch, 233 MemOps, Merges); 234 return; 235 } 236 237 if (MemOps[i].Position > Pos) { 238 Pos = MemOps[i].Position; 239 Loc = MemOps[i].MBBI; 240 } 241 } 242 243 bool BaseKill = Loc->findRegisterUseOperandIdx(Base, true) != -1; 244 if (MergeOps(MBB, ++Loc, SOffset, Base, BaseKill, Opcode, Pred, PredReg, 245 Scratch, dl, Regs)) { 246 Merges.push_back(prior(Loc)); 247 for (unsigned i = SIndex, e = MemOps.size(); i != e; ++i) { 248 MBB.erase(MemOps[i].MBBI); 249 MemOps[i].Merged = true; 250 } 251 } 252 253 return; 254 } 255 256 /// getInstrPredicate - If instruction is predicated, returns its predicate 257 /// condition, otherwise returns AL. It also returns the condition code 258 /// register by reference. 259 static ARMCC::CondCodes getInstrPredicate(MachineInstr *MI, unsigned &PredReg) { 260 int PIdx = MI->findFirstPredOperandIdx(); 261 if (PIdx == -1) { 262 PredReg = 0; 263 return ARMCC::AL; 264 } 265 266 PredReg = MI->getOperand(PIdx+1).getReg(); 267 return (ARMCC::CondCodes)MI->getOperand(PIdx).getImm(); 268 } 269 270 static inline bool isMatchingDecrement(MachineInstr *MI, unsigned Base, 271 unsigned Bytes, ARMCC::CondCodes Pred, 272 unsigned PredReg) { 273 unsigned MyPredReg = 0; 274 return (MI && MI->getOpcode() == ARM::SUBri && 275 MI->getOperand(0).getReg() == Base && 276 MI->getOperand(1).getReg() == Base && 277 ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes && 278 getInstrPredicate(MI, MyPredReg) == Pred && 279 MyPredReg == PredReg); 280 } 281 282 static inline bool isMatchingIncrement(MachineInstr *MI, unsigned Base, 283 unsigned Bytes, ARMCC::CondCodes Pred, 284 unsigned PredReg) { 285 unsigned MyPredReg = 0; 286 return (MI && MI->getOpcode() == ARM::ADDri && 287 MI->getOperand(0).getReg() == Base && 288 MI->getOperand(1).getReg() == Base && 289 ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes && 290 getInstrPredicate(MI, MyPredReg) == Pred && 291 MyPredReg == PredReg); 292 } 293 294 static inline unsigned getLSMultipleTransferSize(MachineInstr *MI) { 295 switch (MI->getOpcode()) { 296 default: return 0; 297 case ARM::LDR: 298 case ARM::STR: 299 case ARM::FLDS: 300 case ARM::FSTS: 301 return 4; 302 case ARM::FLDD: 303 case ARM::FSTD: 304 return 8; 305 case ARM::LDM: 306 case ARM::STM: 307 return (MI->getNumOperands() - 4) * 4; 308 case ARM::FLDMS: 309 case ARM::FSTMS: 310 case ARM::FLDMD: 311 case ARM::FSTMD: 312 return ARM_AM::getAM5Offset(MI->getOperand(1).getImm()) * 4; 313 } 314 } 315 316 /// mergeBaseUpdateLSMultiple - Fold proceeding/trailing inc/dec of base 317 /// register into the LDM/STM/FLDM{D|S}/FSTM{D|S} op when possible: 318 /// 319 /// stmia rn, <ra, rb, rc> 320 /// rn := rn + 4 * 3; 321 /// => 322 /// stmia rn!, <ra, rb, rc> 323 /// 324 /// rn := rn - 4 * 3; 325 /// ldmia rn, <ra, rb, rc> 326 /// => 327 /// ldmdb rn!, <ra, rb, rc> 328 static bool mergeBaseUpdateLSMultiple(MachineBasicBlock &MBB, 329 MachineBasicBlock::iterator MBBI, 330 bool &Advance, 331 MachineBasicBlock::iterator &I) { 332 MachineInstr *MI = MBBI; 333 unsigned Base = MI->getOperand(0).getReg(); 334 unsigned Bytes = getLSMultipleTransferSize(MI); 335 unsigned PredReg = 0; 336 ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg); 337 int Opcode = MI->getOpcode(); 338 bool isAM4 = Opcode == ARM::LDM || Opcode == ARM::STM; 339 340 if (isAM4) { 341 if (ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm())) 342 return false; 343 344 // Can't use the updating AM4 sub-mode if the base register is also a dest 345 // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined. 346 for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) { 347 if (MI->getOperand(i).getReg() == Base) 348 return false; 349 } 350 351 ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm()); 352 if (MBBI != MBB.begin()) { 353 MachineBasicBlock::iterator PrevMBBI = prior(MBBI); 354 if (Mode == ARM_AM::ia && 355 isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) { 356 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::db, true)); 357 MBB.erase(PrevMBBI); 358 return true; 359 } else if (Mode == ARM_AM::ib && 360 isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) { 361 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::da, true)); 362 MBB.erase(PrevMBBI); 363 return true; 364 } 365 } 366 367 if (MBBI != MBB.end()) { 368 MachineBasicBlock::iterator NextMBBI = next(MBBI); 369 if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) && 370 isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) { 371 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true)); 372 if (NextMBBI == I) { 373 Advance = true; 374 ++I; 375 } 376 MBB.erase(NextMBBI); 377 return true; 378 } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) && 379 isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) { 380 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true)); 381 if (NextMBBI == I) { 382 Advance = true; 383 ++I; 384 } 385 MBB.erase(NextMBBI); 386 return true; 387 } 388 } 389 } else { 390 // FLDM{D|S}, FSTM{D|S} addressing mode 5 ops. 391 if (ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm())) 392 return false; 393 394 ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm()); 395 unsigned Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm()); 396 if (MBBI != MBB.begin()) { 397 MachineBasicBlock::iterator PrevMBBI = prior(MBBI); 398 if (Mode == ARM_AM::ia && 399 isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) { 400 MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::db, true, Offset)); 401 MBB.erase(PrevMBBI); 402 return true; 403 } 404 } 405 406 if (MBBI != MBB.end()) { 407 MachineBasicBlock::iterator NextMBBI = next(MBBI); 408 if (Mode == ARM_AM::ia && 409 isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) { 410 MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::ia, true, Offset)); 411 if (NextMBBI == I) { 412 Advance = true; 413 ++I; 414 } 415 MBB.erase(NextMBBI); 416 } 417 return true; 418 } 419 } 420 421 return false; 422 } 423 424 static unsigned getPreIndexedLoadStoreOpcode(unsigned Opc) { 425 switch (Opc) { 426 case ARM::LDR: return ARM::LDR_PRE; 427 case ARM::STR: return ARM::STR_PRE; 428 case ARM::FLDS: return ARM::FLDMS; 429 case ARM::FLDD: return ARM::FLDMD; 430 case ARM::FSTS: return ARM::FSTMS; 431 case ARM::FSTD: return ARM::FSTMD; 432 default: abort(); 433 } 434 return 0; 435 } 436 437 static unsigned getPostIndexedLoadStoreOpcode(unsigned Opc) { 438 switch (Opc) { 439 case ARM::LDR: return ARM::LDR_POST; 440 case ARM::STR: return ARM::STR_POST; 441 case ARM::FLDS: return ARM::FLDMS; 442 case ARM::FLDD: return ARM::FLDMD; 443 case ARM::FSTS: return ARM::FSTMS; 444 case ARM::FSTD: return ARM::FSTMD; 445 default: abort(); 446 } 447 return 0; 448 } 449 450 /// mergeBaseUpdateLoadStore - Fold proceeding/trailing inc/dec of base 451 /// register into the LDR/STR/FLD{D|S}/FST{D|S} op when possible: 452 static bool mergeBaseUpdateLoadStore(MachineBasicBlock &MBB, 453 MachineBasicBlock::iterator MBBI, 454 const TargetInstrInfo *TII, 455 bool &Advance, 456 MachineBasicBlock::iterator &I) { 457 MachineInstr *MI = MBBI; 458 unsigned Base = MI->getOperand(1).getReg(); 459 bool BaseKill = MI->getOperand(1).isKill(); 460 unsigned Bytes = getLSMultipleTransferSize(MI); 461 int Opcode = MI->getOpcode(); 462 DebugLoc dl = MI->getDebugLoc(); 463 bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR; 464 if ((isAM2 && ARM_AM::getAM2Offset(MI->getOperand(3).getImm()) != 0) || 465 (!isAM2 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0)) 466 return false; 467 468 bool isLd = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD; 469 // Can't do the merge if the destination register is the same as the would-be 470 // writeback register. 471 if (isLd && MI->getOperand(0).getReg() == Base) 472 return false; 473 474 unsigned PredReg = 0; 475 ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg); 476 bool DoMerge = false; 477 ARM_AM::AddrOpc AddSub = ARM_AM::add; 478 unsigned NewOpc = 0; 479 if (MBBI != MBB.begin()) { 480 MachineBasicBlock::iterator PrevMBBI = prior(MBBI); 481 if (isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) { 482 DoMerge = true; 483 AddSub = ARM_AM::sub; 484 NewOpc = getPreIndexedLoadStoreOpcode(Opcode); 485 } else if (isAM2 && isMatchingIncrement(PrevMBBI, Base, Bytes, 486 Pred, PredReg)) { 487 DoMerge = true; 488 NewOpc = getPreIndexedLoadStoreOpcode(Opcode); 489 } 490 if (DoMerge) 491 MBB.erase(PrevMBBI); 492 } 493 494 if (!DoMerge && MBBI != MBB.end()) { 495 MachineBasicBlock::iterator NextMBBI = next(MBBI); 496 if (isAM2 && isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) { 497 DoMerge = true; 498 AddSub = ARM_AM::sub; 499 NewOpc = getPostIndexedLoadStoreOpcode(Opcode); 500 } else if (isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) { 501 DoMerge = true; 502 NewOpc = getPostIndexedLoadStoreOpcode(Opcode); 503 } 504 if (DoMerge) { 505 if (NextMBBI == I) { 506 Advance = true; 507 ++I; 508 } 509 MBB.erase(NextMBBI); 510 } 511 } 512 513 if (!DoMerge) 514 return false; 515 516 bool isDPR = NewOpc == ARM::FLDMD || NewOpc == ARM::FSTMD; 517 unsigned Offset = isAM2 ? ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift) 518 : ARM_AM::getAM5Opc((AddSub == ARM_AM::sub) ? ARM_AM::db : ARM_AM::ia, 519 true, isDPR ? 2 : 1); 520 if (isLd) { 521 if (isAM2) 522 // LDR_PRE, LDR_POST; 523 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), MI->getOperand(0).getReg()) 524 .addReg(Base, RegState::Define) 525 .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg); 526 else 527 // FLDMS, FLDMD 528 BuildMI(MBB, MBBI, dl, TII->get(NewOpc)) 529 .addReg(Base, getKillRegState(BaseKill)) 530 .addImm(Offset).addImm(Pred).addReg(PredReg) 531 .addReg(MI->getOperand(0).getReg(), RegState::Define); 532 } else { 533 MachineOperand &MO = MI->getOperand(0); 534 if (isAM2) 535 // STR_PRE, STR_POST; 536 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), Base) 537 .addReg(MO.getReg(), getKillRegState(MO.isKill())) 538 .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg); 539 else 540 // FSTMS, FSTMD 541 BuildMI(MBB, MBBI, dl, TII->get(NewOpc)).addReg(Base).addImm(Offset) 542 .addImm(Pred).addReg(PredReg) 543 .addReg(MO.getReg(), getKillRegState(MO.isKill())); 544 } 545 MBB.erase(MBBI); 546 547 return true; 548 } 549 550 /// isMemoryOp - Returns true if instruction is a memory operations (that this 551 /// pass is capable of operating on). 552 static bool isMemoryOp(MachineInstr *MI) { 553 int Opcode = MI->getOpcode(); 554 switch (Opcode) { 555 default: break; 556 case ARM::LDR: 557 case ARM::STR: 558 return MI->getOperand(1).isReg() && MI->getOperand(2).getReg() == 0; 559 case ARM::FLDS: 560 case ARM::FSTS: 561 return MI->getOperand(1).isReg(); 562 case ARM::FLDD: 563 case ARM::FSTD: 564 return MI->getOperand(1).isReg(); 565 } 566 return false; 567 } 568 569 /// AdvanceRS - Advance register scavenger to just before the earliest memory 570 /// op that is being merged. 571 void ARMLoadStoreOpt::AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps) { 572 MachineBasicBlock::iterator Loc = MemOps[0].MBBI; 573 unsigned Position = MemOps[0].Position; 574 for (unsigned i = 1, e = MemOps.size(); i != e; ++i) { 575 if (MemOps[i].Position < Position) { 576 Position = MemOps[i].Position; 577 Loc = MemOps[i].MBBI; 578 } 579 } 580 581 if (Loc != MBB.begin()) 582 RS->forward(prior(Loc)); 583 } 584 585 /// LoadStoreMultipleOpti - An optimization pass to turn multiple LDR / STR 586 /// ops of the same base and incrementing offset into LDM / STM ops. 587 bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) { 588 unsigned NumMerges = 0; 589 unsigned NumMemOps = 0; 590 MemOpQueue MemOps; 591 unsigned CurrBase = 0; 592 int CurrOpc = -1; 593 unsigned CurrSize = 0; 594 ARMCC::CondCodes CurrPred = ARMCC::AL; 595 unsigned CurrPredReg = 0; 596 unsigned Position = 0; 597 SmallVector<MachineBasicBlock::iterator,4> Merges; 598 599 RS->enterBasicBlock(&MBB); 600 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end(); 601 while (MBBI != E) { 602 bool Advance = false; 603 bool TryMerge = false; 604 bool Clobber = false; 605 606 bool isMemOp = isMemoryOp(MBBI); 607 if (isMemOp) { 608 int Opcode = MBBI->getOpcode(); 609 bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR; 610 unsigned Size = getLSMultipleTransferSize(MBBI); 611 unsigned Base = MBBI->getOperand(1).getReg(); 612 unsigned PredReg = 0; 613 ARMCC::CondCodes Pred = getInstrPredicate(MBBI, PredReg); 614 unsigned NumOperands = MBBI->getDesc().getNumOperands(); 615 unsigned OffField = MBBI->getOperand(NumOperands-3).getImm(); 616 int Offset = isAM2 617 ? ARM_AM::getAM2Offset(OffField) : ARM_AM::getAM5Offset(OffField) * 4; 618 if (isAM2) { 619 if (ARM_AM::getAM2Op(OffField) == ARM_AM::sub) 620 Offset = -Offset; 621 } else { 622 if (ARM_AM::getAM5Op(OffField) == ARM_AM::sub) 623 Offset = -Offset; 624 } 625 // Watch out for: 626 // r4 := ldr [r5] 627 // r5 := ldr [r5, #4] 628 // r6 := ldr [r5, #8] 629 // 630 // The second ldr has effectively broken the chain even though it 631 // looks like the later ldr(s) use the same base register. Try to 632 // merge the ldr's so far, including this one. But don't try to 633 // combine the following ldr(s). 634 Clobber = (Opcode == ARM::LDR && Base == MBBI->getOperand(0).getReg()); 635 if (CurrBase == 0 && !Clobber) { 636 // Start of a new chain. 637 CurrBase = Base; 638 CurrOpc = Opcode; 639 CurrSize = Size; 640 CurrPred = Pred; 641 CurrPredReg = PredReg; 642 MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI)); 643 NumMemOps++; 644 Advance = true; 645 } else { 646 if (Clobber) { 647 TryMerge = true; 648 Advance = true; 649 } 650 651 if (CurrOpc == Opcode && CurrBase == Base && CurrPred == Pred) { 652 // No need to match PredReg. 653 // Continue adding to the queue. 654 if (Offset > MemOps.back().Offset) { 655 MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI)); 656 NumMemOps++; 657 Advance = true; 658 } else { 659 for (MemOpQueueIter I = MemOps.begin(), E = MemOps.end(); 660 I != E; ++I) { 661 if (Offset < I->Offset) { 662 MemOps.insert(I, MemOpQueueEntry(Offset, Position, MBBI)); 663 NumMemOps++; 664 Advance = true; 665 break; 666 } else if (Offset == I->Offset) { 667 // Collision! This can't be merged! 668 break; 669 } 670 } 671 } 672 } 673 } 674 } 675 676 if (Advance) { 677 ++Position; 678 ++MBBI; 679 } else 680 TryMerge = true; 681 682 if (TryMerge) { 683 if (NumMemOps > 1) { 684 // Try to find a free register to use as a new base in case it's needed. 685 // First advance to the instruction just before the start of the chain. 686 AdvanceRS(MBB, MemOps); 687 // Find a scratch register. Make sure it's a call clobbered register or 688 // a spilled callee-saved register. 689 unsigned Scratch = RS->FindUnusedReg(&ARM::GPRRegClass, true); 690 if (!Scratch) 691 Scratch = RS->FindUnusedReg(&ARM::GPRRegClass, 692 AFI->getSpilledCSRegisters()); 693 // Process the load / store instructions. 694 RS->forward(prior(MBBI)); 695 696 // Merge ops. 697 Merges.clear(); 698 MergeLDR_STR(MBB, 0, CurrBase, CurrOpc, CurrSize, 699 CurrPred, CurrPredReg, Scratch, MemOps, Merges); 700 701 // Try folding preceeding/trailing base inc/dec into the generated 702 // LDM/STM ops. 703 for (unsigned i = 0, e = Merges.size(); i < e; ++i) 704 if (mergeBaseUpdateLSMultiple(MBB, Merges[i], Advance, MBBI)) 705 ++NumMerges; 706 NumMerges += Merges.size(); 707 708 // Try folding preceeding/trailing base inc/dec into those load/store 709 // that were not merged to form LDM/STM ops. 710 for (unsigned i = 0; i != NumMemOps; ++i) 711 if (!MemOps[i].Merged) 712 if (mergeBaseUpdateLoadStore(MBB, MemOps[i].MBBI, TII,Advance,MBBI)) 713 ++NumMerges; 714 715 // RS may be pointing to an instruction that's deleted. 716 RS->skipTo(prior(MBBI)); 717 } else if (NumMemOps == 1) { 718 // Try folding preceeding/trailing base inc/dec into the single 719 // load/store. 720 if (mergeBaseUpdateLoadStore(MBB, MemOps[0].MBBI, TII, Advance, MBBI)) { 721 ++NumMerges; 722 RS->forward(prior(MBBI)); 723 } 724 } 725 726 CurrBase = 0; 727 CurrOpc = -1; 728 CurrSize = 0; 729 CurrPred = ARMCC::AL; 730 CurrPredReg = 0; 731 if (NumMemOps) { 732 MemOps.clear(); 733 NumMemOps = 0; 734 } 735 736 // If iterator hasn't been advanced and this is not a memory op, skip it. 737 // It can't start a new chain anyway. 738 if (!Advance && !isMemOp && MBBI != E) { 739 ++Position; 740 ++MBBI; 741 } 742 } 743 } 744 return NumMerges > 0; 745 } 746 747 /// MergeReturnIntoLDM - If this is a exit BB, try merging the return op 748 /// (bx lr) into the preceeding stack restore so it directly restore the value 749 /// of LR into pc. 750 /// ldmfd sp!, {r7, lr} 751 /// bx lr 752 /// => 753 /// ldmfd sp!, {r7, pc} 754 bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) { 755 if (MBB.empty()) return false; 756 757 MachineBasicBlock::iterator MBBI = prior(MBB.end()); 758 if (MBBI->getOpcode() == ARM::BX_RET && MBBI != MBB.begin()) { 759 MachineInstr *PrevMI = prior(MBBI); 760 if (PrevMI->getOpcode() == ARM::LDM) { 761 MachineOperand &MO = PrevMI->getOperand(PrevMI->getNumOperands()-1); 762 if (MO.getReg() == ARM::LR) { 763 PrevMI->setDesc(TII->get(ARM::LDM_RET)); 764 MO.setReg(ARM::PC); 765 MBB.erase(MBBI); 766 return true; 767 } 768 } 769 } 770 return false; 771 } 772 773 bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) { 774 const TargetMachine &TM = Fn.getTarget(); 775 AFI = Fn.getInfo<ARMFunctionInfo>(); 776 TII = TM.getInstrInfo(); 777 TRI = TM.getRegisterInfo(); 778 RS = new RegScavenger(); 779 780 bool Modified = false; 781 for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; 782 ++MFI) { 783 MachineBasicBlock &MBB = *MFI; 784 Modified |= LoadStoreMultipleOpti(MBB); 785 Modified |= MergeReturnIntoLDM(MBB); 786 } 787 788 delete RS; 789 return Modified; 790 } 791