• 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->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