blob: bfb05d5c335362227b9fbcddaf03b435eba92e63 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
buzbee1bc37c62012-11-20 13:35:41 -080017#include "arm_lir.h"
18#include "../codegen_util.h"
19#include "../ralloc_util.h"
20
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080021namespace art {
22
buzbeeb046e162012-10-30 15:48:42 -070023/* This file contains codegen for the Thumb ISA. */
buzbee67bf8852011-08-17 17:51:35 -070024
buzbeeaad94382012-11-21 07:40:50 -080025static int EncodeImmSingle(int value)
buzbee67bf8852011-08-17 17:51:35 -070026{
Bill Buzbeea114add2012-05-03 15:00:40 -070027 int res;
28 int bitA = (value & 0x80000000) >> 31;
29 int notBitB = (value & 0x40000000) >> 30;
30 int bitB = (value & 0x20000000) >> 29;
31 int bSmear = (value & 0x3e000000) >> 25;
32 int slice = (value & 0x01f80000) >> 19;
33 int zeroes = (value & 0x0007ffff);
34 if (zeroes != 0)
35 return -1;
36 if (bitB) {
37 if ((notBitB != 0) || (bSmear != 0x1f))
38 return -1;
39 } else {
40 if ((notBitB != 1) || (bSmear != 0x0))
41 return -1;
42 }
43 res = (bitA << 7) | (bitB << 6) | slice;
44 return res;
buzbee67bf8852011-08-17 17:51:35 -070045}
46
buzbeeaad94382012-11-21 07:40:50 -080047static LIR* LoadFPConstantValue(CompilationUnit* cUnit, int rDest, int value)
buzbee67bf8852011-08-17 17:51:35 -070048{
buzbee52a77fc2012-11-20 19:50:46 -080049 int encodedImm = EncodeImmSingle(value);
buzbeef0504cd2012-11-13 16:31:10 -080050 DCHECK(ARM_SINGLEREG(rDest));
Bill Buzbeea114add2012-05-03 15:00:40 -070051 if (encodedImm >= 0) {
buzbee52a77fc2012-11-20 19:50:46 -080052 return NewLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
Bill Buzbeea114add2012-05-03 15:00:40 -070053 }
buzbee52a77fc2012-11-20 19:50:46 -080054 LIR* dataTarget = ScanLiteralPool(cUnit->literalList, value, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -070055 if (dataTarget == NULL) {
buzbee52a77fc2012-11-20 19:50:46 -080056 dataTarget = AddWordData(cUnit, &cUnit->literalList, value);
Bill Buzbeea114add2012-05-03 15:00:40 -070057 }
buzbee52a77fc2012-11-20 19:50:46 -080058 LIR* loadPcRel = RawLIR(cUnit, cUnit->currentDalvikOffset, kThumb2Vldrs,
Bill Buzbeea114add2012-05-03 15:00:40 -070059 rDest, r15pc, 0, 0, 0, dataTarget);
buzbee52a77fc2012-11-20 19:50:46 -080060 SetMemRefType(loadPcRel, true, kLiteral);
buzbeecbd6d442012-11-17 14:11:25 -080061 loadPcRel->aliasInfo = reinterpret_cast<uintptr_t>(dataTarget);
buzbee52a77fc2012-11-20 19:50:46 -080062 AppendLIR(cUnit, loadPcRel);
Bill Buzbeea114add2012-05-03 15:00:40 -070063 return loadPcRel;
buzbee67bf8852011-08-17 17:51:35 -070064}
65
buzbeeaad94382012-11-21 07:40:50 -080066static int LeadingZeros(uint32_t val)
buzbee67bf8852011-08-17 17:51:35 -070067{
buzbeeeaf09bc2012-11-15 14:51:41 -080068 uint32_t alt;
Bill Buzbeea114add2012-05-03 15:00:40 -070069 int n;
70 int count;
buzbee67bf8852011-08-17 17:51:35 -070071
Bill Buzbeea114add2012-05-03 15:00:40 -070072 count = 16;
73 n = 32;
74 do {
75 alt = val >> count;
76 if (alt != 0) {
77 n = n - count;
78 val = alt;
79 }
80 count >>= 1;
81 } while (count);
82 return n - val;
buzbee67bf8852011-08-17 17:51:35 -070083}
84
85/*
86 * Determine whether value can be encoded as a Thumb2 modified
87 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
88 */
buzbee52a77fc2012-11-20 19:50:46 -080089int ModifiedImmediate(uint32_t value)
buzbee67bf8852011-08-17 17:51:35 -070090{
91 int zLeading;
92 int zTrailing;
buzbeeeaf09bc2012-11-15 14:51:41 -080093 uint32_t b0 = value & 0xff;
buzbee67bf8852011-08-17 17:51:35 -070094
95 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
96 if (value <= 0xFF)
Bill Buzbeea114add2012-05-03 15:00:40 -070097 return b0; // 0:000:a:bcdefgh
buzbee67bf8852011-08-17 17:51:35 -070098 if (value == ((b0 << 16) | b0))
Bill Buzbeea114add2012-05-03 15:00:40 -070099 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
buzbee67bf8852011-08-17 17:51:35 -0700100 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
Bill Buzbeea114add2012-05-03 15:00:40 -0700101 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
buzbee67bf8852011-08-17 17:51:35 -0700102 b0 = (value >> 8) & 0xff;
103 if (value == ((b0 << 24) | (b0 << 8)))
Bill Buzbeea114add2012-05-03 15:00:40 -0700104 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
buzbee67bf8852011-08-17 17:51:35 -0700105 /* Can we do it with rotation? */
buzbee52a77fc2012-11-20 19:50:46 -0800106 zLeading = LeadingZeros(value);
107 zTrailing = 32 - LeadingZeros(~value & (value - 1));
buzbee67bf8852011-08-17 17:51:35 -0700108 /* A run of eight or fewer active bits? */
109 if ((zLeading + zTrailing) < 24)
Bill Buzbeea114add2012-05-03 15:00:40 -0700110 return -1; /* No - bail */
buzbee67bf8852011-08-17 17:51:35 -0700111 /* left-justify the constant, discarding msb (known to be 1) */
112 value <<= zLeading + 1;
113 /* Create bcdefgh */
114 value >>= 25;
115 /* Put it all together */
116 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
117}
118
119/*
120 * Load a immediate using a shortcut if possible; otherwise
121 * grab from the per-translation literal pool.
122 *
123 * No additional register clobbering operation performed. Use this version when
buzbee52a77fc2012-11-20 19:50:46 -0800124 * 1) rDest is freshly returned from AllocTemp or
buzbee67bf8852011-08-17 17:51:35 -0700125 * 2) The codegen is under fixed register usage
126 */
buzbee52a77fc2012-11-20 19:50:46 -0800127LIR* LoadConstantNoClobber(CompilationUnit* cUnit, int rDest, int value)
buzbee67bf8852011-08-17 17:51:35 -0700128{
Bill Buzbeea114add2012-05-03 15:00:40 -0700129 LIR* res;
130 int modImm;
buzbee67bf8852011-08-17 17:51:35 -0700131
buzbeef0504cd2012-11-13 16:31:10 -0800132 if (ARM_FPREG(rDest)) {
buzbee52a77fc2012-11-20 19:50:46 -0800133 return LoadFPConstantValue(cUnit, rDest, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700134 }
buzbee67bf8852011-08-17 17:51:35 -0700135
Bill Buzbeea114add2012-05-03 15:00:40 -0700136 /* See if the value can be constructed cheaply */
buzbeef0504cd2012-11-13 16:31:10 -0800137 if (ARM_LOWREG(rDest) && (value >= 0) && (value <= 255)) {
buzbee52a77fc2012-11-20 19:50:46 -0800138 return NewLIR2(cUnit, kThumbMovImm, rDest, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700139 }
140 /* Check Modified immediate special cases */
buzbee52a77fc2012-11-20 19:50:46 -0800141 modImm = ModifiedImmediate(value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700142 if (modImm >= 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800143 res = NewLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700144 return res;
Bill Buzbeea114add2012-05-03 15:00:40 -0700145 }
buzbee52a77fc2012-11-20 19:50:46 -0800146 modImm = ModifiedImmediate(~value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700147 if (modImm >= 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800148 res = NewLIR2(cUnit, kThumb2MvnImm12, rDest, modImm);
Bill Buzbeea114add2012-05-03 15:00:40 -0700149 return res;
150 }
151 /* 16-bit immediate? */
152 if ((value & 0xffff) == value) {
buzbee52a77fc2012-11-20 19:50:46 -0800153 res = NewLIR2(cUnit, kThumb2MovImm16, rDest, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700154 return res;
155 }
156 /* No shortcut - go ahead and use literal pool */
buzbee52a77fc2012-11-20 19:50:46 -0800157 LIR* dataTarget = ScanLiteralPool(cUnit->literalList, value, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700158 if (dataTarget == NULL) {
buzbee52a77fc2012-11-20 19:50:46 -0800159 dataTarget = AddWordData(cUnit, &cUnit->literalList, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700160 }
buzbee52a77fc2012-11-20 19:50:46 -0800161 LIR* loadPcRel = RawLIR(cUnit, cUnit->currentDalvikOffset,
Bill Buzbeea114add2012-05-03 15:00:40 -0700162 kThumb2LdrPcRel12, rDest, 0, 0, 0, 0, dataTarget);
buzbee52a77fc2012-11-20 19:50:46 -0800163 SetMemRefType(loadPcRel, true, kLiteral);
buzbeecbd6d442012-11-17 14:11:25 -0800164 loadPcRel->aliasInfo = reinterpret_cast<uintptr_t>(dataTarget);
Bill Buzbeea114add2012-05-03 15:00:40 -0700165 res = loadPcRel;
buzbee52a77fc2012-11-20 19:50:46 -0800166 AppendLIR(cUnit, loadPcRel);
Bill Buzbeea114add2012-05-03 15:00:40 -0700167
168 /*
169 * To save space in the constant pool, we use the ADD_RRI8 instruction to
170 * add up to 255 to an existing constant value.
171 */
172 if (dataTarget->operands[0] != value) {
buzbee52a77fc2012-11-20 19:50:46 -0800173 OpRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
Bill Buzbeea114add2012-05-03 15:00:40 -0700174 }
175 return res;
buzbee67bf8852011-08-17 17:51:35 -0700176}
177
buzbee52a77fc2012-11-20 19:50:46 -0800178LIR* OpBranchUnconditional(CompilationUnit* cUnit, OpKind op)
buzbee67bf8852011-08-17 17:51:35 -0700179{
Bill Buzbeea114add2012-05-03 15:00:40 -0700180 DCHECK_EQ(op, kOpUncondBr);
buzbee52a77fc2012-11-20 19:50:46 -0800181 return NewLIR1(cUnit, kThumbBUncond, 0 /* offset to be patched */);
buzbee67bf8852011-08-17 17:51:35 -0700182}
183
buzbee52a77fc2012-11-20 19:50:46 -0800184LIR* OpCondBranch(CompilationUnit* cUnit, ConditionCode cc, LIR* target)
buzbee67bf8852011-08-17 17:51:35 -0700185{
buzbee52a77fc2012-11-20 19:50:46 -0800186 LIR* branch = NewLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */,
187 ArmConditionEncoding(cc));
Bill Buzbeea114add2012-05-03 15:00:40 -0700188 branch->target = target;
189 return branch;
buzbee67bf8852011-08-17 17:51:35 -0700190}
191
buzbee52a77fc2012-11-20 19:50:46 -0800192LIR* OpReg(CompilationUnit* cUnit, OpKind op, int rDestSrc)
buzbee67bf8852011-08-17 17:51:35 -0700193{
Bill Buzbeea114add2012-05-03 15:00:40 -0700194 ArmOpcode opcode = kThumbBkpt;
195 switch (op) {
196 case kOpBlx:
197 opcode = kThumbBlxR;
198 break;
199 default:
buzbeecbd6d442012-11-17 14:11:25 -0800200 LOG(FATAL) << "Bad opcode " << op;
Bill Buzbeea114add2012-05-03 15:00:40 -0700201 }
buzbee52a77fc2012-11-20 19:50:46 -0800202 return NewLIR1(cUnit, opcode, rDestSrc);
buzbee67bf8852011-08-17 17:51:35 -0700203}
204
buzbee52a77fc2012-11-20 19:50:46 -0800205LIR* OpRegRegShift(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
buzbee31a4a6f2012-02-28 15:36:15 -0800206 int rSrc2, int shift)
buzbee67bf8852011-08-17 17:51:35 -0700207{
buzbeef0504cd2012-11-13 16:31:10 -0800208 bool thumbForm = ((shift == 0) && ARM_LOWREG(rDestSrc1) && ARM_LOWREG(rSrc2));
Bill Buzbeea114add2012-05-03 15:00:40 -0700209 ArmOpcode opcode = kThumbBkpt;
210 switch (op) {
211 case kOpAdc:
212 opcode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
213 break;
214 case kOpAnd:
215 opcode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
216 break;
217 case kOpBic:
218 opcode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
219 break;
220 case kOpCmn:
221 DCHECK_EQ(shift, 0);
222 opcode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
223 break;
224 case kOpCmp:
225 if (thumbForm)
226 opcode = kThumbCmpRR;
buzbeef0504cd2012-11-13 16:31:10 -0800227 else if ((shift == 0) && !ARM_LOWREG(rDestSrc1) && !ARM_LOWREG(rSrc2))
Bill Buzbeea114add2012-05-03 15:00:40 -0700228 opcode = kThumbCmpHH;
buzbeef0504cd2012-11-13 16:31:10 -0800229 else if ((shift == 0) && ARM_LOWREG(rDestSrc1))
Bill Buzbeea114add2012-05-03 15:00:40 -0700230 opcode = kThumbCmpLH;
231 else if (shift == 0)
232 opcode = kThumbCmpHL;
233 else
234 opcode = kThumb2CmpRR;
235 break;
236 case kOpXor:
237 opcode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
238 break;
239 case kOpMov:
240 DCHECK_EQ(shift, 0);
buzbeef0504cd2012-11-13 16:31:10 -0800241 if (ARM_LOWREG(rDestSrc1) && ARM_LOWREG(rSrc2))
Bill Buzbeea114add2012-05-03 15:00:40 -0700242 opcode = kThumbMovRR;
buzbeef0504cd2012-11-13 16:31:10 -0800243 else if (!ARM_LOWREG(rDestSrc1) && !ARM_LOWREG(rSrc2))
Bill Buzbeea114add2012-05-03 15:00:40 -0700244 opcode = kThumbMovRR_H2H;
buzbeef0504cd2012-11-13 16:31:10 -0800245 else if (ARM_LOWREG(rDestSrc1))
Bill Buzbeea114add2012-05-03 15:00:40 -0700246 opcode = kThumbMovRR_H2L;
247 else
248 opcode = kThumbMovRR_L2H;
249 break;
250 case kOpMul:
251 DCHECK_EQ(shift, 0);
252 opcode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
253 break;
254 case kOpMvn:
255 opcode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
256 break;
257 case kOpNeg:
258 DCHECK_EQ(shift, 0);
259 opcode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
260 break;
261 case kOpOr:
262 opcode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
263 break;
264 case kOpSbc:
265 opcode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
266 break;
267 case kOpTst:
268 opcode = (thumbForm) ? kThumbTst : kThumb2TstRR;
269 break;
270 case kOpLsl:
271 DCHECK_EQ(shift, 0);
272 opcode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
273 break;
274 case kOpLsr:
275 DCHECK_EQ(shift, 0);
276 opcode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
277 break;
278 case kOpAsr:
279 DCHECK_EQ(shift, 0);
280 opcode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
281 break;
282 case kOpRor:
283 DCHECK_EQ(shift, 0);
284 opcode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
285 break;
286 case kOpAdd:
287 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
288 break;
289 case kOpSub:
290 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
291 break;
292 case kOp2Byte:
293 DCHECK_EQ(shift, 0);
buzbee52a77fc2012-11-20 19:50:46 -0800294 return NewLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
Bill Buzbeea114add2012-05-03 15:00:40 -0700295 case kOp2Short:
296 DCHECK_EQ(shift, 0);
buzbee52a77fc2012-11-20 19:50:46 -0800297 return NewLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
Bill Buzbeea114add2012-05-03 15:00:40 -0700298 case kOp2Char:
299 DCHECK_EQ(shift, 0);
buzbee52a77fc2012-11-20 19:50:46 -0800300 return NewLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
Bill Buzbeea114add2012-05-03 15:00:40 -0700301 default:
buzbeecbd6d442012-11-17 14:11:25 -0800302 LOG(FATAL) << "Bad opcode: " << op;
Bill Buzbeea114add2012-05-03 15:00:40 -0700303 break;
304 }
305 DCHECK_GE(static_cast<int>(opcode), 0);
306 if (EncodingMap[opcode].flags & IS_BINARY_OP)
buzbee52a77fc2012-11-20 19:50:46 -0800307 return NewLIR2(cUnit, opcode, rDestSrc1, rSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700308 else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
309 if (EncodingMap[opcode].fieldLoc[2].kind == kFmtShift)
buzbee52a77fc2012-11-20 19:50:46 -0800310 return NewLIR3(cUnit, opcode, rDestSrc1, rSrc2, shift);
Bill Buzbeea114add2012-05-03 15:00:40 -0700311 else
buzbee52a77fc2012-11-20 19:50:46 -0800312 return NewLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700313 } else if (EncodingMap[opcode].flags & IS_QUAD_OP)
buzbee52a77fc2012-11-20 19:50:46 -0800314 return NewLIR4(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2, shift);
Bill Buzbeea114add2012-05-03 15:00:40 -0700315 else {
316 LOG(FATAL) << "Unexpected encoding operand count";
317 return NULL;
318 }
buzbee67bf8852011-08-17 17:51:35 -0700319}
320
buzbee52a77fc2012-11-20 19:50:46 -0800321LIR* OpRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1, int rSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700322{
buzbee52a77fc2012-11-20 19:50:46 -0800323 return OpRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
buzbee67bf8852011-08-17 17:51:35 -0700324}
325
buzbee52a77fc2012-11-20 19:50:46 -0800326LIR* OpRegRegRegShift(CompilationUnit* cUnit, OpKind op, int rDest, int rSrc1,
Bill Buzbeea114add2012-05-03 15:00:40 -0700327 int rSrc2, int shift)
buzbee67bf8852011-08-17 17:51:35 -0700328{
Bill Buzbeea114add2012-05-03 15:00:40 -0700329 ArmOpcode opcode = kThumbBkpt;
buzbeef0504cd2012-11-13 16:31:10 -0800330 bool thumbForm = (shift == 0) && ARM_LOWREG(rDest) && ARM_LOWREG(rSrc1) &&
331 ARM_LOWREG(rSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700332 switch (op) {
333 case kOpAdd:
334 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
335 break;
336 case kOpSub:
337 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
338 break;
339 case kOpRsub:
340 opcode = kThumb2RsubRRR;
341 break;
342 case kOpAdc:
343 opcode = kThumb2AdcRRR;
344 break;
345 case kOpAnd:
346 opcode = kThumb2AndRRR;
347 break;
348 case kOpBic:
349 opcode = kThumb2BicRRR;
350 break;
351 case kOpXor:
352 opcode = kThumb2EorRRR;
353 break;
354 case kOpMul:
355 DCHECK_EQ(shift, 0);
356 opcode = kThumb2MulRRR;
357 break;
358 case kOpOr:
359 opcode = kThumb2OrrRRR;
360 break;
361 case kOpSbc:
362 opcode = kThumb2SbcRRR;
363 break;
364 case kOpLsl:
365 DCHECK_EQ(shift, 0);
366 opcode = kThumb2LslRRR;
367 break;
368 case kOpLsr:
369 DCHECK_EQ(shift, 0);
370 opcode = kThumb2LsrRRR;
371 break;
372 case kOpAsr:
373 DCHECK_EQ(shift, 0);
374 opcode = kThumb2AsrRRR;
375 break;
376 case kOpRor:
377 DCHECK_EQ(shift, 0);
378 opcode = kThumb2RorRRR;
379 break;
380 default:
buzbeecbd6d442012-11-17 14:11:25 -0800381 LOG(FATAL) << "Bad opcode: " << op;
Bill Buzbeea114add2012-05-03 15:00:40 -0700382 break;
383 }
384 DCHECK_GE(static_cast<int>(opcode), 0);
385 if (EncodingMap[opcode].flags & IS_QUAD_OP)
buzbee52a77fc2012-11-20 19:50:46 -0800386 return NewLIR4(cUnit, opcode, rDest, rSrc1, rSrc2, shift);
Bill Buzbeea114add2012-05-03 15:00:40 -0700387 else {
388 DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP);
buzbee52a77fc2012-11-20 19:50:46 -0800389 return NewLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700390 }
buzbee67bf8852011-08-17 17:51:35 -0700391}
392
buzbee52a77fc2012-11-20 19:50:46 -0800393LIR* OpRegRegReg(CompilationUnit* cUnit, OpKind op, int rDest, int rSrc1,
buzbee31a4a6f2012-02-28 15:36:15 -0800394 int rSrc2)
buzbee67bf8852011-08-17 17:51:35 -0700395{
buzbee52a77fc2012-11-20 19:50:46 -0800396 return OpRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
buzbee67bf8852011-08-17 17:51:35 -0700397}
398
buzbee52a77fc2012-11-20 19:50:46 -0800399LIR* OpRegRegImm(CompilationUnit* cUnit, OpKind op, int rDest, int rSrc1,
buzbee31a4a6f2012-02-28 15:36:15 -0800400 int value)
buzbee67bf8852011-08-17 17:51:35 -0700401{
Bill Buzbeea114add2012-05-03 15:00:40 -0700402 LIR* res;
403 bool neg = (value < 0);
404 int absValue = (neg) ? -value : value;
405 ArmOpcode opcode = kThumbBkpt;
406 ArmOpcode altOpcode = kThumbBkpt;
buzbeef0504cd2012-11-13 16:31:10 -0800407 bool allLowRegs = (ARM_LOWREG(rDest) && ARM_LOWREG(rSrc1));
buzbee52a77fc2012-11-20 19:50:46 -0800408 int modImm = ModifiedImmediate(value);
409 int modImmNeg = ModifiedImmediate(-value);
buzbee67bf8852011-08-17 17:51:35 -0700410
Bill Buzbeea114add2012-05-03 15:00:40 -0700411 switch (op) {
412 case kOpLsl:
413 if (allLowRegs)
buzbee52a77fc2012-11-20 19:50:46 -0800414 return NewLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700415 else
buzbee52a77fc2012-11-20 19:50:46 -0800416 return NewLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700417 case kOpLsr:
418 if (allLowRegs)
buzbee52a77fc2012-11-20 19:50:46 -0800419 return NewLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700420 else
buzbee52a77fc2012-11-20 19:50:46 -0800421 return NewLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700422 case kOpAsr:
423 if (allLowRegs)
buzbee52a77fc2012-11-20 19:50:46 -0800424 return NewLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700425 else
buzbee52a77fc2012-11-20 19:50:46 -0800426 return NewLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700427 case kOpRor:
buzbee52a77fc2012-11-20 19:50:46 -0800428 return NewLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700429 case kOpAdd:
buzbeef0504cd2012-11-13 16:31:10 -0800430 if (ARM_LOWREG(rDest) && (rSrc1 == r13sp) &&
Bill Buzbeea114add2012-05-03 15:00:40 -0700431 (value <= 1020) && ((value & 0x3)==0)) {
buzbee52a77fc2012-11-20 19:50:46 -0800432 return NewLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1, value >> 2);
buzbeef0504cd2012-11-13 16:31:10 -0800433 } else if (ARM_LOWREG(rDest) && (rSrc1 == r15pc) &&
Bill Buzbeea114add2012-05-03 15:00:40 -0700434 (value <= 1020) && ((value & 0x3)==0)) {
buzbee52a77fc2012-11-20 19:50:46 -0800435 return NewLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1, value >> 2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700436 }
437 // Note: intentional fallthrough
438 case kOpSub:
439 if (allLowRegs && ((absValue & 0x7) == absValue)) {
440 if (op == kOpAdd)
441 opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
buzbee67bf8852011-08-17 17:51:35 -0700442 else
Bill Buzbeea114add2012-05-03 15:00:40 -0700443 opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
buzbee52a77fc2012-11-20 19:50:46 -0800444 return NewLIR3(cUnit, opcode, rDest, rSrc1, absValue);
Bill Buzbeea114add2012-05-03 15:00:40 -0700445 } else if ((absValue & 0xff) == absValue) {
446 if (op == kOpAdd)
447 opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
448 else
449 opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
buzbee52a77fc2012-11-20 19:50:46 -0800450 return NewLIR3(cUnit, opcode, rDest, rSrc1, absValue);
Bill Buzbeea114add2012-05-03 15:00:40 -0700451 }
452 if (modImmNeg >= 0) {
453 op = (op == kOpAdd) ? kOpSub : kOpAdd;
454 modImm = modImmNeg;
455 }
456 if (op == kOpSub) {
457 opcode = kThumb2SubRRI8;
458 altOpcode = kThumb2SubRRR;
459 } else {
460 opcode = kThumb2AddRRI8;
461 altOpcode = kThumb2AddRRR;
462 }
463 break;
464 case kOpAdc:
465 opcode = kThumb2AdcRRI8;
466 altOpcode = kThumb2AdcRRR;
467 break;
468 case kOpSbc:
469 opcode = kThumb2SbcRRI8;
470 altOpcode = kThumb2SbcRRR;
471 break;
472 case kOpOr:
473 opcode = kThumb2OrrRRI8;
474 altOpcode = kThumb2OrrRRR;
475 break;
476 case kOpAnd:
477 opcode = kThumb2AndRRI8;
478 altOpcode = kThumb2AndRRR;
479 break;
480 case kOpXor:
481 opcode = kThumb2EorRRI8;
482 altOpcode = kThumb2EorRRR;
483 break;
484 case kOpMul:
485 //TUNING: power of 2, shift & add
486 modImm = -1;
487 altOpcode = kThumb2MulRRR;
488 break;
489 case kOpCmp: {
buzbee52a77fc2012-11-20 19:50:46 -0800490 int modImm = ModifiedImmediate(value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700491 LIR* res;
492 if (modImm >= 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800493 res = NewLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
Bill Buzbeea114add2012-05-03 15:00:40 -0700494 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800495 int rTmp = AllocTemp(cUnit);
496 res = LoadConstant(cUnit, rTmp, value);
497 OpRegReg(cUnit, kOpCmp, rSrc1, rTmp);
498 FreeTemp(cUnit, rTmp);
Bill Buzbeea114add2012-05-03 15:00:40 -0700499 }
500 return res;
buzbee67bf8852011-08-17 17:51:35 -0700501 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700502 default:
buzbeecbd6d442012-11-17 14:11:25 -0800503 LOG(FATAL) << "Bad opcode: " << op;
Bill Buzbeea114add2012-05-03 15:00:40 -0700504 }
505
506 if (modImm >= 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800507 return NewLIR3(cUnit, opcode, rDest, rSrc1, modImm);
Bill Buzbeea114add2012-05-03 15:00:40 -0700508 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800509 int rScratch = AllocTemp(cUnit);
510 LoadConstant(cUnit, rScratch, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700511 if (EncodingMap[altOpcode].flags & IS_QUAD_OP)
buzbee52a77fc2012-11-20 19:50:46 -0800512 res = NewLIR4(cUnit, altOpcode, rDest, rSrc1, rScratch, 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700513 else
buzbee52a77fc2012-11-20 19:50:46 -0800514 res = NewLIR3(cUnit, altOpcode, rDest, rSrc1, rScratch);
515 FreeTemp(cUnit, rScratch);
Bill Buzbeea114add2012-05-03 15:00:40 -0700516 return res;
517 }
buzbee67bf8852011-08-17 17:51:35 -0700518}
519
buzbee52a77fc2012-11-20 19:50:46 -0800520/* Handle Thumb-only variants here - otherwise punt to OpRegRegImm */
521LIR* OpRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1, int value)
buzbee67bf8852011-08-17 17:51:35 -0700522{
Bill Buzbeea114add2012-05-03 15:00:40 -0700523 bool neg = (value < 0);
524 int absValue = (neg) ? -value : value;
buzbeef0504cd2012-11-13 16:31:10 -0800525 bool shortForm = (((absValue & 0xff) == absValue) && ARM_LOWREG(rDestSrc1));
Bill Buzbeea114add2012-05-03 15:00:40 -0700526 ArmOpcode opcode = kThumbBkpt;
527 switch (op) {
528 case kOpAdd:
529 if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
530 DCHECK_EQ((value & 0x3), 0);
buzbee52a77fc2012-11-20 19:50:46 -0800531 return NewLIR1(cUnit, kThumbAddSpI7, value >> 2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700532 } else if (shortForm) {
533 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
534 }
535 break;
536 case kOpSub:
537 if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
538 DCHECK_EQ((value & 0x3), 0);
buzbee52a77fc2012-11-20 19:50:46 -0800539 return NewLIR1(cUnit, kThumbSubSpI7, value >> 2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700540 } else if (shortForm) {
541 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
542 }
543 break;
544 case kOpCmp:
buzbeef0504cd2012-11-13 16:31:10 -0800545 if (ARM_LOWREG(rDestSrc1) && shortForm)
Bill Buzbeea114add2012-05-03 15:00:40 -0700546 opcode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR;
buzbeef0504cd2012-11-13 16:31:10 -0800547 else if (ARM_LOWREG(rDestSrc1))
Bill Buzbeea114add2012-05-03 15:00:40 -0700548 opcode = kThumbCmpRR;
549 else {
550 shortForm = false;
551 opcode = kThumbCmpHL;
552 }
553 break;
554 default:
buzbee52a77fc2012-11-20 19:50:46 -0800555 /* Punt to OpRegRegImm - if bad case catch it there */
Bill Buzbeea114add2012-05-03 15:00:40 -0700556 shortForm = false;
557 break;
558 }
559 if (shortForm)
buzbee52a77fc2012-11-20 19:50:46 -0800560 return NewLIR2(cUnit, opcode, rDestSrc1, absValue);
Bill Buzbeea114add2012-05-03 15:00:40 -0700561 else {
buzbee52a77fc2012-11-20 19:50:46 -0800562 return OpRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
Bill Buzbeea114add2012-05-03 15:00:40 -0700563 }
buzbee67bf8852011-08-17 17:51:35 -0700564}
565
566/*
567 * Determine whether value can be encoded as a Thumb2 floating point
568 * immediate. If not, return -1. If so return encoded 8-bit value.
569 */
buzbeeaad94382012-11-21 07:40:50 -0800570static int EncodeImmDoubleHigh(int value)
buzbee67bf8852011-08-17 17:51:35 -0700571{
Bill Buzbeea114add2012-05-03 15:00:40 -0700572 int res;
573 int bitA = (value & 0x80000000) >> 31;
574 int notBitB = (value & 0x40000000) >> 30;
575 int bitB = (value & 0x20000000) >> 29;
576 int bSmear = (value & 0x3fc00000) >> 22;
577 int slice = (value & 0x003f0000) >> 16;
578 int zeroes = (value & 0x0000ffff);
579 if (zeroes != 0)
580 return -1;
581 if (bitB) {
582 if ((notBitB != 0) || (bSmear != 0xff))
583 return -1;
584 } else {
585 if ((notBitB != 1) || (bSmear != 0x0))
586 return -1;
587 }
588 res = (bitA << 7) | (bitB << 6) | slice;
589 return res;
buzbee67bf8852011-08-17 17:51:35 -0700590}
591
buzbeeaad94382012-11-21 07:40:50 -0800592static int EncodeImmDouble(int valLo, int valHi)
buzbee67bf8852011-08-17 17:51:35 -0700593{
Bill Buzbeea114add2012-05-03 15:00:40 -0700594 int res = -1;
595 if (valLo == 0)
buzbee52a77fc2012-11-20 19:50:46 -0800596 res = EncodeImmDoubleHigh(valHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700597 return res;
buzbee67bf8852011-08-17 17:51:35 -0700598}
599
buzbee52a77fc2012-11-20 19:50:46 -0800600LIR* LoadConstantValueWide(CompilationUnit* cUnit, int rDestLo, int rDestHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700601 int valLo, int valHi)
buzbee67bf8852011-08-17 17:51:35 -0700602{
buzbee52a77fc2012-11-20 19:50:46 -0800603 int encodedImm = EncodeImmDouble(valLo, valHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700604 LIR* res;
buzbeef0504cd2012-11-13 16:31:10 -0800605 if (ARM_FPREG(rDestLo)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700606 if (encodedImm >= 0) {
buzbee52a77fc2012-11-20 19:50:46 -0800607 res = NewLIR2(cUnit, kThumb2Vmovd_IMM8, S2d(rDestLo, rDestHi),
Bill Buzbeea114add2012-05-03 15:00:40 -0700608 encodedImm);
buzbee67bf8852011-08-17 17:51:35 -0700609 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800610 LIR* dataTarget = ScanLiteralPoolWide(cUnit->literalList, valLo, valHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700611 if (dataTarget == NULL) {
buzbee52a77fc2012-11-20 19:50:46 -0800612 dataTarget = AddWideData(cUnit, &cUnit->literalList, valLo, valHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700613 }
614 LIR* loadPcRel =
buzbee52a77fc2012-11-20 19:50:46 -0800615 RawLIR(cUnit, cUnit->currentDalvikOffset, kThumb2Vldrd,
616 S2d(rDestLo, rDestHi), r15pc, 0, 0, 0, dataTarget);
617 SetMemRefType(loadPcRel, true, kLiteral);
buzbeecbd6d442012-11-17 14:11:25 -0800618 loadPcRel->aliasInfo = reinterpret_cast<uintptr_t>(dataTarget);
buzbee52a77fc2012-11-20 19:50:46 -0800619 AppendLIR(cUnit, loadPcRel);
Bill Buzbeea114add2012-05-03 15:00:40 -0700620 res = loadPcRel;
buzbee67bf8852011-08-17 17:51:35 -0700621 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700622 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800623 res = LoadConstantNoClobber(cUnit, rDestLo, valLo);
624 LoadConstantNoClobber(cUnit, rDestHi, valHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700625 }
626 return res;
buzbee67bf8852011-08-17 17:51:35 -0700627}
628
buzbee52a77fc2012-11-20 19:50:46 -0800629int EncodeShift(int code, int amount) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700630 return ((amount & 0x1f) << 2) | code;
buzbee67bf8852011-08-17 17:51:35 -0700631}
632
buzbee52a77fc2012-11-20 19:50:46 -0800633LIR* LoadBaseIndexed(CompilationUnit* cUnit, int rBase, int rIndex, int rDest,
buzbee31a4a6f2012-02-28 15:36:15 -0800634 int scale, OpSize size)
buzbee67bf8852011-08-17 17:51:35 -0700635{
buzbeef0504cd2012-11-13 16:31:10 -0800636 bool allLowRegs = ARM_LOWREG(rBase) && ARM_LOWREG(rIndex) && ARM_LOWREG(rDest);
Bill Buzbeea114add2012-05-03 15:00:40 -0700637 LIR* load;
638 ArmOpcode opcode = kThumbBkpt;
639 bool thumbForm = (allLowRegs && (scale == 0));
640 int regPtr;
buzbee67bf8852011-08-17 17:51:35 -0700641
buzbeef0504cd2012-11-13 16:31:10 -0800642 if (ARM_FPREG(rDest)) {
643 if (ARM_SINGLEREG(rDest)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700644 DCHECK((size == kWord) || (size == kSingle));
645 opcode = kThumb2Vldrs;
646 size = kSingle;
buzbee67bf8852011-08-17 17:51:35 -0700647 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800648 DCHECK(ARM_DOUBLEREG(rDest));
Bill Buzbeea114add2012-05-03 15:00:40 -0700649 DCHECK((size == kLong) || (size == kDouble));
Elliott Hughes74847412012-06-20 18:10:21 -0700650 DCHECK_EQ((rDest & 0x1), 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700651 opcode = kThumb2Vldrd;
652 size = kDouble;
buzbee67bf8852011-08-17 17:51:35 -0700653 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700654 } else {
655 if (size == kSingle)
656 size = kWord;
657 }
buzbee67bf8852011-08-17 17:51:35 -0700658
Bill Buzbeea114add2012-05-03 15:00:40 -0700659 switch (size) {
660 case kDouble: // fall-through
661 case kSingle:
buzbee52a77fc2012-11-20 19:50:46 -0800662 regPtr = AllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700663 if (scale) {
buzbee52a77fc2012-11-20 19:50:46 -0800664 NewLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
665 EncodeShift(kArmLsl, scale));
Bill Buzbeea114add2012-05-03 15:00:40 -0700666 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800667 OpRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
Bill Buzbeea114add2012-05-03 15:00:40 -0700668 }
buzbee52a77fc2012-11-20 19:50:46 -0800669 load = NewLIR3(cUnit, opcode, rDest, regPtr, 0);
670 FreeTemp(cUnit, regPtr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700671 return load;
672 case kWord:
673 opcode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
674 break;
675 case kUnsignedHalf:
676 opcode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
677 break;
678 case kSignedHalf:
679 opcode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
680 break;
681 case kUnsignedByte:
682 opcode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
683 break;
684 case kSignedByte:
685 opcode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
686 break;
687 default:
buzbeecbd6d442012-11-17 14:11:25 -0800688 LOG(FATAL) << "Bad size: " << size;
Bill Buzbeea114add2012-05-03 15:00:40 -0700689 }
690 if (thumbForm)
buzbee52a77fc2012-11-20 19:50:46 -0800691 load = NewLIR3(cUnit, opcode, rDest, rBase, rIndex);
Bill Buzbeea114add2012-05-03 15:00:40 -0700692 else
buzbee52a77fc2012-11-20 19:50:46 -0800693 load = NewLIR4(cUnit, opcode, rDest, rBase, rIndex, scale);
buzbee67bf8852011-08-17 17:51:35 -0700694
Bill Buzbeea114add2012-05-03 15:00:40 -0700695 return load;
buzbee67bf8852011-08-17 17:51:35 -0700696}
697
buzbee52a77fc2012-11-20 19:50:46 -0800698LIR* StoreBaseIndexed(CompilationUnit* cUnit, int rBase, int rIndex, int rSrc,
buzbee31a4a6f2012-02-28 15:36:15 -0800699 int scale, OpSize size)
buzbee67bf8852011-08-17 17:51:35 -0700700{
buzbeef0504cd2012-11-13 16:31:10 -0800701 bool allLowRegs = ARM_LOWREG(rBase) && ARM_LOWREG(rIndex) && ARM_LOWREG(rSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -0700702 LIR* store;
703 ArmOpcode opcode = kThumbBkpt;
704 bool thumbForm = (allLowRegs && (scale == 0));
705 int regPtr;
buzbee67bf8852011-08-17 17:51:35 -0700706
buzbeef0504cd2012-11-13 16:31:10 -0800707 if (ARM_FPREG(rSrc)) {
708 if (ARM_SINGLEREG(rSrc)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700709 DCHECK((size == kWord) || (size == kSingle));
710 opcode = kThumb2Vstrs;
711 size = kSingle;
buzbee67bf8852011-08-17 17:51:35 -0700712 } else {
buzbeef0504cd2012-11-13 16:31:10 -0800713 DCHECK(ARM_DOUBLEREG(rSrc));
Bill Buzbeea114add2012-05-03 15:00:40 -0700714 DCHECK((size == kLong) || (size == kDouble));
Elliott Hughes74847412012-06-20 18:10:21 -0700715 DCHECK_EQ((rSrc & 0x1), 0);
Bill Buzbeea114add2012-05-03 15:00:40 -0700716 opcode = kThumb2Vstrd;
717 size = kDouble;
buzbee67bf8852011-08-17 17:51:35 -0700718 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700719 } else {
720 if (size == kSingle)
721 size = kWord;
722 }
buzbee67bf8852011-08-17 17:51:35 -0700723
Bill Buzbeea114add2012-05-03 15:00:40 -0700724 switch (size) {
725 case kDouble: // fall-through
726 case kSingle:
buzbee52a77fc2012-11-20 19:50:46 -0800727 regPtr = AllocTemp(cUnit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700728 if (scale) {
buzbee52a77fc2012-11-20 19:50:46 -0800729 NewLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
730 EncodeShift(kArmLsl, scale));
Bill Buzbeea114add2012-05-03 15:00:40 -0700731 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800732 OpRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
Bill Buzbeea114add2012-05-03 15:00:40 -0700733 }
buzbee52a77fc2012-11-20 19:50:46 -0800734 store = NewLIR3(cUnit, opcode, rSrc, regPtr, 0);
735 FreeTemp(cUnit, regPtr);
Bill Buzbeea114add2012-05-03 15:00:40 -0700736 return store;
737 case kWord:
738 opcode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
739 break;
740 case kUnsignedHalf:
741 case kSignedHalf:
742 opcode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
743 break;
744 case kUnsignedByte:
745 case kSignedByte:
746 opcode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
747 break;
748 default:
buzbeecbd6d442012-11-17 14:11:25 -0800749 LOG(FATAL) << "Bad size: " << size;
Bill Buzbeea114add2012-05-03 15:00:40 -0700750 }
751 if (thumbForm)
buzbee52a77fc2012-11-20 19:50:46 -0800752 store = NewLIR3(cUnit, opcode, rSrc, rBase, rIndex);
Bill Buzbeea114add2012-05-03 15:00:40 -0700753 else
buzbee52a77fc2012-11-20 19:50:46 -0800754 store = NewLIR4(cUnit, opcode, rSrc, rBase, rIndex, scale);
buzbee67bf8852011-08-17 17:51:35 -0700755
Bill Buzbeea114add2012-05-03 15:00:40 -0700756 return store;
buzbee67bf8852011-08-17 17:51:35 -0700757}
758
759/*
760 * Load value from base + displacement. Optionally perform null check
761 * on base (which must have an associated sReg and MIR). If not
762 * performing null check, incoming MIR can be null.
763 */
buzbee52a77fc2012-11-20 19:50:46 -0800764LIR* LoadBaseDispBody(CompilationUnit* cUnit, int rBase,
buzbee31a4a6f2012-02-28 15:36:15 -0800765 int displacement, int rDest, int rDestHi, OpSize size,
766 int sReg)
buzbee67bf8852011-08-17 17:51:35 -0700767{
Bill Buzbeea114add2012-05-03 15:00:40 -0700768 LIR* res;
769 LIR* load;
770 ArmOpcode opcode = kThumbBkpt;
771 bool shortForm = false;
772 bool thumb2Form = (displacement < 4092 && displacement >= 0);
buzbeef0504cd2012-11-13 16:31:10 -0800773 bool allLowRegs = (ARM_LOWREG(rBase) && ARM_LOWREG(rDest));
Bill Buzbeea114add2012-05-03 15:00:40 -0700774 int encodedDisp = displacement;
775 bool is64bit = false;
776 switch (size) {
777 case kDouble:
778 case kLong:
779 is64bit = true;
buzbeef0504cd2012-11-13 16:31:10 -0800780 if (ARM_FPREG(rDest)) {
781 if (ARM_SINGLEREG(rDest)) {
782 DCHECK(ARM_FPREG(rDestHi));
buzbee52a77fc2012-11-20 19:50:46 -0800783 rDest = S2d(rDest, rDestHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700784 }
785 opcode = kThumb2Vldrd;
786 if (displacement <= 1020) {
787 shortForm = true;
788 encodedDisp >>= 2;
789 }
790 break;
791 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800792 res = LoadBaseDispBody(cUnit, rBase, displacement, rDest,
Bill Buzbeea114add2012-05-03 15:00:40 -0700793 -1, kWord, sReg);
buzbee52a77fc2012-11-20 19:50:46 -0800794 LoadBaseDispBody(cUnit, rBase, displacement + 4, rDestHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700795 -1, kWord, INVALID_SREG);
796 return res;
797 }
798 case kSingle:
799 case kWord:
buzbeef0504cd2012-11-13 16:31:10 -0800800 if (ARM_FPREG(rDest)) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700801 opcode = kThumb2Vldrs;
802 if (displacement <= 1020) {
803 shortForm = true;
804 encodedDisp >>= 2;
805 }
806 break;
807 }
buzbeef0504cd2012-11-13 16:31:10 -0800808 if (ARM_LOWREG(rDest) && (rBase == r15pc) &&
Bill Buzbeea114add2012-05-03 15:00:40 -0700809 (displacement <= 1020) && (displacement >= 0)) {
810 shortForm = true;
811 encodedDisp >>= 2;
812 opcode = kThumbLdrPcRel;
buzbeef0504cd2012-11-13 16:31:10 -0800813 } else if (ARM_LOWREG(rDest) && (rBase == r13sp) &&
Bill Buzbeea114add2012-05-03 15:00:40 -0700814 (displacement <= 1020) && (displacement >= 0)) {
815 shortForm = true;
816 encodedDisp >>= 2;
817 opcode = kThumbLdrSpRel;
818 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
819 DCHECK_EQ((displacement & 0x3), 0);
820 shortForm = true;
821 encodedDisp >>= 2;
822 opcode = kThumbLdrRRI5;
823 } else if (thumb2Form) {
824 shortForm = true;
825 opcode = kThumb2LdrRRI12;
826 }
827 break;
828 case kUnsignedHalf:
829 if (allLowRegs && displacement < 64 && displacement >= 0) {
830 DCHECK_EQ((displacement & 0x1), 0);
831 shortForm = true;
832 encodedDisp >>= 1;
833 opcode = kThumbLdrhRRI5;
834 } else if (displacement < 4092 && displacement >= 0) {
835 shortForm = true;
836 opcode = kThumb2LdrhRRI12;
837 }
838 break;
839 case kSignedHalf:
840 if (thumb2Form) {
841 shortForm = true;
842 opcode = kThumb2LdrshRRI12;
843 }
844 break;
845 case kUnsignedByte:
846 if (allLowRegs && displacement < 32 && displacement >= 0) {
847 shortForm = true;
848 opcode = kThumbLdrbRRI5;
849 } else if (thumb2Form) {
850 shortForm = true;
851 opcode = kThumb2LdrbRRI12;
852 }
853 break;
854 case kSignedByte:
855 if (thumb2Form) {
856 shortForm = true;
857 opcode = kThumb2LdrsbRRI12;
858 }
859 break;
860 default:
buzbeecbd6d442012-11-17 14:11:25 -0800861 LOG(FATAL) << "Bad size: " << size;
Bill Buzbeea114add2012-05-03 15:00:40 -0700862 }
buzbee67bf8852011-08-17 17:51:35 -0700863
Bill Buzbeea114add2012-05-03 15:00:40 -0700864 if (shortForm) {
buzbee52a77fc2012-11-20 19:50:46 -0800865 load = res = NewLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
Bill Buzbeea114add2012-05-03 15:00:40 -0700866 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800867 int regOffset = AllocTemp(cUnit);
868 res = LoadConstant(cUnit, regOffset, encodedDisp);
869 load = LoadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
870 FreeTemp(cUnit, regOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700871 }
buzbee67bf8852011-08-17 17:51:35 -0700872
Bill Buzbeea114add2012-05-03 15:00:40 -0700873 // TODO: in future may need to differentiate Dalvik accesses w/ spills
buzbeef0504cd2012-11-13 16:31:10 -0800874 if (rBase == rARM_SP) {
buzbee52a77fc2012-11-20 19:50:46 -0800875 AnnotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */, is64bit);
Bill Buzbeea114add2012-05-03 15:00:40 -0700876 }
877 return load;
buzbee67bf8852011-08-17 17:51:35 -0700878}
879
buzbee52a77fc2012-11-20 19:50:46 -0800880LIR* LoadBaseDisp(CompilationUnit* cUnit, int rBase,
buzbee31a4a6f2012-02-28 15:36:15 -0800881 int displacement, int rDest, OpSize size, int sReg)
buzbee67bf8852011-08-17 17:51:35 -0700882{
buzbee52a77fc2012-11-20 19:50:46 -0800883 return LoadBaseDispBody(cUnit, rBase, displacement, rDest, -1, size,
Bill Buzbeea114add2012-05-03 15:00:40 -0700884 sReg);
buzbee67bf8852011-08-17 17:51:35 -0700885}
886
buzbee52a77fc2012-11-20 19:50:46 -0800887 LIR* LoadBaseDispWide(CompilationUnit* cUnit, int rBase,
buzbee31a4a6f2012-02-28 15:36:15 -0800888 int displacement, int rDestLo, int rDestHi, int sReg)
buzbee67bf8852011-08-17 17:51:35 -0700889{
buzbee52a77fc2012-11-20 19:50:46 -0800890 return LoadBaseDispBody(cUnit, rBase, displacement, rDestLo, rDestHi,
Bill Buzbeea114add2012-05-03 15:00:40 -0700891 kLong, sReg);
buzbee67bf8852011-08-17 17:51:35 -0700892}
893
894
buzbee52a77fc2012-11-20 19:50:46 -0800895LIR* StoreBaseDispBody(CompilationUnit* cUnit, int rBase, int displacement,
buzbee31a4a6f2012-02-28 15:36:15 -0800896 int rSrc, int rSrcHi, OpSize size)
buzbee67bf8852011-08-17 17:51:35 -0700897{
Bill Buzbeea114add2012-05-03 15:00:40 -0700898 LIR* res, *store;
899 ArmOpcode opcode = kThumbBkpt;
900 bool shortForm = false;
901 bool thumb2Form = (displacement < 4092 && displacement >= 0);
buzbeef0504cd2012-11-13 16:31:10 -0800902 bool allLowRegs = (ARM_LOWREG(rBase) && ARM_LOWREG(rSrc));
Bill Buzbeea114add2012-05-03 15:00:40 -0700903 int encodedDisp = displacement;
904 bool is64bit = false;
905 switch (size) {
906 case kLong:
907 case kDouble:
908 is64bit = true;
buzbeef0504cd2012-11-13 16:31:10 -0800909 if (!ARM_FPREG(rSrc)) {
buzbee52a77fc2012-11-20 19:50:46 -0800910 res = StoreBaseDispBody(cUnit, rBase, displacement, rSrc, -1, kWord);
911 StoreBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi, -1, kWord);
Bill Buzbeea114add2012-05-03 15:00:40 -0700912 return res;
913 }
buzbeef0504cd2012-11-13 16:31:10 -0800914 if (ARM_SINGLEREG(rSrc)) {
915 DCHECK(ARM_FPREG(rSrcHi));
buzbee52a77fc2012-11-20 19:50:46 -0800916 rSrc = S2d(rSrc, rSrcHi);
Bill Buzbeea114add2012-05-03 15:00:40 -0700917 }
918 opcode = kThumb2Vstrd;
919 if (displacement <= 1020) {
920 shortForm = true;
921 encodedDisp >>= 2;
922 }
923 break;
924 case kSingle:
925 case kWord:
buzbeef0504cd2012-11-13 16:31:10 -0800926 if (ARM_FPREG(rSrc)) {
927 DCHECK(ARM_SINGLEREG(rSrc));
Bill Buzbeea114add2012-05-03 15:00:40 -0700928 opcode = kThumb2Vstrs;
929 if (displacement <= 1020) {
930 shortForm = true;
931 encodedDisp >>= 2;
932 }
933 break;
934 }
935 if (allLowRegs && displacement < 128 && displacement >= 0) {
936 DCHECK_EQ((displacement & 0x3), 0);
937 shortForm = true;
938 encodedDisp >>= 2;
939 opcode = kThumbStrRRI5;
940 } else if (thumb2Form) {
941 shortForm = true;
942 opcode = kThumb2StrRRI12;
943 }
944 break;
945 case kUnsignedHalf:
946 case kSignedHalf:
947 if (allLowRegs && displacement < 64 && displacement >= 0) {
948 DCHECK_EQ((displacement & 0x1), 0);
949 shortForm = true;
950 encodedDisp >>= 1;
951 opcode = kThumbStrhRRI5;
952 } else if (thumb2Form) {
953 shortForm = true;
954 opcode = kThumb2StrhRRI12;
955 }
956 break;
957 case kUnsignedByte:
958 case kSignedByte:
959 if (allLowRegs && displacement < 32 && displacement >= 0) {
960 shortForm = true;
961 opcode = kThumbStrbRRI5;
962 } else if (thumb2Form) {
963 shortForm = true;
964 opcode = kThumb2StrbRRI12;
965 }
966 break;
967 default:
buzbeecbd6d442012-11-17 14:11:25 -0800968 LOG(FATAL) << "Bad size: " << size;
Bill Buzbeea114add2012-05-03 15:00:40 -0700969 }
970 if (shortForm) {
buzbee52a77fc2012-11-20 19:50:46 -0800971 store = res = NewLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
Bill Buzbeea114add2012-05-03 15:00:40 -0700972 } else {
buzbee52a77fc2012-11-20 19:50:46 -0800973 int rScratch = AllocTemp(cUnit);
974 res = LoadConstant(cUnit, rScratch, encodedDisp);
975 store = StoreBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
976 FreeTemp(cUnit, rScratch);
Bill Buzbeea114add2012-05-03 15:00:40 -0700977 }
buzbee67bf8852011-08-17 17:51:35 -0700978
Bill Buzbeea114add2012-05-03 15:00:40 -0700979 // TODO: In future, may need to differentiate Dalvik & spill accesses
buzbeef0504cd2012-11-13 16:31:10 -0800980 if (rBase == rARM_SP) {
buzbee52a77fc2012-11-20 19:50:46 -0800981 AnnotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */,
Bill Buzbeea114add2012-05-03 15:00:40 -0700982 is64bit);
983 }
984 return res;
buzbee67bf8852011-08-17 17:51:35 -0700985}
986
buzbee52a77fc2012-11-20 19:50:46 -0800987LIR* StoreBaseDisp(CompilationUnit* cUnit, int rBase, int displacement,
buzbee31a4a6f2012-02-28 15:36:15 -0800988 int rSrc, OpSize size)
buzbee67bf8852011-08-17 17:51:35 -0700989{
buzbee52a77fc2012-11-20 19:50:46 -0800990 return StoreBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
buzbee67bf8852011-08-17 17:51:35 -0700991}
992
buzbee52a77fc2012-11-20 19:50:46 -0800993LIR* StoreBaseDispWide(CompilationUnit* cUnit, int rBase, int displacement,
buzbee31a4a6f2012-02-28 15:36:15 -0800994 int rSrcLo, int rSrcHi)
buzbee67bf8852011-08-17 17:51:35 -0700995{
buzbee52a77fc2012-11-20 19:50:46 -0800996 return StoreBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
buzbee67bf8852011-08-17 17:51:35 -0700997}
998
buzbee52a77fc2012-11-20 19:50:46 -0800999void LoadPair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
buzbee67bf8852011-08-17 17:51:35 -07001000{
buzbee52a77fc2012-11-20 19:50:46 -08001001 LoadBaseDispWide(cUnit, base, 0, lowReg, highReg, INVALID_SREG);
buzbee67bf8852011-08-17 17:51:35 -07001002}
1003
buzbee52a77fc2012-11-20 19:50:46 -08001004LIR* FpRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -07001005{
Bill Buzbeea114add2012-05-03 15:00:40 -07001006 int opcode;
buzbeef0504cd2012-11-13 16:31:10 -08001007 DCHECK_EQ(ARM_DOUBLEREG(rDest), ARM_DOUBLEREG(rSrc));
1008 if (ARM_DOUBLEREG(rDest)) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001009 opcode = kThumb2Vmovd;
1010 } else {
buzbeef0504cd2012-11-13 16:31:10 -08001011 if (ARM_SINGLEREG(rDest)) {
1012 opcode = ARM_SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
buzbeea2ebdd72012-03-04 14:57:06 -08001013 } else {
buzbeef0504cd2012-11-13 16:31:10 -08001014 DCHECK(ARM_SINGLEREG(rSrc));
Bill Buzbeea114add2012-05-03 15:00:40 -07001015 opcode = kThumb2Fmrs;
buzbeea2ebdd72012-03-04 14:57:06 -08001016 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001017 }
buzbee52a77fc2012-11-20 19:50:46 -08001018 LIR* res = RawLIR(cUnit, cUnit->currentDalvikOffset, opcode, rDest, rSrc);
Bill Buzbeea114add2012-05-03 15:00:40 -07001019 if (!(cUnit->disableOpt & (1 << kSafeOptimizations)) && rDest == rSrc) {
1020 res->flags.isNop = true;
1021 }
1022 return res;
buzbee67bf8852011-08-17 17:51:35 -07001023}
1024
buzbee52a77fc2012-11-20 19:50:46 -08001025LIR* OpThreadMem(CompilationUnit* cUnit, OpKind op, int threadOffset)
buzbeeb046e162012-10-30 15:48:42 -07001026{
buzbee52a77fc2012-11-20 19:50:46 -08001027 LOG(FATAL) << "Unexpected use of OpThreadMem for Arm";
buzbeeb046e162012-10-30 15:48:42 -07001028 return NULL;
1029}
buzbee67bf8852011-08-17 17:51:35 -07001030
buzbee52a77fc2012-11-20 19:50:46 -08001031LIR* OpMem(CompilationUnit* cUnit, OpKind op, int rBase, int disp)
buzbeeb046e162012-10-30 15:48:42 -07001032{
buzbee52a77fc2012-11-20 19:50:46 -08001033 LOG(FATAL) << "Unexpected use of OpMem for Arm";
buzbeeb046e162012-10-30 15:48:42 -07001034 return NULL;
1035}
1036
buzbee52a77fc2012-11-20 19:50:46 -08001037LIR* StoreBaseIndexedDisp(CompilationUnit *cUnit,
buzbeeb046e162012-10-30 15:48:42 -07001038 int rBase, int rIndex, int scale, int displacement,
1039 int rSrc, int rSrcHi,
1040 OpSize size, int sReg)
1041{
buzbee52a77fc2012-11-20 19:50:46 -08001042 LOG(FATAL) << "Unexpected use of StoreBaseIndexedDisp for Arm";
buzbeeb046e162012-10-30 15:48:42 -07001043 return NULL;
1044}
1045
buzbee52a77fc2012-11-20 19:50:46 -08001046LIR* OpRegMem(CompilationUnit *cUnit, OpKind op, int rDest, int rBase,
buzbeeb046e162012-10-30 15:48:42 -07001047 int offset)
1048{
buzbee52a77fc2012-11-20 19:50:46 -08001049 LOG(FATAL) << "Unexpected use of OpRegMem for Arm";
buzbeeb046e162012-10-30 15:48:42 -07001050 return NULL;
1051}
1052
buzbee52a77fc2012-11-20 19:50:46 -08001053LIR* LoadBaseIndexedDisp(CompilationUnit *cUnit,
buzbeeb046e162012-10-30 15:48:42 -07001054 int rBase, int rIndex, int scale, int displacement,
1055 int rDest, int rDestHi,
1056 OpSize size, int sReg)
1057{
buzbee52a77fc2012-11-20 19:50:46 -08001058 LOG(FATAL) << "Unexpected use of LoadBaseIndexedDisp for Arm";
buzbeeb046e162012-10-30 15:48:42 -07001059 return NULL;
1060}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001061
1062} // namespace art