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