blob: b3f3a41fcece7aafb528be640f281634d40c4b87 [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
17/*
18 * This file contains codegen for the Thumb ISA and is intended to be
19 * includes by:
20 *
21 * Codegen-$(TARGET_ARCH_VARIANT).c
22 *
23 */
24
25static int coreRegs[] = {r0, r1, r2, r3, r4, r5, r6, r7, rSELF, r8, r10, r11,
26 r12, rSP, rLR, rPC};
27static int reservedRegs[] = {rSELF, rSP, rLR, rPC};
28static int fpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
29 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
30 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
31 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
32static int coreTemps[] = {r0, r1, r2, r3, r12};
33static int fpTemps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
34 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
35
36static int encodeImmSingle(int value)
37{
38 int res;
39 int bitA = (value & 0x80000000) >> 31;
40 int notBitB = (value & 0x40000000) >> 30;
41 int bitB = (value & 0x20000000) >> 29;
42 int bSmear = (value & 0x3e000000) >> 25;
43 int slice = (value & 0x01f80000) >> 19;
44 int zeroes = (value & 0x0007ffff);
45 if (zeroes != 0)
46 return -1;
47 if (bitB) {
48 if ((notBitB != 0) || (bSmear != 0x1f))
49 return -1;
50 } else {
51 if ((notBitB != 1) || (bSmear != 0x0))
52 return -1;
53 }
54 res = (bitA << 7) | (bitB << 6) | slice;
55 return res;
56}
57
58static ArmLIR* loadFPConstantValue(CompilationUnit* cUnit, int rDest,
59 int value)
60{
61 int encodedImm = encodeImmSingle(value);
62 assert(SINGLEREG(rDest));
63 if (encodedImm >= 0) {
64 return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
65 }
66 ArmLIR* dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
67 if (dataTarget == NULL) {
68 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
69 }
70 ArmLIR* loadPcRel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
71 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
72 loadPcRel->opcode = kThumb2Vldrs;
73 loadPcRel->generic.target = (LIR* ) dataTarget;
74 loadPcRel->operands[0] = rDest;
75 loadPcRel->operands[1] = r15pc;
76 setupResourceMasks(loadPcRel);
77 setMemRefType(loadPcRel, true, kLiteral);
78 loadPcRel->aliasInfo = dataTarget->operands[0];
79 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
80 return loadPcRel;
81}
82
83static int leadingZeros(u4 val)
84{
85 u4 alt;
86 int n;
87 int count;
88
89 count = 16;
90 n = 32;
91 do {
92 alt = val >> count;
93 if (alt != 0) {
94 n = n - count;
95 val = alt;
96 }
97 count >>= 1;
98 } while (count);
99 return n - val;
100}
101
102/*
103 * Determine whether value can be encoded as a Thumb2 modified
104 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
105 */
106static int modifiedImmediate(u4 value)
107{
108 int zLeading;
109 int zTrailing;
110 u4 b0 = value & 0xff;
111
112 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
113 if (value <= 0xFF)
114 return b0; // 0:000:a:bcdefgh
115 if (value == ((b0 << 16) | b0))
116 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
117 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
118 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
119 b0 = (value >> 8) & 0xff;
120 if (value == ((b0 << 24) | (b0 << 8)))
121 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
122 /* Can we do it with rotation? */
123 zLeading = leadingZeros(value);
124 zTrailing = 32 - leadingZeros(~value & (value - 1));
125 /* A run of eight or fewer active bits? */
126 if ((zLeading + zTrailing) < 24)
127 return -1; /* No - bail */
128 /* left-justify the constant, discarding msb (known to be 1) */
129 value <<= zLeading + 1;
130 /* Create bcdefgh */
131 value >>= 25;
132 /* Put it all together */
133 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
134}
135
136/*
137 * Load a immediate using a shortcut if possible; otherwise
138 * grab from the per-translation literal pool.
139 *
140 * No additional register clobbering operation performed. Use this version when
141 * 1) rDest is freshly returned from oatAllocTemp or
142 * 2) The codegen is under fixed register usage
143 */
144static ArmLIR* loadConstantNoClobber(CompilationUnit* cUnit, int rDest,
145 int value)
146{
147 ArmLIR* res;
148 int modImm;
149
150 if (FPREG(rDest)) {
151 return loadFPConstantValue(cUnit, rDest, value);
152 }
153
154 /* See if the value can be constructed cheaply */
155 if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
156 return newLIR2(cUnit, kThumbMovImm, rDest, value);
157 }
158 /* Check Modified immediate special cases */
159 modImm = modifiedImmediate(value);
160 if (modImm >= 0) {
161 res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
162 return res;
163 }
164 modImm = modifiedImmediate(~value);
165 if (modImm >= 0) {
166 res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
167 return res;
168 }
169 /* 16-bit immediate? */
170 if ((value & 0xffff) == value) {
171 res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
172 return res;
173 }
174 /* No shortcut - go ahead and use literal pool */
175 ArmLIR* dataTarget = scanLiteralPool(cUnit->literalList, value, 0);
176 if (dataTarget == NULL) {
177 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
178 }
179 ArmLIR* loadPcRel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
180 loadPcRel->opcode = kThumb2LdrPcRel12;
181 loadPcRel->generic.target = (LIR* ) dataTarget;
182 loadPcRel->generic.dalvikOffset = cUnit->currentDalvikOffset;
183 loadPcRel->operands[0] = rDest;
184 setupResourceMasks(loadPcRel);
185 setMemRefType(loadPcRel, true, kLiteral);
186 loadPcRel->aliasInfo = dataTarget->operands[0];
187 res = loadPcRel;
188 oatAppendLIR(cUnit, (LIR* ) loadPcRel);
189
190 /*
191 * To save space in the constant pool, we use the ADD_RRI8 instruction to
192 * add up to 255 to an existing constant value.
193 */
194 if (dataTarget->operands[0] != value) {
195 opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
196 }
197 return res;
198}
199
200/*
201 * Load an immediate value into a fixed or temp register. Target
202 * register is clobbered, and marked inUse.
203 */
204static ArmLIR* loadConstant(CompilationUnit* cUnit, int rDest, int value)
205{
206 if (oatIsTemp(cUnit, rDest)) {
207 oatClobber(cUnit, rDest);
208 oatMarkInUse(cUnit, rDest);
209 }
210 return loadConstantNoClobber(cUnit, rDest, value);
211}
212
213static ArmLIR* opNone(CompilationUnit* cUnit, OpKind op)
214{
215 ArmOpcode opcode = kThumbBkpt;
216 switch (op) {
217 case kOpUncondBr:
218 opcode = kThumbBUncond;
219 break;
220 default:
221 assert(0);
222 }
223 return newLIR0(cUnit, opcode);
224}
225
226static ArmLIR* opCondBranch(CompilationUnit* cUnit, ArmConditionCode cc)
227{
228 return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc);
229}
230
231static ArmLIR* opReg(CompilationUnit* cUnit, OpKind op, int rDestSrc)
232{
233 ArmOpcode opcode = kThumbBkpt;
234 switch (op) {
235 case kOpBlx:
236 opcode = kThumbBlxR;
237 break;
238 default:
239 assert(0);
240 }
241 return newLIR1(cUnit, opcode, rDestSrc);
242}
243
244static ArmLIR* opRegRegShift(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
245 int rSrc2, int shift)
246{
247 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
248 ArmOpcode opcode = kThumbBkpt;
249 switch (op) {
250 case kOpAdc:
251 opcode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
252 break;
253 case kOpAnd:
254 opcode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
255 break;
256 case kOpBic:
257 opcode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
258 break;
259 case kOpCmn:
260 assert(shift == 0);
261 opcode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
262 break;
263 case kOpCmp:
264 if (thumbForm)
265 opcode = kThumbCmpRR;
266 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
267 opcode = kThumbCmpHH;
268 else if ((shift == 0) && LOWREG(rDestSrc1))
269 opcode = kThumbCmpLH;
270 else if (shift == 0)
271 opcode = kThumbCmpHL;
272 else
273 opcode = kThumb2CmpRR;
274 break;
275 case kOpXor:
276 opcode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
277 break;
278 case kOpMov:
279 assert(shift == 0);
280 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
281 opcode = kThumbMovRR;
282 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
283 opcode = kThumbMovRR_H2H;
284 else if (LOWREG(rDestSrc1))
285 opcode = kThumbMovRR_H2L;
286 else
287 opcode = kThumbMovRR_L2H;
288 break;
289 case kOpMul:
290 assert(shift == 0);
291 opcode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
292 break;
293 case kOpMvn:
294 opcode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
295 break;
296 case kOpNeg:
297 assert(shift == 0);
298 opcode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
299 break;
300 case kOpOr:
301 opcode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
302 break;
303 case kOpSbc:
304 opcode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
305 break;
306 case kOpTst:
307 opcode = (thumbForm) ? kThumbTst : kThumb2TstRR;
308 break;
309 case kOpLsl:
310 assert(shift == 0);
311 opcode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
312 break;
313 case kOpLsr:
314 assert(shift == 0);
315 opcode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
316 break;
317 case kOpAsr:
318 assert(shift == 0);
319 opcode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
320 break;
321 case kOpRor:
322 assert(shift == 0);
323 opcode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
324 break;
325 case kOpAdd:
326 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
327 break;
328 case kOpSub:
329 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
330 break;
331 case kOp2Byte:
332 assert(shift == 0);
333 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
334 case kOp2Short:
335 assert(shift == 0);
336 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
337 case kOp2Char:
338 assert(shift == 0);
339 return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
340 default:
341 assert(0);
342 break;
343 }
344 assert(opcode >= 0);
345 if (EncodingMap[opcode].flags & IS_BINARY_OP)
346 return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
347 else if (EncodingMap[opcode].flags & IS_TERTIARY_OP) {
348 if (EncodingMap[opcode].fieldLoc[2].kind == kFmtShift)
349 return newLIR3(cUnit, opcode, rDestSrc1, rSrc2, shift);
350 else
351 return newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2);
352 } else if (EncodingMap[opcode].flags & IS_QUAD_OP)
353 return newLIR4(cUnit, opcode, rDestSrc1, rDestSrc1, rSrc2, shift);
354 else {
355 assert(0);
356 return NULL;
357 }
358}
359
360static ArmLIR* opRegReg(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
361 int rSrc2)
362{
363 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
364}
365
366static ArmLIR* opRegRegRegShift(CompilationUnit* cUnit, OpKind op,
367 int rDest, int rSrc1, int rSrc2, int shift)
368{
369 ArmOpcode opcode = kThumbBkpt;
370 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
371 LOWREG(rSrc2);
372 switch (op) {
373 case kOpAdd:
374 opcode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
375 break;
376 case kOpSub:
377 opcode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
378 break;
379 case kOpAdc:
380 opcode = kThumb2AdcRRR;
381 break;
382 case kOpAnd:
383 opcode = kThumb2AndRRR;
384 break;
385 case kOpBic:
386 opcode = kThumb2BicRRR;
387 break;
388 case kOpXor:
389 opcode = kThumb2EorRRR;
390 break;
391 case kOpMul:
392 assert(shift == 0);
393 opcode = kThumb2MulRRR;
394 break;
395 case kOpOr:
396 opcode = kThumb2OrrRRR;
397 break;
398 case kOpSbc:
399 opcode = kThumb2SbcRRR;
400 break;
401 case kOpLsl:
402 assert(shift == 0);
403 opcode = kThumb2LslRRR;
404 break;
405 case kOpLsr:
406 assert(shift == 0);
407 opcode = kThumb2LsrRRR;
408 break;
409 case kOpAsr:
410 assert(shift == 0);
411 opcode = kThumb2AsrRRR;
412 break;
413 case kOpRor:
414 assert(shift == 0);
415 opcode = kThumb2RorRRR;
416 break;
417 default:
418 assert(0);
419 break;
420 }
421 assert(opcode >= 0);
422 if (EncodingMap[opcode].flags & IS_QUAD_OP)
423 return newLIR4(cUnit, opcode, rDest, rSrc1, rSrc2, shift);
424 else {
425 assert(EncodingMap[opcode].flags & IS_TERTIARY_OP);
426 return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
427 }
428}
429
430static ArmLIR* opRegRegReg(CompilationUnit* cUnit, OpKind op, int rDest,
431 int rSrc1, int rSrc2)
432{
433 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
434}
435
436static ArmLIR* opRegRegImm(CompilationUnit* cUnit, OpKind op, int rDest,
437 int rSrc1, int value)
438{
439 ArmLIR* res;
440 bool neg = (value < 0);
441 int absValue = (neg) ? -value : value;
442 ArmOpcode opcode = kThumbBkpt;
443 ArmOpcode altOpcode = kThumbBkpt;
444 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
445 int modImm = modifiedImmediate(value);
446 int modImmNeg = modifiedImmediate(-value);
447
448 switch(op) {
449 case kOpLsl:
450 if (allLowRegs)
451 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
452 else
453 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
454 case kOpLsr:
455 if (allLowRegs)
456 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
457 else
458 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
459 case kOpAsr:
460 if (allLowRegs)
461 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
462 else
463 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
464 case kOpRor:
465 return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
466 case kOpAdd:
467 if (LOWREG(rDest) && (rSrc1 == r13sp) &&
468 (value <= 1020) && ((value & 0x3)==0)) {
469 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
470 value >> 2);
471 } else if (LOWREG(rDest) && (rSrc1 == r15pc) &&
472 (value <= 1020) && ((value & 0x3)==0)) {
473 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
474 value >> 2);
475 }
476 opcode = kThumb2AddRRI8;
477 altOpcode = kThumb2AddRRR;
478 // 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;
500 }
501 break;
502 case kOpAdc:
503 opcode = kThumb2AdcRRI8;
504 altOpcode = kThumb2AdcRRR;
505 break;
506 case kOpSbc:
507 opcode = kThumb2SbcRRI8;
508 altOpcode = kThumb2SbcRRR;
509 break;
510 case kOpOr:
511 opcode = kThumb2OrrRRI8;
512 altOpcode = kThumb2OrrRRR;
513 break;
514 case kOpAnd:
515 opcode = kThumb2AndRRI8;
516 altOpcode = kThumb2AndRRR;
517 break;
518 case kOpXor:
519 opcode = kThumb2EorRRI8;
520 altOpcode = kThumb2EorRRR;
521 break;
522 case kOpMul:
523 //TUNING: power of 2, shift & add
524 modImm = -1;
525 altOpcode = kThumb2MulRRR;
526 break;
527 case kOpCmp: {
528 int modImm = modifiedImmediate(value);
529 ArmLIR* res;
530 if (modImm >= 0) {
531 res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
532 } else {
533 int rTmp = oatAllocTemp(cUnit);
534 res = loadConstant(cUnit, rTmp, value);
535 opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
536 oatFreeTemp(cUnit, rTmp);
537 }
538 return res;
539 }
540 default:
541 assert(0);
542 }
543
544 if (modImm >= 0) {
545 return newLIR3(cUnit, opcode, rDest, rSrc1, modImm);
546 } else {
547 int rScratch = oatAllocTemp(cUnit);
548 loadConstant(cUnit, rScratch, value);
549 if (EncodingMap[altOpcode].flags & IS_QUAD_OP)
550 res = newLIR4(cUnit, altOpcode, rDest, rSrc1, rScratch, 0);
551 else
552 res = newLIR3(cUnit, altOpcode, rDest, rSrc1, rScratch);
553 oatFreeTemp(cUnit, rScratch);
554 return res;
555 }
556}
557
558/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
559static ArmLIR* opRegImm(CompilationUnit* cUnit, OpKind op, int rDestSrc1,
560 int value)
561{
562 bool neg = (value < 0);
563 int absValue = (neg) ? -value : value;
564 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
565 ArmOpcode opcode = kThumbBkpt;
566 switch (op) {
567 case kOpAdd:
568 if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
569 assert((value & 0x3) == 0);
570 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
571 } else if (shortForm) {
572 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
573 }
574 break;
575 case kOpSub:
576 if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
577 assert((value & 0x3) == 0);
578 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
579 } else if (shortForm) {
580 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
581 }
582 break;
583 case kOpCmp:
584 if (LOWREG(rDestSrc1) && shortForm)
585 opcode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR;
586 else if (LOWREG(rDestSrc1))
587 opcode = kThumbCmpRR;
588 else {
589 shortForm = false;
590 opcode = kThumbCmpHL;
591 }
592 break;
593 default:
594 /* Punt to opRegRegImm - if bad case catch it there */
595 shortForm = false;
596 break;
597 }
598 if (shortForm)
599 return newLIR2(cUnit, opcode, rDestSrc1, absValue);
600 else {
601 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
602 }
603}
604
605/*
606 * Determine whether value can be encoded as a Thumb2 floating point
607 * immediate. If not, return -1. If so return encoded 8-bit value.
608 */
609static int encodeImmDoubleHigh(int value)
610{
611 int res;
612 int bitA = (value & 0x80000000) >> 31;
613 int notBitB = (value & 0x40000000) >> 30;
614 int bitB = (value & 0x20000000) >> 29;
615 int bSmear = (value & 0x3fc00000) >> 22;
616 int slice = (value & 0x003f0000) >> 16;
617 int zeroes = (value & 0x0000ffff);
618 if (zeroes != 0)
619 return -1;
620 if (bitB) {
621 if ((notBitB != 0) || (bSmear != 0x1f))
622 return -1;
623 } else {
624 if ((notBitB != 1) || (bSmear != 0x0))
625 return -1;
626 }
627 res = (bitA << 7) | (bitB << 6) | slice;
628 return res;
629}
630
631static int encodeImmDouble(int valLo, int valHi)
632{
633 int res = -1;
634 if (valLo == 0)
635 res = encodeImmDoubleHigh(valHi);
636 return res;
637}
638
639static ArmLIR* loadConstantValueWide(CompilationUnit* cUnit, int rDestLo,
640 int rDestHi, int valLo, int valHi)
641{
642 int encodedImm = encodeImmDouble(valLo, valHi);
643 ArmLIR* res;
644 if (FPREG(rDestLo) && (encodedImm >= 0)) {
645 res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
646 encodedImm);
647 } else {
648 res = loadConstantNoClobber(cUnit, rDestLo, valLo);
649 loadConstantNoClobber(cUnit, rDestHi, valHi);
650 }
651 return res;
652}
653
654static int encodeShift(int code, int amount) {
655 return ((amount & 0x1f) << 2) | code;
656}
657
658static ArmLIR* loadBaseIndexed(CompilationUnit* cUnit, int rBase,
659 int rIndex, int rDest, int scale, OpSize size)
660{
661 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
662 ArmLIR* load;
663 ArmOpcode opcode = kThumbBkpt;
664 bool thumbForm = (allLowRegs && (scale == 0));
665 int regPtr;
666
667 if (FPREG(rDest)) {
668 assert(SINGLEREG(rDest));
669 assert((size == kWord) || (size == kSingle));
670 opcode = kThumb2Vldrs;
671 size = kSingle;
672 } else {
673 if (size == kSingle)
674 size = kWord;
675 }
676
677 switch (size) {
678 case kSingle:
679 regPtr = oatAllocTemp(cUnit);
680 if (scale) {
681 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
682 encodeShift(kArmLsl, scale));
683 } else {
684 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
685 }
686 load = newLIR3(cUnit, opcode, rDest, regPtr, 0);
687 return load;
688 case kWord:
689 opcode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
690 break;
691 case kUnsignedHalf:
692 opcode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
693 break;
694 case kSignedHalf:
695 opcode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
696 break;
697 case kUnsignedByte:
698 opcode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
699 break;
700 case kSignedByte:
701 opcode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
702 break;
703 default:
704 assert(0);
705 }
706 if (thumbForm)
707 load = newLIR3(cUnit, opcode, rDest, rBase, rIndex);
708 else
709 load = newLIR4(cUnit, opcode, rDest, rBase, rIndex, scale);
710
711 return load;
712}
713
714static ArmLIR* storeBaseIndexed(CompilationUnit* cUnit, int rBase,
715 int rIndex, int rSrc, int scale, OpSize size)
716{
717 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
718 ArmLIR* store;
719 ArmOpcode opcode = kThumbBkpt;
720 bool thumbForm = (allLowRegs && (scale == 0));
721 int regPtr;
722
723 if (FPREG(rSrc)) {
724 assert(SINGLEREG(rSrc));
725 assert((size == kWord) || (size == kSingle));
726 opcode = kThumb2Vstrs;
727 size = kSingle;
728 } else {
729 if (size == kSingle)
730 size = kWord;
731 }
732
733 switch (size) {
734 case kSingle:
735 regPtr = oatAllocTemp(cUnit);
736 if (scale) {
737 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
738 encodeShift(kArmLsl, scale));
739 } else {
740 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
741 }
742 store = newLIR3(cUnit, opcode, rSrc, regPtr, 0);
743 return store;
744 case kWord:
745 opcode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
746 break;
747 case kUnsignedHalf:
748 case kSignedHalf:
749 opcode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
750 break;
751 case kUnsignedByte:
752 case kSignedByte:
753 opcode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
754 break;
755 default:
756 assert(0);
757 }
758 if (thumbForm)
759 store = newLIR3(cUnit, opcode, rSrc, rBase, rIndex);
760 else
761 store = newLIR4(cUnit, opcode, rSrc, rBase, rIndex, scale);
762
763 return store;
764}
765
766/*
767 * Load value from base + displacement. Optionally perform null check
768 * on base (which must have an associated sReg and MIR). If not
769 * performing null check, incoming MIR can be null.
770 */
771static ArmLIR* loadBaseDispBody(CompilationUnit* cUnit, MIR* mir, int rBase,
772 int displacement, int rDest, int rDestHi,
773 OpSize size, int sReg)
774{
775 ArmLIR* res;
776 ArmLIR* load;
777 ArmOpcode opcode = kThumbBkpt;
778 bool shortForm = false;
779 bool thumb2Form = (displacement < 4092 && displacement >= 0);
780 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
781 int encodedDisp = displacement;
782
783 switch (size) {
784 case kDouble:
785 case kLong:
786 if (FPREG(rDest)) {
787 if (SINGLEREG(rDest)) {
788 assert(FPREG(rDestHi));
789 rDest = S2D(rDest, rDestHi);
790 }
791 opcode = kThumb2Vldrd;
792 if (displacement <= 1020) {
793 shortForm = true;
794 encodedDisp >>= 2;
795 }
796 break;
797 } else {
798 res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
799 -1, kWord, sReg);
800 loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
801 -1, kWord, INVALID_SREG);
802 return res;
803 }
804 case kSingle:
805 case kWord:
806 if (FPREG(rDest)) {
807 opcode = kThumb2Vldrs;
808 if (displacement <= 1020) {
809 shortForm = true;
810 encodedDisp >>= 2;
811 }
812 break;
813 }
814 if (LOWREG(rDest) && (rBase == r15pc) &&
815 (displacement <= 1020) && (displacement >= 0)) {
816 shortForm = true;
817 encodedDisp >>= 2;
818 opcode = kThumbLdrPcRel;
819 } else if (LOWREG(rDest) && (rBase == r13sp) &&
820 (displacement <= 1020) && (displacement >= 0)) {
821 shortForm = true;
822 encodedDisp >>= 2;
823 opcode = kThumbLdrSpRel;
824 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
825 assert((displacement & 0x3) == 0);
826 shortForm = true;
827 encodedDisp >>= 2;
828 opcode = kThumbLdrRRI5;
829 } else if (thumb2Form) {
830 shortForm = true;
831 opcode = kThumb2LdrRRI12;
832 }
833 break;
834 case kUnsignedHalf:
835 if (allLowRegs && displacement < 64 && displacement >= 0) {
836 assert((displacement & 0x1) == 0);
837 shortForm = true;
838 encodedDisp >>= 1;
839 opcode = kThumbLdrhRRI5;
840 } else if (displacement < 4092 && displacement >= 0) {
841 shortForm = true;
842 opcode = kThumb2LdrhRRI12;
843 }
844 break;
845 case kSignedHalf:
846 if (thumb2Form) {
847 shortForm = true;
848 opcode = kThumb2LdrshRRI12;
849 }
850 break;
851 case kUnsignedByte:
852 if (allLowRegs && displacement < 32 && displacement >= 0) {
853 shortForm = true;
854 opcode = kThumbLdrbRRI5;
855 } else if (thumb2Form) {
856 shortForm = true;
857 opcode = kThumb2LdrbRRI12;
858 }
859 break;
860 case kSignedByte:
861 if (thumb2Form) {
862 shortForm = true;
863 opcode = kThumb2LdrsbRRI12;
864 }
865 break;
866 default:
867 assert(0);
868 }
869
870 if (shortForm) {
871 load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
872 } else {
873 int regOffset = oatAllocTemp(cUnit);
874 res = loadConstant(cUnit, regOffset, encodedDisp);
875 load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
876 oatFreeTemp(cUnit, regOffset);
877 }
878
879 // TODO: in future may need to differentiate Dalvik accesses w/ spills
880 if (rBase == rSP) {
881 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
882 }
883 return load;
884}
885
886static ArmLIR* loadBaseDisp(CompilationUnit* cUnit, MIR* mir, int rBase,
887 int displacement, int rDest, OpSize size,
888 int sReg)
889{
890 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
891 size, sReg);
892}
893
894static ArmLIR* loadBaseDispWide(CompilationUnit* cUnit, MIR* mir, int rBase,
895 int displacement, int rDestLo, int rDestHi,
896 int sReg)
897{
898 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
899 kLong, sReg);
900}
901
902
903static ArmLIR* storeBaseDispBody(CompilationUnit* cUnit, int rBase,
904 int displacement, int rSrc, int rSrcHi,
905 OpSize size)
906{
907 ArmLIR* res, *store;
908 ArmOpcode opcode = kThumbBkpt;
909 bool shortForm = false;
910 bool thumb2Form = (displacement < 4092 && displacement >= 0);
911 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
912 int encodedDisp = displacement;
913
914 switch (size) {
915 case kLong:
916 case kDouble:
917 if (!FPREG(rSrc)) {
918 res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
919 -1, kWord);
920 storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
921 -1, kWord);
922 return res;
923 }
924 if (SINGLEREG(rSrc)) {
925 assert(FPREG(rSrcHi));
926 rSrc = S2D(rSrc, rSrcHi);
927 }
928 opcode = kThumb2Vstrd;
929 if (displacement <= 1020) {
930 shortForm = true;
931 encodedDisp >>= 2;
932 }
933 break;
934 case kSingle:
935 case kWord:
936 if (FPREG(rSrc)) {
937 assert(SINGLEREG(rSrc));
938 opcode = kThumb2Vstrs;
939 if (displacement <= 1020) {
940 shortForm = true;
941 encodedDisp >>= 2;
942 }
943 break;
944 }
945 if (allLowRegs && displacement < 128 && displacement >= 0) {
946 assert((displacement & 0x3) == 0);
947 shortForm = true;
948 encodedDisp >>= 2;
949 opcode = kThumbStrRRI5;
950 } else if (thumb2Form) {
951 shortForm = true;
952 opcode = kThumb2StrRRI12;
953 }
954 break;
955 case kUnsignedHalf:
956 case kSignedHalf:
957 if (allLowRegs && displacement < 64 && displacement >= 0) {
958 assert((displacement & 0x1) == 0);
959 shortForm = true;
960 encodedDisp >>= 1;
961 opcode = kThumbStrhRRI5;
962 } else if (thumb2Form) {
963 shortForm = true;
964 opcode = kThumb2StrhRRI12;
965 }
966 break;
967 case kUnsignedByte:
968 case kSignedByte:
969 if (allLowRegs && displacement < 32 && displacement >= 0) {
970 shortForm = true;
971 opcode = kThumbStrbRRI5;
972 } else if (thumb2Form) {
973 shortForm = true;
974 opcode = kThumb2StrbRRI12;
975 }
976 break;
977 default:
978 assert(0);
979 }
980 if (shortForm) {
981 store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
982 } else {
983 int rScratch = oatAllocTemp(cUnit);
984 res = loadConstant(cUnit, rScratch, encodedDisp);
985 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
986 oatFreeTemp(cUnit, rScratch);
987 }
988
989 // TODO: In future, may need to differentiate Dalvik & spill accesses
990 if (rBase == rSP) {
991 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
992 }
993 return res;
994}
995
996static ArmLIR* storeBaseDisp(CompilationUnit* cUnit, int rBase,
997 int displacement, int rSrc, OpSize size)
998{
999 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
1000}
1001
1002static ArmLIR* storeBaseDispWide(CompilationUnit* cUnit, int rBase,
1003 int displacement, int rSrcLo, int rSrcHi)
1004{
1005 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
1006}
1007
1008static void storePair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
1009{
1010 storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
1011}
1012
1013static void loadPair(CompilationUnit* cUnit, int base, int lowReg, int highReg)
1014{
1015 loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
1016}
1017
1018/*
1019 * Generate a register comparison to an immediate and branch. Caller
1020 * is responsible for setting branch target field.
1021 */
1022static ArmLIR* genCmpImmBranch(CompilationUnit* cUnit,
1023 ArmConditionCode cond, int reg,
1024 int checkValue)
1025{
1026 ArmLIR* branch;
1027 int modImm;
1028 if ((LOWREG(reg)) && (checkValue == 0) &&
1029 ((cond == kArmCondEq) || (cond == kArmCondNe))) {
1030 branch = newLIR2(cUnit,
1031 (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
1032 reg, 0);
1033 } else {
1034 modImm = modifiedImmediate(checkValue);
1035 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
1036 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
1037 } else if (modImm >= 0) {
1038 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
1039 } else {
1040 int tReg = oatAllocTemp(cUnit);
1041 loadConstant(cUnit, tReg, checkValue);
1042 opRegReg(cUnit, kOpCmp, reg, tReg);
1043 }
1044 branch = newLIR2(cUnit, kThumbBCond, 0, cond);
1045 }
1046 return branch;
1047}
1048
1049static ArmLIR* fpRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1050{
1051 ArmLIR* res = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
1052 res->generic.dalvikOffset = cUnit->currentDalvikOffset;
1053 res->operands[0] = rDest;
1054 res->operands[1] = rSrc;
1055 if (rDest == rSrc) {
1056 res->flags.isNop = true;
1057 } else {
1058 assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
1059 if (DOUBLEREG(rDest)) {
1060 res->opcode = kThumb2Vmovd;
1061 } else {
1062 if (SINGLEREG(rDest)) {
1063 res->opcode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
1064 } else {
1065 assert(SINGLEREG(rSrc));
1066 res->opcode = kThumb2Fmrs;
1067 }
1068 }
1069 res->operands[0] = rDest;
1070 res->operands[1] = rSrc;
1071 }
1072 setupResourceMasks(res);
1073 return res;
1074}
1075
1076static ArmLIR* genRegCopyNoInsert(CompilationUnit* cUnit, int rDest, int rSrc)
1077{
1078 ArmLIR* res;
1079 ArmOpcode opcode;
1080 if (FPREG(rDest) || FPREG(rSrc))
1081 return fpRegCopy(cUnit, rDest, rSrc);
1082 res = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
1083 res->generic.dalvikOffset = cUnit->currentDalvikOffset;
1084 if (LOWREG(rDest) && LOWREG(rSrc))
1085 opcode = kThumbMovRR;
1086 else if (!LOWREG(rDest) && !LOWREG(rSrc))
1087 opcode = kThumbMovRR_H2H;
1088 else if (LOWREG(rDest))
1089 opcode = kThumbMovRR_H2L;
1090 else
1091 opcode = kThumbMovRR_L2H;
1092
1093 res->operands[0] = rDest;
1094 res->operands[1] = rSrc;
1095 res->opcode = opcode;
1096 setupResourceMasks(res);
1097 if (rDest == rSrc) {
1098 res->flags.isNop = true;
1099 }
1100 return res;
1101}
1102
1103static ArmLIR* genRegCopy(CompilationUnit* cUnit, int rDest, int rSrc)
1104{
1105 ArmLIR* res = genRegCopyNoInsert(cUnit, rDest, rSrc);
1106 oatAppendLIR(cUnit, (LIR*)res);
1107 return res;
1108}
1109
1110static void genRegCopyWide(CompilationUnit* cUnit, int destLo, int destHi,
1111 int srcLo, int srcHi)
1112{
1113 bool destFP = FPREG(destLo) && FPREG(destHi);
1114 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
1115 assert(FPREG(srcLo) == FPREG(srcHi));
1116 assert(FPREG(destLo) == FPREG(destHi));
1117 if (destFP) {
1118 if (srcFP) {
1119 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
1120 } else {
1121 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
1122 }
1123 } else {
1124 if (srcFP) {
1125 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
1126 } else {
1127 // Handle overlap
1128 if (srcHi == destLo) {
1129 genRegCopy(cUnit, destHi, srcHi);
1130 genRegCopy(cUnit, destLo, srcLo);
1131 } else {
1132 genRegCopy(cUnit, destLo, srcLo);
1133 genRegCopy(cUnit, destHi, srcHi);
1134 }
1135 }
1136 }
1137}