blob: 3ec147f26624991dca0a04e393834519fae40813 [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
14#include "ARMInstrInfo.h"
15#include "ARM.h"
Evan Cheng6495f632009-07-28 05:48:47 +000016#include "ARMAddressingModes.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000017#include "ARMGenInstrInfo.inc"
18#include "ARMMachineFunctionInfo.h"
19#include "llvm/CodeGen/MachineFrameInfo.h"
20#include "llvm/CodeGen/MachineInstrBuilder.h"
Evan Chenge3ce8aa2009-11-01 22:04:35 +000021#include "llvm/CodeGen/MachineMemOperand.h"
22#include "llvm/CodeGen/PseudoSourceValue.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000023#include "llvm/ADT/SmallVector.h"
David Goodwinb50ea5c2009-07-02 22:18:33 +000024#include "Thumb2InstrInfo.h"
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000025
26using namespace llvm;
27
Chris Lattnerd90183d2009-08-02 05:20:37 +000028Thumb2InstrInfo::Thumb2InstrInfo(const ARMSubtarget &STI) : RI(*this, STI) {
Anton Korobeynikovd49ea772009-06-26 21:28:53 +000029}
30
Evan Cheng446c4282009-07-11 06:43:01 +000031unsigned Thumb2InstrInfo::getUnindexedOpcode(unsigned Opc) const {
David Goodwin334c2642009-07-08 16:09:28 +000032 // FIXME
33 return 0;
34}
35
David Goodwin334c2642009-07-08 16:09:28 +000036bool
37Thumb2InstrInfo::BlockHasNoFallThrough(const MachineBasicBlock &MBB) const {
38 if (MBB.empty()) return false;
39
David Goodwin334c2642009-07-08 16:09:28 +000040 switch (MBB.back().getOpcode()) {
David Goodwinb1beca62009-07-10 15:33:46 +000041 case ARM::t2LDM_RET:
David Goodwin334c2642009-07-08 16:09:28 +000042 case ARM::t2B: // Uncond branch.
Evan Cheng66ac5312009-07-25 00:33:29 +000043 case ARM::t2BR_JT: // Jumptable branch.
Evan Cheng5657c012009-07-29 02:18:14 +000044 case ARM::t2TBB: // Table branch byte.
45 case ARM::t2TBH: // Table branch halfword.
Evan Cheng23606e32009-07-24 18:20:16 +000046 case ARM::tBR_JTr: // Jumptable branch (16-bit version).
David Goodwin334c2642009-07-08 16:09:28 +000047 case ARM::tBX_RET:
48 case ARM::tBX_RET_vararg:
49 case ARM::tPOP_RET:
50 case ARM::tB:
Bob Wilson8d4de5a2009-10-28 18:26:41 +000051 case ARM::tBRIND:
David Goodwin334c2642009-07-08 16:09:28 +000052 return true;
53 default:
54 break;
55 }
56
57 return false;
58}
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000059
60bool
61Thumb2InstrInfo::copyRegToReg(MachineBasicBlock &MBB,
62 MachineBasicBlock::iterator I,
63 unsigned DestReg, unsigned SrcReg,
64 const TargetRegisterClass *DestRC,
65 const TargetRegisterClass *SrcRC) const {
66 DebugLoc DL = DebugLoc::getUnknownLoc();
67 if (I != MBB.end()) DL = I->getDebugLoc();
68
Evan Cheng08b93c62009-07-27 00:33:08 +000069 if (DestRC == ARM::GPRRegisterClass &&
70 SrcRC == ARM::GPRRegisterClass) {
Evan Chenge118cb62009-08-07 19:34:35 +000071 BuildMI(MBB, I, DL, get(ARM::tMOVgpr2gpr), DestReg).addReg(SrcReg);
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000072 return true;
Evan Cheng08b93c62009-07-27 00:33:08 +000073 } else if (DestRC == ARM::GPRRegisterClass &&
Evan Cheng86198642009-08-07 00:34:42 +000074 SrcRC == ARM::tGPRRegisterClass) {
Evan Cheng08b93c62009-07-27 00:33:08 +000075 BuildMI(MBB, I, DL, get(ARM::tMOVtgpr2gpr), DestReg).addReg(SrcReg);
76 return true;
77 } else if (DestRC == ARM::tGPRRegisterClass &&
78 SrcRC == ARM::GPRRegisterClass) {
79 BuildMI(MBB, I, DL, get(ARM::tMOVgpr2tgpr), DestReg).addReg(SrcReg);
80 return true;
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000081 }
82
Evan Cheng08b93c62009-07-27 00:33:08 +000083 // Handle SPR, DPR, and QPR copies.
Anton Korobeynikovb8e9ac82009-07-16 23:26:06 +000084 return ARMBaseInstrInfo::copyRegToReg(MBB, I, DestReg, SrcReg, DestRC, SrcRC);
85}
Evan Cheng5732ca02009-07-27 03:14:20 +000086
87void Thumb2InstrInfo::
88storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
89 unsigned SrcReg, bool isKill, int FI,
90 const TargetRegisterClass *RC) const {
91 DebugLoc DL = DebugLoc::getUnknownLoc();
92 if (I != MBB.end()) DL = I->getDebugLoc();
93
94 if (RC == ARM::GPRRegisterClass) {
Evan Chenge3ce8aa2009-11-01 22:04:35 +000095 MachineFunction &MF = *MBB.getParent();
96 MachineFrameInfo &MFI = *MF.getFrameInfo();
97 MachineMemOperand *MMO =
98 MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FI),
99 MachineMemOperand::MOStore, 0,
100 MFI.getObjectSize(FI),
101 MFI.getObjectAlignment(FI));
Evan Cheng5732ca02009-07-27 03:14:20 +0000102 AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::t2STRi12))
103 .addReg(SrcReg, getKillRegState(isKill))
Evan Chenge3ce8aa2009-11-01 22:04:35 +0000104 .addFrameIndex(FI).addImm(0).addMemOperand(MMO));
Evan Cheng5732ca02009-07-27 03:14:20 +0000105 return;
106 }
107
108 ARMBaseInstrInfo::storeRegToStackSlot(MBB, I, SrcReg, isKill, FI, RC);
109}
110
111void Thumb2InstrInfo::
112loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
113 unsigned DestReg, int FI,
114 const TargetRegisterClass *RC) const {
115 DebugLoc DL = DebugLoc::getUnknownLoc();
116 if (I != MBB.end()) DL = I->getDebugLoc();
117
118 if (RC == ARM::GPRRegisterClass) {
Evan Chenge3ce8aa2009-11-01 22:04:35 +0000119 MachineFunction &MF = *MBB.getParent();
120 MachineFrameInfo &MFI = *MF.getFrameInfo();
121 MachineMemOperand *MMO =
122 MF.getMachineMemOperand(PseudoSourceValue::getFixedStack(FI),
123 MachineMemOperand::MOLoad, 0,
124 MFI.getObjectSize(FI),
125 MFI.getObjectAlignment(FI));
Evan Cheng5732ca02009-07-27 03:14:20 +0000126 AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::t2LDRi12), DestReg)
Evan Chenge3ce8aa2009-11-01 22:04:35 +0000127 .addFrameIndex(FI).addImm(0).addMemOperand(MMO));
Evan Cheng5732ca02009-07-27 03:14:20 +0000128 return;
129 }
130
131 ARMBaseInstrInfo::loadRegFromStackSlot(MBB, I, DestReg, FI, RC);
132}
Evan Cheng6495f632009-07-28 05:48:47 +0000133
134
135void llvm::emitT2RegPlusImmediate(MachineBasicBlock &MBB,
136 MachineBasicBlock::iterator &MBBI, DebugLoc dl,
137 unsigned DestReg, unsigned BaseReg, int NumBytes,
138 ARMCC::CondCodes Pred, unsigned PredReg,
139 const ARMBaseInstrInfo &TII) {
140 bool isSub = NumBytes < 0;
141 if (isSub) NumBytes = -NumBytes;
142
143 // If profitable, use a movw or movt to materialize the offset.
144 // FIXME: Use the scavenger to grab a scratch register.
145 if (DestReg != ARM::SP && DestReg != BaseReg &&
146 NumBytes >= 4096 &&
147 ARM_AM::getT2SOImmVal(NumBytes) == -1) {
148 bool Fits = false;
149 if (NumBytes < 65536) {
150 // Use a movw to materialize the 16-bit constant.
151 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVi16), DestReg)
152 .addImm(NumBytes)
153 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
154 Fits = true;
155 } else if ((NumBytes & 0xffff) == 0) {
156 // Use a movt to materialize the 32-bit constant.
157 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2MOVTi16), DestReg)
158 .addReg(DestReg)
159 .addImm(NumBytes >> 16)
160 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
161 Fits = true;
162 }
163
164 if (Fits) {
165 if (isSub) {
166 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2SUBrr), DestReg)
167 .addReg(BaseReg, RegState::Kill)
168 .addReg(DestReg, RegState::Kill)
169 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
170 } else {
171 BuildMI(MBB, MBBI, dl, TII.get(ARM::t2ADDrr), DestReg)
172 .addReg(DestReg, RegState::Kill)
173 .addReg(BaseReg, RegState::Kill)
174 .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
175 }
176 return;
177 }
178 }
179
180 while (NumBytes) {
Evan Cheng6495f632009-07-28 05:48:47 +0000181 unsigned ThisVal = NumBytes;
Evan Cheng86198642009-08-07 00:34:42 +0000182 unsigned Opc = 0;
183 if (DestReg == ARM::SP && BaseReg != ARM::SP) {
184 // mov sp, rn. Note t2MOVr cannot be used.
185 BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),DestReg).addReg(BaseReg);
186 BaseReg = ARM::SP;
187 continue;
188 }
189
190 if (BaseReg == ARM::SP) {
191 // sub sp, sp, #imm7
192 if (DestReg == ARM::SP && (ThisVal < ((1 << 7)-1) * 4)) {
193 assert((ThisVal & 3) == 0 && "Stack update is not multiple of 4?");
194 Opc = isSub ? ARM::tSUBspi : ARM::tADDspi;
195 // FIXME: Fix Thumb1 immediate encoding.
196 BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
197 .addReg(BaseReg).addImm(ThisVal/4);
198 NumBytes = 0;
199 continue;
200 }
201
202 // sub rd, sp, so_imm
203 Opc = isSub ? ARM::t2SUBrSPi : ARM::t2ADDrSPi;
204 if (ARM_AM::getT2SOImmVal(NumBytes) != -1) {
205 NumBytes = 0;
206 } else {
207 // FIXME: Move this to ARMAddressingModes.h?
208 unsigned RotAmt = CountLeadingZeros_32(ThisVal);
209 ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
210 NumBytes &= ~ThisVal;
211 assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
212 "Bit extraction didn't work?");
213 }
Evan Cheng6495f632009-07-28 05:48:47 +0000214 } else {
Evan Cheng86198642009-08-07 00:34:42 +0000215 assert(DestReg != ARM::SP && BaseReg != ARM::SP);
216 Opc = isSub ? ARM::t2SUBri : ARM::t2ADDri;
217 if (ARM_AM::getT2SOImmVal(NumBytes) != -1) {
218 NumBytes = 0;
219 } else if (ThisVal < 4096) {
220 Opc = isSub ? ARM::t2SUBri12 : ARM::t2ADDri12;
221 NumBytes = 0;
222 } else {
223 // FIXME: Move this to ARMAddressingModes.h?
224 unsigned RotAmt = CountLeadingZeros_32(ThisVal);
225 ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
226 NumBytes &= ~ThisVal;
227 assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
228 "Bit extraction didn't work?");
229 }
Evan Cheng6495f632009-07-28 05:48:47 +0000230 }
231
232 // Build the new ADD / SUB.
Evan Cheng86198642009-08-07 00:34:42 +0000233 AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
234 .addReg(BaseReg, RegState::Kill)
235 .addImm(ThisVal)));
236
Evan Cheng6495f632009-07-28 05:48:47 +0000237 BaseReg = DestReg;
238 }
239}
240
241static unsigned
242negativeOffsetOpcode(unsigned opcode)
243{
244 switch (opcode) {
245 case ARM::t2LDRi12: return ARM::t2LDRi8;
246 case ARM::t2LDRHi12: return ARM::t2LDRHi8;
247 case ARM::t2LDRBi12: return ARM::t2LDRBi8;
248 case ARM::t2LDRSHi12: return ARM::t2LDRSHi8;
249 case ARM::t2LDRSBi12: return ARM::t2LDRSBi8;
250 case ARM::t2STRi12: return ARM::t2STRi8;
251 case ARM::t2STRBi12: return ARM::t2STRBi8;
252 case ARM::t2STRHi12: return ARM::t2STRHi8;
253
254 case ARM::t2LDRi8:
255 case ARM::t2LDRHi8:
256 case ARM::t2LDRBi8:
257 case ARM::t2LDRSHi8:
258 case ARM::t2LDRSBi8:
259 case ARM::t2STRi8:
260 case ARM::t2STRBi8:
261 case ARM::t2STRHi8:
262 return opcode;
263
264 default:
265 break;
266 }
267
268 return 0;
269}
270
271static unsigned
272positiveOffsetOpcode(unsigned opcode)
273{
274 switch (opcode) {
275 case ARM::t2LDRi8: return ARM::t2LDRi12;
276 case ARM::t2LDRHi8: return ARM::t2LDRHi12;
277 case ARM::t2LDRBi8: return ARM::t2LDRBi12;
278 case ARM::t2LDRSHi8: return ARM::t2LDRSHi12;
279 case ARM::t2LDRSBi8: return ARM::t2LDRSBi12;
280 case ARM::t2STRi8: return ARM::t2STRi12;
281 case ARM::t2STRBi8: return ARM::t2STRBi12;
282 case ARM::t2STRHi8: return ARM::t2STRHi12;
283
284 case ARM::t2LDRi12:
285 case ARM::t2LDRHi12:
286 case ARM::t2LDRBi12:
287 case ARM::t2LDRSHi12:
288 case ARM::t2LDRSBi12:
289 case ARM::t2STRi12:
290 case ARM::t2STRBi12:
291 case ARM::t2STRHi12:
292 return opcode;
293
294 default:
295 break;
296 }
297
298 return 0;
299}
300
301static unsigned
302immediateOffsetOpcode(unsigned opcode)
303{
304 switch (opcode) {
305 case ARM::t2LDRs: return ARM::t2LDRi12;
306 case ARM::t2LDRHs: return ARM::t2LDRHi12;
307 case ARM::t2LDRBs: return ARM::t2LDRBi12;
308 case ARM::t2LDRSHs: return ARM::t2LDRSHi12;
309 case ARM::t2LDRSBs: return ARM::t2LDRSBi12;
310 case ARM::t2STRs: return ARM::t2STRi12;
311 case ARM::t2STRBs: return ARM::t2STRBi12;
312 case ARM::t2STRHs: return ARM::t2STRHi12;
313
314 case ARM::t2LDRi12:
315 case ARM::t2LDRHi12:
316 case ARM::t2LDRBi12:
317 case ARM::t2LDRSHi12:
318 case ARM::t2LDRSBi12:
319 case ARM::t2STRi12:
320 case ARM::t2STRBi12:
321 case ARM::t2STRHi12:
322 case ARM::t2LDRi8:
323 case ARM::t2LDRHi8:
324 case ARM::t2LDRBi8:
325 case ARM::t2LDRSHi8:
326 case ARM::t2LDRSBi8:
327 case ARM::t2STRi8:
328 case ARM::t2STRBi8:
329 case ARM::t2STRHi8:
330 return opcode;
331
332 default:
333 break;
334 }
335
336 return 0;
337}
338
Evan Chengcdbb3f52009-08-27 01:23:50 +0000339bool llvm::rewriteT2FrameIndex(MachineInstr &MI, unsigned FrameRegIdx,
340 unsigned FrameReg, int &Offset,
341 const ARMBaseInstrInfo &TII) {
Evan Cheng6495f632009-07-28 05:48:47 +0000342 unsigned Opcode = MI.getOpcode();
Evan Cheng6495f632009-07-28 05:48:47 +0000343 const TargetInstrDesc &Desc = MI.getDesc();
344 unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
345 bool isSub = false;
346
347 // Memory operands in inline assembly always use AddrModeT2_i12.
348 if (Opcode == ARM::INLINEASM)
349 AddrMode = ARMII::AddrModeT2_i12; // FIXME. mode for thumb2?
Jim Grosbach764ab522009-08-11 15:33:49 +0000350
Evan Cheng6495f632009-07-28 05:48:47 +0000351 if (Opcode == ARM::t2ADDri || Opcode == ARM::t2ADDri12) {
352 Offset += MI.getOperand(FrameRegIdx+1).getImm();
Evan Cheng86198642009-08-07 00:34:42 +0000353
354 bool isSP = FrameReg == ARM::SP;
Evan Cheng6495f632009-07-28 05:48:47 +0000355 if (Offset == 0) {
356 // Turn it into a move.
Evan Cheng09d97352009-08-10 02:06:53 +0000357 MI.setDesc(TII.get(ARM::tMOVgpr2gpr));
Evan Cheng6495f632009-07-28 05:48:47 +0000358 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
359 MI.RemoveOperand(FrameRegIdx+1);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000360 Offset = 0;
361 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000362 }
363
364 if (Offset < 0) {
365 Offset = -Offset;
366 isSub = true;
Evan Cheng86198642009-08-07 00:34:42 +0000367 MI.setDesc(TII.get(isSP ? ARM::t2SUBrSPi : ARM::t2SUBri));
368 } else {
369 MI.setDesc(TII.get(isSP ? ARM::t2ADDrSPi : ARM::t2ADDri));
Evan Cheng6495f632009-07-28 05:48:47 +0000370 }
371
372 // Common case: small offset, fits into instruction.
373 if (ARM_AM::getT2SOImmVal(Offset) != -1) {
Evan Cheng6495f632009-07-28 05:48:47 +0000374 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
375 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000376 Offset = 0;
377 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000378 }
379 // Another common case: imm12.
380 if (Offset < 4096) {
Evan Cheng86198642009-08-07 00:34:42 +0000381 unsigned NewOpc = isSP
382 ? (isSub ? ARM::t2SUBrSPi12 : ARM::t2ADDrSPi12)
383 : (isSub ? ARM::t2SUBri12 : ARM::t2ADDri12);
384 MI.setDesc(TII.get(NewOpc));
Evan Cheng6495f632009-07-28 05:48:47 +0000385 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
386 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000387 Offset = 0;
388 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000389 }
390
391 // Otherwise, extract 8 adjacent bits from the immediate into this
392 // t2ADDri/t2SUBri.
393 unsigned RotAmt = CountLeadingZeros_32(Offset);
394 unsigned ThisImmVal = Offset & ARM_AM::rotr32(0xff000000U, RotAmt);
395
396 // We will handle these bits from offset, clear them.
397 Offset &= ~ThisImmVal;
398
399 assert(ARM_AM::getT2SOImmVal(ThisImmVal) != -1 &&
400 "Bit extraction didn't work?");
401 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(ThisImmVal);
402 } else {
Bob Wilsone4863f42009-09-15 17:56:18 +0000403
404 // AddrMode4 cannot handle any offset.
405 if (AddrMode == ARMII::AddrMode4)
406 return false;
407
Evan Cheng6495f632009-07-28 05:48:47 +0000408 // AddrModeT2_so cannot handle any offset. If there is no offset
409 // register then we change to an immediate version.
Evan Cheng86198642009-08-07 00:34:42 +0000410 unsigned NewOpc = Opcode;
Evan Cheng6495f632009-07-28 05:48:47 +0000411 if (AddrMode == ARMII::AddrModeT2_so) {
412 unsigned OffsetReg = MI.getOperand(FrameRegIdx+1).getReg();
413 if (OffsetReg != 0) {
414 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000415 return Offset == 0;
Evan Cheng6495f632009-07-28 05:48:47 +0000416 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000417
Evan Cheng6495f632009-07-28 05:48:47 +0000418 MI.RemoveOperand(FrameRegIdx+1);
419 MI.getOperand(FrameRegIdx+1).ChangeToImmediate(0);
420 NewOpc = immediateOffsetOpcode(Opcode);
421 AddrMode = ARMII::AddrModeT2_i12;
422 }
423
424 unsigned NumBits = 0;
425 unsigned Scale = 1;
426 if (AddrMode == ARMII::AddrModeT2_i8 || AddrMode == ARMII::AddrModeT2_i12) {
427 // i8 supports only negative, and i12 supports only positive, so
428 // based on Offset sign convert Opcode to the appropriate
429 // instruction
430 Offset += MI.getOperand(FrameRegIdx+1).getImm();
431 if (Offset < 0) {
432 NewOpc = negativeOffsetOpcode(Opcode);
433 NumBits = 8;
434 isSub = true;
435 Offset = -Offset;
436 } else {
437 NewOpc = positiveOffsetOpcode(Opcode);
438 NumBits = 12;
439 }
440 } else {
Evan Chengcdbb3f52009-08-27 01:23:50 +0000441 // VFP and NEON address modes.
442 int InstrOffs = 0;
443 if (AddrMode == ARMII::AddrMode5) {
444 const MachineOperand &OffOp = MI.getOperand(FrameRegIdx+1);
445 InstrOffs = ARM_AM::getAM5Offset(OffOp.getImm());
446 if (ARM_AM::getAM5Op(OffOp.getImm()) == ARM_AM::sub)
447 InstrOffs *= -1;
448 }
Evan Cheng6495f632009-07-28 05:48:47 +0000449 NumBits = 8;
450 Scale = 4;
451 Offset += InstrOffs * 4;
452 assert((Offset & (Scale-1)) == 0 && "Can't encode this offset!");
453 if (Offset < 0) {
454 Offset = -Offset;
455 isSub = true;
456 }
457 }
458
459 if (NewOpc != Opcode)
460 MI.setDesc(TII.get(NewOpc));
461
462 MachineOperand &ImmOp = MI.getOperand(FrameRegIdx+1);
463
464 // Attempt to fold address computation
465 // Common case: small offset, fits into instruction.
466 int ImmedOffset = Offset / Scale;
467 unsigned Mask = (1 << NumBits) - 1;
468 if ((unsigned)Offset <= Mask * Scale) {
469 // Replace the FrameIndex with fp/sp
470 MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
471 if (isSub) {
472 if (AddrMode == ARMII::AddrMode5)
473 // FIXME: Not consistent.
474 ImmedOffset |= 1 << NumBits;
Jim Grosbach764ab522009-08-11 15:33:49 +0000475 else
Evan Cheng6495f632009-07-28 05:48:47 +0000476 ImmedOffset = -ImmedOffset;
477 }
478 ImmOp.ChangeToImmediate(ImmedOffset);
Evan Chengcdbb3f52009-08-27 01:23:50 +0000479 Offset = 0;
480 return true;
Evan Cheng6495f632009-07-28 05:48:47 +0000481 }
Jim Grosbach764ab522009-08-11 15:33:49 +0000482
Evan Cheng6495f632009-07-28 05:48:47 +0000483 // Otherwise, offset doesn't fit. Pull in what we can to simplify
David Goodwind9453782009-07-28 23:52:33 +0000484 ImmedOffset = ImmedOffset & Mask;
Evan Cheng6495f632009-07-28 05:48:47 +0000485 if (isSub) {
486 if (AddrMode == ARMII::AddrMode5)
487 // FIXME: Not consistent.
488 ImmedOffset |= 1 << NumBits;
Evan Chenga8e89842009-08-03 02:38:06 +0000489 else {
Evan Cheng6495f632009-07-28 05:48:47 +0000490 ImmedOffset = -ImmedOffset;
Evan Chenga8e89842009-08-03 02:38:06 +0000491 if (ImmedOffset == 0)
492 // Change the opcode back if the encoded offset is zero.
493 MI.setDesc(TII.get(positiveOffsetOpcode(NewOpc)));
494 }
Evan Cheng6495f632009-07-28 05:48:47 +0000495 }
496 ImmOp.ChangeToImmediate(ImmedOffset);
497 Offset &= ~(Mask*Scale);
498 }
499
Evan Chengcdbb3f52009-08-27 01:23:50 +0000500 Offset = (isSub) ? -Offset : Offset;
501 return Offset == 0;
Evan Cheng6495f632009-07-28 05:48:47 +0000502}