blob: 11d4887e2598563dd951657b54a59a6201fd4f9d [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 Cheng8fb90362009-08-08 03:20:32 +000018#include "ARMBaseInstrInfo.h"
Evan Cheng603b83e2007-03-07 20:30:36 +000019#include "ARMMachineFunctionInfo.h"
Evan Chenga8e29892007-01-19 07:51:42 +000020#include "ARMRegisterInfo.h"
Evan Cheng358dec52009-06-15 08:28:29 +000021#include "llvm/DerivedTypes.h"
Evan Chenga8e29892007-01-19 07:51:42 +000022#include "llvm/CodeGen/MachineBasicBlock.h"
23#include "llvm/CodeGen/MachineFunctionPass.h"
24#include "llvm/CodeGen/MachineInstr.h"
25#include "llvm/CodeGen/MachineInstrBuilder.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000026#include "llvm/CodeGen/MachineRegisterInfo.h"
Evan Chengcc1c4272007-03-06 18:02:41 +000027#include "llvm/CodeGen/RegisterScavenging.h"
Evan Cheng358dec52009-06-15 08:28:29 +000028#include "llvm/Target/TargetData.h"
Evan Chenga8e29892007-01-19 07:51:42 +000029#include "llvm/Target/TargetInstrInfo.h"
30#include "llvm/Target/TargetMachine.h"
Evan Cheng358dec52009-06-15 08:28:29 +000031#include "llvm/Target/TargetRegisterInfo.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000032#include "llvm/Support/Compiler.h"
Torok Edwinab7c09b2009-07-08 18:01:40 +000033#include "llvm/Support/ErrorHandling.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000034#include "llvm/ADT/DenseMap.h"
35#include "llvm/ADT/STLExtras.h"
36#include "llvm/ADT/SmallPtrSet.h"
Evan Chengae69a2a2009-06-19 23:17:27 +000037#include "llvm/ADT/SmallSet.h"
Evan Chenge7d6df72009-06-13 09:12:55 +000038#include "llvm/ADT/SmallVector.h"
39#include "llvm/ADT/Statistic.h"
Evan Chenga8e29892007-01-19 07:51:42 +000040using namespace llvm;
41
42STATISTIC(NumLDMGened , "Number of ldm instructions generated");
43STATISTIC(NumSTMGened , "Number of stm instructions generated");
44STATISTIC(NumFLDMGened, "Number of fldm instructions generated");
45STATISTIC(NumFSTMGened, "Number of fstm instructions generated");
Evan Chenge7d6df72009-06-13 09:12:55 +000046STATISTIC(NumLdStMoved, "Number of load / store instructions moved");
Evan Chengf9f1da12009-06-18 02:04:01 +000047STATISTIC(NumLDRDFormed,"Number of ldrd created before allocation");
48STATISTIC(NumSTRDFormed,"Number of strd created before allocation");
49STATISTIC(NumLDRD2LDM, "Number of ldrd instructions turned back into ldm");
50STATISTIC(NumSTRD2STM, "Number of strd instructions turned back into stm");
51STATISTIC(NumLDRD2LDR, "Number of ldrd instructions turned back into ldr's");
52STATISTIC(NumSTRD2STR, "Number of strd instructions turned back into str's");
Evan Chenge7d6df72009-06-13 09:12:55 +000053
54/// ARMAllocLoadStoreOpt - Post- register allocation pass the combine
55/// load / store instructions to form ldm / stm instructions.
Evan Chenga8e29892007-01-19 07:51:42 +000056
57namespace {
58 struct VISIBILITY_HIDDEN ARMLoadStoreOpt : public MachineFunctionPass {
Devang Patel19974732007-05-03 01:11:54 +000059 static char ID;
Dan Gohmanae73dc12008-09-04 17:05:41 +000060 ARMLoadStoreOpt() : MachineFunctionPass(&ID) {}
Devang Patel794fd752007-05-01 21:15:47 +000061
Evan Chenga8e29892007-01-19 07:51:42 +000062 const TargetInstrInfo *TII;
Dan Gohman6f0d0242008-02-10 18:45:23 +000063 const TargetRegisterInfo *TRI;
Evan Cheng603b83e2007-03-07 20:30:36 +000064 ARMFunctionInfo *AFI;
Evan Chengcc1c4272007-03-06 18:02:41 +000065 RegScavenger *RS;
Evan Cheng45032f22009-07-09 23:11:34 +000066 bool isThumb2;
Evan Chenga8e29892007-01-19 07:51:42 +000067
68 virtual bool runOnMachineFunction(MachineFunction &Fn);
69
70 virtual const char *getPassName() const {
71 return "ARM load / store optimization pass";
72 }
73
74 private:
75 struct MemOpQueueEntry {
76 int Offset;
77 unsigned Position;
78 MachineBasicBlock::iterator MBBI;
79 bool Merged;
80 MemOpQueueEntry(int o, int p, MachineBasicBlock::iterator i)
81 : Offset(o), Position(p), MBBI(i), Merged(false) {};
82 };
83 typedef SmallVector<MemOpQueueEntry,8> MemOpQueue;
84 typedef MemOpQueue::iterator MemOpQueueIter;
85
Evan Cheng92549222009-06-05 19:08:58 +000086 bool MergeOps(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
Evan Cheng87d59e42009-06-05 18:19:23 +000087 int Offset, unsigned Base, bool BaseKill, int Opcode,
88 ARMCC::CondCodes Pred, unsigned PredReg, unsigned Scratch,
89 DebugLoc dl, SmallVector<std::pair<unsigned, bool>, 8> &Regs);
Evan Cheng5ba71882009-06-05 17:56:14 +000090 void MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex, unsigned Base,
91 int Opcode, unsigned Size,
92 ARMCC::CondCodes Pred, unsigned PredReg,
93 unsigned Scratch, MemOpQueue &MemOps,
94 SmallVector<MachineBasicBlock::iterator, 4> &Merges);
Evan Chenga8e29892007-01-19 07:51:42 +000095
Evan Cheng11788fd2007-03-08 02:55:08 +000096 void AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps);
Evan Cheng358dec52009-06-15 08:28:29 +000097 bool FixInvalidRegPairOp(MachineBasicBlock &MBB,
98 MachineBasicBlock::iterator &MBBI);
Evan Cheng45032f22009-07-09 23:11:34 +000099 bool MergeBaseUpdateLoadStore(MachineBasicBlock &MBB,
100 MachineBasicBlock::iterator MBBI,
101 const TargetInstrInfo *TII,
102 bool &Advance,
103 MachineBasicBlock::iterator &I);
104 bool MergeBaseUpdateLSMultiple(MachineBasicBlock &MBB,
105 MachineBasicBlock::iterator MBBI,
106 bool &Advance,
107 MachineBasicBlock::iterator &I);
Evan Chenga8e29892007-01-19 07:51:42 +0000108 bool LoadStoreMultipleOpti(MachineBasicBlock &MBB);
109 bool MergeReturnIntoLDM(MachineBasicBlock &MBB);
110 };
Devang Patel19974732007-05-03 01:11:54 +0000111 char ARMLoadStoreOpt::ID = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000112}
113
Evan Chenga8e29892007-01-19 07:51:42 +0000114static int getLoadStoreMultipleOpcode(int Opcode) {
115 switch (Opcode) {
116 case ARM::LDR:
117 NumLDMGened++;
118 return ARM::LDM;
119 case ARM::STR:
120 NumSTMGened++;
121 return ARM::STM;
Evan Cheng45032f22009-07-09 23:11:34 +0000122 case ARM::t2LDRi8:
123 case ARM::t2LDRi12:
124 NumLDMGened++;
125 return ARM::t2LDM;
126 case ARM::t2STRi8:
127 case ARM::t2STRi12:
128 NumSTMGened++;
129 return ARM::t2STM;
Evan Chenga8e29892007-01-19 07:51:42 +0000130 case ARM::FLDS:
131 NumFLDMGened++;
132 return ARM::FLDMS;
133 case ARM::FSTS:
134 NumFSTMGened++;
135 return ARM::FSTMS;
136 case ARM::FLDD:
137 NumFLDMGened++;
138 return ARM::FLDMD;
139 case ARM::FSTD:
140 NumFSTMGened++;
141 return ARM::FSTMD;
Torok Edwinc23197a2009-07-14 16:55:14 +0000142 default: llvm_unreachable("Unhandled opcode!");
Evan Chenga8e29892007-01-19 07:51:42 +0000143 }
144 return 0;
145}
146
Evan Cheng27934da2009-08-04 01:43:45 +0000147static bool isT2i32Load(unsigned Opc) {
148 return Opc == ARM::t2LDRi12 || Opc == ARM::t2LDRi8;
149}
150
Evan Cheng45032f22009-07-09 23:11:34 +0000151static bool isi32Load(unsigned Opc) {
Evan Cheng27934da2009-08-04 01:43:45 +0000152 return Opc == ARM::LDR || isT2i32Load(Opc);
153}
154
155static bool isT2i32Store(unsigned Opc) {
156 return Opc == ARM::t2STRi12 || Opc == ARM::t2STRi8;
Evan Cheng45032f22009-07-09 23:11:34 +0000157}
158
159static bool isi32Store(unsigned Opc) {
Evan Cheng27934da2009-08-04 01:43:45 +0000160 return Opc == ARM::STR || isT2i32Store(Opc);
Evan Cheng45032f22009-07-09 23:11:34 +0000161}
162
Evan Cheng92549222009-06-05 19:08:58 +0000163/// MergeOps - Create and insert a LDM or STM with Base as base register and
Evan Chenga8e29892007-01-19 07:51:42 +0000164/// registers in Regs as the register operands that would be loaded / stored.
Jim Grosbach764ab522009-08-11 15:33:49 +0000165/// It returns true if the transformation is done.
Evan Cheng87d59e42009-06-05 18:19:23 +0000166bool
Evan Cheng92549222009-06-05 19:08:58 +0000167ARMLoadStoreOpt::MergeOps(MachineBasicBlock &MBB,
Evan Cheng87d59e42009-06-05 18:19:23 +0000168 MachineBasicBlock::iterator MBBI,
169 int Offset, unsigned Base, bool BaseKill,
170 int Opcode, ARMCC::CondCodes Pred,
171 unsigned PredReg, unsigned Scratch, DebugLoc dl,
172 SmallVector<std::pair<unsigned, bool>, 8> &Regs) {
Evan Chenga8e29892007-01-19 07:51:42 +0000173 // Only a single register to load / store. Don't bother.
174 unsigned NumRegs = Regs.size();
175 if (NumRegs <= 1)
176 return false;
177
178 ARM_AM::AMSubMode Mode = ARM_AM::ia;
Evan Cheng45032f22009-07-09 23:11:34 +0000179 bool isAM4 = isi32Load(Opcode) || isi32Store(Opcode);
Evan Chengeb084d12009-08-04 08:34:18 +0000180 if (isAM4 && Offset == 4) {
181 if (isThumb2)
182 // Thumb2 does not support ldmib / stmib.
183 return false;
Evan Chenga8e29892007-01-19 07:51:42 +0000184 Mode = ARM_AM::ib;
Evan Chengeb084d12009-08-04 08:34:18 +0000185 } else if (isAM4 && Offset == -4 * (int)NumRegs + 4) {
186 if (isThumb2)
187 // Thumb2 does not support ldmda / stmda.
188 return false;
Evan Chenga8e29892007-01-19 07:51:42 +0000189 Mode = ARM_AM::da;
Evan Chengeb084d12009-08-04 08:34:18 +0000190 } else if (isAM4 && Offset == -4 * (int)NumRegs) {
Evan Chenga8e29892007-01-19 07:51:42 +0000191 Mode = ARM_AM::db;
Evan Chengeb084d12009-08-04 08:34:18 +0000192 } else if (Offset != 0) {
Evan Chenga8e29892007-01-19 07:51:42 +0000193 // If starting offset isn't zero, insert a MI to materialize a new base.
194 // But only do so if it is cost effective, i.e. merging more than two
195 // loads / stores.
196 if (NumRegs <= 2)
197 return false;
198
199 unsigned NewBase;
Evan Cheng45032f22009-07-09 23:11:34 +0000200 if (isi32Load(Opcode))
Evan Chenga8e29892007-01-19 07:51:42 +0000201 // If it is a load, then just use one of the destination register to
202 // use as the new base.
Evan Chenga90f3402007-03-06 21:59:20 +0000203 NewBase = Regs[NumRegs-1].first;
Evan Chenga8e29892007-01-19 07:51:42 +0000204 else {
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000205 // Use the scratch register to use as a new base.
206 NewBase = Scratch;
Evan Chenga90f3402007-03-06 21:59:20 +0000207 if (NewBase == 0)
208 return false;
Evan Chenga8e29892007-01-19 07:51:42 +0000209 }
Evan Cheng86198642009-08-07 00:34:42 +0000210 int BaseOpc = !isThumb2
211 ? ARM::ADDri
212 : ((Base == ARM::SP) ? ARM::t2ADDrSPi : ARM::t2ADDri);
Evan Chenga8e29892007-01-19 07:51:42 +0000213 if (Offset < 0) {
Evan Cheng86198642009-08-07 00:34:42 +0000214 BaseOpc = !isThumb2
215 ? ARM::SUBri
216 : ((Base == ARM::SP) ? ARM::t2SUBrSPi : ARM::t2SUBri);
Evan Chenga8e29892007-01-19 07:51:42 +0000217 Offset = - Offset;
218 }
Evan Cheng45032f22009-07-09 23:11:34 +0000219 int ImmedOffset = isThumb2
220 ? ARM_AM::getT2SOImmVal(Offset) : ARM_AM::getSOImmVal(Offset);
221 if (ImmedOffset == -1)
222 // FIXME: Try t2ADDri12 or t2SUBri12?
Evan Chenga8e29892007-01-19 07:51:42 +0000223 return false; // Probably not worth it then.
Evan Chenga90f3402007-03-06 21:59:20 +0000224
Dale Johannesenb6728402009-02-13 02:25:56 +0000225 BuildMI(MBB, MBBI, dl, TII->get(BaseOpc), NewBase)
Evan Chenge7cbe412009-07-08 21:03:57 +0000226 .addReg(Base, getKillRegState(BaseKill)).addImm(Offset)
Evan Cheng13ab0202007-07-10 18:08:01 +0000227 .addImm(Pred).addReg(PredReg).addReg(0);
Evan Chenga8e29892007-01-19 07:51:42 +0000228 Base = NewBase;
Evan Chenga90f3402007-03-06 21:59:20 +0000229 BaseKill = true; // New base is always killed right its use.
Evan Chenga8e29892007-01-19 07:51:42 +0000230 }
231
232 bool isDPR = Opcode == ARM::FLDD || Opcode == ARM::FSTD;
Evan Cheng27934da2009-08-04 01:43:45 +0000233 bool isDef = isi32Load(Opcode) || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
Evan Chenga8e29892007-01-19 07:51:42 +0000234 Opcode = getLoadStoreMultipleOpcode(Opcode);
235 MachineInstrBuilder MIB = (isAM4)
Dale Johannesenb6728402009-02-13 02:25:56 +0000236 ? BuildMI(MBB, MBBI, dl, TII->get(Opcode))
Bill Wendling587daed2009-05-13 21:33:08 +0000237 .addReg(Base, getKillRegState(BaseKill))
Evan Cheng0e1d3792007-07-05 07:18:20 +0000238 .addImm(ARM_AM::getAM4ModeImm(Mode)).addImm(Pred).addReg(PredReg)
Dale Johannesenb6728402009-02-13 02:25:56 +0000239 : BuildMI(MBB, MBBI, dl, TII->get(Opcode))
Bill Wendling587daed2009-05-13 21:33:08 +0000240 .addReg(Base, getKillRegState(BaseKill))
Evan Cheng44bec522007-05-15 01:29:07 +0000241 .addImm(ARM_AM::getAM5Opc(Mode, false, isDPR ? NumRegs<<1 : NumRegs))
Evan Cheng0e1d3792007-07-05 07:18:20 +0000242 .addImm(Pred).addReg(PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000243 for (unsigned i = 0; i != NumRegs; ++i)
Bill Wendling587daed2009-05-13 21:33:08 +0000244 MIB = MIB.addReg(Regs[i].first, getDefRegState(isDef)
245 | getKillRegState(Regs[i].second));
Evan Chenga8e29892007-01-19 07:51:42 +0000246
247 return true;
248}
249
Evan Chenga90f3402007-03-06 21:59:20 +0000250/// MergeLDR_STR - Merge a number of load / store instructions into one or more
251/// load / store multiple instructions.
Evan Cheng5ba71882009-06-05 17:56:14 +0000252void
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000253ARMLoadStoreOpt::MergeLDR_STR(MachineBasicBlock &MBB, unsigned SIndex,
Evan Cheng5ba71882009-06-05 17:56:14 +0000254 unsigned Base, int Opcode, unsigned Size,
255 ARMCC::CondCodes Pred, unsigned PredReg,
256 unsigned Scratch, MemOpQueue &MemOps,
257 SmallVector<MachineBasicBlock::iterator, 4> &Merges) {
Evan Cheng45032f22009-07-09 23:11:34 +0000258 bool isAM4 = isi32Load(Opcode) || isi32Store(Opcode);
Evan Chenga8e29892007-01-19 07:51:42 +0000259 int Offset = MemOps[SIndex].Offset;
260 int SOffset = Offset;
261 unsigned Pos = MemOps[SIndex].Position;
262 MachineBasicBlock::iterator Loc = MemOps[SIndex].MBBI;
Evan Cheng87d59e42009-06-05 18:19:23 +0000263 DebugLoc dl = Loc->getDebugLoc();
264 unsigned PReg = Loc->getOperand(0).getReg();
Evan Chenga8e29892007-01-19 07:51:42 +0000265 unsigned PRegNum = ARMRegisterInfo::getRegisterNumbering(PReg);
Evan Cheng87d59e42009-06-05 18:19:23 +0000266 bool isKill = Loc->getOperand(0).isKill();
Evan Cheng44bec522007-05-15 01:29:07 +0000267
268 SmallVector<std::pair<unsigned,bool>, 8> Regs;
Evan Chenga90f3402007-03-06 21:59:20 +0000269 Regs.push_back(std::make_pair(PReg, isKill));
Evan Chenga8e29892007-01-19 07:51:42 +0000270 for (unsigned i = SIndex+1, e = MemOps.size(); i != e; ++i) {
271 int NewOffset = MemOps[i].Offset;
272 unsigned Reg = MemOps[i].MBBI->getOperand(0).getReg();
273 unsigned RegNum = ARMRegisterInfo::getRegisterNumbering(Reg);
Evan Chenga90f3402007-03-06 21:59:20 +0000274 isKill = MemOps[i].MBBI->getOperand(0).isKill();
Evan Chenga8e29892007-01-19 07:51:42 +0000275 // AM4 - register numbers in ascending order.
276 // AM5 - consecutive register numbers in ascending order.
277 if (NewOffset == Offset + (int)Size &&
278 ((isAM4 && RegNum > PRegNum) || RegNum == PRegNum+1)) {
279 Offset += Size;
Evan Chenga90f3402007-03-06 21:59:20 +0000280 Regs.push_back(std::make_pair(Reg, isKill));
Evan Chenga8e29892007-01-19 07:51:42 +0000281 PRegNum = RegNum;
282 } else {
283 // Can't merge this in. Try merge the earlier ones first.
Evan Cheng92549222009-06-05 19:08:58 +0000284 if (MergeOps(MBB, ++Loc, SOffset, Base, false, Opcode, Pred, PredReg,
Evan Cheng87d59e42009-06-05 18:19:23 +0000285 Scratch, dl, Regs)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000286 Merges.push_back(prior(Loc));
287 for (unsigned j = SIndex; j < i; ++j) {
288 MBB.erase(MemOps[j].MBBI);
289 MemOps[j].Merged = true;
290 }
291 }
Evan Cheng5ba71882009-06-05 17:56:14 +0000292 MergeLDR_STR(MBB, i, Base, Opcode, Size, Pred, PredReg, Scratch,
293 MemOps, Merges);
294 return;
Evan Chenga8e29892007-01-19 07:51:42 +0000295 }
296
297 if (MemOps[i].Position > Pos) {
298 Pos = MemOps[i].Position;
299 Loc = MemOps[i].MBBI;
300 }
301 }
302
Evan Chengfaa51072007-04-26 19:00:32 +0000303 bool BaseKill = Loc->findRegisterUseOperandIdx(Base, true) != -1;
Evan Cheng92549222009-06-05 19:08:58 +0000304 if (MergeOps(MBB, ++Loc, SOffset, Base, BaseKill, Opcode, Pred, PredReg,
Evan Cheng87d59e42009-06-05 18:19:23 +0000305 Scratch, dl, Regs)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000306 Merges.push_back(prior(Loc));
307 for (unsigned i = SIndex, e = MemOps.size(); i != e; ++i) {
308 MBB.erase(MemOps[i].MBBI);
309 MemOps[i].Merged = true;
310 }
311 }
312
Evan Cheng5ba71882009-06-05 17:56:14 +0000313 return;
Evan Chenga8e29892007-01-19 07:51:42 +0000314}
315
316static inline bool isMatchingDecrement(MachineInstr *MI, unsigned Base,
Evan Cheng27934da2009-08-04 01:43:45 +0000317 unsigned Bytes, unsigned Limit,
318 ARMCC::CondCodes Pred, unsigned PredReg){
Evan Cheng0e1d3792007-07-05 07:18:20 +0000319 unsigned MyPredReg = 0;
Evan Cheng45032f22009-07-09 23:11:34 +0000320 if (!MI)
321 return false;
Evan Cheng27934da2009-08-04 01:43:45 +0000322 if (MI->getOpcode() != ARM::t2SUBri &&
Evan Cheng86198642009-08-07 00:34:42 +0000323 MI->getOpcode() != ARM::t2SUBrSPi &&
324 MI->getOpcode() != ARM::t2SUBrSPi12 &&
325 MI->getOpcode() != ARM::tSUBspi &&
Evan Cheng27934da2009-08-04 01:43:45 +0000326 MI->getOpcode() != ARM::SUBri)
327 return false;
328
329 // Make sure the offset fits in 8 bits.
330 if (Bytes <= 0 || (Limit && Bytes >= Limit))
331 return false;
Evan Cheng45032f22009-07-09 23:11:34 +0000332
Evan Cheng86198642009-08-07 00:34:42 +0000333 unsigned Scale = (MI->getOpcode() == ARM::tSUBspi) ? 4 : 1; // FIXME
Evan Cheng45032f22009-07-09 23:11:34 +0000334 return (MI->getOperand(0).getReg() == Base &&
Evan Chenga8e29892007-01-19 07:51:42 +0000335 MI->getOperand(1).getReg() == Base &&
Evan Cheng86198642009-08-07 00:34:42 +0000336 (MI->getOperand(2).getImm()*Scale) == Bytes &&
Evan Cheng8fb90362009-08-08 03:20:32 +0000337 llvm::getInstrPredicate(MI, MyPredReg) == Pred &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000338 MyPredReg == PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000339}
340
341static inline bool isMatchingIncrement(MachineInstr *MI, unsigned Base,
Evan Cheng27934da2009-08-04 01:43:45 +0000342 unsigned Bytes, unsigned Limit,
343 ARMCC::CondCodes Pred, unsigned PredReg){
Evan Cheng0e1d3792007-07-05 07:18:20 +0000344 unsigned MyPredReg = 0;
Evan Cheng45032f22009-07-09 23:11:34 +0000345 if (!MI)
346 return false;
Evan Cheng27934da2009-08-04 01:43:45 +0000347 if (MI->getOpcode() != ARM::t2ADDri &&
Evan Cheng86198642009-08-07 00:34:42 +0000348 MI->getOpcode() != ARM::t2ADDrSPi &&
349 MI->getOpcode() != ARM::t2ADDrSPi12 &&
350 MI->getOpcode() != ARM::tADDspi &&
Evan Cheng27934da2009-08-04 01:43:45 +0000351 MI->getOpcode() != ARM::ADDri)
352 return false;
353
354 if (Bytes <= 0 || (Limit && Bytes >= Limit))
Evan Cheng45032f22009-07-09 23:11:34 +0000355 // Make sure the offset fits in 8 bits.
Evan Cheng27934da2009-08-04 01:43:45 +0000356 return false;
Evan Cheng45032f22009-07-09 23:11:34 +0000357
Evan Cheng86198642009-08-07 00:34:42 +0000358 unsigned Scale = (MI->getOpcode() == ARM::tADDspi) ? 4 : 1; // FIXME
Evan Cheng45032f22009-07-09 23:11:34 +0000359 return (MI->getOperand(0).getReg() == Base &&
Evan Chenga8e29892007-01-19 07:51:42 +0000360 MI->getOperand(1).getReg() == Base &&
Evan Cheng86198642009-08-07 00:34:42 +0000361 (MI->getOperand(2).getImm()*Scale) == Bytes &&
Evan Cheng8fb90362009-08-08 03:20:32 +0000362 llvm::getInstrPredicate(MI, MyPredReg) == Pred &&
Evan Cheng0e1d3792007-07-05 07:18:20 +0000363 MyPredReg == PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000364}
365
366static inline unsigned getLSMultipleTransferSize(MachineInstr *MI) {
367 switch (MI->getOpcode()) {
368 default: return 0;
369 case ARM::LDR:
370 case ARM::STR:
Evan Cheng45032f22009-07-09 23:11:34 +0000371 case ARM::t2LDRi8:
372 case ARM::t2LDRi12:
373 case ARM::t2STRi8:
374 case ARM::t2STRi12:
Evan Chenga8e29892007-01-19 07:51:42 +0000375 case ARM::FLDS:
376 case ARM::FSTS:
377 return 4;
378 case ARM::FLDD:
379 case ARM::FSTD:
380 return 8;
381 case ARM::LDM:
382 case ARM::STM:
Evan Cheng27934da2009-08-04 01:43:45 +0000383 case ARM::t2LDM:
384 case ARM::t2STM:
Evan Cheng0e1d3792007-07-05 07:18:20 +0000385 return (MI->getNumOperands() - 4) * 4;
Evan Chenga8e29892007-01-19 07:51:42 +0000386 case ARM::FLDMS:
387 case ARM::FSTMS:
388 case ARM::FLDMD:
389 case ARM::FSTMD:
390 return ARM_AM::getAM5Offset(MI->getOperand(1).getImm()) * 4;
391 }
392}
393
Evan Cheng45032f22009-07-09 23:11:34 +0000394/// MergeBaseUpdateLSMultiple - Fold proceeding/trailing inc/dec of base
Evan Chenga8e29892007-01-19 07:51:42 +0000395/// register into the LDM/STM/FLDM{D|S}/FSTM{D|S} op when possible:
396///
397/// stmia rn, <ra, rb, rc>
398/// rn := rn + 4 * 3;
399/// =>
400/// stmia rn!, <ra, rb, rc>
401///
402/// rn := rn - 4 * 3;
403/// ldmia rn, <ra, rb, rc>
404/// =>
405/// ldmdb rn!, <ra, rb, rc>
Evan Cheng45032f22009-07-09 23:11:34 +0000406bool ARMLoadStoreOpt::MergeBaseUpdateLSMultiple(MachineBasicBlock &MBB,
407 MachineBasicBlock::iterator MBBI,
408 bool &Advance,
409 MachineBasicBlock::iterator &I) {
Evan Chenga8e29892007-01-19 07:51:42 +0000410 MachineInstr *MI = MBBI;
411 unsigned Base = MI->getOperand(0).getReg();
412 unsigned Bytes = getLSMultipleTransferSize(MI);
Evan Cheng0e1d3792007-07-05 07:18:20 +0000413 unsigned PredReg = 0;
Evan Cheng8fb90362009-08-08 03:20:32 +0000414 ARMCC::CondCodes Pred = llvm::getInstrPredicate(MI, PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000415 int Opcode = MI->getOpcode();
Evan Cheng45032f22009-07-09 23:11:34 +0000416 bool isAM4 = Opcode == ARM::LDM || Opcode == ARM::t2LDM ||
417 Opcode == ARM::STM || Opcode == ARM::t2STM;
Evan Chenga8e29892007-01-19 07:51:42 +0000418
419 if (isAM4) {
420 if (ARM_AM::getAM4WBFlag(MI->getOperand(1).getImm()))
421 return false;
422
423 // Can't use the updating AM4 sub-mode if the base register is also a dest
424 // register. e.g. ldmdb r0!, {r0, r1, r2}. The behavior is undefined.
Evan Cheng44bec522007-05-15 01:29:07 +0000425 for (unsigned i = 3, e = MI->getNumOperands(); i != e; ++i) {
Evan Chenga8e29892007-01-19 07:51:42 +0000426 if (MI->getOperand(i).getReg() == Base)
427 return false;
428 }
429
430 ARM_AM::AMSubMode Mode = ARM_AM::getAM4SubMode(MI->getOperand(1).getImm());
431 if (MBBI != MBB.begin()) {
432 MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
433 if (Mode == ARM_AM::ia &&
Evan Cheng27934da2009-08-04 01:43:45 +0000434 isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000435 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::db, true));
436 MBB.erase(PrevMBBI);
437 return true;
438 } else if (Mode == ARM_AM::ib &&
Evan Cheng27934da2009-08-04 01:43:45 +0000439 isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000440 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(ARM_AM::da, true));
441 MBB.erase(PrevMBBI);
442 return true;
443 }
444 }
445
446 if (MBBI != MBB.end()) {
447 MachineBasicBlock::iterator NextMBBI = next(MBBI);
448 if ((Mode == ARM_AM::ia || Mode == ARM_AM::ib) &&
Evan Cheng27934da2009-08-04 01:43:45 +0000449 isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000450 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
Evan Chenge71bff72007-09-19 21:48:07 +0000451 if (NextMBBI == I) {
452 Advance = true;
453 ++I;
454 }
Evan Chenga8e29892007-01-19 07:51:42 +0000455 MBB.erase(NextMBBI);
456 return true;
457 } else if ((Mode == ARM_AM::da || Mode == ARM_AM::db) &&
Evan Cheng27934da2009-08-04 01:43:45 +0000458 isMatchingDecrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000459 MI->getOperand(1).setImm(ARM_AM::getAM4ModeImm(Mode, true));
Evan Chenge71bff72007-09-19 21:48:07 +0000460 if (NextMBBI == I) {
461 Advance = true;
462 ++I;
463 }
Evan Chenga8e29892007-01-19 07:51:42 +0000464 MBB.erase(NextMBBI);
465 return true;
466 }
467 }
468 } else {
469 // FLDM{D|S}, FSTM{D|S} addressing mode 5 ops.
470 if (ARM_AM::getAM5WBFlag(MI->getOperand(1).getImm()))
471 return false;
472
473 ARM_AM::AMSubMode Mode = ARM_AM::getAM5SubMode(MI->getOperand(1).getImm());
474 unsigned Offset = ARM_AM::getAM5Offset(MI->getOperand(1).getImm());
475 if (MBBI != MBB.begin()) {
476 MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
477 if (Mode == ARM_AM::ia &&
Evan Cheng27934da2009-08-04 01:43:45 +0000478 isMatchingDecrement(PrevMBBI, Base, Bytes, 0, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000479 MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::db, true, Offset));
480 MBB.erase(PrevMBBI);
481 return true;
482 }
483 }
484
485 if (MBBI != MBB.end()) {
486 MachineBasicBlock::iterator NextMBBI = next(MBBI);
487 if (Mode == ARM_AM::ia &&
Evan Cheng27934da2009-08-04 01:43:45 +0000488 isMatchingIncrement(NextMBBI, Base, Bytes, 0, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000489 MI->getOperand(1).setImm(ARM_AM::getAM5Opc(ARM_AM::ia, true, Offset));
Evan Chenge71bff72007-09-19 21:48:07 +0000490 if (NextMBBI == I) {
491 Advance = true;
492 ++I;
493 }
Evan Chenga8e29892007-01-19 07:51:42 +0000494 MBB.erase(NextMBBI);
495 }
496 return true;
497 }
498 }
499
500 return false;
501}
502
503static unsigned getPreIndexedLoadStoreOpcode(unsigned Opc) {
504 switch (Opc) {
505 case ARM::LDR: return ARM::LDR_PRE;
506 case ARM::STR: return ARM::STR_PRE;
507 case ARM::FLDS: return ARM::FLDMS;
508 case ARM::FLDD: return ARM::FLDMD;
509 case ARM::FSTS: return ARM::FSTMS;
510 case ARM::FSTD: return ARM::FSTMD;
Evan Cheng45032f22009-07-09 23:11:34 +0000511 case ARM::t2LDRi8:
512 case ARM::t2LDRi12:
513 return ARM::t2LDR_PRE;
514 case ARM::t2STRi8:
515 case ARM::t2STRi12:
516 return ARM::t2STR_PRE;
Torok Edwinc23197a2009-07-14 16:55:14 +0000517 default: llvm_unreachable("Unhandled opcode!");
Evan Chenga8e29892007-01-19 07:51:42 +0000518 }
519 return 0;
520}
521
522static unsigned getPostIndexedLoadStoreOpcode(unsigned Opc) {
523 switch (Opc) {
524 case ARM::LDR: return ARM::LDR_POST;
525 case ARM::STR: return ARM::STR_POST;
526 case ARM::FLDS: return ARM::FLDMS;
527 case ARM::FLDD: return ARM::FLDMD;
528 case ARM::FSTS: return ARM::FSTMS;
529 case ARM::FSTD: return ARM::FSTMD;
Evan Cheng45032f22009-07-09 23:11:34 +0000530 case ARM::t2LDRi8:
531 case ARM::t2LDRi12:
532 return ARM::t2LDR_POST;
533 case ARM::t2STRi8:
534 case ARM::t2STRi12:
535 return ARM::t2STR_POST;
Torok Edwinc23197a2009-07-14 16:55:14 +0000536 default: llvm_unreachable("Unhandled opcode!");
Evan Chenga8e29892007-01-19 07:51:42 +0000537 }
538 return 0;
539}
540
Evan Cheng45032f22009-07-09 23:11:34 +0000541/// MergeBaseUpdateLoadStore - Fold proceeding/trailing inc/dec of base
Evan Chenga8e29892007-01-19 07:51:42 +0000542/// register into the LDR/STR/FLD{D|S}/FST{D|S} op when possible:
Evan Cheng45032f22009-07-09 23:11:34 +0000543bool ARMLoadStoreOpt::MergeBaseUpdateLoadStore(MachineBasicBlock &MBB,
544 MachineBasicBlock::iterator MBBI,
545 const TargetInstrInfo *TII,
546 bool &Advance,
547 MachineBasicBlock::iterator &I) {
Evan Chenga8e29892007-01-19 07:51:42 +0000548 MachineInstr *MI = MBBI;
549 unsigned Base = MI->getOperand(1).getReg();
Evan Chenga90f3402007-03-06 21:59:20 +0000550 bool BaseKill = MI->getOperand(1).isKill();
Evan Chenga8e29892007-01-19 07:51:42 +0000551 unsigned Bytes = getLSMultipleTransferSize(MI);
552 int Opcode = MI->getOpcode();
Dale Johannesenb6728402009-02-13 02:25:56 +0000553 DebugLoc dl = MI->getDebugLoc();
Evan Cheng27934da2009-08-04 01:43:45 +0000554 bool isAM5 = Opcode == ARM::FLDD || Opcode == ARM::FLDS ||
555 Opcode == ARM::FSTD || Opcode == ARM::FSTS;
Evan Chenga8e29892007-01-19 07:51:42 +0000556 bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
Evan Cheng45032f22009-07-09 23:11:34 +0000557 if (isAM2 && ARM_AM::getAM2Offset(MI->getOperand(3).getImm()) != 0)
558 return false;
Evan Cheng27934da2009-08-04 01:43:45 +0000559 else if (isAM5 && ARM_AM::getAM5Offset(MI->getOperand(2).getImm()) != 0)
Evan Cheng45032f22009-07-09 23:11:34 +0000560 return false;
Evan Cheng27934da2009-08-04 01:43:45 +0000561 else if (isT2i32Load(Opcode) || isT2i32Store(Opcode))
562 if (MI->getOperand(2).getImm() != 0)
563 return false;
Evan Chenga8e29892007-01-19 07:51:42 +0000564
Evan Cheng45032f22009-07-09 23:11:34 +0000565 bool isLd = isi32Load(Opcode) || Opcode == ARM::FLDS || Opcode == ARM::FLDD;
Evan Chenga8e29892007-01-19 07:51:42 +0000566 // Can't do the merge if the destination register is the same as the would-be
567 // writeback register.
568 if (isLd && MI->getOperand(0).getReg() == Base)
569 return false;
570
Evan Cheng0e1d3792007-07-05 07:18:20 +0000571 unsigned PredReg = 0;
Evan Cheng8fb90362009-08-08 03:20:32 +0000572 ARMCC::CondCodes Pred = llvm::getInstrPredicate(MI, PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000573 bool DoMerge = false;
574 ARM_AM::AddrOpc AddSub = ARM_AM::add;
575 unsigned NewOpc = 0;
Evan Cheng27934da2009-08-04 01:43:45 +0000576 // AM2 - 12 bits, thumb2 - 8 bits.
577 unsigned Limit = isAM5 ? 0 : (isAM2 ? 0x1000 : 0x100);
Evan Chenga8e29892007-01-19 07:51:42 +0000578 if (MBBI != MBB.begin()) {
579 MachineBasicBlock::iterator PrevMBBI = prior(MBBI);
Evan Cheng27934da2009-08-04 01:43:45 +0000580 if (isMatchingDecrement(PrevMBBI, Base, Bytes, Limit, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000581 DoMerge = true;
582 AddSub = ARM_AM::sub;
583 NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
Evan Cheng27934da2009-08-04 01:43:45 +0000584 } else if (!isAM5 &&
585 isMatchingIncrement(PrevMBBI, Base, Bytes, Limit,Pred,PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000586 DoMerge = true;
587 NewOpc = getPreIndexedLoadStoreOpcode(Opcode);
588 }
589 if (DoMerge)
590 MBB.erase(PrevMBBI);
591 }
592
593 if (!DoMerge && MBBI != MBB.end()) {
594 MachineBasicBlock::iterator NextMBBI = next(MBBI);
Evan Cheng27934da2009-08-04 01:43:45 +0000595 if (!isAM5 &&
596 isMatchingDecrement(NextMBBI, Base, Bytes, Limit, Pred, PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000597 DoMerge = true;
598 AddSub = ARM_AM::sub;
599 NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
Evan Cheng27934da2009-08-04 01:43:45 +0000600 } else if (isMatchingIncrement(NextMBBI, Base, Bytes, Limit,Pred,PredReg)) {
Evan Chenga8e29892007-01-19 07:51:42 +0000601 DoMerge = true;
602 NewOpc = getPostIndexedLoadStoreOpcode(Opcode);
603 }
Evan Chenge71bff72007-09-19 21:48:07 +0000604 if (DoMerge) {
605 if (NextMBBI == I) {
606 Advance = true;
607 ++I;
608 }
Evan Chenga8e29892007-01-19 07:51:42 +0000609 MBB.erase(NextMBBI);
Evan Chenge71bff72007-09-19 21:48:07 +0000610 }
Evan Chenga8e29892007-01-19 07:51:42 +0000611 }
612
613 if (!DoMerge)
614 return false;
615
616 bool isDPR = NewOpc == ARM::FLDMD || NewOpc == ARM::FSTMD;
Evan Cheng9e7a3122009-08-04 21:12:13 +0000617 unsigned Offset = 0;
618 if (isAM5)
619 Offset = ARM_AM::getAM5Opc((AddSub == ARM_AM::sub)
620 ? ARM_AM::db
621 : ARM_AM::ia, true, (isDPR ? 2 : 1));
622 else if (isAM2)
623 Offset = ARM_AM::getAM2Opc(AddSub, Bytes, ARM_AM::no_shift);
624 else
625 Offset = AddSub == ARM_AM::sub ? -Bytes : Bytes;
Evan Chenga8e29892007-01-19 07:51:42 +0000626 if (isLd) {
Evan Cheng27934da2009-08-04 01:43:45 +0000627 if (isAM5)
Evan Cheng44bec522007-05-15 01:29:07 +0000628 // FLDMS, FLDMD
Dale Johannesenb6728402009-02-13 02:25:56 +0000629 BuildMI(MBB, MBBI, dl, TII->get(NewOpc))
Bill Wendling587daed2009-05-13 21:33:08 +0000630 .addReg(Base, getKillRegState(BaseKill))
Evan Cheng0e1d3792007-07-05 07:18:20 +0000631 .addImm(Offset).addImm(Pred).addReg(PredReg)
Bill Wendling587daed2009-05-13 21:33:08 +0000632 .addReg(MI->getOperand(0).getReg(), RegState::Define);
Evan Cheng27934da2009-08-04 01:43:45 +0000633 else if (isAM2)
634 // LDR_PRE, LDR_POST,
635 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), MI->getOperand(0).getReg())
636 .addReg(Base, RegState::Define)
Evan Cheng0e1d3792007-07-05 07:18:20 +0000637 .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000638 else
Evan Cheng27934da2009-08-04 01:43:45 +0000639 // t2LDR_PRE, t2LDR_POST
640 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), MI->getOperand(0).getReg())
641 .addReg(Base, RegState::Define)
642 .addReg(Base).addImm(Offset).addImm(Pred).addReg(PredReg);
643 } else {
644 MachineOperand &MO = MI->getOperand(0);
645 if (isAM5)
Evan Cheng44bec522007-05-15 01:29:07 +0000646 // FSTMS, FSTMD
Dale Johannesenb6728402009-02-13 02:25:56 +0000647 BuildMI(MBB, MBBI, dl, TII->get(NewOpc)).addReg(Base).addImm(Offset)
Evan Cheng0e1d3792007-07-05 07:18:20 +0000648 .addImm(Pred).addReg(PredReg)
Bill Wendling587daed2009-05-13 21:33:08 +0000649 .addReg(MO.getReg(), getKillRegState(MO.isKill()));
Evan Cheng27934da2009-08-04 01:43:45 +0000650 else if (isAM2)
651 // STR_PRE, STR_POST
652 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), Base)
653 .addReg(MO.getReg(), getKillRegState(MO.isKill()))
654 .addReg(Base).addReg(0).addImm(Offset).addImm(Pred).addReg(PredReg);
655 else
656 // t2STR_PRE, t2STR_POST
657 BuildMI(MBB, MBBI, dl, TII->get(NewOpc), Base)
658 .addReg(MO.getReg(), getKillRegState(MO.isKill()))
659 .addReg(Base).addImm(Offset).addImm(Pred).addReg(PredReg);
Evan Chenga8e29892007-01-19 07:51:42 +0000660 }
661 MBB.erase(MBBI);
662
663 return true;
664}
665
Evan Chengcc1c4272007-03-06 18:02:41 +0000666/// isMemoryOp - Returns true if instruction is a memory operations (that this
667/// pass is capable of operating on).
Evan Cheng45032f22009-07-09 23:11:34 +0000668static bool isMemoryOp(const MachineInstr *MI) {
Evan Chengcc1c4272007-03-06 18:02:41 +0000669 int Opcode = MI->getOpcode();
670 switch (Opcode) {
671 default: break;
672 case ARM::LDR:
673 case ARM::STR:
Dan Gohmand735b802008-10-03 15:45:36 +0000674 return MI->getOperand(1).isReg() && MI->getOperand(2).getReg() == 0;
Evan Chengcc1c4272007-03-06 18:02:41 +0000675 case ARM::FLDS:
676 case ARM::FSTS:
Dan Gohmand735b802008-10-03 15:45:36 +0000677 return MI->getOperand(1).isReg();
Evan Chengcc1c4272007-03-06 18:02:41 +0000678 case ARM::FLDD:
679 case ARM::FSTD:
Dan Gohmand735b802008-10-03 15:45:36 +0000680 return MI->getOperand(1).isReg();
Evan Cheng45032f22009-07-09 23:11:34 +0000681 case ARM::t2LDRi8:
682 case ARM::t2LDRi12:
683 case ARM::t2STRi8:
684 case ARM::t2STRi12:
685 return true;
Evan Chengcc1c4272007-03-06 18:02:41 +0000686 }
687 return false;
688}
689
Evan Cheng11788fd2007-03-08 02:55:08 +0000690/// AdvanceRS - Advance register scavenger to just before the earliest memory
691/// op that is being merged.
692void ARMLoadStoreOpt::AdvanceRS(MachineBasicBlock &MBB, MemOpQueue &MemOps) {
693 MachineBasicBlock::iterator Loc = MemOps[0].MBBI;
694 unsigned Position = MemOps[0].Position;
695 for (unsigned i = 1, e = MemOps.size(); i != e; ++i) {
696 if (MemOps[i].Position < Position) {
697 Position = MemOps[i].Position;
698 Loc = MemOps[i].MBBI;
699 }
700 }
701
702 if (Loc != MBB.begin())
703 RS->forward(prior(Loc));
704}
705
Evan Chenge7d6df72009-06-13 09:12:55 +0000706static int getMemoryOpOffset(const MachineInstr *MI) {
707 int Opcode = MI->getOpcode();
708 bool isAM2 = Opcode == ARM::LDR || Opcode == ARM::STR;
Evan Cheng358dec52009-06-15 08:28:29 +0000709 bool isAM3 = Opcode == ARM::LDRD || Opcode == ARM::STRD;
Evan Chenge7d6df72009-06-13 09:12:55 +0000710 unsigned NumOperands = MI->getDesc().getNumOperands();
711 unsigned OffField = MI->getOperand(NumOperands-3).getImm();
Evan Cheng45032f22009-07-09 23:11:34 +0000712
713 if (Opcode == ARM::t2LDRi12 || Opcode == ARM::t2LDRi8 ||
714 Opcode == ARM::t2STRi12 || Opcode == ARM::t2STRi8 ||
715 Opcode == ARM::t2LDRDi8 || Opcode == ARM::t2STRDi8)
716 return OffField;
717
Evan Chenge7d6df72009-06-13 09:12:55 +0000718 int Offset = isAM2
Evan Cheng358dec52009-06-15 08:28:29 +0000719 ? ARM_AM::getAM2Offset(OffField)
720 : (isAM3 ? ARM_AM::getAM3Offset(OffField)
721 : ARM_AM::getAM5Offset(OffField) * 4);
Evan Chenge7d6df72009-06-13 09:12:55 +0000722 if (isAM2) {
723 if (ARM_AM::getAM2Op(OffField) == ARM_AM::sub)
724 Offset = -Offset;
Evan Cheng358dec52009-06-15 08:28:29 +0000725 } else if (isAM3) {
726 if (ARM_AM::getAM3Op(OffField) == ARM_AM::sub)
727 Offset = -Offset;
Evan Chenge7d6df72009-06-13 09:12:55 +0000728 } else {
729 if (ARM_AM::getAM5Op(OffField) == ARM_AM::sub)
730 Offset = -Offset;
731 }
732 return Offset;
733}
734
Evan Cheng358dec52009-06-15 08:28:29 +0000735static void InsertLDR_STR(MachineBasicBlock &MBB,
736 MachineBasicBlock::iterator &MBBI,
737 int OffImm, bool isDef,
738 DebugLoc dl, unsigned NewOpc,
Evan Cheng974fe5d2009-06-19 01:59:04 +0000739 unsigned Reg, bool RegDeadKill,
Evan Cheng358dec52009-06-15 08:28:29 +0000740 unsigned BaseReg, bool BaseKill,
741 unsigned OffReg, bool OffKill,
742 ARMCC::CondCodes Pred, unsigned PredReg,
743 const TargetInstrInfo *TII) {
744 unsigned Offset;
745 if (OffImm < 0)
746 Offset = ARM_AM::getAM2Opc(ARM_AM::sub, -OffImm, ARM_AM::no_shift);
747 else
748 Offset = ARM_AM::getAM2Opc(ARM_AM::add, OffImm, ARM_AM::no_shift);
749 if (isDef)
Evan Cheng974fe5d2009-06-19 01:59:04 +0000750 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
751 .addReg(Reg, getDefRegState(true) | getDeadRegState(RegDeadKill))
Evan Cheng358dec52009-06-15 08:28:29 +0000752 .addReg(BaseReg, getKillRegState(BaseKill))
753 .addReg(OffReg, getKillRegState(OffKill))
754 .addImm(Offset)
755 .addImm(Pred).addReg(PredReg);
756 else
757 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
Evan Cheng974fe5d2009-06-19 01:59:04 +0000758 .addReg(Reg, getKillRegState(RegDeadKill))
Evan Cheng358dec52009-06-15 08:28:29 +0000759 .addReg(BaseReg, getKillRegState(BaseKill))
760 .addReg(OffReg, getKillRegState(OffKill))
761 .addImm(Offset)
762 .addImm(Pred).addReg(PredReg);
763}
764
765bool ARMLoadStoreOpt::FixInvalidRegPairOp(MachineBasicBlock &MBB,
766 MachineBasicBlock::iterator &MBBI) {
767 MachineInstr *MI = &*MBBI;
768 unsigned Opcode = MI->getOpcode();
769 if (Opcode == ARM::LDRD || Opcode == ARM::STRD) {
770 unsigned EvenReg = MI->getOperand(0).getReg();
771 unsigned OddReg = MI->getOperand(1).getReg();
772 unsigned EvenRegNum = TRI->getDwarfRegNum(EvenReg, false);
773 unsigned OddRegNum = TRI->getDwarfRegNum(OddReg, false);
774 if ((EvenRegNum & 1) == 0 && (EvenRegNum + 1) == OddRegNum)
775 return false;
776
Evan Chengf9f1da12009-06-18 02:04:01 +0000777 bool isLd = Opcode == ARM::LDRD;
Evan Cheng974fe5d2009-06-19 01:59:04 +0000778 bool EvenDeadKill = isLd ?
779 MI->getOperand(0).isDead() : MI->getOperand(0).isKill();
780 bool OddDeadKill = isLd ?
781 MI->getOperand(1).isDead() : MI->getOperand(1).isKill();
Evan Cheng358dec52009-06-15 08:28:29 +0000782 const MachineOperand &BaseOp = MI->getOperand(2);
783 unsigned BaseReg = BaseOp.getReg();
784 bool BaseKill = BaseOp.isKill();
785 const MachineOperand &OffOp = MI->getOperand(3);
786 unsigned OffReg = OffOp.getReg();
787 bool OffKill = OffOp.isKill();
788 int OffImm = getMemoryOpOffset(MI);
789 unsigned PredReg = 0;
Evan Cheng8fb90362009-08-08 03:20:32 +0000790 ARMCC::CondCodes Pred = llvm::getInstrPredicate(MI, PredReg);
Evan Cheng358dec52009-06-15 08:28:29 +0000791
792 if (OddRegNum > EvenRegNum && OffReg == 0 && OffImm == 0) {
793 // Ascending register numbers and no offset. It's safe to change it to a
794 // ldm or stm.
795 unsigned NewOpc = (Opcode == ARM::LDRD) ? ARM::LDM : ARM::STM;
Evan Chengf9f1da12009-06-18 02:04:01 +0000796 if (isLd) {
797 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
798 .addReg(BaseReg, getKillRegState(BaseKill))
799 .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))
800 .addImm(Pred).addReg(PredReg)
Evan Cheng974fe5d2009-06-19 01:59:04 +0000801 .addReg(EvenReg, getDefRegState(isLd) | getDeadRegState(EvenDeadKill))
802 .addReg(OddReg, getDefRegState(isLd) | getDeadRegState(OddDeadKill));
Evan Chengf9f1da12009-06-18 02:04:01 +0000803 ++NumLDRD2LDM;
804 } else {
805 BuildMI(MBB, MBBI, MBBI->getDebugLoc(), TII->get(NewOpc))
806 .addReg(BaseReg, getKillRegState(BaseKill))
807 .addImm(ARM_AM::getAM4ModeImm(ARM_AM::ia))
808 .addImm(Pred).addReg(PredReg)
Evan Cheng974fe5d2009-06-19 01:59:04 +0000809 .addReg(EvenReg, getKillRegState(EvenDeadKill))
810 .addReg(OddReg, getKillRegState(OddDeadKill));
Evan Chengf9f1da12009-06-18 02:04:01 +0000811 ++NumSTRD2STM;
812 }
Evan Cheng358dec52009-06-15 08:28:29 +0000813 } else {
814 // Split into two instructions.
815 unsigned NewOpc = (Opcode == ARM::LDRD) ? ARM::LDR : ARM::STR;
816 DebugLoc dl = MBBI->getDebugLoc();
817 // If this is a load and base register is killed, it may have been
818 // re-defed by the load, make sure the first load does not clobber it.
Evan Chengf9f1da12009-06-18 02:04:01 +0000819 if (isLd &&
Evan Cheng358dec52009-06-15 08:28:29 +0000820 (BaseKill || OffKill) &&
821 (TRI->regsOverlap(EvenReg, BaseReg) ||
822 (OffReg && TRI->regsOverlap(EvenReg, OffReg)))) {
823 assert(!TRI->regsOverlap(OddReg, BaseReg) &&
824 (!OffReg || !TRI->regsOverlap(OddReg, OffReg)));
Evan Cheng974fe5d2009-06-19 01:59:04 +0000825 InsertLDR_STR(MBB, MBBI, OffImm+4, isLd, dl, NewOpc, OddReg, OddDeadKill,
Evan Cheng358dec52009-06-15 08:28:29 +0000826 BaseReg, false, OffReg, false, Pred, PredReg, TII);
Evan Cheng974fe5d2009-06-19 01:59:04 +0000827 InsertLDR_STR(MBB, MBBI, OffImm, isLd, dl, NewOpc, EvenReg, EvenDeadKill,
Evan Cheng358dec52009-06-15 08:28:29 +0000828 BaseReg, BaseKill, OffReg, OffKill, Pred, PredReg, TII);
829 } else {
Evan Cheng974fe5d2009-06-19 01:59:04 +0000830 InsertLDR_STR(MBB, MBBI, OffImm, isLd, dl, NewOpc,
831 EvenReg, EvenDeadKill, BaseReg, false, OffReg, false,
832 Pred, PredReg, TII);
833 InsertLDR_STR(MBB, MBBI, OffImm+4, isLd, dl, NewOpc,
834 OddReg, OddDeadKill, BaseReg, BaseKill, OffReg, OffKill,
835 Pred, PredReg, TII);
Evan Cheng358dec52009-06-15 08:28:29 +0000836 }
Evan Chengf9f1da12009-06-18 02:04:01 +0000837 if (isLd)
838 ++NumLDRD2LDR;
839 else
840 ++NumSTRD2STR;
Evan Cheng358dec52009-06-15 08:28:29 +0000841 }
842
843 MBBI = prior(MBBI);
844 MBB.erase(MI);
845 }
846 return false;
847}
848
Evan Chenga8e29892007-01-19 07:51:42 +0000849/// LoadStoreMultipleOpti - An optimization pass to turn multiple LDR / STR
850/// ops of the same base and incrementing offset into LDM / STM ops.
851bool ARMLoadStoreOpt::LoadStoreMultipleOpti(MachineBasicBlock &MBB) {
852 unsigned NumMerges = 0;
853 unsigned NumMemOps = 0;
854 MemOpQueue MemOps;
855 unsigned CurrBase = 0;
856 int CurrOpc = -1;
857 unsigned CurrSize = 0;
Evan Cheng44bec522007-05-15 01:29:07 +0000858 ARMCC::CondCodes CurrPred = ARMCC::AL;
Evan Cheng0e1d3792007-07-05 07:18:20 +0000859 unsigned CurrPredReg = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000860 unsigned Position = 0;
Evan Cheng5ba71882009-06-05 17:56:14 +0000861 SmallVector<MachineBasicBlock::iterator,4> Merges;
Evan Chengcc1c4272007-03-06 18:02:41 +0000862
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000863 RS->enterBasicBlock(&MBB);
Evan Chenga8e29892007-01-19 07:51:42 +0000864 MachineBasicBlock::iterator MBBI = MBB.begin(), E = MBB.end();
865 while (MBBI != E) {
Evan Cheng358dec52009-06-15 08:28:29 +0000866 if (FixInvalidRegPairOp(MBB, MBBI))
867 continue;
868
Evan Chenga8e29892007-01-19 07:51:42 +0000869 bool Advance = false;
870 bool TryMerge = false;
871 bool Clobber = false;
872
Evan Chengcc1c4272007-03-06 18:02:41 +0000873 bool isMemOp = isMemoryOp(MBBI);
Evan Chenga8e29892007-01-19 07:51:42 +0000874 if (isMemOp) {
Evan Chengcc1c4272007-03-06 18:02:41 +0000875 int Opcode = MBBI->getOpcode();
Evan Chengcc1c4272007-03-06 18:02:41 +0000876 unsigned Size = getLSMultipleTransferSize(MBBI);
Evan Chenga8e29892007-01-19 07:51:42 +0000877 unsigned Base = MBBI->getOperand(1).getReg();
Evan Cheng0e1d3792007-07-05 07:18:20 +0000878 unsigned PredReg = 0;
Evan Cheng8fb90362009-08-08 03:20:32 +0000879 ARMCC::CondCodes Pred = llvm::getInstrPredicate(MBBI, PredReg);
Evan Chenge7d6df72009-06-13 09:12:55 +0000880 int Offset = getMemoryOpOffset(MBBI);
Evan Chenga8e29892007-01-19 07:51:42 +0000881 // Watch out for:
882 // r4 := ldr [r5]
883 // r5 := ldr [r5, #4]
884 // r6 := ldr [r5, #8]
885 //
886 // The second ldr has effectively broken the chain even though it
887 // looks like the later ldr(s) use the same base register. Try to
888 // merge the ldr's so far, including this one. But don't try to
889 // combine the following ldr(s).
Evan Cheng45032f22009-07-09 23:11:34 +0000890 Clobber = (isi32Load(Opcode) && Base == MBBI->getOperand(0).getReg());
Evan Chenga8e29892007-01-19 07:51:42 +0000891 if (CurrBase == 0 && !Clobber) {
892 // Start of a new chain.
893 CurrBase = Base;
894 CurrOpc = Opcode;
895 CurrSize = Size;
Evan Cheng44bec522007-05-15 01:29:07 +0000896 CurrPred = Pred;
Evan Cheng0e1d3792007-07-05 07:18:20 +0000897 CurrPredReg = PredReg;
Evan Chenga8e29892007-01-19 07:51:42 +0000898 MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
899 NumMemOps++;
900 Advance = true;
901 } else {
902 if (Clobber) {
903 TryMerge = true;
904 Advance = true;
905 }
906
Evan Cheng44bec522007-05-15 01:29:07 +0000907 if (CurrOpc == Opcode && CurrBase == Base && CurrPred == Pred) {
Evan Cheng0e1d3792007-07-05 07:18:20 +0000908 // No need to match PredReg.
Evan Chenga8e29892007-01-19 07:51:42 +0000909 // Continue adding to the queue.
910 if (Offset > MemOps.back().Offset) {
911 MemOps.push_back(MemOpQueueEntry(Offset, Position, MBBI));
912 NumMemOps++;
913 Advance = true;
914 } else {
915 for (MemOpQueueIter I = MemOps.begin(), E = MemOps.end();
916 I != E; ++I) {
917 if (Offset < I->Offset) {
918 MemOps.insert(I, MemOpQueueEntry(Offset, Position, MBBI));
919 NumMemOps++;
920 Advance = true;
921 break;
922 } else if (Offset == I->Offset) {
923 // Collision! This can't be merged!
924 break;
925 }
926 }
927 }
928 }
929 }
930 }
931
932 if (Advance) {
933 ++Position;
934 ++MBBI;
935 } else
936 TryMerge = true;
937
938 if (TryMerge) {
939 if (NumMemOps > 1) {
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000940 // Try to find a free register to use as a new base in case it's needed.
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000941 // First advance to the instruction just before the start of the chain.
Evan Cheng11788fd2007-03-08 02:55:08 +0000942 AdvanceRS(MBB, MemOps);
Evan Cheng603b83e2007-03-07 20:30:36 +0000943 // Find a scratch register. Make sure it's a call clobbered register or
944 // a spilled callee-saved register.
Evan Cheng11788fd2007-03-08 02:55:08 +0000945 unsigned Scratch = RS->FindUnusedReg(&ARM::GPRRegClass, true);
Evan Cheng603b83e2007-03-07 20:30:36 +0000946 if (!Scratch)
Evan Cheng11788fd2007-03-08 02:55:08 +0000947 Scratch = RS->FindUnusedReg(&ARM::GPRRegClass,
948 AFI->getSpilledCSRegisters());
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000949 // Process the load / store instructions.
950 RS->forward(prior(MBBI));
951
952 // Merge ops.
Evan Cheng5ba71882009-06-05 17:56:14 +0000953 Merges.clear();
954 MergeLDR_STR(MBB, 0, CurrBase, CurrOpc, CurrSize,
955 CurrPred, CurrPredReg, Scratch, MemOps, Merges);
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000956
Evan Chenga8e29892007-01-19 07:51:42 +0000957 // Try folding preceeding/trailing base inc/dec into the generated
958 // LDM/STM ops.
Evan Cheng5ba71882009-06-05 17:56:14 +0000959 for (unsigned i = 0, e = Merges.size(); i < e; ++i)
Evan Cheng45032f22009-07-09 23:11:34 +0000960 if (MergeBaseUpdateLSMultiple(MBB, Merges[i], Advance, MBBI))
Evan Cheng9d5fb982009-06-03 06:14:58 +0000961 ++NumMerges;
Evan Cheng5ba71882009-06-05 17:56:14 +0000962 NumMerges += Merges.size();
Evan Chenga8e29892007-01-19 07:51:42 +0000963
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000964 // Try folding preceeding/trailing base inc/dec into those load/store
965 // that were not merged to form LDM/STM ops.
966 for (unsigned i = 0; i != NumMemOps; ++i)
967 if (!MemOps[i].Merged)
Evan Cheng45032f22009-07-09 23:11:34 +0000968 if (MergeBaseUpdateLoadStore(MBB, MemOps[i].MBBI, TII,Advance,MBBI))
Evan Cheng9d5fb982009-06-03 06:14:58 +0000969 ++NumMerges;
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000970
Jim Grosbach764ab522009-08-11 15:33:49 +0000971 // RS may be pointing to an instruction that's deleted.
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000972 RS->skipTo(prior(MBBI));
Evan Cheng14883262009-06-04 01:15:28 +0000973 } else if (NumMemOps == 1) {
974 // Try folding preceeding/trailing base inc/dec into the single
975 // load/store.
Evan Cheng45032f22009-07-09 23:11:34 +0000976 if (MergeBaseUpdateLoadStore(MBB, MemOps[0].MBBI, TII, Advance, MBBI)) {
Evan Cheng14883262009-06-04 01:15:28 +0000977 ++NumMerges;
978 RS->forward(prior(MBBI));
979 }
Evan Cheng0ea12ec2007-03-07 02:38:05 +0000980 }
Evan Chenga8e29892007-01-19 07:51:42 +0000981
982 CurrBase = 0;
983 CurrOpc = -1;
Evan Cheng44bec522007-05-15 01:29:07 +0000984 CurrSize = 0;
985 CurrPred = ARMCC::AL;
Evan Cheng0e1d3792007-07-05 07:18:20 +0000986 CurrPredReg = 0;
Evan Chenga8e29892007-01-19 07:51:42 +0000987 if (NumMemOps) {
988 MemOps.clear();
989 NumMemOps = 0;
990 }
991
992 // If iterator hasn't been advanced and this is not a memory op, skip it.
993 // It can't start a new chain anyway.
994 if (!Advance && !isMemOp && MBBI != E) {
995 ++Position;
996 ++MBBI;
997 }
998 }
999 }
1000 return NumMerges > 0;
1001}
1002
Evan Chenge7d6df72009-06-13 09:12:55 +00001003namespace {
1004 struct OffsetCompare {
1005 bool operator()(const MachineInstr *LHS, const MachineInstr *RHS) const {
1006 int LOffset = getMemoryOpOffset(LHS);
1007 int ROffset = getMemoryOpOffset(RHS);
1008 assert(LHS == RHS || LOffset != ROffset);
1009 return LOffset > ROffset;
1010 }
1011 };
1012}
1013
Evan Chenga8e29892007-01-19 07:51:42 +00001014/// MergeReturnIntoLDM - If this is a exit BB, try merging the return op
1015/// (bx lr) into the preceeding stack restore so it directly restore the value
1016/// of LR into pc.
1017/// ldmfd sp!, {r7, lr}
1018/// bx lr
1019/// =>
1020/// ldmfd sp!, {r7, pc}
1021bool ARMLoadStoreOpt::MergeReturnIntoLDM(MachineBasicBlock &MBB) {
1022 if (MBB.empty()) return false;
1023
1024 MachineBasicBlock::iterator MBBI = prior(MBB.end());
Evan Cheng45032f22009-07-09 23:11:34 +00001025 if (MBBI != MBB.begin() &&
Evan Cheng446c4282009-07-11 06:43:01 +00001026 (MBBI->getOpcode() == ARM::BX_RET || MBBI->getOpcode() == ARM::tBX_RET)) {
Evan Chenga8e29892007-01-19 07:51:42 +00001027 MachineInstr *PrevMI = prior(MBBI);
Evan Cheng45032f22009-07-09 23:11:34 +00001028 if (PrevMI->getOpcode() == ARM::LDM || PrevMI->getOpcode() == ARM::t2LDM) {
Evan Chenga8e29892007-01-19 07:51:42 +00001029 MachineOperand &MO = PrevMI->getOperand(PrevMI->getNumOperands()-1);
Evan Cheng27934da2009-08-04 01:43:45 +00001030 if (MO.getReg() != ARM::LR)
1031 return false;
1032 unsigned NewOpc = isThumb2 ? ARM::t2LDM_RET : ARM::LDM_RET;
1033 PrevMI->setDesc(TII->get(NewOpc));
1034 MO.setReg(ARM::PC);
1035 MBB.erase(MBBI);
1036 return true;
Evan Chenga8e29892007-01-19 07:51:42 +00001037 }
1038 }
1039 return false;
1040}
1041
1042bool ARMLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
Evan Chengcc1c4272007-03-06 18:02:41 +00001043 const TargetMachine &TM = Fn.getTarget();
Evan Cheng603b83e2007-03-07 20:30:36 +00001044 AFI = Fn.getInfo<ARMFunctionInfo>();
Evan Chengcc1c4272007-03-06 18:02:41 +00001045 TII = TM.getInstrInfo();
Dan Gohman6f0d0242008-02-10 18:45:23 +00001046 TRI = TM.getRegisterInfo();
Evan Cheng0ea12ec2007-03-07 02:38:05 +00001047 RS = new RegScavenger();
Evan Cheng45032f22009-07-09 23:11:34 +00001048 isThumb2 = AFI->isThumb2Function();
Evan Chengcc1c4272007-03-06 18:02:41 +00001049
Evan Chenga8e29892007-01-19 07:51:42 +00001050 bool Modified = false;
1051 for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
1052 ++MFI) {
1053 MachineBasicBlock &MBB = *MFI;
1054 Modified |= LoadStoreMultipleOpti(MBB);
1055 Modified |= MergeReturnIntoLDM(MBB);
1056 }
Evan Chengcc1c4272007-03-06 18:02:41 +00001057
1058 delete RS;
Evan Chenga8e29892007-01-19 07:51:42 +00001059 return Modified;
1060}
Evan Chenge7d6df72009-06-13 09:12:55 +00001061
1062
1063/// ARMPreAllocLoadStoreOpt - Pre- register allocation pass that move
1064/// load / stores from consecutive locations close to make it more
1065/// likely they will be combined later.
1066
1067namespace {
1068 struct VISIBILITY_HIDDEN ARMPreAllocLoadStoreOpt : public MachineFunctionPass{
1069 static char ID;
1070 ARMPreAllocLoadStoreOpt() : MachineFunctionPass(&ID) {}
1071
Evan Cheng358dec52009-06-15 08:28:29 +00001072 const TargetData *TD;
Evan Chenge7d6df72009-06-13 09:12:55 +00001073 const TargetInstrInfo *TII;
1074 const TargetRegisterInfo *TRI;
Evan Cheng358dec52009-06-15 08:28:29 +00001075 const ARMSubtarget *STI;
Evan Chenge7d6df72009-06-13 09:12:55 +00001076 MachineRegisterInfo *MRI;
1077
1078 virtual bool runOnMachineFunction(MachineFunction &Fn);
1079
1080 virtual const char *getPassName() const {
1081 return "ARM pre- register allocation load / store optimization pass";
1082 }
1083
1084 private:
Evan Chengd780f352009-06-15 20:54:56 +00001085 bool CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1, DebugLoc &dl,
1086 unsigned &NewOpc, unsigned &EvenReg,
1087 unsigned &OddReg, unsigned &BaseReg,
1088 unsigned &OffReg, unsigned &Offset,
1089 unsigned &PredReg, ARMCC::CondCodes &Pred);
Evan Chenge7d6df72009-06-13 09:12:55 +00001090 bool RescheduleOps(MachineBasicBlock *MBB,
1091 SmallVector<MachineInstr*, 4> &Ops,
1092 unsigned Base, bool isLd,
1093 DenseMap<MachineInstr*, unsigned> &MI2LocMap);
1094 bool RescheduleLoadStoreInstrs(MachineBasicBlock *MBB);
1095 };
1096 char ARMPreAllocLoadStoreOpt::ID = 0;
1097}
1098
1099bool ARMPreAllocLoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
Evan Cheng358dec52009-06-15 08:28:29 +00001100 TD = Fn.getTarget().getTargetData();
Evan Chenge7d6df72009-06-13 09:12:55 +00001101 TII = Fn.getTarget().getInstrInfo();
1102 TRI = Fn.getTarget().getRegisterInfo();
Evan Cheng358dec52009-06-15 08:28:29 +00001103 STI = &Fn.getTarget().getSubtarget<ARMSubtarget>();
Evan Chenge7d6df72009-06-13 09:12:55 +00001104 MRI = &Fn.getRegInfo();
1105
1106 bool Modified = false;
1107 for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E;
1108 ++MFI)
1109 Modified |= RescheduleLoadStoreInstrs(MFI);
1110
1111 return Modified;
1112}
1113
Evan Chengae69a2a2009-06-19 23:17:27 +00001114static bool IsSafeAndProfitableToMove(bool isLd, unsigned Base,
1115 MachineBasicBlock::iterator I,
1116 MachineBasicBlock::iterator E,
1117 SmallPtrSet<MachineInstr*, 4> &MemOps,
1118 SmallSet<unsigned, 4> &MemRegs,
1119 const TargetRegisterInfo *TRI) {
Evan Chenge7d6df72009-06-13 09:12:55 +00001120 // Are there stores / loads / calls between them?
1121 // FIXME: This is overly conservative. We should make use of alias information
1122 // some day.
Evan Chengae69a2a2009-06-19 23:17:27 +00001123 SmallSet<unsigned, 4> AddedRegPressure;
Evan Chenge7d6df72009-06-13 09:12:55 +00001124 while (++I != E) {
Evan Chengae69a2a2009-06-19 23:17:27 +00001125 if (MemOps.count(&*I))
1126 continue;
Evan Chenge7d6df72009-06-13 09:12:55 +00001127 const TargetInstrDesc &TID = I->getDesc();
1128 if (TID.isCall() || TID.isTerminator() || TID.hasUnmodeledSideEffects())
1129 return false;
1130 if (isLd && TID.mayStore())
1131 return false;
1132 if (!isLd) {
1133 if (TID.mayLoad())
1134 return false;
1135 // It's not safe to move the first 'str' down.
1136 // str r1, [r0]
1137 // strh r5, [r0]
1138 // str r4, [r0, #+4]
Evan Chengae69a2a2009-06-19 23:17:27 +00001139 if (TID.mayStore())
Evan Chenge7d6df72009-06-13 09:12:55 +00001140 return false;
1141 }
1142 for (unsigned j = 0, NumOps = I->getNumOperands(); j != NumOps; ++j) {
1143 MachineOperand &MO = I->getOperand(j);
Evan Chengae69a2a2009-06-19 23:17:27 +00001144 if (!MO.isReg())
1145 continue;
1146 unsigned Reg = MO.getReg();
1147 if (MO.isDef() && TRI->regsOverlap(Reg, Base))
Evan Chenge7d6df72009-06-13 09:12:55 +00001148 return false;
Evan Chengae69a2a2009-06-19 23:17:27 +00001149 if (Reg != Base && !MemRegs.count(Reg))
1150 AddedRegPressure.insert(Reg);
Evan Chenge7d6df72009-06-13 09:12:55 +00001151 }
1152 }
Evan Chengae69a2a2009-06-19 23:17:27 +00001153
1154 // Estimate register pressure increase due to the transformation.
1155 if (MemRegs.size() <= 4)
1156 // Ok if we are moving small number of instructions.
1157 return true;
1158 return AddedRegPressure.size() <= MemRegs.size() * 2;
Evan Chenge7d6df72009-06-13 09:12:55 +00001159}
1160
Evan Chengd780f352009-06-15 20:54:56 +00001161bool
1162ARMPreAllocLoadStoreOpt::CanFormLdStDWord(MachineInstr *Op0, MachineInstr *Op1,
1163 DebugLoc &dl,
1164 unsigned &NewOpc, unsigned &EvenReg,
1165 unsigned &OddReg, unsigned &BaseReg,
1166 unsigned &OffReg, unsigned &Offset,
1167 unsigned &PredReg,
1168 ARMCC::CondCodes &Pred) {
1169 // FIXME: FLDS / FSTS -> FLDD / FSTD
1170 unsigned Opcode = Op0->getOpcode();
1171 if (Opcode == ARM::LDR)
1172 NewOpc = ARM::LDRD;
1173 else if (Opcode == ARM::STR)
1174 NewOpc = ARM::STRD;
1175 else
1176 return 0;
1177
1178 // Must sure the base address satisfies i64 ld / st alignment requirement.
1179 if (!Op0->hasOneMemOperand() ||
1180 !Op0->memoperands_begin()->getValue() ||
1181 Op0->memoperands_begin()->isVolatile())
Evan Cheng358dec52009-06-15 08:28:29 +00001182 return false;
1183
Evan Chengd780f352009-06-15 20:54:56 +00001184 unsigned Align = Op0->memoperands_begin()->getAlignment();
Evan Cheng358dec52009-06-15 08:28:29 +00001185 unsigned ReqAlign = STI->hasV6Ops()
1186 ? TD->getPrefTypeAlignment(Type::Int64Ty) : 8; // Pre-v6 need 8-byte align
Evan Chengd780f352009-06-15 20:54:56 +00001187 if (Align < ReqAlign)
1188 return false;
1189
1190 // Then make sure the immediate offset fits.
1191 int OffImm = getMemoryOpOffset(Op0);
1192 ARM_AM::AddrOpc AddSub = ARM_AM::add;
1193 if (OffImm < 0) {
1194 AddSub = ARM_AM::sub;
1195 OffImm = - OffImm;
1196 }
1197 if (OffImm >= 256) // 8 bits
1198 return false;
1199 Offset = ARM_AM::getAM3Opc(AddSub, OffImm);
1200
1201 EvenReg = Op0->getOperand(0).getReg();
Evan Cheng67586072009-06-15 21:18:20 +00001202 OddReg = Op1->getOperand(0).getReg();
Evan Chengd780f352009-06-15 20:54:56 +00001203 if (EvenReg == OddReg)
1204 return false;
1205 BaseReg = Op0->getOperand(1).getReg();
1206 OffReg = Op0->getOperand(2).getReg();
Evan Cheng8fb90362009-08-08 03:20:32 +00001207 Pred = llvm::getInstrPredicate(Op0, PredReg);
Evan Chengd780f352009-06-15 20:54:56 +00001208 dl = Op0->getDebugLoc();
1209 return true;
Evan Cheng358dec52009-06-15 08:28:29 +00001210}
1211
Evan Chenge7d6df72009-06-13 09:12:55 +00001212bool ARMPreAllocLoadStoreOpt::RescheduleOps(MachineBasicBlock *MBB,
1213 SmallVector<MachineInstr*, 4> &Ops,
1214 unsigned Base, bool isLd,
1215 DenseMap<MachineInstr*, unsigned> &MI2LocMap) {
1216 bool RetVal = false;
1217
1218 // Sort by offset (in reverse order).
1219 std::sort(Ops.begin(), Ops.end(), OffsetCompare());
1220
1221 // The loads / stores of the same base are in order. Scan them from first to
1222 // last and check for the followins:
1223 // 1. Any def of base.
1224 // 2. Any gaps.
1225 while (Ops.size() > 1) {
1226 unsigned FirstLoc = ~0U;
1227 unsigned LastLoc = 0;
1228 MachineInstr *FirstOp = 0;
1229 MachineInstr *LastOp = 0;
1230 int LastOffset = 0;
Evan Chengf9f1da12009-06-18 02:04:01 +00001231 unsigned LastOpcode = 0;
Evan Chenge7d6df72009-06-13 09:12:55 +00001232 unsigned LastBytes = 0;
1233 unsigned NumMove = 0;
1234 for (int i = Ops.size() - 1; i >= 0; --i) {
1235 MachineInstr *Op = Ops[i];
1236 unsigned Loc = MI2LocMap[Op];
1237 if (Loc <= FirstLoc) {
1238 FirstLoc = Loc;
1239 FirstOp = Op;
1240 }
1241 if (Loc >= LastLoc) {
1242 LastLoc = Loc;
1243 LastOp = Op;
1244 }
1245
Evan Chengf9f1da12009-06-18 02:04:01 +00001246 unsigned Opcode = Op->getOpcode();
1247 if (LastOpcode && Opcode != LastOpcode)
1248 break;
1249
Evan Chenge7d6df72009-06-13 09:12:55 +00001250 int Offset = getMemoryOpOffset(Op);
1251 unsigned Bytes = getLSMultipleTransferSize(Op);
1252 if (LastBytes) {
1253 if (Bytes != LastBytes || Offset != (LastOffset + (int)Bytes))
1254 break;
1255 }
1256 LastOffset = Offset;
1257 LastBytes = Bytes;
Evan Chengf9f1da12009-06-18 02:04:01 +00001258 LastOpcode = Opcode;
Evan Chengae69a2a2009-06-19 23:17:27 +00001259 if (++NumMove == 8) // FIXME: Tune
Evan Chenge7d6df72009-06-13 09:12:55 +00001260 break;
1261 }
1262
1263 if (NumMove <= 1)
1264 Ops.pop_back();
1265 else {
Evan Chengae69a2a2009-06-19 23:17:27 +00001266 SmallPtrSet<MachineInstr*, 4> MemOps;
1267 SmallSet<unsigned, 4> MemRegs;
1268 for (int i = NumMove-1; i >= 0; --i) {
1269 MemOps.insert(Ops[i]);
1270 MemRegs.insert(Ops[i]->getOperand(0).getReg());
1271 }
Evan Chenge7d6df72009-06-13 09:12:55 +00001272
1273 // Be conservative, if the instructions are too far apart, don't
1274 // move them. We want to limit the increase of register pressure.
Evan Chengae69a2a2009-06-19 23:17:27 +00001275 bool DoMove = (LastLoc - FirstLoc) <= NumMove*4; // FIXME: Tune this.
Evan Chenge7d6df72009-06-13 09:12:55 +00001276 if (DoMove)
Evan Chengae69a2a2009-06-19 23:17:27 +00001277 DoMove = IsSafeAndProfitableToMove(isLd, Base, FirstOp, LastOp,
1278 MemOps, MemRegs, TRI);
Evan Chenge7d6df72009-06-13 09:12:55 +00001279 if (!DoMove) {
1280 for (unsigned i = 0; i != NumMove; ++i)
1281 Ops.pop_back();
1282 } else {
1283 // This is the new location for the loads / stores.
1284 MachineBasicBlock::iterator InsertPos = isLd ? FirstOp : LastOp;
Evan Chengae69a2a2009-06-19 23:17:27 +00001285 while (InsertPos != MBB->end() && MemOps.count(InsertPos))
Evan Chenge7d6df72009-06-13 09:12:55 +00001286 ++InsertPos;
Evan Cheng358dec52009-06-15 08:28:29 +00001287
1288 // If we are moving a pair of loads / stores, see if it makes sense
1289 // to try to allocate a pair of registers that can form register pairs.
Evan Chengd780f352009-06-15 20:54:56 +00001290 MachineInstr *Op0 = Ops.back();
1291 MachineInstr *Op1 = Ops[Ops.size()-2];
1292 unsigned EvenReg = 0, OddReg = 0;
1293 unsigned BaseReg = 0, OffReg = 0, PredReg = 0;
1294 ARMCC::CondCodes Pred = ARMCC::AL;
1295 unsigned NewOpc = 0;
Evan Cheng358dec52009-06-15 08:28:29 +00001296 unsigned Offset = 0;
Evan Chengd780f352009-06-15 20:54:56 +00001297 DebugLoc dl;
1298 if (NumMove == 2 && CanFormLdStDWord(Op0, Op1, dl, NewOpc,
1299 EvenReg, OddReg, BaseReg, OffReg,
1300 Offset, PredReg, Pred)) {
1301 Ops.pop_back();
1302 Ops.pop_back();
Evan Cheng358dec52009-06-15 08:28:29 +00001303
Evan Chengd780f352009-06-15 20:54:56 +00001304 // Form the pair instruction.
Evan Chengf9f1da12009-06-18 02:04:01 +00001305 if (isLd) {
Evan Chengd780f352009-06-15 20:54:56 +00001306 BuildMI(*MBB, InsertPos, dl, TII->get(NewOpc))
Evan Cheng358dec52009-06-15 08:28:29 +00001307 .addReg(EvenReg, RegState::Define)
1308 .addReg(OddReg, RegState::Define)
1309 .addReg(BaseReg).addReg(0).addImm(Offset)
1310 .addImm(Pred).addReg(PredReg);
Evan Chengf9f1da12009-06-18 02:04:01 +00001311 ++NumLDRDFormed;
1312 } else {
Evan Chengd780f352009-06-15 20:54:56 +00001313 BuildMI(*MBB, InsertPos, dl, TII->get(NewOpc))
Evan Cheng358dec52009-06-15 08:28:29 +00001314 .addReg(EvenReg)
1315 .addReg(OddReg)
1316 .addReg(BaseReg).addReg(0).addImm(Offset)
1317 .addImm(Pred).addReg(PredReg);
Evan Chengf9f1da12009-06-18 02:04:01 +00001318 ++NumSTRDFormed;
1319 }
1320 MBB->erase(Op0);
1321 MBB->erase(Op1);
Evan Cheng358dec52009-06-15 08:28:29 +00001322
1323 // Add register allocation hints to form register pairs.
1324 MRI->setRegAllocationHint(EvenReg, ARMRI::RegPairEven, OddReg);
1325 MRI->setRegAllocationHint(OddReg, ARMRI::RegPairOdd, EvenReg);
Evan Chengd780f352009-06-15 20:54:56 +00001326 } else {
1327 for (unsigned i = 0; i != NumMove; ++i) {
1328 MachineInstr *Op = Ops.back();
1329 Ops.pop_back();
1330 MBB->splice(InsertPos, MBB, Op);
1331 }
Evan Chenge7d6df72009-06-13 09:12:55 +00001332 }
1333
1334 NumLdStMoved += NumMove;
1335 RetVal = true;
1336 }
1337 }
1338 }
1339
1340 return RetVal;
1341}
1342
1343bool
1344ARMPreAllocLoadStoreOpt::RescheduleLoadStoreInstrs(MachineBasicBlock *MBB) {
1345 bool RetVal = false;
1346
1347 DenseMap<MachineInstr*, unsigned> MI2LocMap;
1348 DenseMap<unsigned, SmallVector<MachineInstr*, 4> > Base2LdsMap;
1349 DenseMap<unsigned, SmallVector<MachineInstr*, 4> > Base2StsMap;
1350 SmallVector<unsigned, 4> LdBases;
1351 SmallVector<unsigned, 4> StBases;
1352
1353 unsigned Loc = 0;
1354 MachineBasicBlock::iterator MBBI = MBB->begin();
1355 MachineBasicBlock::iterator E = MBB->end();
1356 while (MBBI != E) {
1357 for (; MBBI != E; ++MBBI) {
1358 MachineInstr *MI = MBBI;
1359 const TargetInstrDesc &TID = MI->getDesc();
1360 if (TID.isCall() || TID.isTerminator()) {
1361 // Stop at barriers.
1362 ++MBBI;
1363 break;
1364 }
1365
1366 MI2LocMap[MI] = Loc++;
1367 if (!isMemoryOp(MI))
1368 continue;
1369 unsigned PredReg = 0;
Evan Cheng8fb90362009-08-08 03:20:32 +00001370 if (llvm::getInstrPredicate(MI, PredReg) != ARMCC::AL)
Evan Chenge7d6df72009-06-13 09:12:55 +00001371 continue;
1372
1373 int Opcode = MI->getOpcode();
1374 bool isLd = Opcode == ARM::LDR ||
1375 Opcode == ARM::FLDS || Opcode == ARM::FLDD;
1376 unsigned Base = MI->getOperand(1).getReg();
1377 int Offset = getMemoryOpOffset(MI);
1378
1379 bool StopHere = false;
1380 if (isLd) {
1381 DenseMap<unsigned, SmallVector<MachineInstr*, 4> >::iterator BI =
1382 Base2LdsMap.find(Base);
1383 if (BI != Base2LdsMap.end()) {
1384 for (unsigned i = 0, e = BI->second.size(); i != e; ++i) {
1385 if (Offset == getMemoryOpOffset(BI->second[i])) {
1386 StopHere = true;
1387 break;
1388 }
1389 }
1390 if (!StopHere)
1391 BI->second.push_back(MI);
1392 } else {
1393 SmallVector<MachineInstr*, 4> MIs;
1394 MIs.push_back(MI);
1395 Base2LdsMap[Base] = MIs;
1396 LdBases.push_back(Base);
1397 }
1398 } else {
1399 DenseMap<unsigned, SmallVector<MachineInstr*, 4> >::iterator BI =
1400 Base2StsMap.find(Base);
1401 if (BI != Base2StsMap.end()) {
1402 for (unsigned i = 0, e = BI->second.size(); i != e; ++i) {
1403 if (Offset == getMemoryOpOffset(BI->second[i])) {
1404 StopHere = true;
1405 break;
1406 }
1407 }
1408 if (!StopHere)
1409 BI->second.push_back(MI);
1410 } else {
1411 SmallVector<MachineInstr*, 4> MIs;
1412 MIs.push_back(MI);
1413 Base2StsMap[Base] = MIs;
1414 StBases.push_back(Base);
1415 }
1416 }
1417
1418 if (StopHere) {
Evan Chengae69a2a2009-06-19 23:17:27 +00001419 // Found a duplicate (a base+offset combination that's seen earlier).
1420 // Backtrack.
Evan Chenge7d6df72009-06-13 09:12:55 +00001421 --Loc;
1422 break;
1423 }
1424 }
1425
1426 // Re-schedule loads.
1427 for (unsigned i = 0, e = LdBases.size(); i != e; ++i) {
1428 unsigned Base = LdBases[i];
1429 SmallVector<MachineInstr*, 4> &Lds = Base2LdsMap[Base];
1430 if (Lds.size() > 1)
1431 RetVal |= RescheduleOps(MBB, Lds, Base, true, MI2LocMap);
1432 }
1433
1434 // Re-schedule stores.
1435 for (unsigned i = 0, e = StBases.size(); i != e; ++i) {
1436 unsigned Base = StBases[i];
1437 SmallVector<MachineInstr*, 4> &Sts = Base2StsMap[Base];
1438 if (Sts.size() > 1)
1439 RetVal |= RescheduleOps(MBB, Sts, Base, false, MI2LocMap);
1440 }
1441
1442 if (MBBI != E) {
1443 Base2LdsMap.clear();
1444 Base2StsMap.clear();
1445 LdBases.clear();
1446 StBases.clear();
1447 }
1448 }
1449
1450 return RetVal;
1451}
1452
1453
1454/// createARMLoadStoreOptimizationPass - returns an instance of the load / store
1455/// optimization pass.
1456FunctionPass *llvm::createARMLoadStoreOptimizationPass(bool PreAlloc) {
1457 if (PreAlloc)
1458 return new ARMPreAllocLoadStoreOpt();
1459 return new ARMLoadStoreOpt();
1460}