blob: 6f24bcca11f1e4e397e52a30884d701336184be2 [file] [log] [blame]
David Goodwinb50ea5c2009-07-02 22:18:33 +00001//===- Thumb2InstrInfo.cpp - Thumb-2 Instruction Information --------*- C++ -*-===//
Anton Korobeynikovd49ea772009-06-26 21:28:53 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
David Goodwinb50ea5c2009-07-02 22:18:33 +000010// This file contains the Thumb-2 implementation of the TargetInstrInfo class.
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000011//
12//===----------------------------------------------------------------------===//
13
Evan Chengb9803a82009-11-06 23:52:48 +000014#include "Thumb2InstrInfo.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000015#include "ARM.h"
Evan Chengb9803a82009-11-06 23:52:48 +000016#include "ARMConstantPoolValue.h"
Evan Cheng6495f632009-07-28 05:48:47 +000017#include "ARMAddressingModes.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000018#include "ARMGenInstrInfo.inc"
19#include "ARMMachineFunctionInfo.h"
Evan Chengbf992812009-11-07 19:40:04 +000020#include "llvm/Constants.h"
21#include "llvm/Function.h"
Evan Chengb9803a82009-11-06 23:52:48 +000022#include "llvm/GlobalValue.h"
23#include "llvm/CodeGen/MachineConstantPool.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000024#include "llvm/CodeGen/MachineFrameInfo.h"
25#include "llvm/CodeGen/MachineInstrBuilder.h"
Evan Chenge3ce8aa2009-11-01 22:04:35 +000026#include "llvm/CodeGen/MachineMemOperand.h"
27#include "llvm/CodeGen/PseudoSourceValue.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000028#include "llvm/ADT/SmallVector.h"
David Goodwinb50ea5c2009-07-02 22:18:33 +000029#include "Thumb2InstrInfo.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000030
31using namespace llvm;
32
Anton Korobeynikovf95215f2009-11-02 00:10:38 +000033Thumb2InstrInfo::Thumb2InstrInfo(const ARMSubtarget &STI)
34 : ARMBaseInstrInfo(STI), RI(*this, STI) {
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000035}
36
Evan Cheng446c4282009-07-11 06:43:01 +000037unsigned Thumb2InstrInfo::getUnindexedOpcode(unsigned Opc) const {
David Goodwin334c2642009-07-08 16:09:28 +000038 // FIXME
39 return 0;
40}
41
David Goodwin334c2642009-07-08 16:09:28 +000042bool
43Thumb2InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
44 if (MBB.empty()) return false;
45
David Goodwin334c2642009-07-08 16:09:28 +000046 switch (MBB.back().getOpcode()) {
David Goodwinb1beca62009-07-10 15:33:46 +000047 case ARM::t2LDM_RET:
David Goodwin334c2642009-07-08 16:09:28 +000048 case ARM::t2B: // Uncond branch.
Evan Cheng66ac5312009-07-25 00:33:29 +000049 case ARM::t2BR_JT: // Jumptable branch.
Evan Cheng5657c012009-07-29 02:18:14 +000050 case ARM::t2TBB: // Table branch byte.
51 case ARM::t2TBH: // Table branch halfword.
Evan Cheng23606e32009-07-24 18:20:16 +000052 case ARM::tBR_JTr: // Jumptable branch (16-bit version).
David Goodwin334c2642009-07-08 16:09:28 +000053 case ARM::tBX_RET:
54 case ARM::tBX_RET_vararg:
55 case ARM::tPOP_RET:
56 case ARM::tB:
Bob Wilson8d4de5a2009-10-28 18:26:41 +000057 case ARM::tBRIND:
David Goodwin334c2642009-07-08 16:09:28 +000058 return true;
59 default:
60 break;
61 }
62
63 return false;
64}
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000065
66bool
67Thumb2InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
68 MachineBasicBlock::iterator I,
69 unsigned DestReg, unsigned SrcReg,
70 const TargetRegisterClass *DestRC,
71 const TargetRegisterClass *SrcRC) const {
72 DebugLoc DL = DebugLoc::getUnknownLoc();
73 if (I != MBB.end()) DL = I->getDebugLoc();
74
Evan Cheng08b93c62009-07-27 00:33:08 +000075 if (DestRC == ARM::GPRRegisterClass &&
76 SrcRC == ARM::GPRRegisterClass) {
Evan Chenge118cb62009-08-07 19:34:35 +000077 BuildMI(MBB, I, DL, get(ARM::tMOVgpr2gpr), DestReg).addReg(SrcReg);
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000078 return true;
Evan Cheng08b93c62009-07-27 00:33:08 +000079 } else if (DestRC == ARM::GPRRegisterClass &&
Evan Cheng86198642009-08-07 00:34:42 +000080 SrcRC == ARM::tGPRRegisterClass) {
Evan Cheng08b93c62009-07-27 00:33:08 +000081 BuildMI(MBB, I, DL, get(ARM::tMOVtgpr2gpr), DestReg).addReg(SrcReg);
82 return true;
83 } else if (DestRC == ARM::tGPRRegisterClass &&
84 SrcRC == ARM::GPRRegisterClass) {
85 BuildMI(MBB, I, DL, get(ARM::tMOVgpr2tgpr), DestReg).addReg(SrcReg);
86 return true;
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000087 }
88
Evan Cheng08b93c62009-07-27 00:33:08 +000089 // Handle SPR, DPR, and QPR copies.
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000090 return ARMBaseInstrInfo::copyRegToReg(MBB, I, DestReg, SrcReg, DestRC, SrcRC);
91}
Evan Cheng5732ca02009-07-27 03:14:20 +000092
93void Thumb2InstrInfo::
94storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
95 unsigned SrcReg, bool isKill, int FI,
96 const TargetRegisterClass *RC) const {
97 DebugLoc DL = DebugLoc::getUnknownLoc();
98 if (I != MBB.end()) DL = I->getDebugLoc();
99
100 if (RC == ARM::GPRRegisterClass) {
Evan Chenge3ce8aa2009-11-01 22:04:35 +0000101 MachineFunction &MF = *MBB.getParent();
102 MachineFrameInfo &MFI = *MF.getFrameInfo();
103 MachineMemOperand *MMO =
104 MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FI),
105 MachineMemOperand::MOStore, 0,
106 MFI.getObjectSize(FI),
107 MFI.getObjectAlignment(FI));
Evan Cheng5732ca02009-07-27 03:14:20 +0000108 AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::t2STRi12))
109 .addReg(SrcReg, getKillRegState(isKill))
Evan Chenge3ce8aa2009-11-01 22:04:35 +0000110 .addFrameIndex(FI).addImm(0).addMemOperand(MMO));
Evan Cheng5732ca02009-07-27 03:14:20 +0000111 return;
112 }
113
114 ARMBaseInstrInfo::storeRegToStackSlot(MBB, I, SrcReg, isKill, FI, RC);
115}
116
117void Thumb2InstrInfo::
118loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
119 unsigned DestReg, int FI,
120 const TargetRegisterClass *RC) const {
121 DebugLoc DL = DebugLoc::getUnknownLoc();
122 if (I != MBB.end()) DL = I->getDebugLoc();
123
124 if (RC == ARM::GPRRegisterClass) {
Evan Chenge3ce8aa2009-11-01 22:04:35 +0000125 MachineFunction &MF = *MBB.getParent();
126 MachineFrameInfo &MFI = *MF.getFrameInfo();
127 MachineMemOperand *MMO =
128 MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FI),
129 MachineMemOperand::MOLoad, 0,
130 MFI.getObjectSize(FI),
131 MFI.getObjectAlignment(FI));
Evan Cheng5732ca02009-07-27 03:14:20 +0000132 AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::t2LDRi12), DestReg)
Evan Chenge3ce8aa2009-11-01 22:04:35 +0000133 .addFrameIndex(FI).addImm(0).addMemOperand(MMO));
Evan Cheng5732ca02009-07-27 03:14:20 +0000134 return;
135 }
136
137 ARMBaseInstrInfo::loadRegFromStackSlot(MBB, I, DestReg, FI, RC);
138}
Evan Cheng6495f632009-07-28 05:48:47 +0000139
Evan Chengb9803a82009-11-06 23:52:48 +0000140void Thumb2InstrInfo::reMaterialize(MachineBasicBlock &MBB,
141 MachineBasicBlock::iterator I,
142 unsigned DestReg, unsigned SubIdx,
143 const MachineInstr *Orig) const {
144 DebugLoc dl = Orig->getDebugLoc();
145 unsigned Opcode = Orig->getOpcode();
146 switch (Opcode) {
147 default: {
148 MachineInstr *MI = MBB.getParent()->CloneMachineInstr(Orig);
149 MI->getOperand(0).setReg(DestReg);
150 MBB.insert(I, MI);
151 break;
152 }
153 case ARM::t2LDRpci_pic: {
154 MachineFunction &MF = *MBB.getParent();
155 ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
156 MachineConstantPool *MCP = MF.getConstantPool();
157 unsigned CPI = Orig->getOperand(1).getIndex();
158 const MachineConstantPoolEntry &MCPE = MCP->getConstants()[CPI];
159 assert(MCPE.isMachineConstantPoolEntry() &&
160 "Expecting a machine constantpool entry!");
161 ARMConstantPoolValue *ACPV =
162 static_cast<ARMConstantPoolValue*>(MCPE.Val.MachineCPVal);
Evan Chengb9803a82009-11-06 23:52:48 +0000163 unsigned PCLabelId = AFI->createConstPoolEntryUId();
Evan Chengbf992812009-11-07 19:40:04 +0000164 ARMConstantPoolValue *NewCPV = 0;
165 if (ACPV->isGlobalValue())
166 NewCPV = new ARMConstantPoolValue(ACPV->getGV(), PCLabelId,
167 ARMCP::CPValue, 4);
168 else if (ACPV->isExtSymbol())
169 NewCPV = new ARMConstantPoolValue(MF.getFunction()->getContext(),
170 ACPV->getSymbol(), PCLabelId, 4);
171 else if (ACPV->isBlockAddress())
172 NewCPV = new ARMConstantPoolValue(ACPV->getBlockAddress(), PCLabelId,
173 ARMCP::CPBlockAddress, 4);
174 else
175 llvm_unreachable("Unexpected ARM constantpool value type!!");
Evan Chengb9803a82009-11-06 23:52:48 +0000176 CPI = MCP->getConstantPoolIndex(NewCPV, MCPE.getAlignment());
177 MachineInstrBuilder MIB = BuildMI(MBB, I, Orig->getDebugLoc(), get(Opcode),
178 DestReg)
179 .addConstantPoolIndex(CPI).addImm(PCLabelId);
180 (*MIB).setMemRefs(Orig->memoperands_begin(), Orig->memoperands_end());
181 break;
182 }
183 }
184
185 MachineInstr *NewMI = prior(I);
186 NewMI->getOperand(0).setSubReg(SubIdx);
187}
Evan Cheng6495f632009-07-28 05:48:47 +0000188
189void llvm::emitT2RegPlusImmediate(MachineBasicBlock &MBB,
190 MachineBasicBlock::iterator &MBBI, DebugLoc dl,
191 unsigned DestReg, unsigned BaseReg, int NumBytes,
192 ARMCC::CondCodes Pred, unsigned PredReg,
193 const ARMBaseInstrInfo &TII) {
194 bool isSub = NumBytes < 0;
195 if (isSub) NumBytes = -NumBytes;
196
197 // If profitable, use a movw or movt to materialize the offset.
198 // FIXME: Use the scavenger to grab a scratch register.
199 if (DestReg != ARM::SP && DestReg != BaseReg &&
200 NumBytes >= 4096 &&
201 ARM_AM::getT2SOImmVal(NumBytes) == -1) {
202 bool Fits = false;
203 if (NumBytes < 65536) {
204 // Use a movw to materialize the 16-bit constant.
205 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi16), DestReg)
206 .addImm(NumBytes)
207 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
208 Fits = true;
209 } else if ((NumBytes & 0xffff) == 0) {
210 // Use a movt to materialize the 32-bit constant.
211 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVTi16), DestReg)
212 .addReg(DestReg)
213 .addImm(NumBytes >> 16)
214 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
215 Fits = true;
216 }
217
218 if (Fits) {
219 if (isSub) {
220 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2SUBrr), DestReg)
221 .addReg(BaseReg, RegState::Kill)
222 .addReg(DestReg, RegState::Kill)
223 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
224 } else {
225 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2ADDrr), DestReg)
226 .addReg(DestReg, RegState::Kill)
227 .addReg(BaseReg, RegState::Kill)
228 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
229 }
230 return;
231 }
232 }
233
234 while (NumBytes) {
Evan Cheng6495f632009-07-28 05:48:47 +0000235 unsigned ThisVal = NumBytes;
Evan Cheng86198642009-08-07 00:34:42 +0000236 unsigned Opc = 0;
237 if (DestReg == ARM::SP && BaseReg != ARM::SP) {
238 // mov sp, rn. Note t2MOVr cannot be used.
239 BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),DestReg).addReg(BaseReg);
240 BaseReg = ARM::SP;
241 continue;
242 }
243
244 if (BaseReg == ARM::SP) {
245 // sub sp, sp, #imm7
246 if (DestReg == ARM::SP && (ThisVal < ((1 << 7)-1) * 4)) {
247 assert((ThisVal & 3) == 0 && "Stack update is not multiple of 4?");
248 Opc = isSub ? ARM::tSUBspi : ARM::tADDspi;
249 // FIXME: Fix Thumb1 immediate encoding.
250 BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
251 .addReg(BaseReg).addImm(ThisVal/4);
252 NumBytes = 0;
253 continue;
254 }
255
256 // sub rd, sp, so_imm
257 Opc = isSub ? ARM::t2SUBrSPi : ARM::t2ADDrSPi;
258 if (ARM_AM::getT2SOImmVal(NumBytes) != -1) {
259 NumBytes = 0;
260 } else {
261 // FIXME: Move this to ARMAddressingModes.h?
262 unsigned RotAmt = CountLeadingZeros_32(ThisVal);
263 ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
264 NumBytes &= ~ThisVal;
265 assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
266 "Bit extraction didn't work?");
267 }
Evan Cheng6495f632009-07-28 05:48:47 +0000268 } else {
Evan Cheng86198642009-08-07 00:34:42 +0000269 assert(DestReg != ARM::SP && BaseReg != ARM::SP);
270 Opc = isSub ? ARM::t2SUBri : ARM::t2ADDri;
271 if (ARM_AM::getT2SOImmVal(NumBytes) != -1) {
272 NumBytes = 0;
273 } else if (ThisVal < 4096) {
274 Opc = isSub ? ARM::t2SUBri12 : ARM::t2ADDri12;
275 NumBytes = 0;
276 } else {
277 // FIXME: Move this to ARMAddressingModes.h?
278 unsigned RotAmt = CountLeadingZeros_32(ThisVal);
279 ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
280 NumBytes &= ~ThisVal;
281 assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
282 "Bit extraction didn't work?");
283 }
Evan Cheng6495f632009-07-28 05:48:47 +0000284 }
285
286 // Build the new ADD / SUB.
Evan Cheng86198642009-08-07 00:34:42 +0000287 AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
288 .addReg(BaseReg, RegState::Kill)
289 .addImm(ThisVal)));
290
Evan Cheng6495f632009-07-28 05:48:47 +0000291 BaseReg = DestReg;
292 }
293}
294
295static unsigned
296negativeOffsetOpcode(unsigned opcode)
297{
298 switch (opcode) {
299 case ARM::t2LDRi12: return ARM::t2LDRi8;
300 case ARM::t2LDRHi12: return ARM::t2LDRHi8;
301 case ARM::t2LDRBi12: return ARM::t2LDRBi8;
302 case ARM::t2LDRSHi12: return ARM::t2LDRSHi8;
303 case ARM::t2LDRSBi12: return ARM::t2LDRSBi8;
304 case ARM::t2STRi12: return ARM::t2STRi8;
305 case ARM::t2STRBi12: return ARM::t2STRBi8;
306 case ARM::t2STRHi12: return ARM::t2STRHi8;
307
308 case ARM::t2LDRi8:
309 case ARM::t2LDRHi8:
310 case ARM::t2LDRBi8:
311 case ARM::t2LDRSHi8:
312 case ARM::t2LDRSBi8:
313 case ARM::t2STRi8:
314 case ARM::t2STRBi8:
315 case ARM::t2STRHi8:
316 return opcode;
317
318 default:
319 break;
320 }
321
322 return 0;
323}
324
325static unsigned
326positiveOffsetOpcode(unsigned opcode)
327{
328 switch (opcode) {
329 case ARM::t2LDRi8: return ARM::t2LDRi12;
330 case ARM::t2LDRHi8: return ARM::t2LDRHi12;
331 case ARM::t2LDRBi8: return ARM::t2LDRBi12;
332 case ARM::t2LDRSHi8: return ARM::t2LDRSHi12;
333 case ARM::t2LDRSBi8: return ARM::t2LDRSBi12;
334 case ARM::t2STRi8: return ARM::t2STRi12;
335 case ARM::t2STRBi8: return ARM::t2STRBi12;
336 case ARM::t2STRHi8: return ARM::t2STRHi12;
337
338 case ARM::t2LDRi12:
339 case ARM::t2LDRHi12:
340 case ARM::t2LDRBi12:
341 case ARM::t2LDRSHi12:
342 case ARM::t2LDRSBi12:
343 case ARM::t2STRi12:
344 case ARM::t2STRBi12:
345 case ARM::t2STRHi12:
346 return opcode;
347
348 default:
349 break;
350 }
351
352 return 0;
353}
354
355static unsigned
356immediateOffsetOpcode(unsigned opcode)
357{
358 switch (opcode) {
359 case ARM::t2LDRs: return ARM::t2LDRi12;
360 case ARM::t2LDRHs: return ARM::t2LDRHi12;
361 case ARM::t2LDRBs: return ARM::t2LDRBi12;
362 case ARM::t2LDRSHs: return ARM::t2LDRSHi12;
363 case ARM::t2LDRSBs: return ARM::t2LDRSBi12;
364 case ARM::t2STRs: return ARM::t2STRi12;
365 case ARM::t2STRBs: return ARM::t2STRBi12;
366 case ARM::t2STRHs: return ARM::t2STRHi12;
367
368 case ARM::t2LDRi12:
369 case ARM::t2LDRHi12:
370 case ARM::t2LDRBi12:
371 case ARM::t2LDRSHi12:
372 case ARM::t2LDRSBi12:
373 case ARM::t2STRi12:
374 case ARM::t2STRBi12:
375 case ARM::t2STRHi12:
376 case ARM::t2LDRi8:
377 case ARM::t2LDRHi8:
378 case ARM::t2LDRBi8:
379 case ARM::t2LDRSHi8:
380 case ARM::t2LDRSBi8:
381 case ARM::t2STRi8:
382 case ARM::t2STRBi8:
383 case ARM::t2STRHi8:
384 return opcode;
385
386 default:
387 break;
388 }
389
390 return 0;
391}
392
Evan Chengcdbb3f52009-08-27 01:23:50 +0000393bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
394 unsigned FrameReg, int &Offset,
395 const ARMBaseInstrInfo &TII) {
Evan Cheng6495f632009-07-28 05:48:47 +0000396 unsigned Opcode = MI.getOpcode();
Evan Cheng6495f632009-07-28 05:48:47 +0000397 const TargetInstrDesc &Desc = MI.getDesc();
398 unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
399 bool isSub = false;
400
401 // Memory operands in inline assembly always use AddrModeT2_i12.
402 if (Opcode == ARM::INLINEASM)
403 AddrMode = ARMII::AddrModeT2_i12; // FIXME. mode for thumb2?
Jim Grosbach764ab522009-08-11 15:33:49 +0000404
Evan Cheng6495f632009-07-28 05:48:47 +0000405 if (Opcode == ARM::t2ADDri || Opcode == ARM::t2ADDri12) {
406 Offset += MI.getOperand(FrameRegIdx+1).getImm();
Evan Cheng86198642009-08-07 00:34:42 +0000407
408 bool isSP = FrameReg == ARM::SP;
Evan Cheng6495f632009-07-28 05:48:47 +0000409 if (Offset == 0) {
410 // Turn it into a move.
Evan Cheng09d97352009-08-10 02:06:53 +0000411 MI.setDesc(TII.get(ARM::tMOVgpr2gpr));
Evan Cheng6495f632009-07-28 05:48:47 +0000412 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
413 MI.RemoveOperand(FrameRegIdx+1);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000414 Offset = 0;
415 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000416 }
417
418 if (Offset < 0) {
419 Offset = -Offset;
420 isSub = true;
Evan Cheng86198642009-08-07 00:34:42 +0000421 MI.setDesc(TII.get(isSP ? ARM::t2SUBrSPi : ARM::t2SUBri));
422 } else {
423 MI.setDesc(TII.get(isSP ? ARM::t2ADDrSPi : ARM::t2ADDri));
Evan Cheng6495f632009-07-28 05:48:47 +0000424 }
425
426 // Common case: small offset, fits into instruction.
427 if (ARM_AM::getT2SOImmVal(Offset) != -1) {
Evan Cheng6495f632009-07-28 05:48:47 +0000428 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
429 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000430 Offset = 0;
431 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000432 }
433 // Another common case: imm12.
434 if (Offset < 4096) {
Evan Cheng86198642009-08-07 00:34:42 +0000435 unsigned NewOpc = isSP
436 ? (isSub ? ARM::t2SUBrSPi12 : ARM::t2ADDrSPi12)
437 : (isSub ? ARM::t2SUBri12 : ARM::t2ADDri12);
438 MI.setDesc(TII.get(NewOpc));
Evan Cheng6495f632009-07-28 05:48:47 +0000439 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
440 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000441 Offset = 0;
442 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000443 }
444
445 // Otherwise, extract 8 adjacent bits from the immediate into this
446 // t2ADDri/t2SUBri.
447 unsigned RotAmt = CountLeadingZeros_32(Offset);
448 unsigned ThisImmVal = Offset & ARM_AM::rotr32(0xff000000U, RotAmt);
449
450 // We will handle these bits from offset, clear them.
451 Offset &= ~ThisImmVal;
452
453 assert(ARM_AM::getT2SOImmVal(ThisImmVal) != -1 &&
454 "Bit extraction didn't work?");
455 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(ThisImmVal);
456 } else {
Bob Wilsone4863f42009-09-15 17:56:18 +0000457
458 // AddrMode4 cannot handle any offset.
459 if (AddrMode == ARMII::AddrMode4)
460 return false;
461
Evan Cheng6495f632009-07-28 05:48:47 +0000462 // AddrModeT2_so cannot handle any offset. If there is no offset
463 // register then we change to an immediate version.
Evan Cheng86198642009-08-07 00:34:42 +0000464 unsigned NewOpc = Opcode;
Evan Cheng6495f632009-07-28 05:48:47 +0000465 if (AddrMode == ARMII::AddrModeT2_so) {
466 unsigned OffsetReg = MI.getOperand(FrameRegIdx+1).getReg();
467 if (OffsetReg != 0) {
468 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000469 return Offset == 0;
Evan Cheng6495f632009-07-28 05:48:47 +0000470 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000471
Evan Cheng6495f632009-07-28 05:48:47 +0000472 MI.RemoveOperand(FrameRegIdx+1);
473 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(0);
474 NewOpc = immediateOffsetOpcode(Opcode);
475 AddrMode = ARMII::AddrModeT2_i12;
476 }
477
478 unsigned NumBits = 0;
479 unsigned Scale = 1;
480 if (AddrMode == ARMII::AddrModeT2_i8 || AddrMode == ARMII::AddrModeT2_i12) {
481 // i8 supports only negative, and i12 supports only positive, so
482 // based on Offset sign convert Opcode to the appropriate
483 // instruction
484 Offset += MI.getOperand(FrameRegIdx+1).getImm();
485 if (Offset < 0) {
486 NewOpc = negativeOffsetOpcode(Opcode);
487 NumBits = 8;
488 isSub = true;
489 Offset = -Offset;
490 } else {
491 NewOpc = positiveOffsetOpcode(Opcode);
492 NumBits = 12;
493 }
494 } else {
Evan Chengcdbb3f52009-08-27 01:23:50 +0000495 // VFP and NEON address modes.
496 int InstrOffs = 0;
497 if (AddrMode == ARMII::AddrMode5) {
498 const MachineOperand &OffOp = MI.getOperand(FrameRegIdx+1);
499 InstrOffs = ARM_AM::getAM5Offset(OffOp.getImm());
500 if (ARM_AM::getAM5Op(OffOp.getImm()) == ARM_AM::sub)
501 InstrOffs *= -1;
502 }
Evan Cheng6495f632009-07-28 05:48:47 +0000503 NumBits = 8;
504 Scale = 4;
505 Offset += InstrOffs * 4;
506 assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
507 if (Offset < 0) {
508 Offset = -Offset;
509 isSub = true;
510 }
511 }
512
513 if (NewOpc != Opcode)
514 MI.setDesc(TII.get(NewOpc));
515
516 MachineOperand &ImmOp = MI.getOperand(FrameRegIdx+1);
517
518 // Attempt to fold address computation
519 // Common case: small offset, fits into instruction.
520 int ImmedOffset = Offset / Scale;
521 unsigned Mask = (1 << NumBits) - 1;
522 if ((unsigned)Offset <= Mask * Scale) {
523 // Replace the FrameIndex with fp/sp
524 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
525 if (isSub) {
526 if (AddrMode == ARMII::AddrMode5)
527 // FIXME: Not consistent.
528 ImmedOffset |= 1 << NumBits;
Jim Grosbach764ab522009-08-11 15:33:49 +0000529 else
Evan Cheng6495f632009-07-28 05:48:47 +0000530 ImmedOffset = -ImmedOffset;
531 }
532 ImmOp.ChangeToImmediate(ImmedOffset);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000533 Offset = 0;
534 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000535 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000536
Evan Cheng6495f632009-07-28 05:48:47 +0000537 // Otherwise, offset doesn't fit. Pull in what we can to simplify
David Goodwind9453782009-07-28 23:52:33 +0000538 ImmedOffset = ImmedOffset & Mask;
Evan Cheng6495f632009-07-28 05:48:47 +0000539 if (isSub) {
540 if (AddrMode == ARMII::AddrMode5)
541 // FIXME: Not consistent.
542 ImmedOffset |= 1 << NumBits;
Evan Chenga8e89842009-08-03 02:38:06 +0000543 else {
Evan Cheng6495f632009-07-28 05:48:47 +0000544 ImmedOffset = -ImmedOffset;
Evan Chenga8e89842009-08-03 02:38:06 +0000545 if (ImmedOffset == 0)
546 // Change the opcode back if the encoded offset is zero.
547 MI.setDesc(TII.get(positiveOffsetOpcode(NewOpc)));
548 }
Evan Cheng6495f632009-07-28 05:48:47 +0000549 }
550 ImmOp.ChangeToImmediate(ImmedOffset);
551 Offset &= ~(Mask*Scale);
552 }
553
Evan Chengcdbb3f52009-08-27 01:23:50 +0000554 Offset = (isSub) ? -Offset : Offset;
555 return Offset == 0;
Evan Cheng6495f632009-07-28 05:48:47 +0000556}