blob: ebc30f8daa87132db2a2b8966e7e2e770a3b2702 [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
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080017namespace art {
18
buzbee67bf8852011-08-17 17:51:35 -070019/*
20 * This file contains codegen for the Thumb ISA and is intended to be
21 * includes by:
22 *
23 * Codegen-$(TARGET_ARCH_VARIANT).c
24 *
25 */
26
buzbee68253262011-10-07 14:02:25 -070027static int coreRegs[] = {r0, r1, r2, r3, rSUSPEND, r5, r6, r7, r8, rSELF, r10,
buzbeec1f45042011-09-21 16:03:19 -070028 r11, r12, rSP, rLR, rPC};
29static int reservedRegs[] = {rSUSPEND, rSELF, rSP, rLR, rPC};
buzbee67bf8852011-08-17 17:51:35 -070030static int fpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
31 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
32 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
33 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
34static int coreTemps[] = {r0, r1, r2, r3, r12};
35static int fpTemps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
36 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
37
buzbeeed3e9302011-09-23 17:34:19 -070038STATIC int encodeImmSingle(int value)
buzbee67bf8852011-08-17 17:51:35 -070039{
40 int res;
41 int bitA = (value & 0x80000000) >> 31;
42 int notBitB = (value & 0x40000000) >> 30;
43 int bitB = (value & 0x20000000) >> 29;
44 int bSmear = (value & 0x3e000000) >> 25;
45 int slice = (value & 0x01f80000) >> 19;
46 int zeroes = (value & 0x0007ffff);
47 if (zeroes != 0)
48 return -1;
49 if (bitB) {
50 if ((notBitB != 0) || (bSmear != 0x1f))
51 return -1;
52 } else {
53 if ((notBitB != 1) || (bSmear != 0x0))
54 return -1;
55 }
56 res = (bitA << 7) | (bitB << 6) | slice;
57 return res;
58}
59
buzbeeed3e9302011-09-23 17:34:19 -070060STATIC ArmLIR* loadFPConstantValue(CompilationUnit* cUnit, int rDest,
buzbee67bf8852011-08-17 17:51:35 -070061 int value)
62{
63 int encodedImm = encodeImmSingle(value);
buzbeeed3e9302011-09-23 17:34:19 -070064 DCHECK(SINGLEREG(rDest));
buzbee67bf8852011-08-17 17:51:35 -070065 if (encodedImm >= 0) {
66 return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
67 }
68 ArmLIR* dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
69 if (dataTarget == NULL) {
70 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
71 }
72 ArmLIR* loadPcRel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
73 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
74 loadPcRel->opcode = kThumb2Vldrs;
75 loadPcRel->generic.target = (LIR* ) dataTarget;
76 loadPcRel->operands[0] = rDest;
77 loadPcRel->operands[1] = r15pc;
78 setupResourceMasks(loadPcRel);
79 setMemRefType(loadPcRel, true, kLiteral);
buzbeebbaf8942011-10-02 13:08:29 -070080 loadPcRel->aliasInfo = (intptr_t)dataTarget;
buzbee67bf8852011-08-17 17:51:35 -070081 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
82 return loadPcRel;
83}
84
buzbeeed3e9302011-09-23 17:34:19 -070085STATIC int leadingZeros(u4 val)
buzbee67bf8852011-08-17 17:51:35 -070086{
87 u4 alt;
88 int n;
89 int count;
90
91 count = 16;
92 n = 32;
93 do {
94 alt = val >> count;
95 if (alt != 0) {
96 n = n - count;
97 val = alt;
98 }
99 count >>= 1;
100 } while (count);
101 return n - val;
102}
103
104/*
105 * Determine whether value can be encoded as a Thumb2 modified
106 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
107 */
buzbeeed3e9302011-09-23 17:34:19 -0700108STATIC int modifiedImmediate(u4 value)
buzbee67bf8852011-08-17 17:51:35 -0700109{
110 int zLeading;
111 int zTrailing;
112 u4 b0 = value & 0xff;
113
114 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
115 if (value <= 0xFF)
116 return b0; // 0:000:a:bcdefgh
117 if (value == ((b0 << 16) | b0))
118 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
119 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
120 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
121 b0 = (value >> 8) & 0xff;
122 if (value == ((b0 << 24) | (b0 << 8)))
123 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
124 /* Can we do it with rotation? */
125 zLeading = leadingZeros(value);
126 zTrailing = 32 - leadingZeros(~value & (value - 1));
127 /* A run of eight or fewer active bits? */
128 if ((zLeading + zTrailing) < 24)
129 return -1; /* No - bail */
130 /* left-justify the constant, discarding msb (known to be 1) */
131 value <<= zLeading + 1;
132 /* Create bcdefgh */
133 value >>= 25;
134 /* Put it all together */
135 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
136}
137
138/*
139 * Load a immediate using a shortcut if possible; otherwise
140 * grab from the per-translation literal pool.
141 *
142 * No additional register clobbering operation performed. Use this version when
143 * 1) rDest is freshly returned from oatAllocTemp or
144 * 2) The codegen is under fixed register usage
145 */
buzbeeed3e9302011-09-23 17:34:19 -0700146STATIC ArmLIR* loadConstantNoClobber(CompilationUnit* cUnit, int rDest,
buzbee67bf8852011-08-17 17:51:35 -0700147 int value)
148{
149 ArmLIR* res;
150 int modImm;
151
152 if (FPREG(rDest)) {
153 return loadFPConstantValue(cUnit, rDest, value);
154 }
155
156 /* See if the value can be constructed cheaply */
157 if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
158 return newLIR2(cUnit, kThumbMovImm, rDest, value);
159 }
160 /* Check Modified immediate special cases */
161 modImm = modifiedImmediate(value);
162 if (modImm >= 0) {
163 res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
164 return res;
165 }
166 modImm = modifiedImmediate(~value);
167 if (modImm >= 0) {
buzbee58f92742011-10-01 11:22:17 -0700168 res = newLIR2(cUnit, kThumb2MvnImm12, rDest, modImm);
buzbee67bf8852011-08-17 17:51:35 -0700169 return res;
170 }
171 /* 16-bit immediate? */
172 if ((value & 0xffff) == value) {
173 res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
174 return res;
175 }
176 /* No shortcut - go ahead and use literal pool */
177 ArmLIR* dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
178 if (dataTarget == NULL) {
179 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
180 }
181 ArmLIR* loadPcRel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
182 loadPcRel->opcode = kThumb2LdrPcRel12;
183 loadPcRel->generic.target = (LIR* ) dataTarget;
184 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
185 loadPcRel->operands[0] = rDest;
186 setupResourceMasks(loadPcRel);
187 setMemRefType(loadPcRel, true, kLiteral);
buzbeebbaf8942011-10-02 13:08:29 -0700188 loadPcRel->aliasInfo = (intptr_t)dataTarget;
buzbee67bf8852011-08-17 17:51:35 -0700189 res = loadPcRel;
190 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
191
192 /*
193 * To save space in the constant pool, we use the ADD_RRI8 instruction to
194 * add up to 255 to an existing constant value.
195 */
196 if (dataTarget->operands[0] != value) {
197 opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
198 }
199 return res;
200}
201
202/*
203 * Load an immediate value into a fixed or temp register. Target
204 * register is clobbered, and marked inUse.
205 */
buzbeeed3e9302011-09-23 17:34:19 -0700206STATIC ArmLIR* loadConstant(CompilationUnit* cUnit, int rDest, int value)
buzbee67bf8852011-08-17 17:51:35 -0700207{
208 if (oatIsTemp(cUnit, rDest)) {
209 oatClobber(cUnit, rDest);
210 oatMarkInUse(cUnit, rDest);
211 }
212 return loadConstantNoClobber(cUnit, rDest, value);
213}
214
buzbeeed3e9302011-09-23 17:34:19 -0700215STATIC ArmLIR* opNone(CompilationUnit* cUnit, OpKind op)
buzbee67bf8852011-08-17 17:51:35 -0700216{
217 ArmOpcode opcode = kThumbBkpt;
218 switch (op) {
219 case kOpUncondBr:
220 opcode = kThumbBUncond;
221 break;
222 default:
buzbeeed3e9302011-09-23 17:34:19 -0700223 LOG(FATAL) << "Bad opcode " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700224 }
225 return newLIR0(cUnit, opcode);
226}
227
buzbeeed3e9302011-09-23 17:34:19 -0700228STATIC ArmLIR* opCondBranch(CompilationUnit* cUnit, ArmConditionCode cc)
buzbee67bf8852011-08-17 17:51:35 -0700229{
230 return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc);
231}
232
buzbeeed3e9302011-09-23 17:34:19 -0700233STATIC ArmLIR* opReg(CompilationUnit* cUnit, OpKind op, int rDestSrc)
buzbee67bf8852011-08-17 17:51:35 -0700234{
235 ArmOpcode opcode = kThumbBkpt;
236 switch (op) {
237 case kOpBlx:
238 opcode = kThumbBlxR;
239 break;
240 default:
buzbeeed3e9302011-09-23 17:34:19 -0700241 LOG(FATAL) << "Bad opcode " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700242 }
243 return newLIR1(cUnit, opcode, rDestSrc);
244}
245
buzbeeed3e9302011-09-23 17:34:19 -0700246STATIC ArmLIR* opRegRegShift(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
buzbee67bf8852011-08-17 17:51:35 -0700247 int rSrc2, int shift)
248{
249 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
250 ArmOpcode opcode = kThumbBkpt;
251 switch (op) {
252 case kOpAdc:
253 opcode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
254 break;
255 case kOpAnd:
256 opcode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
257 break;
258 case kOpBic:
259 opcode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
260 break;
261 case kOpCmn:
buzbeeed3e9302011-09-23 17:34:19 -0700262 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700263 opcode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
264 break;
265 case kOpCmp:
266 if (thumbForm)
267 opcode = kThumbCmpRR;
268 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
269 opcode = kThumbCmpHH;
270 else if ((shift == 0) && LOWREG(rDestSrc1))
271 opcode = kThumbCmpLH;
272 else if (shift == 0)
273 opcode = kThumbCmpHL;
274 else
275 opcode = kThumb2CmpRR;
276 break;
277 case kOpXor:
278 opcode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
279 break;
280 case kOpMov:
buzbeeed3e9302011-09-23 17:34:19 -0700281 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700282 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
283 opcode = kThumbMovRR;
284 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
285 opcode = kThumbMovRR_H2H;
286 else if (LOWREG(rDestSrc1))
287 opcode = kThumbMovRR_H2L;
288 else
289 opcode = kThumbMovRR_L2H;
290 break;
291 case kOpMul:
buzbeeed3e9302011-09-23 17:34:19 -0700292 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700293 opcode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
294 break;
295 case kOpMvn:
296 opcode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
297 break;
298 case kOpNeg:
buzbeeed3e9302011-09-23 17:34:19 -0700299 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700300 opcode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
301 break;
302 case kOpOr:
303 opcode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
304 break;
305 case kOpSbc:
306 opcode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
307 break;
308 case kOpTst:
309 opcode = (thumbForm) ? kThumbTst : kThumb2TstRR;
310 break;
311 case kOpLsl:
buzbeeed3e9302011-09-23 17:34:19 -0700312 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700313 opcode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
314 break;
315 case kOpLsr:
buzbeeed3e9302011-09-23 17:34:19 -0700316 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700317 opcode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
318 break;
319 case kOpAsr:
buzbeeed3e9302011-09-23 17:34:19 -0700320 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700321 opcode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
322 break;
323 case kOpRor:
buzbeeed3e9302011-09-23 17:34:19 -0700324 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700325 opcode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
326 break;
327 case kOpAdd:
328 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
329 break;
330 case kOpSub:
331 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
332 break;
333 case kOp2Byte:
buzbeeed3e9302011-09-23 17:34:19 -0700334 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700335 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
336 case kOp2Short:
buzbeeed3e9302011-09-23 17:34:19 -0700337 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700338 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
339 case kOp2Char:
buzbeeed3e9302011-09-23 17:34:19 -0700340 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700341 return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
342 default:
buzbeeed3e9302011-09-23 17:34:19 -0700343 LOG(FATAL) << "Bad opcode: " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700344 break;
345 }
Elliott Hughesf5a7a472011-10-07 14:31:02 -0700346 DCHECK_GE(static_cast<int>(opcode), 0);
buzbee67bf8852011-08-17 17:51:35 -0700347 if (EncodingMap[opcode].flags & IS_BINARY_OP)
348 return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
349 else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
350 if (EncodingMap[opcode].fieldLoc[2].kind == kFmtShift)
351 return newLIR3(cUnit, opcode, rDestSrc1, rSrc2, shift);
352 else
353 return newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2);
354 } else if (EncodingMap[opcode].flags & IS_QUAD_OP)
355 return newLIR4(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2, shift);
356 else {
buzbeeed3e9302011-09-23 17:34:19 -0700357 LOG(FATAL) << "Unexpected encoding operand count";
buzbee67bf8852011-08-17 17:51:35 -0700358 return NULL;
359 }
360}
361
buzbeeed3e9302011-09-23 17:34:19 -0700362STATIC ArmLIR* opRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
buzbee67bf8852011-08-17 17:51:35 -0700363 int rSrc2)
364{
365 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
366}
367
buzbeeed3e9302011-09-23 17:34:19 -0700368STATIC ArmLIR* opRegRegRegShift(CompilationUnit* cUnit, OpKind op,
buzbee67bf8852011-08-17 17:51:35 -0700369 int rDest, int rSrc1, int rSrc2, int shift)
370{
371 ArmOpcode opcode = kThumbBkpt;
372 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
373 LOWREG(rSrc2);
374 switch (op) {
375 case kOpAdd:
376 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
377 break;
378 case kOpSub:
379 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
380 break;
381 case kOpAdc:
382 opcode = kThumb2AdcRRR;
383 break;
384 case kOpAnd:
385 opcode = kThumb2AndRRR;
386 break;
387 case kOpBic:
388 opcode = kThumb2BicRRR;
389 break;
390 case kOpXor:
391 opcode = kThumb2EorRRR;
392 break;
393 case kOpMul:
buzbeeed3e9302011-09-23 17:34:19 -0700394 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700395 opcode = kThumb2MulRRR;
396 break;
397 case kOpOr:
398 opcode = kThumb2OrrRRR;
399 break;
400 case kOpSbc:
401 opcode = kThumb2SbcRRR;
402 break;
403 case kOpLsl:
buzbeeed3e9302011-09-23 17:34:19 -0700404 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700405 opcode = kThumb2LslRRR;
406 break;
407 case kOpLsr:
buzbeeed3e9302011-09-23 17:34:19 -0700408 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700409 opcode = kThumb2LsrRRR;
410 break;
411 case kOpAsr:
buzbeeed3e9302011-09-23 17:34:19 -0700412 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700413 opcode = kThumb2AsrRRR;
414 break;
415 case kOpRor:
buzbeeed3e9302011-09-23 17:34:19 -0700416 DCHECK_EQ(shift, 0);
buzbee67bf8852011-08-17 17:51:35 -0700417 opcode = kThumb2RorRRR;
418 break;
419 default:
buzbeeed3e9302011-09-23 17:34:19 -0700420 LOG(FATAL) << "Bad opcode: " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700421 break;
422 }
Elliott Hughesf5a7a472011-10-07 14:31:02 -0700423 DCHECK_GE(static_cast<int>(opcode), 0);
buzbee67bf8852011-08-17 17:51:35 -0700424 if (EncodingMap[opcode].flags & IS_QUAD_OP)
425 return newLIR4(cUnit, opcode, rDest, rSrc1, rSrc2, shift);
426 else {
buzbeeed3e9302011-09-23 17:34:19 -0700427 DCHECK(EncodingMap[opcode].flags & IS_TERTIARY_OP);
buzbee67bf8852011-08-17 17:51:35 -0700428 return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
429 }
430}
431
buzbeeed3e9302011-09-23 17:34:19 -0700432STATIC ArmLIR* opRegRegReg(CompilationUnit* cUnit, OpKind op, int rDest,
buzbee67bf8852011-08-17 17:51:35 -0700433 int rSrc1, int rSrc2)
434{
435 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
436}
437
buzbeeed3e9302011-09-23 17:34:19 -0700438STATIC ArmLIR* opRegRegImm(CompilationUnit* cUnit, OpKind op, int rDest,
buzbee67bf8852011-08-17 17:51:35 -0700439 int rSrc1, int value)
440{
441 ArmLIR* res;
442 bool neg = (value < 0);
443 int absValue = (neg) ? -value : value;
444 ArmOpcode opcode = kThumbBkpt;
445 ArmOpcode altOpcode = kThumbBkpt;
446 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
447 int modImm = modifiedImmediate(value);
448 int modImmNeg = modifiedImmediate(-value);
449
450 switch(op) {
451 case kOpLsl:
452 if (allLowRegs)
453 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
454 else
455 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
456 case kOpLsr:
457 if (allLowRegs)
458 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
459 else
460 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
461 case kOpAsr:
462 if (allLowRegs)
463 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
464 else
465 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
466 case kOpRor:
467 return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
468 case kOpAdd:
469 if (LOWREG(rDest) && (rSrc1 == r13sp) &&
470 (value <= 1020) && ((value & 0x3)==0)) {
471 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
472 value >> 2);
473 } else if (LOWREG(rDest) && (rSrc1 == r15pc) &&
474 (value <= 1020) && ((value & 0x3)==0)) {
475 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
476 value >> 2);
477 }
buzbee67bf8852011-08-17 17:51:35 -0700478 // Note: intentional fallthrough
479 case kOpSub:
480 if (allLowRegs && ((absValue & 0x7) == absValue)) {
481 if (op == kOpAdd)
482 opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
483 else
484 opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
485 return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
486 } else if ((absValue & 0xff) == absValue) {
487 if (op == kOpAdd)
488 opcode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
489 else
490 opcode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
491 return newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
492 }
493 if (modImmNeg >= 0) {
494 op = (op == kOpAdd) ? kOpSub : kOpAdd;
495 modImm = modImmNeg;
496 }
497 if (op == kOpSub) {
498 opcode = kThumb2SubRRI8;
499 altOpcode = kThumb2SubRRR;
buzbee3b5d3792011-09-20 11:01:40 -0700500 } else {
501 opcode = kThumb2AddRRI8;
502 altOpcode = kThumb2AddRRR;
buzbee67bf8852011-08-17 17:51:35 -0700503 }
504 break;
505 case kOpAdc:
506 opcode = kThumb2AdcRRI8;
507 altOpcode = kThumb2AdcRRR;
508 break;
509 case kOpSbc:
510 opcode = kThumb2SbcRRI8;
511 altOpcode = kThumb2SbcRRR;
512 break;
513 case kOpOr:
514 opcode = kThumb2OrrRRI8;
515 altOpcode = kThumb2OrrRRR;
516 break;
517 case kOpAnd:
518 opcode = kThumb2AndRRI8;
519 altOpcode = kThumb2AndRRR;
520 break;
521 case kOpXor:
522 opcode = kThumb2EorRRI8;
523 altOpcode = kThumb2EorRRR;
524 break;
525 case kOpMul:
526 //TUNING: power of 2, shift & add
527 modImm = -1;
528 altOpcode = kThumb2MulRRR;
529 break;
530 case kOpCmp: {
531 int modImm = modifiedImmediate(value);
532 ArmLIR* res;
533 if (modImm >= 0) {
534 res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
535 } else {
536 int rTmp = oatAllocTemp(cUnit);
537 res = loadConstant(cUnit, rTmp, value);
538 opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
539 oatFreeTemp(cUnit, rTmp);
540 }
541 return res;
542 }
543 default:
buzbeeed3e9302011-09-23 17:34:19 -0700544 LOG(FATAL) << "Bad opcode: " << (int)op;
buzbee67bf8852011-08-17 17:51:35 -0700545 }
546
547 if (modImm >= 0) {
548 return newLIR3(cUnit, opcode, rDest, rSrc1, modImm);
549 } else {
550 int rScratch = oatAllocTemp(cUnit);
551 loadConstant(cUnit, rScratch, value);
552 if (EncodingMap[altOpcode].flags & IS_QUAD_OP)
553 res = newLIR4(cUnit, altOpcode, rDest, rSrc1, rScratch, 0);
554 else
555 res = newLIR3(cUnit, altOpcode, rDest, rSrc1, rScratch);
556 oatFreeTemp(cUnit, rScratch);
557 return res;
558 }
559}
560
561/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
buzbeeed3e9302011-09-23 17:34:19 -0700562STATIC ArmLIR* opRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
buzbee67bf8852011-08-17 17:51:35 -0700563 int value)
564{
565 bool neg = (value < 0);
566 int absValue = (neg) ? -value : value;
567 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
568 ArmOpcode opcode = kThumbBkpt;
569 switch (op) {
570 case kOpAdd:
571 if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
buzbeeed3e9302011-09-23 17:34:19 -0700572 DCHECK_EQ((value & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700573 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
574 } else if (shortForm) {
575 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
576 }
577 break;
578 case kOpSub:
579 if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
buzbeeed3e9302011-09-23 17:34:19 -0700580 DCHECK_EQ((value & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700581 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
582 } else if (shortForm) {
583 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
584 }
585 break;
586 case kOpCmp:
587 if (LOWREG(rDestSrc1) && shortForm)
588 opcode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR;
589 else if (LOWREG(rDestSrc1))
590 opcode = kThumbCmpRR;
591 else {
592 shortForm = false;
593 opcode = kThumbCmpHL;
594 }
595 break;
596 default:
597 /* Punt to opRegRegImm - if bad case catch it there */
598 shortForm = false;
599 break;
600 }
601 if (shortForm)
602 return newLIR2(cUnit, opcode, rDestSrc1, absValue);
603 else {
604 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
605 }
606}
607
608/*
609 * Determine whether value can be encoded as a Thumb2 floating point
610 * immediate. If not, return -1. If so return encoded 8-bit value.
611 */
buzbeeed3e9302011-09-23 17:34:19 -0700612STATIC int encodeImmDoubleHigh(int value)
buzbee67bf8852011-08-17 17:51:35 -0700613{
614 int res;
615 int bitA = (value & 0x80000000) >> 31;
616 int notBitB = (value & 0x40000000) >> 30;
617 int bitB = (value & 0x20000000) >> 29;
618 int bSmear = (value & 0x3fc00000) >> 22;
619 int slice = (value & 0x003f0000) >> 16;
620 int zeroes = (value & 0x0000ffff);
621 if (zeroes != 0)
622 return -1;
623 if (bitB) {
buzbee03fa2632011-09-20 17:10:57 -0700624 if ((notBitB != 0) || (bSmear != 0xff))
buzbee67bf8852011-08-17 17:51:35 -0700625 return -1;
626 } else {
627 if ((notBitB != 1) || (bSmear != 0x0))
628 return -1;
629 }
630 res = (bitA << 7) | (bitB << 6) | slice;
631 return res;
632}
633
buzbeeed3e9302011-09-23 17:34:19 -0700634STATIC int encodeImmDouble(int valLo, int valHi)
buzbee67bf8852011-08-17 17:51:35 -0700635{
636 int res = -1;
637 if (valLo == 0)
638 res = encodeImmDoubleHigh(valHi);
639 return res;
640}
641
buzbeeed3e9302011-09-23 17:34:19 -0700642STATIC ArmLIR* loadConstantValueWide(CompilationUnit* cUnit, int rDestLo,
buzbee67bf8852011-08-17 17:51:35 -0700643 int rDestHi, int valLo, int valHi)
644{
645 int encodedImm = encodeImmDouble(valLo, valHi);
646 ArmLIR* res;
buzbee03fa2632011-09-20 17:10:57 -0700647 if (FPREG(rDestLo)) {
648 if (encodedImm >= 0) {
649 res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
650 encodedImm);
651 } else {
652 ArmLIR* dataTarget = scanLiteralPoolWide(cUnit->literalList, valLo,
653 valHi);
654 if (dataTarget == NULL) {
655 dataTarget = addWideData(cUnit, &cUnit->literalList, valLo,
656 valHi);
657 }
658 ArmLIR* loadPcRel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
659 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
660 loadPcRel->opcode = kThumb2Vldrd;
661 loadPcRel->generic.target = (LIR* ) dataTarget;
662 loadPcRel->operands[0] = S2D(rDestLo, rDestHi);
663 loadPcRel->operands[1] = r15pc;
664 setupResourceMasks(loadPcRel);
665 setMemRefType(loadPcRel, true, kLiteral);
buzbeebbaf8942011-10-02 13:08:29 -0700666 loadPcRel->aliasInfo = (intptr_t)dataTarget;
buzbee03fa2632011-09-20 17:10:57 -0700667 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
668 res = loadPcRel;
669 }
buzbee67bf8852011-08-17 17:51:35 -0700670 } else {
671 res = loadConstantNoClobber(cUnit, rDestLo, valLo);
672 loadConstantNoClobber(cUnit, rDestHi, valHi);
673 }
674 return res;
675}
676
buzbeeed3e9302011-09-23 17:34:19 -0700677STATIC int encodeShift(int code, int amount) {
buzbee67bf8852011-08-17 17:51:35 -0700678 return ((amount & 0x1f) << 2) | code;
679}
680
buzbeeed3e9302011-09-23 17:34:19 -0700681STATIC ArmLIR* loadBaseIndexed(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700682 int rIndex, int rDest, int scale, OpSize size)
683{
684 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
685 ArmLIR* load;
686 ArmOpcode opcode = kThumbBkpt;
687 bool thumbForm = (allLowRegs && (scale == 0));
688 int regPtr;
689
690 if (FPREG(rDest)) {
buzbeeed3e9302011-09-23 17:34:19 -0700691 DCHECK(SINGLEREG(rDest));
692 DCHECK((size == kWord) || (size == kSingle));
buzbee67bf8852011-08-17 17:51:35 -0700693 opcode = kThumb2Vldrs;
694 size = kSingle;
695 } else {
696 if (size == kSingle)
697 size = kWord;
698 }
699
700 switch (size) {
701 case kSingle:
702 regPtr = oatAllocTemp(cUnit);
703 if (scale) {
704 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
705 encodeShift(kArmLsl, scale));
706 } else {
707 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
708 }
709 load = newLIR3(cUnit, opcode, rDest, regPtr, 0);
710 return load;
711 case kWord:
712 opcode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
713 break;
714 case kUnsignedHalf:
715 opcode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
716 break;
717 case kSignedHalf:
718 opcode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
719 break;
720 case kUnsignedByte:
721 opcode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
722 break;
723 case kSignedByte:
724 opcode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
725 break;
726 default:
buzbeeed3e9302011-09-23 17:34:19 -0700727 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -0700728 }
729 if (thumbForm)
730 load = newLIR3(cUnit, opcode, rDest, rBase, rIndex);
731 else
732 load = newLIR4(cUnit, opcode, rDest, rBase, rIndex, scale);
733
734 return load;
735}
736
buzbeeed3e9302011-09-23 17:34:19 -0700737STATIC ArmLIR* storeBaseIndexed(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700738 int rIndex, int rSrc, int scale, OpSize size)
739{
740 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
741 ArmLIR* store;
742 ArmOpcode opcode = kThumbBkpt;
743 bool thumbForm = (allLowRegs && (scale == 0));
744 int regPtr;
745
746 if (FPREG(rSrc)) {
buzbeeed3e9302011-09-23 17:34:19 -0700747 DCHECK(SINGLEREG(rSrc));
748 DCHECK((size == kWord) || (size == kSingle));
buzbee67bf8852011-08-17 17:51:35 -0700749 opcode = kThumb2Vstrs;
750 size = kSingle;
751 } else {
752 if (size == kSingle)
753 size = kWord;
754 }
755
756 switch (size) {
757 case kSingle:
758 regPtr = oatAllocTemp(cUnit);
759 if (scale) {
760 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
761 encodeShift(kArmLsl, scale));
762 } else {
763 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
764 }
765 store = newLIR3(cUnit, opcode, rSrc, regPtr, 0);
766 return store;
767 case kWord:
768 opcode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
769 break;
770 case kUnsignedHalf:
771 case kSignedHalf:
772 opcode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
773 break;
774 case kUnsignedByte:
775 case kSignedByte:
776 opcode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
777 break;
778 default:
buzbeeed3e9302011-09-23 17:34:19 -0700779 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -0700780 }
781 if (thumbForm)
782 store = newLIR3(cUnit, opcode, rSrc, rBase, rIndex);
783 else
784 store = newLIR4(cUnit, opcode, rSrc, rBase, rIndex, scale);
785
786 return store;
787}
788
789/*
790 * Load value from base + displacement. Optionally perform null check
791 * on base (which must have an associated sReg and MIR). If not
792 * performing null check, incoming MIR can be null.
793 */
buzbeeed3e9302011-09-23 17:34:19 -0700794STATIC ArmLIR* loadBaseDispBody(CompilationUnit* cUnit, MIR* mir, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700795 int displacement, int rDest, int rDestHi,
796 OpSize size, int sReg)
797{
798 ArmLIR* res;
799 ArmLIR* load;
800 ArmOpcode opcode = kThumbBkpt;
801 bool shortForm = false;
802 bool thumb2Form = (displacement < 4092 && displacement >= 0);
803 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
804 int encodedDisp = displacement;
805
806 switch (size) {
807 case kDouble:
808 case kLong:
809 if (FPREG(rDest)) {
810 if (SINGLEREG(rDest)) {
buzbeeed3e9302011-09-23 17:34:19 -0700811 DCHECK(FPREG(rDestHi));
buzbee67bf8852011-08-17 17:51:35 -0700812 rDest = S2D(rDest, rDestHi);
813 }
814 opcode = kThumb2Vldrd;
815 if (displacement <= 1020) {
816 shortForm = true;
817 encodedDisp >>= 2;
818 }
819 break;
820 } else {
821 res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
822 -1, kWord, sReg);
823 loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
824 -1, kWord, INVALID_SREG);
825 return res;
826 }
827 case kSingle:
828 case kWord:
829 if (FPREG(rDest)) {
830 opcode = kThumb2Vldrs;
831 if (displacement <= 1020) {
832 shortForm = true;
833 encodedDisp >>= 2;
834 }
835 break;
836 }
837 if (LOWREG(rDest) && (rBase == r15pc) &&
838 (displacement <= 1020) && (displacement >= 0)) {
839 shortForm = true;
840 encodedDisp >>= 2;
841 opcode = kThumbLdrPcRel;
842 } else if (LOWREG(rDest) && (rBase == r13sp) &&
843 (displacement <= 1020) && (displacement >= 0)) {
844 shortForm = true;
845 encodedDisp >>= 2;
846 opcode = kThumbLdrSpRel;
847 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700848 DCHECK_EQ((displacement & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700849 shortForm = true;
850 encodedDisp >>= 2;
851 opcode = kThumbLdrRRI5;
852 } else if (thumb2Form) {
853 shortForm = true;
854 opcode = kThumb2LdrRRI12;
855 }
856 break;
857 case kUnsignedHalf:
858 if (allLowRegs && displacement < 64 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700859 DCHECK_EQ((displacement & 0x1), 0);
buzbee67bf8852011-08-17 17:51:35 -0700860 shortForm = true;
861 encodedDisp >>= 1;
862 opcode = kThumbLdrhRRI5;
863 } else if (displacement < 4092 && displacement >= 0) {
864 shortForm = true;
865 opcode = kThumb2LdrhRRI12;
866 }
867 break;
868 case kSignedHalf:
869 if (thumb2Form) {
870 shortForm = true;
871 opcode = kThumb2LdrshRRI12;
872 }
873 break;
874 case kUnsignedByte:
875 if (allLowRegs && displacement < 32 && displacement >= 0) {
876 shortForm = true;
877 opcode = kThumbLdrbRRI5;
878 } else if (thumb2Form) {
879 shortForm = true;
880 opcode = kThumb2LdrbRRI12;
881 }
882 break;
883 case kSignedByte:
884 if (thumb2Form) {
885 shortForm = true;
886 opcode = kThumb2LdrsbRRI12;
887 }
888 break;
889 default:
buzbeeed3e9302011-09-23 17:34:19 -0700890 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -0700891 }
892
893 if (shortForm) {
894 load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
895 } else {
896 int regOffset = oatAllocTemp(cUnit);
897 res = loadConstant(cUnit, regOffset, encodedDisp);
898 load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
899 oatFreeTemp(cUnit, regOffset);
900 }
901
902 // TODO: in future may need to differentiate Dalvik accesses w/ spills
903 if (rBase == rSP) {
904 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
905 }
906 return load;
907}
908
buzbeeed3e9302011-09-23 17:34:19 -0700909STATIC ArmLIR* loadBaseDisp(CompilationUnit* cUnit, MIR* mir, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700910 int displacement, int rDest, OpSize size,
911 int sReg)
912{
913 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
914 size, sReg);
915}
916
buzbeeed3e9302011-09-23 17:34:19 -0700917STATIC ArmLIR* loadBaseDispWide(CompilationUnit* cUnit, MIR* mir, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700918 int displacement, int rDestLo, int rDestHi,
919 int sReg)
920{
921 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
922 kLong, sReg);
923}
924
925
buzbeeed3e9302011-09-23 17:34:19 -0700926STATIC ArmLIR* storeBaseDispBody(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -0700927 int displacement, int rSrc, int rSrcHi,
928 OpSize size)
929{
930 ArmLIR* res, *store;
931 ArmOpcode opcode = kThumbBkpt;
932 bool shortForm = false;
933 bool thumb2Form = (displacement < 4092 && displacement >= 0);
934 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
935 int encodedDisp = displacement;
936
937 switch (size) {
938 case kLong:
939 case kDouble:
940 if (!FPREG(rSrc)) {
941 res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
942 -1, kWord);
943 storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
944 -1, kWord);
945 return res;
946 }
947 if (SINGLEREG(rSrc)) {
buzbeeed3e9302011-09-23 17:34:19 -0700948 DCHECK(FPREG(rSrcHi));
buzbee67bf8852011-08-17 17:51:35 -0700949 rSrc = S2D(rSrc, rSrcHi);
950 }
951 opcode = kThumb2Vstrd;
952 if (displacement <= 1020) {
953 shortForm = true;
954 encodedDisp >>= 2;
955 }
956 break;
957 case kSingle:
958 case kWord:
959 if (FPREG(rSrc)) {
buzbeeed3e9302011-09-23 17:34:19 -0700960 DCHECK(SINGLEREG(rSrc));
buzbee67bf8852011-08-17 17:51:35 -0700961 opcode = kThumb2Vstrs;
962 if (displacement <= 1020) {
963 shortForm = true;
964 encodedDisp >>= 2;
965 }
966 break;
967 }
968 if (allLowRegs && displacement < 128 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700969 DCHECK_EQ((displacement & 0x3), 0);
buzbee67bf8852011-08-17 17:51:35 -0700970 shortForm = true;
971 encodedDisp >>= 2;
972 opcode = kThumbStrRRI5;
973 } else if (thumb2Form) {
974 shortForm = true;
975 opcode = kThumb2StrRRI12;
976 }
977 break;
978 case kUnsignedHalf:
979 case kSignedHalf:
980 if (allLowRegs && displacement < 64 && displacement >= 0) {
buzbeeed3e9302011-09-23 17:34:19 -0700981 DCHECK_EQ((displacement & 0x1), 0);
buzbee67bf8852011-08-17 17:51:35 -0700982 shortForm = true;
983 encodedDisp >>= 1;
984 opcode = kThumbStrhRRI5;
985 } else if (thumb2Form) {
986 shortForm = true;
987 opcode = kThumb2StrhRRI12;
988 }
989 break;
990 case kUnsignedByte:
991 case kSignedByte:
992 if (allLowRegs && displacement < 32 && displacement >= 0) {
993 shortForm = true;
994 opcode = kThumbStrbRRI5;
995 } else if (thumb2Form) {
996 shortForm = true;
997 opcode = kThumb2StrbRRI12;
998 }
999 break;
1000 default:
buzbeeed3e9302011-09-23 17:34:19 -07001001 LOG(FATAL) << "Bad size: " << (int)size;
buzbee67bf8852011-08-17 17:51:35 -07001002 }
1003 if (shortForm) {
1004 store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
1005 } else {
1006 int rScratch = oatAllocTemp(cUnit);
1007 res = loadConstant(cUnit, rScratch, encodedDisp);
1008 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
1009 oatFreeTemp(cUnit, rScratch);
1010 }
1011
1012 // TODO: In future, may need to differentiate Dalvik & spill accesses
1013 if (rBase == rSP) {
1014 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
1015 }
1016 return res;
1017}
1018
buzbeeed3e9302011-09-23 17:34:19 -07001019STATIC ArmLIR* storeBaseDisp(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -07001020 int displacement, int rSrc, OpSize size)
1021{
1022 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
1023}
1024
buzbeeed3e9302011-09-23 17:34:19 -07001025STATIC ArmLIR* storeBaseDispWide(CompilationUnit* cUnit, int rBase,
buzbee67bf8852011-08-17 17:51:35 -07001026 int displacement, int rSrcLo, int rSrcHi)
1027{
1028 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
1029}
1030
buzbeeed3e9302011-09-23 17:34:19 -07001031STATIC void storePair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
buzbee67bf8852011-08-17 17:51:35 -07001032{
1033 storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
1034}
1035
buzbeeed3e9302011-09-23 17:34:19 -07001036STATIC void loadPair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
buzbee67bf8852011-08-17 17:51:35 -07001037{
1038 loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
1039}
1040
1041/*
1042 * Generate a register comparison to an immediate and branch. Caller
1043 * is responsible for setting branch target field.
1044 */
buzbeeed3e9302011-09-23 17:34:19 -07001045STATIC ArmLIR* genCmpImmBranch(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -07001046 ArmConditionCode cond, int reg,
1047 int checkValue)
1048{
1049 ArmLIR* branch;
1050 int modImm;
1051 if ((LOWREG(reg)) && (checkValue == 0) &&
1052 ((cond == kArmCondEq) || (cond == kArmCondNe))) {
1053 branch = newLIR2(cUnit,
1054 (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
1055 reg, 0);
1056 } else {
1057 modImm = modifiedImmediate(checkValue);
1058 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
1059 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
1060 } else if (modImm >= 0) {
1061 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
1062 } else {
1063 int tReg = oatAllocTemp(cUnit);
1064 loadConstant(cUnit, tReg, checkValue);
1065 opRegReg(cUnit, kOpCmp, reg, tReg);
1066 }
1067 branch = newLIR2(cUnit, kThumbBCond, 0, cond);
1068 }
1069 return branch;
1070}
1071
buzbeeed3e9302011-09-23 17:34:19 -07001072STATIC ArmLIR* fpRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -07001073{
1074 ArmLIR* res = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
1075 res->generic.dalvikOffset = cUnit->currentDalvikOffset;
1076 res->operands[0] = rDest;
1077 res->operands[1] = rSrc;
1078 if (rDest == rSrc) {
1079 res->flags.isNop = true;
1080 } else {
buzbeeed3e9302011-09-23 17:34:19 -07001081 DCHECK_EQ(DOUBLEREG(rDest), DOUBLEREG(rSrc));
buzbee67bf8852011-08-17 17:51:35 -07001082 if (DOUBLEREG(rDest)) {
1083 res->opcode = kThumb2Vmovd;
1084 } else {
1085 if (SINGLEREG(rDest)) {
1086 res->opcode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
1087 } else {
buzbeeed3e9302011-09-23 17:34:19 -07001088 DCHECK(SINGLEREG(rSrc));
buzbee67bf8852011-08-17 17:51:35 -07001089 res->opcode = kThumb2Fmrs;
1090 }
1091 }
1092 res->operands[0] = rDest;
1093 res->operands[1] = rSrc;
1094 }
1095 setupResourceMasks(res);
1096 return res;
1097}
1098
buzbeeed3e9302011-09-23 17:34:19 -07001099STATIC ArmLIR* genRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -07001100{
1101 ArmLIR* res;
1102 ArmOpcode opcode;
1103 if (FPREG(rDest) || FPREG(rSrc))
1104 return fpRegCopy(cUnit, rDest, rSrc);
1105 res = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
1106 res->generic.dalvikOffset = cUnit->currentDalvikOffset;
1107 if (LOWREG(rDest) && LOWREG(rSrc))
1108 opcode = kThumbMovRR;
1109 else if (!LOWREG(rDest) && !LOWREG(rSrc))
1110 opcode = kThumbMovRR_H2H;
1111 else if (LOWREG(rDest))
1112 opcode = kThumbMovRR_H2L;
1113 else
1114 opcode = kThumbMovRR_L2H;
1115
1116 res->operands[0] = rDest;
1117 res->operands[1] = rSrc;
1118 res->opcode = opcode;
1119 setupResourceMasks(res);
1120 if (rDest == rSrc) {
1121 res->flags.isNop = true;
1122 }
1123 return res;
1124}
1125
buzbeeed3e9302011-09-23 17:34:19 -07001126STATIC ArmLIR* genRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
buzbee67bf8852011-08-17 17:51:35 -07001127{
1128 ArmLIR* res = genRegCopyNoInsert(cUnit, rDest, rSrc);
1129 oatAppendLIR(cUnit, (LIR*)res);
1130 return res;
1131}
1132
buzbeeed3e9302011-09-23 17:34:19 -07001133STATIC void genRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
buzbee67bf8852011-08-17 17:51:35 -07001134 int srcLo, int srcHi)
1135{
1136 bool destFP = FPREG(destLo) && FPREG(destHi);
1137 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
buzbeeed3e9302011-09-23 17:34:19 -07001138 DCHECK_EQ(FPREG(srcLo), FPREG(srcHi));
1139 DCHECK_EQ(FPREG(destLo), FPREG(destHi));
buzbee67bf8852011-08-17 17:51:35 -07001140 if (destFP) {
1141 if (srcFP) {
1142 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
1143 } else {
1144 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
1145 }
1146 } else {
1147 if (srcFP) {
1148 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
1149 } else {
1150 // Handle overlap
1151 if (srcHi == destLo) {
1152 genRegCopy(cUnit, destHi, srcHi);
1153 genRegCopy(cUnit, destLo, srcLo);
1154 } else {
1155 genRegCopy(cUnit, destLo, srcLo);
1156 genRegCopy(cUnit, destHi, srcHi);
1157 }
1158 }
1159 }
1160}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001161
1162} // namespace art