1 /*
2 * Copyright (C) 2009 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
25 static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
26
27 static void storePair(CompilationUnit *cUnit, int base, int lowReg,
28 int highReg);
29 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
30 static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
31 int rDest);
32 static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
33 int displacement, int rSrc);
34 static ArmLIR *genRegRegCheck(CompilationUnit *cUnit,
35 ArmConditionCode cond,
36 int reg1, int reg2, int dOffset,
37 ArmLIR *pcrLabel);
38
39
40 /*
41 * Load a immediate using a shortcut if possible; otherwise
42 * grab from the per-translation literal pool. If target is
43 * a high register, build constant into a low register and copy.
44 *
45 * No additional register clobbering operation performed. Use this version when
46 * 1) rDest is freshly returned from dvmCompilerAllocTemp or
47 * 2) The codegen is under fixed register usage
48 */
loadConstantNoClobber(CompilationUnit * cUnit,int rDest,int value)49 static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
50 int value)
51 {
52 ArmLIR *res;
53 int tDest = LOWREG(rDest) ? rDest : dvmCompilerAllocTemp(cUnit);
54 /* See if the value can be constructed cheaply */
55 if ((value >= 0) && (value <= 255)) {
56 res = newLIR2(cUnit, kThumbMovImm, tDest, value);
57 if (rDest != tDest) {
58 opRegReg(cUnit, kOpMov, rDest, tDest);
59 dvmCompilerFreeTemp(cUnit, tDest);
60 }
61 return res;
62 } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
63 res = newLIR2(cUnit, kThumbMovImm, tDest, ~value);
64 newLIR2(cUnit, kThumbMvn, tDest, tDest);
65 if (rDest != tDest) {
66 opRegReg(cUnit, kOpMov, rDest, tDest);
67 dvmCompilerFreeTemp(cUnit, tDest);
68 }
69 return res;
70 }
71 /* No shortcut - go ahead and use literal pool */
72 ArmLIR *dataTarget = scanLiteralPool(cUnit->literalList, value, 255);
73 if (dataTarget == NULL) {
74 dataTarget = addWordData(cUnit, &cUnit->literalList, value);
75 }
76 ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
77 loadPcRel->opcode = kThumbLdrPcRel;
78 loadPcRel->generic.target = (LIR *) dataTarget;
79 loadPcRel->operands[0] = tDest;
80 setupResourceMasks(loadPcRel);
81 setMemRefType(loadPcRel, true, kLiteral);
82 loadPcRel->aliasInfo = dataTarget->operands[0];
83 res = loadPcRel;
84 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
85
86 /*
87 * To save space in the constant pool, we use the ADD_RRI8 instruction to
88 * add up to 255 to an existing constant value.
89 */
90 if (dataTarget->operands[0] != value) {
91 newLIR2(cUnit, kThumbAddRI8, tDest, value - dataTarget->operands[0]);
92 }
93 if (rDest != tDest) {
94 opRegReg(cUnit, kOpMov, rDest, tDest);
95 dvmCompilerFreeTemp(cUnit, tDest);
96 }
97 return res;
98 }
99
100 /*
101 * Load an immediate value into a fixed or temp register. Target
102 * register is clobbered, and marked inUse.
103 */
loadConstant(CompilationUnit * cUnit,int rDest,int value)104 static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
105 {
106 if (dvmCompilerIsTemp(cUnit, rDest)) {
107 dvmCompilerClobber(cUnit, rDest);
108 dvmCompilerMarkInUse(cUnit, rDest);
109 }
110 return loadConstantNoClobber(cUnit, rDest, value);
111 }
112
113 /*
114 * Load a class pointer value into a fixed or temp register. Target
115 * register is clobbered, and marked inUse.
116 */
loadClassPointer(CompilationUnit * cUnit,int rDest,int value)117 static ArmLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
118 {
119 ArmLIR *res;
120 cUnit->hasClassLiterals = true;
121 if (dvmCompilerIsTemp(cUnit, rDest)) {
122 dvmCompilerClobber(cUnit, rDest);
123 dvmCompilerMarkInUse(cUnit, rDest);
124 }
125 ArmLIR *dataTarget = scanLiteralPool(cUnit->classPointerList, value, 0);
126 if (dataTarget == NULL) {
127 dataTarget = addWordData(cUnit, &cUnit->classPointerList, value);
128 /* Counts the number of class pointers in this translation */
129 cUnit->numClassPointers++;
130 }
131 ArmLIR *loadPcRel = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
132 loadPcRel->opcode = kThumbLdrPcRel;
133 loadPcRel->generic.target = (LIR *) dataTarget;
134 loadPcRel->operands[0] = rDest;
135 setupResourceMasks(loadPcRel);
136 setMemRefType(loadPcRel, true, kLiteral);
137 loadPcRel->aliasInfo = dataTarget->operands[0];
138 res = loadPcRel;
139 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
140 return res;
141 }
142
opNone(CompilationUnit * cUnit,OpKind op)143 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
144 {
145 ArmOpcode opcode = kThumbBkpt;
146 switch (op) {
147 case kOpUncondBr:
148 opcode = kThumbBUncond;
149 break;
150 default:
151 ALOGE("Jit: bad case in opNone");
152 dvmCompilerAbort(cUnit);
153 }
154 return newLIR0(cUnit, opcode);
155 }
156
opCondBranch(CompilationUnit * cUnit,ArmConditionCode cc)157 static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
158 {
159 return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
160 }
161
opImm(CompilationUnit * cUnit,OpKind op,int value)162 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
163 {
164 ArmOpcode opcode = kThumbBkpt;
165 switch (op) {
166 case kOpPush:
167 opcode = kThumbPush;
168 break;
169 case kOpPop:
170 opcode = kThumbPop;
171 break;
172 default:
173 ALOGE("Jit: bad case in opCondBranch");
174 dvmCompilerAbort(cUnit);
175 }
176 return newLIR1(cUnit, opcode, value);
177 }
178
opReg(CompilationUnit * cUnit,OpKind op,int rDestSrc)179 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
180 {
181 ArmOpcode opcode = kThumbBkpt;
182 switch (op) {
183 case kOpBlx:
184 opcode = kThumbBlxR;
185 break;
186 default:
187 ALOGE("Jit: bad case in opReg");
188 dvmCompilerAbort(cUnit);
189 }
190 return newLIR1(cUnit, opcode, rDestSrc);
191 }
192
opRegImm(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int value)193 static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
194 int value)
195 {
196 ArmLIR *res;
197 bool neg = (value < 0);
198 int absValue = (neg) ? -value : value;
199 bool shortForm = (absValue & 0xff) == absValue;
200 ArmOpcode opcode = kThumbBkpt;
201 switch (op) {
202 case kOpAdd:
203 if ( !neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
204 assert((value & 0x3) == 0);
205 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
206 } else if (shortForm) {
207 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
208 } else
209 opcode = kThumbAddRRR;
210 break;
211 case kOpSub:
212 if (!neg && (rDestSrc1 == r13sp) && (value <= 508)) { /* sp */
213 assert((value & 0x3) == 0);
214 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
215 } else if (shortForm) {
216 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
217 } else
218 opcode = kThumbSubRRR;
219 break;
220 case kOpCmp:
221 if (neg)
222 shortForm = false;
223 if (LOWREG(rDestSrc1) && shortForm) {
224 opcode = kThumbCmpRI8;
225 } else if (LOWREG(rDestSrc1)) {
226 opcode = kThumbCmpRR;
227 } else {
228 shortForm = false;
229 opcode = kThumbCmpHL;
230 }
231 break;
232 default:
233 ALOGE("Jit: bad case in opRegImm");
234 dvmCompilerAbort(cUnit);
235 break;
236 }
237 if (shortForm)
238 res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
239 else {
240 int rScratch = dvmCompilerAllocTemp(cUnit);
241 res = loadConstant(cUnit, rScratch, value);
242 if (op == kOpCmp)
243 newLIR2(cUnit, opcode, rDestSrc1, rScratch);
244 else
245 newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
246 }
247 return res;
248 }
249
opRegRegReg(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int rSrc2)250 static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
251 int rSrc1, int rSrc2)
252 {
253 ArmOpcode opcode = kThumbBkpt;
254 switch (op) {
255 case kOpAdd:
256 opcode = kThumbAddRRR;
257 break;
258 case kOpSub:
259 opcode = kThumbSubRRR;
260 break;
261 default:
262 if (rDest == rSrc1) {
263 return opRegReg(cUnit, op, rDest, rSrc2);
264 } else if (rDest == rSrc2) {
265 assert(dvmCompilerIsTemp(cUnit, rSrc1));
266 dvmCompilerClobber(cUnit, rSrc1);
267 opRegReg(cUnit, op, rSrc1, rSrc2);
268 return opRegReg(cUnit, kOpMov, rDest, rSrc1);
269 } else {
270 opRegReg(cUnit, kOpMov, rDest, rSrc1);
271 return opRegReg(cUnit, op, rDest, rSrc2);
272 }
273 break;
274 }
275 return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
276 }
277
opRegRegImm(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int value)278 static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
279 int rSrc1, int value)
280 {
281 ArmLIR *res;
282 bool neg = (value < 0);
283 int absValue = (neg) ? -value : value;
284 ArmOpcode opcode = kThumbBkpt;
285 bool shortForm = (absValue & 0x7) == absValue;
286 switch(op) {
287 case kOpAdd:
288 if (rDest == rSrc1)
289 return opRegImm(cUnit, op, rDest, value);
290 if ((rSrc1 == r13sp) && (value <= 1020)) { /* sp */
291 assert((value & 0x3) == 0);
292 shortForm = true;
293 opcode = kThumbAddSpRel;
294 value >>= 2;
295 } else if ((rSrc1 == r15pc) && (value <= 1020)) { /* pc */
296 assert((value & 0x3) == 0);
297 shortForm = true;
298 opcode = kThumbAddPcRel;
299 value >>= 2;
300 } else if (shortForm) {
301 opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
302 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
303 /* Two shots - 1st handle the 7 */
304 opcode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
305 res = newLIR3(cUnit, opcode, rDest, rSrc1, 7);
306 opcode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
307 newLIR2(cUnit, opcode, rDest, absValue - 7);
308 return res;
309 } else
310 opcode = kThumbAddRRR;
311 break;
312
313 case kOpSub:
314 if (rDest == rSrc1)
315 return opRegImm(cUnit, op, rDest, value);
316 if (shortForm) {
317 opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
318 } else if ((absValue > 0) && (absValue <= (255 + 7))) {
319 /* Two shots - 1st handle the 7 */
320 opcode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
321 res = newLIR3(cUnit, opcode, rDest, rSrc1, 7);
322 opcode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
323 newLIR2(cUnit, opcode, rDest, absValue - 7);
324 return res;
325 } else
326 opcode = kThumbSubRRR;
327 break;
328 case kOpLsl:
329 shortForm = (!neg && value <= 31);
330 opcode = kThumbLslRRI5;
331 break;
332 case kOpLsr:
333 shortForm = (!neg && value <= 31);
334 opcode = kThumbLsrRRI5;
335 break;
336 case kOpAsr:
337 shortForm = (!neg && value <= 31);
338 opcode = kThumbAsrRRI5;
339 break;
340 case kOpMul:
341 case kOpAnd:
342 case kOpOr:
343 case kOpXor:
344 if (rDest == rSrc1) {
345 int rScratch = dvmCompilerAllocTemp(cUnit);
346 res = loadConstant(cUnit, rScratch, value);
347 opRegReg(cUnit, op, rDest, rScratch);
348 } else {
349 res = loadConstant(cUnit, rDest, value);
350 opRegReg(cUnit, op, rDest, rSrc1);
351 }
352 return res;
353 default:
354 ALOGE("Jit: bad case in opRegRegImm");
355 dvmCompilerAbort(cUnit);
356 break;
357 }
358 if (shortForm)
359 res = newLIR3(cUnit, opcode, rDest, rSrc1, absValue);
360 else {
361 if (rDest != rSrc1) {
362 res = loadConstant(cUnit, rDest, value);
363 newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
364 } else {
365 int rScratch = dvmCompilerAllocTemp(cUnit);
366 res = loadConstant(cUnit, rScratch, value);
367 newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
368 }
369 }
370 return res;
371 }
372
opRegReg(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int rSrc2)373 static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
374 int rSrc2)
375 {
376 ArmLIR *res;
377 ArmOpcode opcode = kThumbBkpt;
378 switch (op) {
379 case kOpAdc:
380 opcode = kThumbAdcRR;
381 break;
382 case kOpAnd:
383 opcode = kThumbAndRR;
384 break;
385 case kOpBic:
386 opcode = kThumbBicRR;
387 break;
388 case kOpCmn:
389 opcode = kThumbCmnRR;
390 break;
391 case kOpCmp:
392 opcode = kThumbCmpRR;
393 break;
394 case kOpXor:
395 opcode = kThumbEorRR;
396 break;
397 case kOpMov:
398 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
399 opcode = kThumbMovRR;
400 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
401 opcode = kThumbMovRR_H2H;
402 else if (LOWREG(rDestSrc1))
403 opcode = kThumbMovRR_H2L;
404 else
405 opcode = kThumbMovRR_L2H;
406 break;
407 case kOpMul:
408 opcode = kThumbMul;
409 break;
410 case kOpMvn:
411 opcode = kThumbMvn;
412 break;
413 case kOpNeg:
414 opcode = kThumbNeg;
415 break;
416 case kOpOr:
417 opcode = kThumbOrr;
418 break;
419 case kOpSbc:
420 opcode = kThumbSbc;
421 break;
422 case kOpTst:
423 opcode = kThumbTst;
424 break;
425 case kOpLsl:
426 opcode = kThumbLslRR;
427 break;
428 case kOpLsr:
429 opcode = kThumbLsrRR;
430 break;
431 case kOpAsr:
432 opcode = kThumbAsrRR;
433 break;
434 case kOpRor:
435 opcode = kThumbRorRR;
436 case kOpAdd:
437 case kOpSub:
438 return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
439 case kOp2Byte:
440 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
441 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
442 return res;
443 case kOp2Short:
444 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
445 opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
446 return res;
447 case kOp2Char:
448 res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
449 opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16);
450 return res;
451 default:
452 ALOGE("Jit: bad case in opRegReg");
453 dvmCompilerAbort(cUnit);
454 break;
455 }
456 return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
457 }
458
loadConstantValueWide(CompilationUnit * cUnit,int rDestLo,int rDestHi,int valLo,int valHi)459 static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
460 int rDestHi, int valLo, int valHi)
461 {
462 ArmLIR *res;
463 res = loadConstantNoClobber(cUnit, rDestLo, valLo);
464 loadConstantNoClobber(cUnit, rDestHi, valHi);
465 return res;
466 }
467
468 /* Load value from base + scaled index. */
loadBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rDest,int scale,OpSize size)469 static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
470 int rIndex, int rDest, int scale, OpSize size)
471 {
472 ArmLIR *first = NULL;
473 ArmLIR *res;
474 ArmOpcode opcode = kThumbBkpt;
475 int rNewIndex = rIndex;
476 if (scale) {
477 // Scale the index, but can't trash the original.
478 rNewIndex = dvmCompilerAllocTemp(cUnit);
479 first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
480 }
481 switch (size) {
482 case kWord:
483 opcode = kThumbLdrRRR;
484 break;
485 case kUnsignedHalf:
486 opcode = kThumbLdrhRRR;
487 break;
488 case kSignedHalf:
489 opcode = kThumbLdrshRRR;
490 break;
491 case kUnsignedByte:
492 opcode = kThumbLdrbRRR;
493 break;
494 case kSignedByte:
495 opcode = kThumbLdrsbRRR;
496 break;
497 default:
498 ALOGE("Jit: bad case in loadBaseIndexed");
499 dvmCompilerAbort(cUnit);
500 }
501 res = newLIR3(cUnit, opcode, rDest, rBase, rNewIndex);
502 #if defined(WITH_SELF_VERIFICATION)
503 if (cUnit->heapMemOp)
504 res->flags.insertWrapper = true;
505 #endif
506 if (scale)
507 dvmCompilerFreeTemp(cUnit, rNewIndex);
508 return (first) ? first : res;
509 }
510
511 /* store value base base + scaled index. */
storeBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rSrc,int scale,OpSize size)512 static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
513 int rIndex, int rSrc, int scale, OpSize size)
514 {
515 ArmLIR *first = NULL;
516 ArmLIR *res;
517 ArmOpcode opcode = kThumbBkpt;
518 int rNewIndex = rIndex;
519 if (scale) {
520 rNewIndex = dvmCompilerAllocTemp(cUnit);
521 first = opRegRegImm(cUnit, kOpLsl, rNewIndex, rIndex, scale);
522 }
523 switch (size) {
524 case kWord:
525 opcode = kThumbStrRRR;
526 break;
527 case kUnsignedHalf:
528 case kSignedHalf:
529 opcode = kThumbStrhRRR;
530 break;
531 case kUnsignedByte:
532 case kSignedByte:
533 opcode = kThumbStrbRRR;
534 break;
535 default:
536 ALOGE("Jit: bad case in storeBaseIndexed");
537 dvmCompilerAbort(cUnit);
538 }
539 res = newLIR3(cUnit, opcode, rSrc, rBase, rNewIndex);
540 #if defined(WITH_SELF_VERIFICATION)
541 if (cUnit->heapMemOp)
542 res->flags.insertWrapper = true;
543 #endif
544 if (scale)
545 dvmCompilerFreeTemp(cUnit, rNewIndex);
546 return (first) ? first : res;
547 }
548
loadMultiple(CompilationUnit * cUnit,int rBase,int rMask)549 static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
550 {
551 ArmLIR *res;
552 genBarrier(cUnit);
553 res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
554 #if defined(WITH_SELF_VERIFICATION)
555 if (cUnit->heapMemOp)
556 res->flags.insertWrapper = true;
557 #endif
558 genBarrier(cUnit);
559 return res;
560 }
561
storeMultiple(CompilationUnit * cUnit,int rBase,int rMask)562 static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
563 {
564 ArmLIR *res;
565 genBarrier(cUnit);
566 res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
567 #if defined(WITH_SELF_VERIFICATION)
568 if (cUnit->heapMemOp)
569 res->flags.insertWrapper = true;
570 #endif
571 genBarrier(cUnit);
572 return res;
573 }
574
loadBaseDispBody(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,int rDestHi,OpSize size,int sReg)575 static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
576 int displacement, int rDest, int rDestHi,
577 OpSize size, int sReg)
578 /*
579 * Load value from base + displacement. Optionally perform null check
580 * on base (which must have an associated sReg and MIR). If not
581 * performing null check, incoming MIR can be null. IMPORTANT: this
582 * code must not allocate any new temps. If a new register is needed
583 * and base and dest are the same, spill some other register to
584 * rlp and then restore.
585 */
586 {
587 ArmLIR *res;
588 ArmLIR *load = NULL;
589 ArmLIR *load2 = NULL;
590 ArmOpcode opcode = kThumbBkpt;
591 bool shortForm = false;
592 int encodedDisp = displacement;
593 bool pair = false;
594
595 switch (size) {
596 case kLong:
597 case kDouble:
598 pair = true;
599 if ((displacement < 124) && (displacement >= 0)) {
600 assert((displacement & 0x3) == 0);
601 shortForm = true;
602 encodedDisp >>= 2;
603 opcode = kThumbLdrRRI5;
604 } else {
605 opcode = kThumbLdrRRR;
606 }
607 break;
608 case kWord:
609 if (LOWREG(rDest) && (rBase == r15pc) &&
610 (displacement <= 1020) && (displacement >= 0)) {
611 shortForm = true;
612 encodedDisp >>= 2;
613 opcode = kThumbLdrPcRel;
614 } else if (LOWREG(rDest) && (rBase == r13sp) &&
615 (displacement <= 1020) && (displacement >= 0)) {
616 shortForm = true;
617 encodedDisp >>= 2;
618 opcode = kThumbLdrSpRel;
619 } else if (displacement < 128 && displacement >= 0) {
620 assert((displacement & 0x3) == 0);
621 shortForm = true;
622 encodedDisp >>= 2;
623 opcode = kThumbLdrRRI5;
624 } else {
625 opcode = kThumbLdrRRR;
626 }
627 break;
628 case kUnsignedHalf:
629 if (displacement < 64 && displacement >= 0) {
630 assert((displacement & 0x1) == 0);
631 shortForm = true;
632 encodedDisp >>= 1;
633 opcode = kThumbLdrhRRI5;
634 } else {
635 opcode = kThumbLdrhRRR;
636 }
637 break;
638 case kSignedHalf:
639 opcode = kThumbLdrshRRR;
640 break;
641 case kUnsignedByte:
642 if (displacement < 32 && displacement >= 0) {
643 shortForm = true;
644 opcode = kThumbLdrbRRI5;
645 } else {
646 opcode = kThumbLdrbRRR;
647 }
648 break;
649 case kSignedByte:
650 opcode = kThumbLdrsbRRR;
651 break;
652 default:
653 ALOGE("Jit: bad case in loadBaseIndexedBody");
654 dvmCompilerAbort(cUnit);
655 }
656 if (shortForm) {
657 load = res = newLIR3(cUnit, opcode, rDest, rBase, encodedDisp);
658 if (pair) {
659 load2 = newLIR3(cUnit, opcode, rDestHi, rBase, encodedDisp+1);
660 }
661 } else {
662 if (pair) {
663 int rTmp = dvmCompilerAllocFreeTemp(cUnit);
664 res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
665 load = newLIR3(cUnit, kThumbLdrRRI5, rDest, rTmp, 0);
666 load2 = newLIR3(cUnit, kThumbLdrRRI5, rDestHi, rTmp, 1);
667 dvmCompilerFreeTemp(cUnit, rTmp);
668 } else {
669 int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit)
670 : rDest;
671 res = loadConstant(cUnit, rTmp, displacement);
672 load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
673 if (rBase == r5FP)
674 annotateDalvikRegAccess(load, displacement >> 2,
675 true /* isLoad */);
676 if (rTmp != rDest)
677 dvmCompilerFreeTemp(cUnit, rTmp);
678 }
679 }
680 if (rBase == r5FP) {
681 if (load != NULL)
682 annotateDalvikRegAccess(load, displacement >> 2,
683 true /* isLoad */);
684 if (load2 != NULL)
685 annotateDalvikRegAccess(load2, (displacement >> 2) + 1,
686 true /* isLoad */);
687 }
688 #if defined(WITH_SELF_VERIFICATION)
689 if (load != NULL && cUnit->heapMemOp)
690 load->flags.insertWrapper = true;
691 if (load2 != NULL && cUnit->heapMemOp)
692 load2->flags.insertWrapper = true;
693 #endif
694 return load;
695 }
696
loadBaseDisp(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,OpSize size,int sReg)697 static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
698 int displacement, int rDest, OpSize size,
699 int sReg)
700 {
701 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
702 size, sReg);
703 }
704
loadBaseDispWide(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDestLo,int rDestHi,int sReg)705 static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
706 int displacement, int rDestLo, int rDestHi,
707 int sReg)
708 {
709 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
710 kLong, sReg);
711 }
712
storeBaseDispBody(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,int rSrcHi,OpSize size)713 static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
714 int displacement, int rSrc, int rSrcHi,
715 OpSize size)
716 {
717 ArmLIR *res;
718 ArmLIR *store = NULL;
719 ArmLIR *store2 = NULL;
720 ArmOpcode opcode = kThumbBkpt;
721 bool shortForm = false;
722 int encodedDisp = displacement;
723 bool pair = false;
724
725 switch (size) {
726 case kLong:
727 case kDouble:
728 pair = true;
729 if ((displacement < 124) && (displacement >= 0)) {
730 assert((displacement & 0x3) == 0);
731 pair = true;
732 shortForm = true;
733 encodedDisp >>= 2;
734 opcode = kThumbStrRRI5;
735 } else {
736 opcode = kThumbStrRRR;
737 }
738 break;
739 case kWord:
740 if (displacement < 128 && displacement >= 0) {
741 assert((displacement & 0x3) == 0);
742 shortForm = true;
743 encodedDisp >>= 2;
744 opcode = kThumbStrRRI5;
745 } else {
746 opcode = kThumbStrRRR;
747 }
748 break;
749 case kUnsignedHalf:
750 case kSignedHalf:
751 if (displacement < 64 && displacement >= 0) {
752 assert((displacement & 0x1) == 0);
753 shortForm = true;
754 encodedDisp >>= 1;
755 opcode = kThumbStrhRRI5;
756 } else {
757 opcode = kThumbStrhRRR;
758 }
759 break;
760 case kUnsignedByte:
761 case kSignedByte:
762 if (displacement < 32 && displacement >= 0) {
763 shortForm = true;
764 opcode = kThumbStrbRRI5;
765 } else {
766 opcode = kThumbStrbRRR;
767 }
768 break;
769 default:
770 ALOGE("Jit: bad case in storeBaseIndexedBody");
771 dvmCompilerAbort(cUnit);
772 }
773 if (shortForm) {
774 store = res = newLIR3(cUnit, opcode, rSrc, rBase, encodedDisp);
775 if (pair) {
776 store2 = newLIR3(cUnit, opcode, rSrcHi, rBase, encodedDisp + 1);
777 }
778 } else {
779 int rScratch = dvmCompilerAllocTemp(cUnit);
780 if (pair) {
781 res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
782 store = newLIR3(cUnit, kThumbStrRRI5, rSrc, rScratch, 0);
783 store2 = newLIR3(cUnit, kThumbStrRRI5, rSrcHi, rScratch, 1);
784 } else {
785 res = loadConstant(cUnit, rScratch, displacement);
786 store = newLIR3(cUnit, opcode, rSrc, rBase, rScratch);
787 }
788 dvmCompilerFreeTemp(cUnit, rScratch);
789 }
790 if (rBase == r5FP) {
791 if (store != NULL)
792 annotateDalvikRegAccess(store, displacement >> 2,
793 false /* isLoad */);
794 if (store2 != NULL)
795 annotateDalvikRegAccess(store2, (displacement >> 2) + 1,
796 false /* isLoad */);
797 }
798 #if defined(WITH_SELF_VERIFICATION)
799 if (store != NULL && cUnit->heapMemOp)
800 store->flags.insertWrapper = true;
801 if (store2 != NULL && cUnit->heapMemOp)
802 store2->flags.insertWrapper = true;
803 #endif
804 return res;
805 }
806
storeBaseDisp(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,OpSize size)807 static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
808 int displacement, int rSrc, OpSize size)
809 {
810 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
811 }
812
storeBaseDispWide(CompilationUnit * cUnit,int rBase,int displacement,int rSrcLo,int rSrcHi)813 static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
814 int displacement, int rSrcLo, int rSrcHi)
815 {
816 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
817 }
818
storePair(CompilationUnit * cUnit,int base,int lowReg,int highReg)819 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
820 {
821 if (lowReg < highReg) {
822 storeMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
823 } else {
824 storeWordDisp(cUnit, base, 0, lowReg);
825 storeWordDisp(cUnit, base, 4, highReg);
826 }
827 }
828
loadPair(CompilationUnit * cUnit,int base,int lowReg,int highReg)829 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
830 {
831 if (lowReg < highReg) {
832 loadMultiple(cUnit, base, (1 << lowReg) | (1 << highReg));
833 } else {
834 loadWordDisp(cUnit, base, 0 , lowReg);
835 loadWordDisp(cUnit, base, 4 , highReg);
836 }
837 }
838
genRegCopyNoInsert(CompilationUnit * cUnit,int rDest,int rSrc)839 static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
840 {
841 ArmLIR* res;
842 ArmOpcode opcode;
843 res = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
844 if (LOWREG(rDest) && LOWREG(rSrc))
845 opcode = kThumbMovRR;
846 else if (!LOWREG(rDest) && !LOWREG(rSrc))
847 opcode = kThumbMovRR_H2H;
848 else if (LOWREG(rDest))
849 opcode = kThumbMovRR_H2L;
850 else
851 opcode = kThumbMovRR_L2H;
852
853 res->operands[0] = rDest;
854 res->operands[1] = rSrc;
855 res->opcode = opcode;
856 setupResourceMasks(res);
857 if (rDest == rSrc) {
858 res->flags.isNop = true;
859 }
860 return res;
861 }
862
genRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)863 static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
864 {
865 ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
866 dvmCompilerAppendLIR(cUnit, (LIR*)res);
867 return res;
868 }
869
genRegCopyWide(CompilationUnit * cUnit,int destLo,int destHi,int srcLo,int srcHi)870 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
871 int srcLo, int srcHi)
872 {
873 // Handle overlap
874 if (srcHi == destLo) {
875 genRegCopy(cUnit, destHi, srcHi);
876 genRegCopy(cUnit, destLo, srcLo);
877 } else {
878 genRegCopy(cUnit, destLo, srcLo);
879 genRegCopy(cUnit, destHi, srcHi);
880 }
881 }
882
genCmpImmBranch(CompilationUnit * cUnit,ArmConditionCode cond,int reg,int checkValue)883 static ArmLIR *genCmpImmBranch(CompilationUnit *cUnit,
884 ArmConditionCode cond, int reg,
885 int checkValue)
886 {
887 if ((checkValue & 0xff) != checkValue) {
888 int tReg = dvmCompilerAllocTemp(cUnit);
889 loadConstant(cUnit, tReg, checkValue);
890 newLIR2(cUnit, kThumbCmpRR, reg, tReg);
891 dvmCompilerFreeTemp(cUnit, tReg);
892 } else {
893 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
894 }
895 ArmLIR *branch = newLIR2(cUnit, kThumbBCond, 0, cond);
896 return branch;
897 }
898
899 #if defined(WITH_SELF_VERIFICATION)
genSelfVerificationPreBranch(CompilationUnit * cUnit,ArmLIR * origLIR)900 static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
901 ArmLIR *origLIR) {
902 /*
903 * We need two separate pushes, since we want r5 to be pushed first.
904 * Store multiple will push LR first.
905 */
906 ArmLIR *pushFP = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
907 pushFP->opcode = kThumbPush;
908 pushFP->operands[0] = 1 << r5FP;
909 setupResourceMasks(pushFP);
910 dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP);
911
912 ArmLIR *pushLR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
913 pushLR->opcode = kThumbPush;
914 /* Thumb push can handle LR, but is encoded differently at bit 8 */
915 pushLR->operands[0] = 1 << 8;
916 setupResourceMasks(pushLR);
917 dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR);
918 }
919
genSelfVerificationPostBranch(CompilationUnit * cUnit,ArmLIR * origLIR)920 static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
921 ArmLIR *origLIR) {
922 /*
923 * Since Thumb cannot pop memory content into LR, we have to pop LR
924 * to a temp first (r5 in this case). Then we move r5 to LR, then pop the
925 * original r5 from stack.
926 */
927 /* Pop memory content(LR) into r5 first */
928 ArmLIR *popForLR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
929 popForLR->opcode = kThumbPop;
930 popForLR->operands[0] = 1 << r5FP;
931 setupResourceMasks(popForLR);
932 dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR);
933
934 ArmLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP);
935 dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy);
936
937 /* Now restore the original r5 */
938 ArmLIR *popFP = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true);
939 popFP->opcode = kThumbPop;
940 popFP->operands[0] = 1 << r5FP;
941 setupResourceMasks(popFP);
942 dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP);
943 }
944 #endif
945