• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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