blob: 67c42580465e0cea81e2abd884839d42fccfb7fa [file] [log] [blame]
Evan Chenga8e29892007-01-19 07:51:42 +00001//===-- ARMLoadStoreOptimizer.cpp - ARM load / store opt. pass ----*- C++ -*-=//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner4ee451d2007-12-29 20:36:04 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Evan Chenga8e29892007-01-19 07:51:42 +00007//
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"
Evan Cheng603b83e2007-03-07 20:30:36 +000018#include "ARMMachineFunctionInfo.h"
Evan Chenga8e29892007-01-19 07:51:42 +000019#include "ARMRegisterInfo.h"
Evan Cheng358dec52009-06-15 08:28:29 +000020#include "llvm/DerivedTypes.h"
Evan Chenga8e29892007-01-19 07:51:42 +000021#include "llvm/CodeGen/MachineBasicBlock.h"
22#include "llvm/CodeGen/MachineFunctionPass.h"
23#include "llvm/CodeGen/MachineInstr.h"
24#include "llvm/CodeGen/MachineInstrBuilder.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000025#include "llvm/CodeGen/MachineRegisterInfo.h"
Evan Chengcc1c4272007-03-06 18:02:41 +000026#include "llvm/CodeGen/RegisterScavenging.h"
Evan Cheng358dec52009-06-15 08:28:29 +000027#include "llvm/Target/TargetData.h"
Evan Chenga8e29892007-01-19 07:51:42 +000028#include "llvm/Target/TargetInstrInfo.h"
29#include "llvm/Target/TargetMachine.h"
Evan Cheng358dec52009-06-15 08:28:29 +000030#include "llvm/Target/TargetRegisterInfo.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000031#include "llvm/Support/Compiler.h"
Torok Edwinab7c09b2009-07-08 18:01:40 +000032#include "llvm/Support/ErrorHandling.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000033#include "llvm/ADT/DenseMap.h"
34#include "llvm/ADT/STLExtras.h"
35#include "llvm/ADT/SmallPtrSet.h"
Evan Chengae69a2a2009-06-19 23:17:27 +000036#include "llvm/ADT/SmallSet.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000037#include "llvm/ADT/SmallVector.h"
38#include "llvm/ADT/Statistic.h"
Evan Chenga8e29892007-01-19 07:51:42 +000039using namespace llvm;
40
41STATISTIC(NumLDMGened , "Number of ldm instructions generated");
42STATISTIC(NumSTMGened , "Number of stm instructions generated");
43STATISTIC(NumFLDMGened, "Number of fldm instructions generated");
44STATISTIC(NumFSTMGened, "Number of fstm instructions generated");
Evan Chenge7d6df72009-06-13 09:12:55 +000045STATISTIC(NumLdStMoved, "Number of load / store instructions moved");
Evan Chengf9f1da12009-06-18 02:04:01 +000046STATISTIC(NumLDRDFormed,"Number of ldrd created before allocation");
47STATISTIC(NumSTRDFormed,"Number of strd created before allocation");
48STATISTIC(NumLDRD2LDM, "Number of ldrd instructions turned back into ldm");
49STATISTIC(NumSTRD2STM, "Number of strd instructions turned back into stm");
50STATISTIC(NumLDRD2LDR, "Number of ldrd instructions turned back into ldr's");
51STATISTIC(NumSTRD2STR, "Number of strd instructions turned back into str's");
Evan Chenge7d6df72009-06-13 09:12:55 +000052
53/// ARMAllocLoadStoreOpt - Post- register allocation pass the combine
54/// load / store instructions to form ldm / stm instructions.
Evan Chenga8e29892007-01-19 07:51:42 +000055
56namespace {
57 struct VISIBILITY_HIDDEN ARMLoadStoreOpt : public MachineFunctionPass {
Devang Patel19974732007-05-03 01:11:54 +000058 static char ID;
Dan Gohmanae73dc12008-09-04 17:05:41 +000059 ARMLoadStoreOpt() : MachineFunctionPass(&ID) {}
Devang Patel794fd752007-05-01 21:15:47 +000060
Evan Chenga8e29892007-01-19 07:51:42 +000061 const TargetInstrInfo *TII;
Dan Gohman6f0d0242008-02-10 18:45:23 +000062 const TargetRegisterInfo *TRI;
Evan Cheng603b83e2007-03-07 20:30:36 +000063 ARMFunctionInfo *AFI;
Evan Chengcc1c4272007-03-06 18:02:41 +000064 RegScavenger *RS;
Evan Chenga8e29892007-01-19 07:51:42 +000065
66 virtual bool runOnMachineFunction(MachineFunction &Fn);
67
68 virtual const char *getPassName() const {
69 return "ARM load / store optimization pass";
70 }
71
72 private:
73 struct MemOpQueueEntry {
74 int Offset;
75 unsigned Position;
76 MachineBasicBlock::iterator MBBI;
77 bool Merged;
78 MemOpQueueEntry(int o, int p, MachineBasicBlock::iterator i)
79 : Offset(o), Position(p), MBBI(i), Merged(false) {};
80 };
81 typedef SmallVector<MemOpQueueEntry,8> MemOpQueue;
82 typedef MemOpQueue::iterator MemOpQueueIter;
83
Evan Cheng92549222009-06-05 19:08:58 +000084 bool MergeOps(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
Evan Cheng87d59e42009-06-05 18:19:23 +000085 int Offset, unsigned Base, bool BaseKill, int Opcode,
86 ARMCC::CondCodes Pred, unsigned PredReg, unsigned Scratch,
87 DebugLoc dl, SmallVector<std::pair<unsigned, bool>, 8> &Regs);
Evan Cheng5ba71882009-06-05 17:56:14 +000088 void MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, unsigned Base,
89 int Opcode, unsigned Size,
90 ARMCC::CondCodes Pred, unsigned PredReg,
91 unsigned Scratch, MemOpQueue &MemOps,
92 SmallVector<MachineBasicBlock::iterator, 4> &Merges);
Evan Chenga8e29892007-01-19 07:51:42 +000093
Evan Cheng11788fd2007-03-08 02:55:08 +000094 void AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps);
Evan Cheng358dec52009-06-15 08:28:29 +000095 bool FixInvalidRegPairOp(MachineBasicBlock &MBB,
96 MachineBasicBlock::iterator &MBBI);
Evan Chenga8e29892007-01-19 07:51:42 +000097 bool LoadStoreMultipleOpti(MachineBasicBlock &MBB);
98 bool MergeReturnIntoLDM(MachineBasicBlock &MBB);
99 };
Devang Patel19974732007-05-03 01:11:54 +0000100 char ARMLoadStoreOpt::ID = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000101}
102
Evan Chenga8e29892007-01-19 07:51:42 +0000103static int getLoadStoreMultipleOpcode(int Opcode) {
104 switch (Opcode) {
105 case ARM::LDR:
106 NumLDMGened++;
107 return ARM::LDM;
108 case ARM::STR:
109 NumSTMGened++;
110 return ARM::STM;
111 case ARM::FLDS:
112 NumFLDMGened++;
113 return ARM::FLDMS;
114 case ARM::FSTS:
115 NumFSTMGened++;
116 return ARM::FSTMS;
117 case ARM::FLDD:
118 NumFLDMGened++;
119 return ARM::FLDMD;
120 case ARM::FSTD:
121 NumFSTMGened++;
122 return ARM::FSTMD;
Torok Edwindac237e2009-07-08 20:53:28 +0000123 default: LLVM_UNREACHABLE("Unhandled opcode!");
Evan Chenga8e29892007-01-19 07:51:42 +0000124 }
125 return 0;
126}
127
Evan Cheng92549222009-06-05 19:08:58 +0000128/// MergeOps - Create and insert a LDM or STM with Base as base register and
Evan Chenga8e29892007-01-19 07:51:42 +0000129/// registers in Regs as the register operands that would be loaded / stored.
130/// It returns true if the transformation is done.
Evan Cheng87d59e42009-06-05 18:19:23 +0000131bool
Evan Cheng92549222009-06-05 19:08:58 +0000132ARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB,
Evan Cheng87d59e42009-06-05 18:19:23 +0000133 MachineBasicBlock::iterator MBBI,
134 int Offset, unsigned Base, bool BaseKill,
135 int Opcode, ARMCC::CondCodes Pred,
136 unsigned PredReg, unsigned Scratch, DebugLoc dl,
137 SmallVector<std::pair<unsigned, bool>, 8> &Regs) {
Evan Chenga8e29892007-01-19 07:51:42 +0000138 // Only a single register to load / store. Don't bother.
139 unsigned NumRegs = Regs.size();
140 if (NumRegs <= 1)
141 return false;
142
143 ARM_AM::AMSubMode Mode = ARM_AM::ia;
144 bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR;
145 if (isAM4 && Offset == 4)
146 Mode = ARM_AM::ib;
147 else if (isAM4 && Offset == -4 * (int)NumRegs + 4)
148 Mode = ARM_AM::da;
149 else if (isAM4 && Offset == -4 * (int)NumRegs)
150 Mode = ARM_AM::db;
151 else if (Offset != 0) {
152 // If starting offset isn't zero, insert a MI to materialize a new base.
153 // But only do so if it is cost effective, i.e. merging more than two
154 // loads / stores.
155 if (NumRegs <= 2)
156 return false;
157
158 unsigned NewBase;
159 if (Opcode == ARM::LDR)
160 // If it is a load, then just use one of the destination register to
161 // use as the new base.
Evan Chenga90f3402007-03-06 21:59:20 +0000162 NewBase = Regs[NumRegs-1].first;
Evan Chenga8e29892007-01-19 07:51:42 +0000163 else {
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000164 // Use the scratch register to use as a new base.
165 NewBase = Scratch;
Evan Chenga90f3402007-03-06 21:59:20 +0000166 if (NewBase == 0)
167 return false;
Evan Chenga8e29892007-01-19 07:51:42 +0000168 }
169 int BaseOpc = ARM::ADDri;
170 if (Offset < 0) {
171 BaseOpc = ARM::SUBri;
172 Offset = - Offset;
173 }
174 int ImmedOffset = ARM_AM::getSOImmVal(Offset);
175 if (ImmedOffset == -1)
176 return false; // Probably not worth it then.
Evan Chenga90f3402007-03-06 21:59:20 +0000177
Dale Johannesenb6728402009-02-13 02:25:56 +0000178 BuildMI(MBB, MBBI, dl, TII->get(BaseOpc), NewBase)
Bill Wendling587daed2009-05-13 21:33:08 +0000179 .addReg(Base, getKillRegState(BaseKill)).addImm(ImmedOffset)
Evan Cheng13ab0202007-07-10 18:08:01 +0000180 .addImm(Pred).addReg(PredReg).addReg(0);
Evan Chenga8e29892007-01-19 07:51:42 +0000181 Base = NewBase;
Evan Chenga90f3402007-03-06 21:59:20 +0000182 BaseKill = true; // New base is always killed right its use.
Evan Chenga8e29892007-01-19 07:51:42 +0000183 }
184
185 bool isDPR = Opcode == ARM::FLDD || Opcode == ARM::FSTD;
186 bool isDef = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
187 Opcode = getLoadStoreMultipleOpcode(Opcode);
188 MachineInstrBuilder MIB = (isAM4)
Dale Johannesenb6728402009-02-13 02:25:56 +0000189 ? BuildMI(MBB, MBBI, dl, TII->get(Opcode))
Bill Wendling587daed2009-05-13 21:33:08 +0000190 .addReg(Base, getKillRegState(BaseKill))
Evan Cheng0e1d3792007-07-05 07:18:20 +0000191 .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg)
Dale Johannesenb6728402009-02-13 02:25:56 +0000192 : BuildMI(MBB, MBBI, dl, TII->get(Opcode))
Bill Wendling587daed2009-05-13 21:33:08 +0000193 .addReg(Base, getKillRegState(BaseKill))
Evan Cheng44bec522007-05-15 01:29:07 +0000194 .addImm(ARM_AM::getAM5Opc(Mode, false, isDPR ? NumRegs<<1 : NumRegs))
Evan Cheng0e1d3792007-07-05 07:18:20 +0000195 .addImm(Pred).addReg(PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000196 for (unsigned i = 0; i != NumRegs; ++i)
Bill Wendling587daed2009-05-13 21:33:08 +0000197 MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef)
198 | getKillRegState(Regs[i].second));
Evan Chenga8e29892007-01-19 07:51:42 +0000199
200 return true;
201}
202
Evan Chenga90f3402007-03-06 21:59:20 +0000203/// MergeLDR_STR - Merge a number of load / store instructions into one or more
204/// load / store multiple instructions.
Evan Cheng5ba71882009-06-05 17:56:14 +0000205void
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000206ARMLoadStoreOpt::MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex,
Evan Cheng5ba71882009-06-05 17:56:14 +0000207 unsigned Base, int Opcode, unsigned Size,
208 ARMCC::CondCodes Pred, unsigned PredReg,
209 unsigned Scratch, MemOpQueue &MemOps,
210 SmallVector<MachineBasicBlock::iterator, 4> &Merges) {
Evan Chenga90f3402007-03-06 21:59:20 +0000211 bool isAM4 = Opcode == ARM::LDR || Opcode == ARM::STR;
Evan Chenga8e29892007-01-19 07:51:42 +0000212 int Offset = MemOps[SIndex].Offset;
213 int SOffset = Offset;
214 unsigned Pos = MemOps[SIndex].Position;
215 MachineBasicBlock::iterator Loc = MemOps[SIndex].MBBI;
Evan Cheng87d59e42009-06-05 18:19:23 +0000216 DebugLoc dl = Loc->getDebugLoc();
217 unsigned PReg = Loc->getOperand(0).getReg();
Evan Chenga8e29892007-01-19 07:51:42 +0000218 unsigned PRegNum = ARMRegisterInfo::getRegisterNumbering(PReg);
Evan Cheng87d59e42009-06-05 18:19:23 +0000219 bool isKill = Loc->getOperand(0).isKill();
Evan Cheng44bec522007-05-15 01:29:07 +0000220
221 SmallVector<std::pair<unsigned,bool>, 8> Regs;
Evan Chenga90f3402007-03-06 21:59:20 +0000222 Regs.push_back(std::make_pair(PReg, isKill));
Evan Chenga8e29892007-01-19 07:51:42 +0000223 for (unsigned i = SIndex+1, e = MemOps.size(); i != e; ++i) {
224 int NewOffset = MemOps[i].Offset;
225 unsigned Reg = MemOps[i].MBBI->getOperand(0).getReg();
226 unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg);
Evan Chenga90f3402007-03-06 21:59:20 +0000227 isKill = MemOps[i].MBBI->getOperand(0).isKill();
Evan Chenga8e29892007-01-19 07:51:42 +0000228 // AM4 - register numbers in ascending order.
229 // AM5 - consecutive register numbers in ascending order.
230 if (NewOffset == Offset + (int)Size &&
231 ((isAM4 && RegNum > PRegNum) || RegNum == PRegNum+1)) {
232 Offset += Size;
Evan Chenga90f3402007-03-06 21:59:20 +0000233 Regs.push_back(std::make_pair(Reg, isKill));
Evan Chenga8e29892007-01-19 07:51:42 +0000234 PRegNum = RegNum;
235 } else {
236 // Can't merge this in. Try merge the earlier ones first.
Evan Cheng92549222009-06-05 19:08:58 +0000237 if (MergeOps(MBB, ++Loc, SOffset, Base, false, Opcode, Pred, PredReg,
Evan Cheng87d59e42009-06-05 18:19:23 +0000238 Scratch, dl, Regs)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000239 Merges.push_back(prior(Loc));
240 for (unsigned j = SIndex; j < i; ++j) {
241 MBB.erase(MemOps[j].MBBI);
242 MemOps[j].Merged = true;
243 }
244 }
Evan Cheng5ba71882009-06-05 17:56:14 +0000245 MergeLDR_STR(MBB, i, Base, Opcode, Size, Pred, PredReg, Scratch,
246 MemOps, Merges);
247 return;
Evan Chenga8e29892007-01-19 07:51:42 +0000248 }
249
250 if (MemOps[i].Position > Pos) {
251 Pos = MemOps[i].Position;
252 Loc = MemOps[i].MBBI;
253 }
254 }
255
Evan Chengfaa51072007-04-26 19:00:32 +0000256 bool BaseKill = Loc->findRegisterUseOperandIdx(Base, true) != -1;
Evan Cheng92549222009-06-05 19:08:58 +0000257 if (MergeOps(MBB, ++Loc, SOffset, Base, BaseKill, Opcode, Pred, PredReg,
Evan Cheng87d59e42009-06-05 18:19:23 +0000258 Scratch, dl, Regs)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000259 Merges.push_back(prior(Loc));
260 for (unsigned i = SIndex, e = MemOps.size(); i != e; ++i) {
261 MBB.erase(MemOps[i].MBBI);
262 MemOps[i].Merged = true;
263 }
264 }
265
Evan Cheng5ba71882009-06-05 17:56:14 +0000266 return;
Evan Chenga8e29892007-01-19 07:51:42 +0000267}
268
Evan Cheng44bec522007-05-15 01:29:07 +0000269/// getInstrPredicate - If instruction is predicated, returns its predicate
Evan Cheng0e1d3792007-07-05 07:18:20 +0000270/// condition, otherwise returns AL. It also returns the condition code
271/// register by reference.
272static ARMCC::CondCodes getInstrPredicate(MachineInstr *MI, unsigned &PredReg) {
Evan Cheng62ccdbf2007-05-29 18:42:18 +0000273 int PIdx = MI->findFirstPredOperandIdx();
Evan Cheng0e1d3792007-07-05 07:18:20 +0000274 if (PIdx == -1) {
275 PredReg = 0;
276 return ARMCC::AL;
277 }
278
279 PredReg = MI->getOperand(PIdx+1).getReg();
Chris Lattner9a1ceae2007-12-30 20:49:49 +0000280 return (ARMCC::CondCodes)MI->getOperand(PIdx).getImm();
Evan Cheng44bec522007-05-15 01:29:07 +0000281}
282
Evan Chenga8e29892007-01-19 07:51:42 +0000283static inline bool isMatchingDecrement(MachineInstr *MI, unsigned Base,
Evan Cheng0e1d3792007-07-05 07:18:20 +0000284 unsigned Bytes, ARMCC::CondCodes Pred,
285 unsigned PredReg) {
286 unsigned MyPredReg = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000287 return (MI && MI->getOpcode() == ARM::SUBri &&
288 MI->getOperand(0).getReg() == Base &&
289 MI->getOperand(1).getReg() == Base &&
Evan Cheng44bec522007-05-15 01:29:07 +0000290 ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000291 getInstrPredicate(MI, MyPredReg) == Pred &&
292 MyPredReg == PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000293}
294
295static inline bool isMatchingIncrement(MachineInstr *MI, unsigned Base,
Evan Cheng0e1d3792007-07-05 07:18:20 +0000296 unsigned Bytes, ARMCC::CondCodes Pred,
297 unsigned PredReg) {
298 unsigned MyPredReg = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000299 return (MI && MI->getOpcode() == ARM::ADDri &&
300 MI->getOperand(0).getReg() == Base &&
301 MI->getOperand(1).getReg() == Base &&
Evan Cheng44bec522007-05-15 01:29:07 +0000302 ARM_AM::getAM2Offset(MI->getOperand(2).getImm()) == Bytes &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000303 getInstrPredicate(MI, MyPredReg) == Pred &&
304 MyPredReg == PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000305}
306
307static inline unsigned getLSMultipleTransferSize(MachineInstr *MI) {
308 switch (MI->getOpcode()) {
309 default: return 0;
310 case ARM::LDR:
311 case ARM::STR:
312 case ARM::FLDS:
313 case ARM::FSTS:
314 return 4;
315 case ARM::FLDD:
316 case ARM::FSTD:
317 return 8;
318 case ARM::LDM:
319 case ARM::STM:
Evan Cheng0e1d3792007-07-05 07:18:20 +0000320 return (MI->getNumOperands() - 4) * 4;
Evan Chenga8e29892007-01-19 07:51:42 +0000321 case ARM::FLDMS:
322 case ARM::FSTMS:
323 case ARM::FLDMD:
324 case ARM::FSTMD:
325 return ARM_AM::getAM5Offset(MI->getOperand(1).getImm()) * 4;
326 }
327}
328
329/// mergeBaseUpdateLSMultiple - Fold proceeding/trailing inc/dec of base
330/// register into the LDM/STM/FLDM{D|S}/FSTM{D|S} op when possible:
331///
332/// stmia rn, <ra, rb, rc>
333/// rn := rn + 4 * 3;
334/// =>
335/// stmia rn!, <ra, rb, rc>
336///
337/// rn := rn - 4 * 3;
338/// ldmia rn, <ra, rb, rc>
339/// =>
340/// ldmdb rn!, <ra, rb, rc>
341static bool mergeBaseUpdateLSMultiple(MachineBasicBlock &MBB,
Evan Chenge71bff72007-09-19 21:48:07 +0000342 MachineBasicBlock::iterator MBBI,
343 bool &Advance,
344 MachineBasicBlock::iterator &I) {
Evan Chenga8e29892007-01-19 07:51:42 +0000345 MachineInstr *MI = MBBI;
346 unsigned Base = MI->getOperand(0).getReg();
347 unsigned Bytes = getLSMultipleTransferSize(MI);
Evan Cheng0e1d3792007-07-05 07:18:20 +0000348 unsigned PredReg = 0;
349 ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000350 int Opcode = MI->getOpcode();
351 bool isAM4 = Opcode == ARM::LDM || Opcode == ARM::STM;
352
353 if (isAM4) {
354 if (ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm()))
355 return false;
356
357 // Can't use the updating AM4 sub-mode if the base register is also a dest
358 // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined.
Evan Cheng44bec522007-05-15 01:29:07 +0000359 for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) {
Evan Chenga8e29892007-01-19 07:51:42 +0000360 if (MI->getOperand(i).getReg() == Base)
361 return false;
362 }
363
364 ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm());
365 if (MBBI != MBB.begin()) {
366 MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
367 if (Mode == ARM_AM::ia &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000368 isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000369 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::db, true));
370 MBB.erase(PrevMBBI);
371 return true;
372 } else if (Mode == ARM_AM::ib &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000373 isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000374 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::da, true));
375 MBB.erase(PrevMBBI);
376 return true;
377 }
378 }
379
380 if (MBBI != MBB.end()) {
381 MachineBasicBlock::iterator NextMBBI = next(MBBI);
382 if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000383 isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000384 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
Evan Chenge71bff72007-09-19 21:48:07 +0000385 if (NextMBBI == I) {
386 Advance = true;
387 ++I;
388 }
Evan Chenga8e29892007-01-19 07:51:42 +0000389 MBB.erase(NextMBBI);
390 return true;
391 } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000392 isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000393 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
Evan Chenge71bff72007-09-19 21:48:07 +0000394 if (NextMBBI == I) {
395 Advance = true;
396 ++I;
397 }
Evan Chenga8e29892007-01-19 07:51:42 +0000398 MBB.erase(NextMBBI);
399 return true;
400 }
401 }
402 } else {
403 // FLDM{D|S}, FSTM{D|S} addressing mode 5 ops.
404 if (ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm()))
405 return false;
406
407 ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm());
408 unsigned Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm());
409 if (MBBI != MBB.begin()) {
410 MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
411 if (Mode == ARM_AM::ia &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000412 isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000413 MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::db, true, Offset));
414 MBB.erase(PrevMBBI);
415 return true;
416 }
417 }
418
419 if (MBBI != MBB.end()) {
420 MachineBasicBlock::iterator NextMBBI = next(MBBI);
421 if (Mode == ARM_AM::ia &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000422 isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000423 MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::ia, true, Offset));
Evan Chenge71bff72007-09-19 21:48:07 +0000424 if (NextMBBI == I) {
425 Advance = true;
426 ++I;
427 }
Evan Chenga8e29892007-01-19 07:51:42 +0000428 MBB.erase(NextMBBI);
429 }
430 return true;
431 }
432 }
433
434 return false;
435}
436
437static unsigned getPreIndexedLoadStoreOpcode(unsigned Opc) {
438 switch (Opc) {
439 case ARM::LDR: return ARM::LDR_PRE;
440 case ARM::STR: return ARM::STR_PRE;
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;
Torok Edwindac237e2009-07-08 20:53:28 +0000445 default: LLVM_UNREACHABLE("Unhandled opcode!");
Evan Chenga8e29892007-01-19 07:51:42 +0000446 }
447 return 0;
448}
449
450static unsigned getPostIndexedLoadStoreOpcode(unsigned Opc) {
451 switch (Opc) {
452 case ARM::LDR: return ARM::LDR_POST;
453 case ARM::STR: return ARM::STR_POST;
454 case ARM::FLDS: return ARM::FLDMS;
455 case ARM::FLDD: return ARM::FLDMD;
456 case ARM::FSTS: return ARM::FSTMS;
457 case ARM::FSTD: return ARM::FSTMD;
Torok Edwindac237e2009-07-08 20:53:28 +0000458 default: LLVM_UNREACHABLE("Unhandled opcode!");
Evan Chenga8e29892007-01-19 07:51:42 +0000459 }
460 return 0;
461}
462
463/// mergeBaseUpdateLoadStore - Fold proceeding/trailing inc/dec of base
464/// register into the LDR/STR/FLD{D|S}/FST{D|S} op when possible:
465static bool mergeBaseUpdateLoadStore(MachineBasicBlock &MBB,
466 MachineBasicBlock::iterator MBBI,
Evan Chenge71bff72007-09-19 21:48:07 +0000467 const TargetInstrInfo *TII,
468 bool &Advance,
469 MachineBasicBlock::iterator &I) {
Evan Chenga8e29892007-01-19 07:51:42 +0000470 MachineInstr *MI = MBBI;
471 unsigned Base = MI->getOperand(1).getReg();
Evan Chenga90f3402007-03-06 21:59:20 +0000472 bool BaseKill = MI->getOperand(1).isKill();
Evan Chenga8e29892007-01-19 07:51:42 +0000473 unsigned Bytes = getLSMultipleTransferSize(MI);
474 int Opcode = MI->getOpcode();
Dale Johannesenb6728402009-02-13 02:25:56 +0000475 DebugLoc dl = MI->getDebugLoc();
Evan Chenga8e29892007-01-19 07:51:42 +0000476 bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
477 if ((isAM2 && ARM_AM::getAM2Offset(MI->getOperand(3).getImm()) != 0) ||
478 (!isAM2 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0))
479 return false;
480
481 bool isLd = Opcode == ARM::LDR || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
482 // Can't do the merge if the destination register is the same as the would-be
483 // writeback register.
484 if (isLd && MI->getOperand(0).getReg() == Base)
485 return false;
486
Evan Cheng0e1d3792007-07-05 07:18:20 +0000487 unsigned PredReg = 0;
488 ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000489 bool DoMerge = false;
490 ARM_AM::AddrOpc AddSub = ARM_AM::add;
491 unsigned NewOpc = 0;
492 if (MBBI != MBB.begin()) {
493 MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
Evan Cheng0e1d3792007-07-05 07:18:20 +0000494 if (isMatchingDecrement(PrevMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000495 DoMerge = true;
496 AddSub = ARM_AM::sub;
497 NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
Evan Cheng0e1d3792007-07-05 07:18:20 +0000498 } else if (isAM2 && isMatchingIncrement(PrevMBBI, Base, Bytes,
499 Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000500 DoMerge = true;
501 NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
502 }
503 if (DoMerge)
504 MBB.erase(PrevMBBI);
505 }
506
507 if (!DoMerge && MBBI != MBB.end()) {
508 MachineBasicBlock::iterator NextMBBI = next(MBBI);
Evan Cheng0e1d3792007-07-05 07:18:20 +0000509 if (isAM2 && isMatchingDecrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000510 DoMerge = true;
511 AddSub = ARM_AM::sub;
512 NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
Evan Cheng0e1d3792007-07-05 07:18:20 +0000513 } else if (isMatchingIncrement(NextMBBI, Base, Bytes, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000514 DoMerge = true;
515 NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
516 }
Evan Chenge71bff72007-09-19 21:48:07 +0000517 if (DoMerge) {
518 if (NextMBBI == I) {
519 Advance = true;
520 ++I;
521 }
Evan Chenga8e29892007-01-19 07:51:42 +0000522 MBB.erase(NextMBBI);
Evan Chenge71bff72007-09-19 21:48:07 +0000523 }
Evan Chenga8e29892007-01-19 07:51:42 +0000524 }
525
526 if (!DoMerge)
527 return false;
528
529 bool isDPR = NewOpc == ARM::FLDMD || NewOpc == ARM::FSTMD;
530 unsigned Offset = isAM2 ? ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift)
531 : ARM_AM::getAM5Opc((AddSub == ARM_AM::sub) ? ARM_AM::db : ARM_AM::ia,
532 true, isDPR ? 2 : 1);
533 if (isLd) {
534 if (isAM2)
Evan Chenga90f3402007-03-06 21:59:20 +0000535 // LDR_PRE, LDR_POST;
Dale Johannesenb6728402009-02-13 02:25:56 +0000536 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), MI->getOperand(0).getReg())
Bill Wendling587daed2009-05-13 21:33:08 +0000537 .addReg(Base, RegState::Define)
Evan Cheng0e1d3792007-07-05 07:18:20 +0000538 .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000539 else
Evan Cheng44bec522007-05-15 01:29:07 +0000540 // FLDMS, FLDMD
Dale Johannesenb6728402009-02-13 02:25:56 +0000541 BuildMI(MBB, MBBI, dl, TII->get(NewOpc))
Bill Wendling587daed2009-05-13 21:33:08 +0000542 .addReg(Base, getKillRegState(BaseKill))
Evan Cheng0e1d3792007-07-05 07:18:20 +0000543 .addImm(Offset).addImm(Pred).addReg(PredReg)
Bill Wendling587daed2009-05-13 21:33:08 +0000544 .addReg(MI->getOperand(0).getReg(), RegState::Define);
Evan Chenga8e29892007-01-19 07:51:42 +0000545 } else {
Evan Chenga90f3402007-03-06 21:59:20 +0000546 MachineOperand &MO = MI->getOperand(0);
Evan Chenga8e29892007-01-19 07:51:42 +0000547 if (isAM2)
Evan Chenga90f3402007-03-06 21:59:20 +0000548 // STR_PRE, STR_POST;
Dale Johannesenb6728402009-02-13 02:25:56 +0000549 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), Base)
Evan Cheng14883262009-06-04 01:15:28 +0000550 .addReg(MO.getReg(), getKillRegState(MO.isKill()))
Evan Cheng0e1d3792007-07-05 07:18:20 +0000551 .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000552 else
Evan Cheng44bec522007-05-15 01:29:07 +0000553 // FSTMS, FSTMD
Dale Johannesenb6728402009-02-13 02:25:56 +0000554 BuildMI(MBB, MBBI, dl, TII->get(NewOpc)).addReg(Base).addImm(Offset)
Evan Cheng0e1d3792007-07-05 07:18:20 +0000555 .addImm(Pred).addReg(PredReg)
Bill Wendling587daed2009-05-13 21:33:08 +0000556 .addReg(MO.getReg(), getKillRegState(MO.isKill()));
Evan Chenga8e29892007-01-19 07:51:42 +0000557 }
558 MBB.erase(MBBI);
559
560 return true;
561}
562
Evan Chengcc1c4272007-03-06 18:02:41 +0000563/// isMemoryOp - Returns true if instruction is a memory operations (that this
564/// pass is capable of operating on).
565static bool isMemoryOp(MachineInstr *MI) {
566 int Opcode = MI->getOpcode();
567 switch (Opcode) {
568 default: break;
569 case ARM::LDR:
570 case ARM::STR:
Dan Gohmand735b802008-10-03 15:45:36 +0000571 return MI->getOperand(1).isReg() && MI->getOperand(2).getReg() == 0;
Evan Chengcc1c4272007-03-06 18:02:41 +0000572 case ARM::FLDS:
573 case ARM::FSTS:
Dan Gohmand735b802008-10-03 15:45:36 +0000574 return MI->getOperand(1).isReg();
Evan Chengcc1c4272007-03-06 18:02:41 +0000575 case ARM::FLDD:
576 case ARM::FSTD:
Dan Gohmand735b802008-10-03 15:45:36 +0000577 return MI->getOperand(1).isReg();
Evan Chengcc1c4272007-03-06 18:02:41 +0000578 }
579 return false;
580}
581
Evan Cheng11788fd2007-03-08 02:55:08 +0000582/// AdvanceRS - Advance register scavenger to just before the earliest memory
583/// op that is being merged.
584void ARMLoadStoreOpt::AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps) {
585 MachineBasicBlock::iterator Loc = MemOps[0].MBBI;
586 unsigned Position = MemOps[0].Position;
587 for (unsigned i = 1, e = MemOps.size(); i != e; ++i) {
588 if (MemOps[i].Position < Position) {
589 Position = MemOps[i].Position;
590 Loc = MemOps[i].MBBI;
591 }
592 }
593
594 if (Loc != MBB.begin())
595 RS->forward(prior(Loc));
596}
597
Evan Chenge7d6df72009-06-13 09:12:55 +0000598static int getMemoryOpOffset(const MachineInstr *MI) {
599 int Opcode = MI->getOpcode();
600 bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
Evan Cheng358dec52009-06-15 08:28:29 +0000601 bool isAM3 = Opcode == ARM::LDRD || Opcode == ARM::STRD;
Evan Chenge7d6df72009-06-13 09:12:55 +0000602 unsigned NumOperands = MI->getDesc().getNumOperands();
603 unsigned OffField = MI->getOperand(NumOperands-3).getImm();
604 int Offset = isAM2
Evan Cheng358dec52009-06-15 08:28:29 +0000605 ? ARM_AM::getAM2Offset(OffField)
606 : (isAM3 ? ARM_AM::getAM3Offset(OffField)
607 : ARM_AM::getAM5Offset(OffField) * 4);
Evan Chenge7d6df72009-06-13 09:12:55 +0000608 if (isAM2) {
609 if (ARM_AM::getAM2Op(OffField) == ARM_AM::sub)
610 Offset = -Offset;
Evan Cheng358dec52009-06-15 08:28:29 +0000611 } else if (isAM3) {
612 if (ARM_AM::getAM3Op(OffField) == ARM_AM::sub)
613 Offset = -Offset;
Evan Chenge7d6df72009-06-13 09:12:55 +0000614 } else {
615 if (ARM_AM::getAM5Op(OffField) == ARM_AM::sub)
616 Offset = -Offset;
617 }
618 return Offset;
619}
620
Evan Cheng358dec52009-06-15 08:28:29 +0000621static void InsertLDR_STR(MachineBasicBlock &MBB,
622 MachineBasicBlock::iterator &MBBI,
623 int OffImm, bool isDef,
624 DebugLoc dl, unsigned NewOpc,
Evan Cheng974fe5d2009-06-19 01:59:04 +0000625 unsigned Reg, bool RegDeadKill,
Evan Cheng358dec52009-06-15 08:28:29 +0000626 unsigned BaseReg, bool BaseKill,
627 unsigned OffReg, bool OffKill,
628 ARMCC::CondCodes Pred, unsigned PredReg,
629 const TargetInstrInfo *TII) {
630 unsigned Offset;
631 if (OffImm < 0)
632 Offset = ARM_AM::getAM2Opc(ARM_AM::sub, -OffImm, ARM_AM::no_shift);
633 else
634 Offset = ARM_AM::getAM2Opc(ARM_AM::add, OffImm, ARM_AM::no_shift);
635 if (isDef)
Evan Cheng974fe5d2009-06-19 01:59:04 +0000636 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
637 .addReg(Reg, getDefRegState(true) | getDeadRegState(RegDeadKill))
Evan Cheng358dec52009-06-15 08:28:29 +0000638 .addReg(BaseReg, getKillRegState(BaseKill))
639 .addReg(OffReg, getKillRegState(OffKill))
640 .addImm(Offset)
641 .addImm(Pred).addReg(PredReg);
642 else
643 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
Evan Cheng974fe5d2009-06-19 01:59:04 +0000644 .addReg(Reg, getKillRegState(RegDeadKill))
Evan Cheng358dec52009-06-15 08:28:29 +0000645 .addReg(BaseReg, getKillRegState(BaseKill))
646 .addReg(OffReg, getKillRegState(OffKill))
647 .addImm(Offset)
648 .addImm(Pred).addReg(PredReg);
649}
650
651bool ARMLoadStoreOpt::FixInvalidRegPairOp(MachineBasicBlock &MBB,
652 MachineBasicBlock::iterator &MBBI) {
653 MachineInstr *MI = &*MBBI;
654 unsigned Opcode = MI->getOpcode();
655 if (Opcode == ARM::LDRD || Opcode == ARM::STRD) {
656 unsigned EvenReg = MI->getOperand(0).getReg();
657 unsigned OddReg = MI->getOperand(1).getReg();
658 unsigned EvenRegNum = TRI->getDwarfRegNum(EvenReg, false);
659 unsigned OddRegNum = TRI->getDwarfRegNum(OddReg, false);
660 if ((EvenRegNum & 1) == 0 && (EvenRegNum + 1) == OddRegNum)
661 return false;
662
Evan Chengf9f1da12009-06-18 02:04:01 +0000663 bool isLd = Opcode == ARM::LDRD;
Evan Cheng974fe5d2009-06-19 01:59:04 +0000664 bool EvenDeadKill = isLd ?
665 MI->getOperand(0).isDead() : MI->getOperand(0).isKill();
666 bool OddDeadKill = isLd ?
667 MI->getOperand(1).isDead() : MI->getOperand(1).isKill();
Evan Cheng358dec52009-06-15 08:28:29 +0000668 const MachineOperand &BaseOp = MI->getOperand(2);
669 unsigned BaseReg = BaseOp.getReg();
670 bool BaseKill = BaseOp.isKill();
671 const MachineOperand &OffOp = MI->getOperand(3);
672 unsigned OffReg = OffOp.getReg();
673 bool OffKill = OffOp.isKill();
674 int OffImm = getMemoryOpOffset(MI);
675 unsigned PredReg = 0;
676 ARMCC::CondCodes Pred = getInstrPredicate(MI, PredReg);
677
678 if (OddRegNum > EvenRegNum && OffReg == 0 && OffImm == 0) {
679 // Ascending register numbers and no offset. It's safe to change it to a
680 // ldm or stm.
681 unsigned NewOpc = (Opcode == ARM::LDRD) ? ARM::LDM : ARM::STM;
Evan Chengf9f1da12009-06-18 02:04:01 +0000682 if (isLd) {
683 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
684 .addReg(BaseReg, getKillRegState(BaseKill))
685 .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))
686 .addImm(Pred).addReg(PredReg)
Evan Cheng974fe5d2009-06-19 01:59:04 +0000687 .addReg(EvenReg, getDefRegState(isLd) | getDeadRegState(EvenDeadKill))
688 .addReg(OddReg, getDefRegState(isLd) | getDeadRegState(OddDeadKill));
Evan Chengf9f1da12009-06-18 02:04:01 +0000689 ++NumLDRD2LDM;
690 } else {
691 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
692 .addReg(BaseReg, getKillRegState(BaseKill))
693 .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))
694 .addImm(Pred).addReg(PredReg)
Evan Cheng974fe5d2009-06-19 01:59:04 +0000695 .addReg(EvenReg, getKillRegState(EvenDeadKill))
696 .addReg(OddReg, getKillRegState(OddDeadKill));
Evan Chengf9f1da12009-06-18 02:04:01 +0000697 ++NumSTRD2STM;
698 }
Evan Cheng358dec52009-06-15 08:28:29 +0000699 } else {
700 // Split into two instructions.
701 unsigned NewOpc = (Opcode == ARM::LDRD) ? ARM::LDR : ARM::STR;
702 DebugLoc dl = MBBI->getDebugLoc();
703 // If this is a load and base register is killed, it may have been
704 // re-defed by the load, make sure the first load does not clobber it.
Evan Chengf9f1da12009-06-18 02:04:01 +0000705 if (isLd &&
Evan Cheng358dec52009-06-15 08:28:29 +0000706 (BaseKill || OffKill) &&
707 (TRI->regsOverlap(EvenReg, BaseReg) ||
708 (OffReg && TRI->regsOverlap(EvenReg, OffReg)))) {
709 assert(!TRI->regsOverlap(OddReg, BaseReg) &&
710 (!OffReg || !TRI->regsOverlap(OddReg, OffReg)));
Evan Cheng974fe5d2009-06-19 01:59:04 +0000711 InsertLDR_STR(MBB, MBBI, OffImm+4, isLd, dl, NewOpc, OddReg, OddDeadKill,
Evan Cheng358dec52009-06-15 08:28:29 +0000712 BaseReg, false, OffReg, false, Pred, PredReg, TII);
Evan Cheng974fe5d2009-06-19 01:59:04 +0000713 InsertLDR_STR(MBB, MBBI, OffImm, isLd, dl, NewOpc, EvenReg, EvenDeadKill,
Evan Cheng358dec52009-06-15 08:28:29 +0000714 BaseReg, BaseKill, OffReg, OffKill, Pred, PredReg, TII);
715 } else {
Evan Cheng974fe5d2009-06-19 01:59:04 +0000716 InsertLDR_STR(MBB, MBBI, OffImm, isLd, dl, NewOpc,
717 EvenReg, EvenDeadKill, BaseReg, false, OffReg, false,
718 Pred, PredReg, TII);
719 InsertLDR_STR(MBB, MBBI, OffImm+4, isLd, dl, NewOpc,
720 OddReg, OddDeadKill, BaseReg, BaseKill, OffReg, OffKill,
721 Pred, PredReg, TII);
Evan Cheng358dec52009-06-15 08:28:29 +0000722 }
Evan Chengf9f1da12009-06-18 02:04:01 +0000723 if (isLd)
724 ++NumLDRD2LDR;
725 else
726 ++NumSTRD2STR;
Evan Cheng358dec52009-06-15 08:28:29 +0000727 }
728
729 MBBI = prior(MBBI);
730 MBB.erase(MI);
731 }
732 return false;
733}
734
Evan Chenga8e29892007-01-19 07:51:42 +0000735/// LoadStoreMultipleOpti - An optimization pass to turn multiple LDR / STR
736/// ops of the same base and incrementing offset into LDM / STM ops.
737bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) {
738 unsigned NumMerges = 0;
739 unsigned NumMemOps = 0;
740 MemOpQueue MemOps;
741 unsigned CurrBase = 0;
742 int CurrOpc = -1;
743 unsigned CurrSize = 0;
Evan Cheng44bec522007-05-15 01:29:07 +0000744 ARMCC::CondCodes CurrPred = ARMCC::AL;
Evan Cheng0e1d3792007-07-05 07:18:20 +0000745 unsigned CurrPredReg = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000746 unsigned Position = 0;
Evan Cheng5ba71882009-06-05 17:56:14 +0000747 SmallVector<MachineBasicBlock::iterator,4> Merges;
Evan Chengcc1c4272007-03-06 18:02:41 +0000748
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000749 RS->enterBasicBlock(&MBB);
Evan Chenga8e29892007-01-19 07:51:42 +0000750 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
751 while (MBBI != E) {
Evan Cheng358dec52009-06-15 08:28:29 +0000752 if (FixInvalidRegPairOp(MBB, MBBI))
753 continue;
754
Evan Chenga8e29892007-01-19 07:51:42 +0000755 bool Advance = false;
756 bool TryMerge = false;
757 bool Clobber = false;
758
Evan Chengcc1c4272007-03-06 18:02:41 +0000759 bool isMemOp = isMemoryOp(MBBI);
Evan Chenga8e29892007-01-19 07:51:42 +0000760 if (isMemOp) {
Evan Chengcc1c4272007-03-06 18:02:41 +0000761 int Opcode = MBBI->getOpcode();
Evan Chengcc1c4272007-03-06 18:02:41 +0000762 unsigned Size = getLSMultipleTransferSize(MBBI);
Evan Chenga8e29892007-01-19 07:51:42 +0000763 unsigned Base = MBBI->getOperand(1).getReg();
Evan Cheng0e1d3792007-07-05 07:18:20 +0000764 unsigned PredReg = 0;
765 ARMCC::CondCodes Pred = getInstrPredicate(MBBI, PredReg);
Evan Chenge7d6df72009-06-13 09:12:55 +0000766 int Offset = getMemoryOpOffset(MBBI);
Evan Chenga8e29892007-01-19 07:51:42 +0000767 // Watch out for:
768 // r4 := ldr [r5]
769 // r5 := ldr [r5, #4]
770 // r6 := ldr [r5, #8]
771 //
772 // The second ldr has effectively broken the chain even though it
773 // looks like the later ldr(s) use the same base register. Try to
774 // merge the ldr's so far, including this one. But don't try to
775 // combine the following ldr(s).
776 Clobber = (Opcode == ARM::LDR && Base == MBBI->getOperand(0).getReg());
777 if (CurrBase == 0 && !Clobber) {
778 // Start of a new chain.
779 CurrBase = Base;
780 CurrOpc = Opcode;
781 CurrSize = Size;
Evan Cheng44bec522007-05-15 01:29:07 +0000782 CurrPred = Pred;
Evan Cheng0e1d3792007-07-05 07:18:20 +0000783 CurrPredReg = PredReg;
Evan Chenga8e29892007-01-19 07:51:42 +0000784 MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
785 NumMemOps++;
786 Advance = true;
787 } else {
788 if (Clobber) {
789 TryMerge = true;
790 Advance = true;
791 }
792
Evan Cheng44bec522007-05-15 01:29:07 +0000793 if (CurrOpc == Opcode && CurrBase == Base && CurrPred == Pred) {
Evan Cheng0e1d3792007-07-05 07:18:20 +0000794 // No need to match PredReg.
Evan Chenga8e29892007-01-19 07:51:42 +0000795 // Continue adding to the queue.
796 if (Offset > MemOps.back().Offset) {
797 MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
798 NumMemOps++;
799 Advance = true;
800 } else {
801 for (MemOpQueueIter I = MemOps.begin(), E = MemOps.end();
802 I != E; ++I) {
803 if (Offset < I->Offset) {
804 MemOps.insert(I, MemOpQueueEntry(Offset, Position, MBBI));
805 NumMemOps++;
806 Advance = true;
807 break;
808 } else if (Offset == I->Offset) {
809 // Collision! This can't be merged!
810 break;
811 }
812 }
813 }
814 }
815 }
816 }
817
818 if (Advance) {
819 ++Position;
820 ++MBBI;
821 } else
822 TryMerge = true;
823
824 if (TryMerge) {
825 if (NumMemOps > 1) {
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000826 // Try to find a free register to use as a new base in case it's needed.
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000827 // First advance to the instruction just before the start of the chain.
Evan Cheng11788fd2007-03-08 02:55:08 +0000828 AdvanceRS(MBB, MemOps);
Evan Cheng603b83e2007-03-07 20:30:36 +0000829 // Find a scratch register. Make sure it's a call clobbered register or
830 // a spilled callee-saved register.
Evan Cheng11788fd2007-03-08 02:55:08 +0000831 unsigned Scratch = RS->FindUnusedReg(&ARM::GPRRegClass, true);
Evan Cheng603b83e2007-03-07 20:30:36 +0000832 if (!Scratch)
Evan Cheng11788fd2007-03-08 02:55:08 +0000833 Scratch = RS->FindUnusedReg(&ARM::GPRRegClass,
834 AFI->getSpilledCSRegisters());
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000835 // Process the load / store instructions.
836 RS->forward(prior(MBBI));
837
838 // Merge ops.
Evan Cheng5ba71882009-06-05 17:56:14 +0000839 Merges.clear();
840 MergeLDR_STR(MBB, 0, CurrBase, CurrOpc, CurrSize,
841 CurrPred, CurrPredReg, Scratch, MemOps, Merges);
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000842
Evan Chenga8e29892007-01-19 07:51:42 +0000843 // Try folding preceeding/trailing base inc/dec into the generated
844 // LDM/STM ops.
Evan Cheng5ba71882009-06-05 17:56:14 +0000845 for (unsigned i = 0, e = Merges.size(); i < e; ++i)
846 if (mergeBaseUpdateLSMultiple(MBB, Merges[i], Advance, MBBI))
Evan Cheng9d5fb982009-06-03 06:14:58 +0000847 ++NumMerges;
Evan Cheng5ba71882009-06-05 17:56:14 +0000848 NumMerges += Merges.size();
Evan Chenga8e29892007-01-19 07:51:42 +0000849
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000850 // Try folding preceeding/trailing base inc/dec into those load/store
851 // that were not merged to form LDM/STM ops.
852 for (unsigned i = 0; i != NumMemOps; ++i)
853 if (!MemOps[i].Merged)
Evan Chenge71bff72007-09-19 21:48:07 +0000854 if (mergeBaseUpdateLoadStore(MBB, MemOps[i].MBBI, TII,Advance,MBBI))
Evan Cheng9d5fb982009-06-03 06:14:58 +0000855 ++NumMerges;
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000856
857 // RS may be pointing to an instruction that's deleted.
858 RS->skipTo(prior(MBBI));
Evan Cheng14883262009-06-04 01:15:28 +0000859 } else if (NumMemOps == 1) {
860 // Try folding preceeding/trailing base inc/dec into the single
861 // load/store.
862 if (mergeBaseUpdateLoadStore(MBB, MemOps[0].MBBI, TII, Advance, MBBI)) {
863 ++NumMerges;
864 RS->forward(prior(MBBI));
865 }
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000866 }
Evan Chenga8e29892007-01-19 07:51:42 +0000867
868 CurrBase = 0;
869 CurrOpc = -1;
Evan Cheng44bec522007-05-15 01:29:07 +0000870 CurrSize = 0;
871 CurrPred = ARMCC::AL;
Evan Cheng0e1d3792007-07-05 07:18:20 +0000872 CurrPredReg = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000873 if (NumMemOps) {
874 MemOps.clear();
875 NumMemOps = 0;
876 }
877
878 // If iterator hasn't been advanced and this is not a memory op, skip it.
879 // It can't start a new chain anyway.
880 if (!Advance && !isMemOp && MBBI != E) {
881 ++Position;
882 ++MBBI;
883 }
884 }
885 }
886 return NumMerges > 0;
887}
888
Evan Chenge7d6df72009-06-13 09:12:55 +0000889namespace {
890 struct OffsetCompare {
891 bool operator()(const MachineInstr *LHS, const MachineInstr *RHS) const {
892 int LOffset = getMemoryOpOffset(LHS);
893 int ROffset = getMemoryOpOffset(RHS);
894 assert(LHS == RHS || LOffset != ROffset);
895 return LOffset > ROffset;
896 }
897 };
898}
899
Evan Chenga8e29892007-01-19 07:51:42 +0000900/// MergeReturnIntoLDM - If this is a exit BB, try merging the return op
901/// (bx lr) into the preceeding stack restore so it directly restore the value
902/// of LR into pc.
903/// ldmfd sp!, {r7, lr}
904/// bx lr
905/// =>
906/// ldmfd sp!, {r7, pc}
907bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
908 if (MBB.empty()) return false;
909
910 MachineBasicBlock::iterator MBBI = prior(MBB.end());
911 if (MBBI->getOpcode() == ARM::BX_RET && MBBI != MBB.begin()) {
912 MachineInstr *PrevMI = prior(MBBI);
913 if (PrevMI->getOpcode() == ARM::LDM) {
914 MachineOperand &MO = PrevMI->getOperand(PrevMI->getNumOperands()-1);
915 if (MO.getReg() == ARM::LR) {
Chris Lattner5080f4d2008-01-11 18:10:50 +0000916 PrevMI->setDesc(TII->get(ARM::LDM_RET));
Evan Chenga8e29892007-01-19 07:51:42 +0000917 MO.setReg(ARM::PC);
918 MBB.erase(MBBI);
919 return true;
920 }
921 }
922 }
923 return false;
924}
925
926bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
Evan Chengcc1c4272007-03-06 18:02:41 +0000927 const TargetMachine &TM = Fn.getTarget();
Evan Cheng603b83e2007-03-07 20:30:36 +0000928 AFI = Fn.getInfo<ARMFunctionInfo>();
Evan Chengcc1c4272007-03-06 18:02:41 +0000929 TII = TM.getInstrInfo();
Dan Gohman6f0d0242008-02-10 18:45:23 +0000930 TRI = TM.getRegisterInfo();
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000931 RS = new RegScavenger();
Evan Chengcc1c4272007-03-06 18:02:41 +0000932
Evan Chenga8e29892007-01-19 07:51:42 +0000933 bool Modified = false;
934 for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
935 ++MFI) {
936 MachineBasicBlock &MBB = *MFI;
937 Modified |= LoadStoreMultipleOpti(MBB);
938 Modified |= MergeReturnIntoLDM(MBB);
939 }
Evan Chengcc1c4272007-03-06 18:02:41 +0000940
941 delete RS;
Evan Chenga8e29892007-01-19 07:51:42 +0000942 return Modified;
943}
Evan Chenge7d6df72009-06-13 09:12:55 +0000944
945
946/// ARMPreAllocLoadStoreOpt - Pre- register allocation pass that move
947/// load / stores from consecutive locations close to make it more
948/// likely they will be combined later.
949
950namespace {
951 struct VISIBILITY_HIDDEN ARMPreAllocLoadStoreOpt : public MachineFunctionPass{
952 static char ID;
953 ARMPreAllocLoadStoreOpt() : MachineFunctionPass(&ID) {}
954
Evan Cheng358dec52009-06-15 08:28:29 +0000955 const TargetData *TD;
Evan Chenge7d6df72009-06-13 09:12:55 +0000956 const TargetInstrInfo *TII;
957 const TargetRegisterInfo *TRI;
Evan Cheng358dec52009-06-15 08:28:29 +0000958 const ARMSubtarget *STI;
Evan Chenge7d6df72009-06-13 09:12:55 +0000959 MachineRegisterInfo *MRI;
960
961 virtual bool runOnMachineFunction(MachineFunction &Fn);
962
963 virtual const char *getPassName() const {
964 return "ARM pre- register allocation load / store optimization pass";
965 }
966
967 private:
Evan Chengd780f352009-06-15 20:54:56 +0000968 bool CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1, DebugLoc &dl,
969 unsigned &NewOpc, unsigned &EvenReg,
970 unsigned &OddReg, unsigned &BaseReg,
971 unsigned &OffReg, unsigned &Offset,
972 unsigned &PredReg, ARMCC::CondCodes &Pred);
Evan Chenge7d6df72009-06-13 09:12:55 +0000973 bool RescheduleOps(MachineBasicBlock *MBB,
974 SmallVector<MachineInstr*, 4> &Ops,
975 unsigned Base, bool isLd,
976 DenseMap<MachineInstr*, unsigned> &MI2LocMap);
977 bool RescheduleLoadStoreInstrs(MachineBasicBlock *MBB);
978 };
979 char ARMPreAllocLoadStoreOpt::ID = 0;
980}
981
982bool ARMPreAllocLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
Evan Cheng358dec52009-06-15 08:28:29 +0000983 TD = Fn.getTarget().getTargetData();
Evan Chenge7d6df72009-06-13 09:12:55 +0000984 TII = Fn.getTarget().getInstrInfo();
985 TRI = Fn.getTarget().getRegisterInfo();
Evan Cheng358dec52009-06-15 08:28:29 +0000986 STI = &Fn.getTarget().getSubtarget<ARMSubtarget>();
Evan Chenge7d6df72009-06-13 09:12:55 +0000987 MRI = &Fn.getRegInfo();
988
989 bool Modified = false;
990 for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
991 ++MFI)
992 Modified |= RescheduleLoadStoreInstrs(MFI);
993
994 return Modified;
995}
996
Evan Chengae69a2a2009-06-19 23:17:27 +0000997static bool IsSafeAndProfitableToMove(bool isLd, unsigned Base,
998 MachineBasicBlock::iterator I,
999 MachineBasicBlock::iterator E,
1000 SmallPtrSet<MachineInstr*, 4> &MemOps,
1001 SmallSet<unsigned, 4> &MemRegs,
1002 const TargetRegisterInfo *TRI) {
Evan Chenge7d6df72009-06-13 09:12:55 +00001003 // Are there stores / loads / calls between them?
1004 // FIXME: This is overly conservative. We should make use of alias information
1005 // some day.
Evan Chengae69a2a2009-06-19 23:17:27 +00001006 SmallSet<unsigned, 4> AddedRegPressure;
Evan Chenge7d6df72009-06-13 09:12:55 +00001007 while (++I != E) {
Evan Chengae69a2a2009-06-19 23:17:27 +00001008 if (MemOps.count(&*I))
1009 continue;
Evan Chenge7d6df72009-06-13 09:12:55 +00001010 const TargetInstrDesc &TID = I->getDesc();
1011 if (TID.isCall() || TID.isTerminator() || TID.hasUnmodeledSideEffects())
1012 return false;
1013 if (isLd && TID.mayStore())
1014 return false;
1015 if (!isLd) {
1016 if (TID.mayLoad())
1017 return false;
1018 // It's not safe to move the first 'str' down.
1019 // str r1, [r0]
1020 // strh r5, [r0]
1021 // str r4, [r0, #+4]
Evan Chengae69a2a2009-06-19 23:17:27 +00001022 if (TID.mayStore())
Evan Chenge7d6df72009-06-13 09:12:55 +00001023 return false;
1024 }
1025 for (unsigned j = 0, NumOps = I->getNumOperands(); j != NumOps; ++j) {
1026 MachineOperand &MO = I->getOperand(j);
Evan Chengae69a2a2009-06-19 23:17:27 +00001027 if (!MO.isReg())
1028 continue;
1029 unsigned Reg = MO.getReg();
1030 if (MO.isDef() && TRI->regsOverlap(Reg, Base))
Evan Chenge7d6df72009-06-13 09:12:55 +00001031 return false;
Evan Chengae69a2a2009-06-19 23:17:27 +00001032 if (Reg != Base && !MemRegs.count(Reg))
1033 AddedRegPressure.insert(Reg);
Evan Chenge7d6df72009-06-13 09:12:55 +00001034 }
1035 }
Evan Chengae69a2a2009-06-19 23:17:27 +00001036
1037 // Estimate register pressure increase due to the transformation.
1038 if (MemRegs.size() <= 4)
1039 // Ok if we are moving small number of instructions.
1040 return true;
1041 return AddedRegPressure.size() <= MemRegs.size() * 2;
Evan Chenge7d6df72009-06-13 09:12:55 +00001042}
1043
Evan Chengd780f352009-06-15 20:54:56 +00001044bool
1045ARMPreAllocLoadStoreOpt::CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1,
1046 DebugLoc &dl,
1047 unsigned &NewOpc, unsigned &EvenReg,
1048 unsigned &OddReg, unsigned &BaseReg,
1049 unsigned &OffReg, unsigned &Offset,
1050 unsigned &PredReg,
1051 ARMCC::CondCodes &Pred) {
1052 // FIXME: FLDS / FSTS -> FLDD / FSTD
1053 unsigned Opcode = Op0->getOpcode();
1054 if (Opcode == ARM::LDR)
1055 NewOpc = ARM::LDRD;
1056 else if (Opcode == ARM::STR)
1057 NewOpc = ARM::STRD;
1058 else
1059 return 0;
1060
1061 // Must sure the base address satisfies i64 ld / st alignment requirement.
1062 if (!Op0->hasOneMemOperand() ||
1063 !Op0->memoperands_begin()->getValue() ||
1064 Op0->memoperands_begin()->isVolatile())
Evan Cheng358dec52009-06-15 08:28:29 +00001065 return false;
1066
Evan Chengd780f352009-06-15 20:54:56 +00001067 unsigned Align = Op0->memoperands_begin()->getAlignment();
Evan Cheng358dec52009-06-15 08:28:29 +00001068 unsigned ReqAlign = STI->hasV6Ops()
1069 ? TD->getPrefTypeAlignment(Type::Int64Ty) : 8; // Pre-v6 need 8-byte align
Evan Chengd780f352009-06-15 20:54:56 +00001070 if (Align < ReqAlign)
1071 return false;
1072
1073 // Then make sure the immediate offset fits.
1074 int OffImm = getMemoryOpOffset(Op0);
1075 ARM_AM::AddrOpc AddSub = ARM_AM::add;
1076 if (OffImm < 0) {
1077 AddSub = ARM_AM::sub;
1078 OffImm = - OffImm;
1079 }
1080 if (OffImm >= 256) // 8 bits
1081 return false;
1082 Offset = ARM_AM::getAM3Opc(AddSub, OffImm);
1083
1084 EvenReg = Op0->getOperand(0).getReg();
Evan Cheng67586072009-06-15 21:18:20 +00001085 OddReg = Op1->getOperand(0).getReg();
Evan Chengd780f352009-06-15 20:54:56 +00001086 if (EvenReg == OddReg)
1087 return false;
1088 BaseReg = Op0->getOperand(1).getReg();
1089 OffReg = Op0->getOperand(2).getReg();
1090 Pred = getInstrPredicate(Op0, PredReg);
1091 dl = Op0->getDebugLoc();
1092 return true;
Evan Cheng358dec52009-06-15 08:28:29 +00001093}
1094
Evan Chenge7d6df72009-06-13 09:12:55 +00001095bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
1096 SmallVector<MachineInstr*, 4> &Ops,
1097 unsigned Base, bool isLd,
1098 DenseMap<MachineInstr*, unsigned> &MI2LocMap) {
1099 bool RetVal = false;
1100
1101 // Sort by offset (in reverse order).
1102 std::sort(Ops.begin(), Ops.end(), OffsetCompare());
1103
1104 // The loads / stores of the same base are in order. Scan them from first to
1105 // last and check for the followins:
1106 // 1. Any def of base.
1107 // 2. Any gaps.
1108 while (Ops.size() > 1) {
1109 unsigned FirstLoc = ~0U;
1110 unsigned LastLoc = 0;
1111 MachineInstr *FirstOp = 0;
1112 MachineInstr *LastOp = 0;
1113 int LastOffset = 0;
Evan Chengf9f1da12009-06-18 02:04:01 +00001114 unsigned LastOpcode = 0;
Evan Chenge7d6df72009-06-13 09:12:55 +00001115 unsigned LastBytes = 0;
1116 unsigned NumMove = 0;
1117 for (int i = Ops.size() - 1; i >= 0; --i) {
1118 MachineInstr *Op = Ops[i];
1119 unsigned Loc = MI2LocMap[Op];
1120 if (Loc <= FirstLoc) {
1121 FirstLoc = Loc;
1122 FirstOp = Op;
1123 }
1124 if (Loc >= LastLoc) {
1125 LastLoc = Loc;
1126 LastOp = Op;
1127 }
1128
Evan Chengf9f1da12009-06-18 02:04:01 +00001129 unsigned Opcode = Op->getOpcode();
1130 if (LastOpcode && Opcode != LastOpcode)
1131 break;
1132
Evan Chenge7d6df72009-06-13 09:12:55 +00001133 int Offset = getMemoryOpOffset(Op);
1134 unsigned Bytes = getLSMultipleTransferSize(Op);
1135 if (LastBytes) {
1136 if (Bytes != LastBytes || Offset != (LastOffset + (int)Bytes))
1137 break;
1138 }
1139 LastOffset = Offset;
1140 LastBytes = Bytes;
Evan Chengf9f1da12009-06-18 02:04:01 +00001141 LastOpcode = Opcode;
Evan Chengae69a2a2009-06-19 23:17:27 +00001142 if (++NumMove == 8) // FIXME: Tune
Evan Chenge7d6df72009-06-13 09:12:55 +00001143 break;
1144 }
1145
1146 if (NumMove <= 1)
1147 Ops.pop_back();
1148 else {
Evan Chengae69a2a2009-06-19 23:17:27 +00001149 SmallPtrSet<MachineInstr*, 4> MemOps;
1150 SmallSet<unsigned, 4> MemRegs;
1151 for (int i = NumMove-1; i >= 0; --i) {
1152 MemOps.insert(Ops[i]);
1153 MemRegs.insert(Ops[i]->getOperand(0).getReg());
1154 }
Evan Chenge7d6df72009-06-13 09:12:55 +00001155
1156 // Be conservative, if the instructions are too far apart, don't
1157 // move them. We want to limit the increase of register pressure.
Evan Chengae69a2a2009-06-19 23:17:27 +00001158 bool DoMove = (LastLoc - FirstLoc) <= NumMove*4; // FIXME: Tune this.
Evan Chenge7d6df72009-06-13 09:12:55 +00001159 if (DoMove)
Evan Chengae69a2a2009-06-19 23:17:27 +00001160 DoMove = IsSafeAndProfitableToMove(isLd, Base, FirstOp, LastOp,
1161 MemOps, MemRegs, TRI);
Evan Chenge7d6df72009-06-13 09:12:55 +00001162 if (!DoMove) {
1163 for (unsigned i = 0; i != NumMove; ++i)
1164 Ops.pop_back();
1165 } else {
1166 // This is the new location for the loads / stores.
1167 MachineBasicBlock::iterator InsertPos = isLd ? FirstOp : LastOp;
Evan Chengae69a2a2009-06-19 23:17:27 +00001168 while (InsertPos != MBB->end() && MemOps.count(InsertPos))
Evan Chenge7d6df72009-06-13 09:12:55 +00001169 ++InsertPos;
Evan Cheng358dec52009-06-15 08:28:29 +00001170
1171 // If we are moving a pair of loads / stores, see if it makes sense
1172 // to try to allocate a pair of registers that can form register pairs.
Evan Chengd780f352009-06-15 20:54:56 +00001173 MachineInstr *Op0 = Ops.back();
1174 MachineInstr *Op1 = Ops[Ops.size()-2];
1175 unsigned EvenReg = 0, OddReg = 0;
1176 unsigned BaseReg = 0, OffReg = 0, PredReg = 0;
1177 ARMCC::CondCodes Pred = ARMCC::AL;
1178 unsigned NewOpc = 0;
Evan Cheng358dec52009-06-15 08:28:29 +00001179 unsigned Offset = 0;
Evan Chengd780f352009-06-15 20:54:56 +00001180 DebugLoc dl;
1181 if (NumMove == 2 && CanFormLdStDWord(Op0, Op1, dl, NewOpc,
1182 EvenReg, OddReg, BaseReg, OffReg,
1183 Offset, PredReg, Pred)) {
1184 Ops.pop_back();
1185 Ops.pop_back();
Evan Cheng358dec52009-06-15 08:28:29 +00001186
Evan Chengd780f352009-06-15 20:54:56 +00001187 // Form the pair instruction.
Evan Chengf9f1da12009-06-18 02:04:01 +00001188 if (isLd) {
Evan Chengd780f352009-06-15 20:54:56 +00001189 BuildMI(*MBB, InsertPos, dl, TII->get(NewOpc))
Evan Cheng358dec52009-06-15 08:28:29 +00001190 .addReg(EvenReg, RegState::Define)
1191 .addReg(OddReg, RegState::Define)
1192 .addReg(BaseReg).addReg(0).addImm(Offset)
1193 .addImm(Pred).addReg(PredReg);
Evan Chengf9f1da12009-06-18 02:04:01 +00001194 ++NumLDRDFormed;
1195 } else {
Evan Chengd780f352009-06-15 20:54:56 +00001196 BuildMI(*MBB, InsertPos, dl, TII->get(NewOpc))
Evan Cheng358dec52009-06-15 08:28:29 +00001197 .addReg(EvenReg)
1198 .addReg(OddReg)
1199 .addReg(BaseReg).addReg(0).addImm(Offset)
1200 .addImm(Pred).addReg(PredReg);
Evan Chengf9f1da12009-06-18 02:04:01 +00001201 ++NumSTRDFormed;
1202 }
1203 MBB->erase(Op0);
1204 MBB->erase(Op1);
Evan Cheng358dec52009-06-15 08:28:29 +00001205
1206 // Add register allocation hints to form register pairs.
1207 MRI->setRegAllocationHint(EvenReg, ARMRI::RegPairEven, OddReg);
1208 MRI->setRegAllocationHint(OddReg, ARMRI::RegPairOdd, EvenReg);
Evan Chengd780f352009-06-15 20:54:56 +00001209 } else {
1210 for (unsigned i = 0; i != NumMove; ++i) {
1211 MachineInstr *Op = Ops.back();
1212 Ops.pop_back();
1213 MBB->splice(InsertPos, MBB, Op);
1214 }
Evan Chenge7d6df72009-06-13 09:12:55 +00001215 }
1216
1217 NumLdStMoved += NumMove;
1218 RetVal = true;
1219 }
1220 }
1221 }
1222
1223 return RetVal;
1224}
1225
1226bool
1227ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
1228 bool RetVal = false;
1229
1230 DenseMap<MachineInstr*, unsigned> MI2LocMap;
1231 DenseMap<unsigned, SmallVector<MachineInstr*, 4> > Base2LdsMap;
1232 DenseMap<unsigned, SmallVector<MachineInstr*, 4> > Base2StsMap;
1233 SmallVector<unsigned, 4> LdBases;
1234 SmallVector<unsigned, 4> StBases;
1235
1236 unsigned Loc = 0;
1237 MachineBasicBlock::iterator MBBI = MBB->begin();
1238 MachineBasicBlock::iterator E = MBB->end();
1239 while (MBBI != E) {
1240 for (; MBBI != E; ++MBBI) {
1241 MachineInstr *MI = MBBI;
1242 const TargetInstrDesc &TID = MI->getDesc();
1243 if (TID.isCall() || TID.isTerminator()) {
1244 // Stop at barriers.
1245 ++MBBI;
1246 break;
1247 }
1248
1249 MI2LocMap[MI] = Loc++;
1250 if (!isMemoryOp(MI))
1251 continue;
1252 unsigned PredReg = 0;
1253 if (getInstrPredicate(MI, PredReg) != ARMCC::AL)
1254 continue;
1255
1256 int Opcode = MI->getOpcode();
1257 bool isLd = Opcode == ARM::LDR ||
1258 Opcode == ARM::FLDS || Opcode == ARM::FLDD;
1259 unsigned Base = MI->getOperand(1).getReg();
1260 int Offset = getMemoryOpOffset(MI);
1261
1262 bool StopHere = false;
1263 if (isLd) {
1264 DenseMap<unsigned, SmallVector<MachineInstr*, 4> >::iterator BI =
1265 Base2LdsMap.find(Base);
1266 if (BI != Base2LdsMap.end()) {
1267 for (unsigned i = 0, e = BI->second.size(); i != e; ++i) {
1268 if (Offset == getMemoryOpOffset(BI->second[i])) {
1269 StopHere = true;
1270 break;
1271 }
1272 }
1273 if (!StopHere)
1274 BI->second.push_back(MI);
1275 } else {
1276 SmallVector<MachineInstr*, 4> MIs;
1277 MIs.push_back(MI);
1278 Base2LdsMap[Base] = MIs;
1279 LdBases.push_back(Base);
1280 }
1281 } else {
1282 DenseMap<unsigned, SmallVector<MachineInstr*, 4> >::iterator BI =
1283 Base2StsMap.find(Base);
1284 if (BI != Base2StsMap.end()) {
1285 for (unsigned i = 0, e = BI->second.size(); i != e; ++i) {
1286 if (Offset == getMemoryOpOffset(BI->second[i])) {
1287 StopHere = true;
1288 break;
1289 }
1290 }
1291 if (!StopHere)
1292 BI->second.push_back(MI);
1293 } else {
1294 SmallVector<MachineInstr*, 4> MIs;
1295 MIs.push_back(MI);
1296 Base2StsMap[Base] = MIs;
1297 StBases.push_back(Base);
1298 }
1299 }
1300
1301 if (StopHere) {
Evan Chengae69a2a2009-06-19 23:17:27 +00001302 // Found a duplicate (a base+offset combination that's seen earlier).
1303 // Backtrack.
Evan Chenge7d6df72009-06-13 09:12:55 +00001304 --Loc;
1305 break;
1306 }
1307 }
1308
1309 // Re-schedule loads.
1310 for (unsigned i = 0, e = LdBases.size(); i != e; ++i) {
1311 unsigned Base = LdBases[i];
1312 SmallVector<MachineInstr*, 4> &Lds = Base2LdsMap[Base];
1313 if (Lds.size() > 1)
1314 RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap);
1315 }
1316
1317 // Re-schedule stores.
1318 for (unsigned i = 0, e = StBases.size(); i != e; ++i) {
1319 unsigned Base = StBases[i];
1320 SmallVector<MachineInstr*, 4> &Sts = Base2StsMap[Base];
1321 if (Sts.size() > 1)
1322 RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap);
1323 }
1324
1325 if (MBBI != E) {
1326 Base2LdsMap.clear();
1327 Base2StsMap.clear();
1328 LdBases.clear();
1329 StBases.clear();
1330 }
1331 }
1332
1333 return RetVal;
1334}
1335
1336
1337/// createARMLoadStoreOptimizationPass - returns an instance of the load / store
1338/// optimization pass.
1339FunctionPass *llvm::createARMLoadStoreOptimizationPass(bool PreAlloc) {
1340 if (PreAlloc)
1341 return new ARMPreAllocLoadStoreOpt();
1342 return new ARMLoadStoreOpt();
1343}