• 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[] = {r_V0, r_V1, r_A0, r_A1, r_A2, r_A3, r_T0, r_T1, r_T2,
26                           r_T3, r_T4, r_T5, r_T6, r_T7, r_T8, r_T9, r_S0, r_S4};
27 #ifdef __mips_hard_float
28 static int fpTemps[] = {r_F0, r_F1, r_F2, r_F3, r_F4, r_F5, r_F6, r_F7,
29                         r_F8, r_F9, r_F10, r_F11, r_F12, r_F13, r_F14, r_F15};
30 #endif
31 
32 static void storePair(CompilationUnit *cUnit, int base, int lowReg,
33                       int highReg);
34 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
35 static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
36                             int rDest);
37 static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
38                              int displacement, int rSrc);
39 static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
40                               MipsConditionCode cond,
41                               int reg1, int reg2, int dOffset,
42                               MipsLIR *pcrLabel);
43 static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
44 
45 #ifdef __mips_hard_float
fpRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)46 static MipsLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
47 {
48     MipsLIR* res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
49     res->operands[0] = rDest;
50     res->operands[1] = rSrc;
51     if (rDest == rSrc) {
52         res->flags.isNop = true;
53     } else {
54         /* must be both DOUBLE or both not DOUBLE */
55         assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
56         if (DOUBLEREG(rDest)) {
57             res->opcode = kMipsFmovd;
58         } else {
59             if (SINGLEREG(rDest)) {
60                 if (SINGLEREG(rSrc)) {
61                     res->opcode = kMipsFmovs;
62                 } else {
63                     /* note the operands are swapped for the mtc1 instr */
64                     res->opcode = kMipsMtc1;
65                     res->operands[0] = rSrc;
66                     res->operands[1] = rDest;
67                 }
68             } else {
69                 assert(SINGLEREG(rSrc));
70                 res->opcode = kMipsMfc1;
71             }
72         }
73     }
74     setupResourceMasks(res);
75     return res;
76 }
77 #endif
78 
79 /*
80  * Load a immediate using a shortcut if possible; otherwise
81  * grab from the per-translation literal pool.  If target is
82  * a high register, build constant into a low register and copy.
83  *
84  * No additional register clobbering operation performed. Use this version when
85  * 1) rDest is freshly returned from dvmCompilerAllocTemp or
86  * 2) The codegen is under fixed register usage
87  */
loadConstantNoClobber(CompilationUnit * cUnit,int rDest,int value)88 static MipsLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
89                                      int value)
90 {
91     MipsLIR *res;
92 
93 #ifdef __mips_hard_float
94     int rDestSave = rDest;
95     int isFpReg = FPREG(rDest);
96     if (isFpReg) {
97         assert(SINGLEREG(rDest));
98         rDest = dvmCompilerAllocTemp(cUnit);
99     }
100 #endif
101 
102     /* See if the value can be constructed cheaply */
103     if (value == 0) {
104         res = newLIR2(cUnit, kMipsMove, rDest, r_ZERO);
105     } else if ((value > 0) && (value <= 65535)) {
106         res = newLIR3(cUnit, kMipsOri, rDest, r_ZERO, value);
107     } else if ((value < 0) && (value >= -32768)) {
108         res = newLIR3(cUnit, kMipsAddiu, rDest, r_ZERO, value);
109     } else {
110         res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
111         if (value & 0xffff)
112 	    newLIR3(cUnit, kMipsOri, rDest, rDest, value);
113     }
114 
115 #ifdef __mips_hard_float
116     if (isFpReg) {
117         newLIR2(cUnit, kMipsMtc1, rDest, rDestSave);
118         dvmCompilerFreeTemp(cUnit, rDest);
119     }
120 #endif
121 
122     return res;
123 }
124 
125 /*
126  * Load an immediate value into a fixed or temp register.  Target
127  * register is clobbered, and marked inUse.
128  */
loadConstant(CompilationUnit * cUnit,int rDest,int value)129 static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
130 {
131     if (dvmCompilerIsTemp(cUnit, rDest)) {
132         dvmCompilerClobber(cUnit, rDest);
133         dvmCompilerMarkInUse(cUnit, rDest);
134     }
135     return loadConstantNoClobber(cUnit, rDest, value);
136 }
137 
138 /*
139  * Load a class pointer value into a fixed or temp register.  Target
140  * register is clobbered, and marked inUse.
141  */
loadClassPointer(CompilationUnit * cUnit,int rDest,int value)142 static MipsLIR *loadClassPointer(CompilationUnit *cUnit, int rDest, int value)
143 {
144     MipsLIR *res;
145     if (dvmCompilerIsTemp(cUnit, rDest)) {
146         dvmCompilerClobber(cUnit, rDest);
147         dvmCompilerMarkInUse(cUnit, rDest);
148     }
149     res = newLIR2(cUnit, kMipsLui, rDest, value>>16);
150     if (value & 0xffff)
151         newLIR3(cUnit, kMipsOri, rDest, rDest, value);
152     return res;
153 }
154 
opNone(CompilationUnit * cUnit,OpKind op)155 static MipsLIR *opNone(CompilationUnit *cUnit, OpKind op)
156 {
157     MipsLIR *res;
158     MipsOpCode opcode = kMipsNop;
159     switch (op) {
160         case kOpUncondBr:
161             opcode = kMipsB;
162             break;
163         default:
164             ALOGE("Jit: bad case in opNone");
165             dvmCompilerAbort(cUnit);
166     }
167     res = newLIR0(cUnit, opcode);
168     return res;
169 }
170 
opCompareBranch(CompilationUnit * cUnit,MipsOpCode opc,int rs,int rt)171 static MipsLIR *opCompareBranch(CompilationUnit *cUnit, MipsOpCode opc, int rs, int rt)
172 {
173     MipsLIR *res;
174     if (rt < 0) {
175       assert(opc >= kMipsBeqz && opc <= kMipsBnez);
176       res = newLIR1(cUnit, opc, rs);
177     } else  {
178       assert(opc == kMipsBeq || opc == kMipsBne);
179       res = newLIR2(cUnit, opc, rs, rt);
180     }
181     return res;
182 }
183 
184 static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
185 
opReg(CompilationUnit * cUnit,OpKind op,int rDestSrc)186 static MipsLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
187 {
188     MipsOpCode opcode = kMipsNop;
189     switch (op) {
190         case kOpBlx:
191             opcode = kMipsJalr;
192             break;
193         default:
194             assert(0);
195     }
196     return newLIR2(cUnit, opcode, r_RA, rDestSrc);
197 }
198 
199 static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
200                            int rSrc1, int value);
opRegImm(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int value)201 static MipsLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
202                         int value)
203 {
204     MipsLIR *res;
205     bool neg = (value < 0);
206     int absValue = (neg) ? -value : value;
207     bool shortForm = (absValue & 0xff) == absValue;
208     MipsOpCode opcode = kMipsNop;
209     switch (op) {
210         case kOpAdd:
211             return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
212             break;
213         case kOpSub:
214             return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
215             break;
216         default:
217             ALOGE("Jit: bad case in opRegImm");
218             dvmCompilerAbort(cUnit);
219             break;
220     }
221     if (shortForm)
222         res = newLIR2(cUnit, opcode, rDestSrc1, absValue);
223     else {
224         int rScratch = dvmCompilerAllocTemp(cUnit);
225         res = loadConstant(cUnit, rScratch, value);
226         if (op == kOpCmp)
227             newLIR2(cUnit, opcode, rDestSrc1, rScratch);
228         else
229             newLIR3(cUnit, opcode, rDestSrc1, rDestSrc1, rScratch);
230     }
231     return res;
232 }
233 
opRegRegReg(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int rSrc2)234 static MipsLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
235                            int rSrc1, int rSrc2)
236 {
237     MipsOpCode opcode = kMipsNop;
238     switch (op) {
239         case kOpAdd:
240             opcode = kMipsAddu;
241             break;
242         case kOpSub:
243             opcode = kMipsSubu;
244             break;
245         case kOpAnd:
246             opcode = kMipsAnd;
247             break;
248         case kOpMul:
249             opcode = kMipsMul;
250             break;
251         case kOpOr:
252             opcode = kMipsOr;
253             break;
254         case kOpXor:
255             opcode = kMipsXor;
256             break;
257         case kOpLsl:
258             opcode = kMipsSllv;
259             break;
260         case kOpLsr:
261             opcode = kMipsSrlv;
262             break;
263         case kOpAsr:
264             opcode = kMipsSrav;
265             break;
266         default:
267             ALOGE("Jit: bad case in opRegRegReg");
268             dvmCompilerAbort(cUnit);
269             break;
270     }
271     return newLIR3(cUnit, opcode, rDest, rSrc1, rSrc2);
272 }
273 
opRegRegImm(CompilationUnit * cUnit,OpKind op,int rDest,int rSrc1,int value)274 static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
275                            int rSrc1, int value)
276 {
277     MipsLIR *res;
278     MipsOpCode opcode = kMipsNop;
279     bool shortForm = true;
280 
281     switch(op) {
282         case kOpAdd:
283             if (IS_SIMM16(value)) {
284                 opcode = kMipsAddiu;
285             }
286             else {
287                 shortForm = false;
288                 opcode = kMipsAddu;
289             }
290             break;
291         case kOpSub:
292             if (IS_SIMM16((-value))) {
293                 value = -value;
294                 opcode = kMipsAddiu;
295             }
296             else {
297                 shortForm = false;
298                 opcode = kMipsSubu;
299             }
300             break;
301         case kOpLsl:
302                 assert(value >= 0 && value <= 31);
303                 opcode = kMipsSll;
304                 break;
305         case kOpLsr:
306                 assert(value >= 0 && value <= 31);
307                 opcode = kMipsSrl;
308                 break;
309         case kOpAsr:
310                 assert(value >= 0 && value <= 31);
311                 opcode = kMipsSra;
312                 break;
313         case kOpAnd:
314             if (IS_UIMM16((value))) {
315                 opcode = kMipsAndi;
316             }
317             else {
318                 shortForm = false;
319                 opcode = kMipsAnd;
320             }
321             break;
322         case kOpOr:
323             if (IS_UIMM16((value))) {
324                 opcode = kMipsOri;
325             }
326             else {
327                 shortForm = false;
328                 opcode = kMipsOr;
329             }
330             break;
331         case kOpXor:
332             if (IS_UIMM16((value))) {
333                 opcode = kMipsXori;
334             }
335             else {
336                 shortForm = false;
337                 opcode = kMipsXor;
338             }
339             break;
340         case kOpMul:
341             shortForm = false;
342             opcode = kMipsMul;
343             break;
344         default:
345             ALOGE("Jit: bad case in opRegRegImm");
346             dvmCompilerAbort(cUnit);
347             break;
348     }
349 
350     if (shortForm)
351         res = newLIR3(cUnit, opcode, rDest, rSrc1, value);
352     else {
353         if (rDest != rSrc1) {
354             res = loadConstant(cUnit, rDest, value);
355             newLIR3(cUnit, opcode, rDest, rSrc1, rDest);
356         } else {
357             int rScratch = dvmCompilerAllocTemp(cUnit);
358             res = loadConstant(cUnit, rScratch, value);
359             newLIR3(cUnit, opcode, rDest, rSrc1, rScratch);
360         }
361     }
362     return res;
363 }
364 
opRegReg(CompilationUnit * cUnit,OpKind op,int rDestSrc1,int rSrc2)365 static MipsLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
366                         int rSrc2)
367 {
368     MipsOpCode opcode = kMipsNop;
369     MipsLIR *res;
370     switch (op) {
371         case kOpMov:
372             opcode = kMipsMove;
373             break;
374         case kOpMvn:
375             return newLIR3(cUnit, kMipsNor, rDestSrc1, rSrc2, r_ZERO);
376         case kOpNeg:
377             return newLIR3(cUnit, kMipsSubu, rDestSrc1, r_ZERO, rSrc2);
378         case kOpAdd:
379         case kOpAnd:
380         case kOpMul:
381         case kOpOr:
382         case kOpSub:
383         case kOpXor:
384             return opRegRegReg(cUnit, op, rDestSrc1, rDestSrc1, rSrc2);
385         case kOp2Byte:
386 #if __mips_isa_rev>=2
387             res = newLIR2(cUnit, kMipsSeb, rDestSrc1, rSrc2);
388 #else
389             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 24);
390             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 24);
391 #endif
392             return res;
393         case kOp2Short:
394 #if __mips_isa_rev>=2
395             res = newLIR2(cUnit, kMipsSeh, rDestSrc1, rSrc2);
396 #else
397             res = opRegRegImm(cUnit, kOpLsl, rDestSrc1, rSrc2, 16);
398             opRegRegImm(cUnit, kOpAsr, rDestSrc1, rDestSrc1, 16);
399 #endif
400             return res;
401         case kOp2Char:
402              return newLIR3(cUnit, kMipsAndi, rDestSrc1, rSrc2, 0xFFFF);
403         default:
404             ALOGE("Jit: bad case in opRegReg");
405             dvmCompilerAbort(cUnit);
406             break;
407     }
408     return newLIR2(cUnit, opcode, rDestSrc1, rSrc2);
409 }
410 
loadConstantValueWide(CompilationUnit * cUnit,int rDestLo,int rDestHi,int valLo,int valHi)411 static MipsLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
412                                      int rDestHi, int valLo, int valHi)
413 {
414     MipsLIR *res;
415     res = loadConstantNoClobber(cUnit, rDestLo, valLo);
416     loadConstantNoClobber(cUnit, rDestHi, valHi);
417     return res;
418 }
419 
420 /* Load value from base + scaled index. */
loadBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rDest,int scale,OpSize size)421 static MipsLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
422                                int rIndex, int rDest, int scale, OpSize size)
423 {
424     MipsLIR *first = NULL;
425     MipsLIR *res;
426     MipsOpCode opcode = kMipsNop;
427     int tReg = dvmCompilerAllocTemp(cUnit);
428 
429 #ifdef __mips_hard_float
430     if (FPREG(rDest)) {
431         assert(SINGLEREG(rDest));
432         assert((size == kWord) || (size == kSingle));
433         size = kSingle;
434     } else {
435         if (size == kSingle)
436             size = kWord;
437     }
438 #endif
439 
440     if (!scale) {
441         first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
442     } else {
443         first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
444         newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
445     }
446 
447     switch (size) {
448 #ifdef __mips_hard_float
449         case kSingle:
450             opcode = kMipsFlwc1;
451             break;
452 #endif
453         case kWord:
454             opcode = kMipsLw;
455             break;
456         case kUnsignedHalf:
457             opcode = kMipsLhu;
458             break;
459         case kSignedHalf:
460             opcode = kMipsLh;
461             break;
462         case kUnsignedByte:
463             opcode = kMipsLbu;
464             break;
465         case kSignedByte:
466             opcode = kMipsLb;
467             break;
468         default:
469             ALOGE("Jit: bad case in loadBaseIndexed");
470             dvmCompilerAbort(cUnit);
471     }
472 
473     res = newLIR3(cUnit, opcode, rDest, 0, tReg);
474 #if defined(WITH_SELF_VERIFICATION)
475     if (cUnit->heapMemOp)
476         res->flags.insertWrapper = true;
477 #endif
478     dvmCompilerFreeTemp(cUnit, tReg);
479     return (first) ? first : res;
480 }
481 
482 /* store value base base + scaled index. */
storeBaseIndexed(CompilationUnit * cUnit,int rBase,int rIndex,int rSrc,int scale,OpSize size)483 static MipsLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
484                                 int rIndex, int rSrc, int scale, OpSize size)
485 {
486     MipsLIR *first = NULL;
487     MipsLIR *res;
488     MipsOpCode opcode = kMipsNop;
489     int rNewIndex = rIndex;
490     int tReg = dvmCompilerAllocTemp(cUnit);
491 
492 #ifdef __mips_hard_float
493     if (FPREG(rSrc)) {
494         assert(SINGLEREG(rSrc));
495         assert((size == kWord) || (size == kSingle));
496         size = kSingle;
497     } else {
498         if (size == kSingle)
499             size = kWord;
500     }
501 #endif
502 
503     if (!scale) {
504         first = newLIR3(cUnit, kMipsAddu, tReg , rBase, rIndex);
505     } else {
506         first = opRegRegImm(cUnit, kOpLsl, tReg, rIndex, scale);
507         newLIR3(cUnit, kMipsAddu, tReg , rBase, tReg);
508     }
509 
510     switch (size) {
511 #ifdef __mips_hard_float
512         case kSingle:
513             opcode = kMipsFswc1;
514             break;
515 #endif
516         case kWord:
517             opcode = kMipsSw;
518             break;
519         case kUnsignedHalf:
520         case kSignedHalf:
521             opcode = kMipsSh;
522             break;
523         case kUnsignedByte:
524         case kSignedByte:
525             opcode = kMipsSb;
526             break;
527         default:
528             ALOGE("Jit: bad case in storeBaseIndexed");
529             dvmCompilerAbort(cUnit);
530     }
531     res = newLIR3(cUnit, opcode, rSrc, 0, tReg);
532 #if defined(WITH_SELF_VERIFICATION)
533     if (cUnit->heapMemOp)
534         res->flags.insertWrapper = true;
535 #endif
536     dvmCompilerFreeTemp(cUnit, rNewIndex);
537     return first;
538 }
539 
loadMultiple(CompilationUnit * cUnit,int rBase,int rMask)540 static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
541 {
542     int i;
543     int loadCnt = 0;
544     MipsLIR *res = NULL ;
545     genBarrier(cUnit);
546 
547     for (i = 0; i < 8; i++, rMask >>= 1) {
548         if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
549             newLIR3(cUnit, kMipsLw, i+r_A0, loadCnt*4, rBase);
550             loadCnt++;
551         }
552     }
553 
554     if (loadCnt) {/* increment after */
555         newLIR3(cUnit, kMipsAddiu, rBase, rBase, loadCnt*4);
556     }
557 
558 #if defined(WITH_SELF_VERIFICATION)
559     if (cUnit->heapMemOp)
560         res->flags.insertWrapper = true;
561 #endif
562     genBarrier(cUnit);
563     return res; /* NULL always returned which should be ok since no callers use it */
564 }
565 
storeMultiple(CompilationUnit * cUnit,int rBase,int rMask)566 static MipsLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
567 {
568     int i;
569     int storeCnt = 0;
570     MipsLIR *res = NULL ;
571     genBarrier(cUnit);
572 
573     for (i = 0; i < 8; i++, rMask >>= 1) {
574         if (rMask & 0x1) { /* map r0 to MIPS r_A0 */
575             newLIR3(cUnit, kMipsSw, i+r_A0, storeCnt*4, rBase);
576             storeCnt++;
577         }
578     }
579 
580     if (storeCnt) { /* increment after */
581         newLIR3(cUnit, kMipsAddiu, rBase, rBase, storeCnt*4);
582     }
583 
584 #if defined(WITH_SELF_VERIFICATION)
585     if (cUnit->heapMemOp)
586         res->flags.insertWrapper = true;
587 #endif
588     genBarrier(cUnit);
589     return res; /* NULL always returned which should be ok since no callers use it */
590 }
591 
loadBaseDispBody(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,int rDestHi,OpSize size,int sReg)592 static MipsLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
593                                 int displacement, int rDest, int rDestHi,
594                                 OpSize size, int sReg)
595 /*
596  * Load value from base + displacement.  Optionally perform null check
597  * on base (which must have an associated sReg and MIR).  If not
598  * performing null check, incoming MIR can be null. IMPORTANT: this
599  * code must not allocate any new temps.  If a new register is needed
600  * and base and dest are the same, spill some other register to
601  * rlp and then restore.
602  */
603 {
604     MipsLIR *res;
605     MipsLIR *load = NULL;
606     MipsLIR *load2 = NULL;
607     MipsOpCode opcode = kMipsNop;
608     bool shortForm = IS_SIMM16(displacement);
609     bool pair = false;
610 
611     switch (size) {
612         case kLong:
613         case kDouble:
614             pair = true;
615             opcode = kMipsLw;
616 #ifdef __mips_hard_float
617             if (FPREG(rDest)) {
618                 opcode = kMipsFlwc1;
619                 if (DOUBLEREG(rDest)) {
620                     rDest = rDest - FP_DOUBLE;
621                 } else {
622                     assert(FPREG(rDestHi));
623                     assert(rDest == (rDestHi - 1));
624                 }
625                 rDestHi = rDest + 1;
626             }
627 #endif
628             shortForm = IS_SIMM16_2WORD(displacement);
629             assert((displacement & 0x3) == 0);
630             break;
631         case kWord:
632         case kSingle:
633             opcode = kMipsLw;
634 #ifdef __mips_hard_float
635             if (FPREG(rDest)) {
636                 opcode = kMipsFlwc1;
637                 assert(SINGLEREG(rDest));
638             }
639 #endif
640             assert((displacement & 0x3) == 0);
641             break;
642         case kUnsignedHalf:
643             opcode = kMipsLhu;
644             assert((displacement & 0x1) == 0);
645             break;
646         case kSignedHalf:
647             opcode = kMipsLh;
648             assert((displacement & 0x1) == 0);
649             break;
650         case kUnsignedByte:
651             opcode = kMipsLbu;
652             break;
653         case kSignedByte:
654             opcode = kMipsLb;
655             break;
656         default:
657             ALOGE("Jit: bad case in loadBaseIndexedBody");
658             dvmCompilerAbort(cUnit);
659     }
660 
661     if (shortForm) {
662         if (!pair) {
663             load = res = newLIR3(cUnit, opcode, rDest, displacement, rBase);
664         } else {
665             load = res = newLIR3(cUnit, opcode, rDest, displacement + LOWORD_OFFSET, rBase);
666             load2 = newLIR3(cUnit, opcode, rDestHi, displacement + HIWORD_OFFSET, rBase);
667         }
668     } else {
669         if (pair) {
670             int rTmp = dvmCompilerAllocFreeTemp(cUnit);
671             res = opRegRegImm(cUnit, kOpAdd, rTmp, rBase, displacement);
672             load = newLIR3(cUnit, opcode, rDest, LOWORD_OFFSET, rTmp);
673             load2 = newLIR3(cUnit, opcode, rDestHi, HIWORD_OFFSET, rTmp);
674             dvmCompilerFreeTemp(cUnit, rTmp);
675         } else {
676             int rTmp = (rBase == rDest) ? dvmCompilerAllocFreeTemp(cUnit)
677                                         : rDest;
678             res = loadConstant(cUnit, rTmp, displacement);
679             load = newLIR3(cUnit, opcode, rDest, rBase, rTmp);
680             if (rTmp != rDest)
681                 dvmCompilerFreeTemp(cUnit, rTmp);
682         }
683     }
684 
685     if (rBase == rFP) {
686         if (load != NULL)
687             annotateDalvikRegAccess(load, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
688                                     true /* isLoad */);
689         if (load2 != NULL)
690             annotateDalvikRegAccess(load2, (displacement + HIWORD_OFFSET) >> 2,
691                                     true /* isLoad */);
692     }
693 #if defined(WITH_SELF_VERIFICATION)
694     if (load != NULL && cUnit->heapMemOp)
695         load->flags.insertWrapper = true;
696     if (load2 != NULL && cUnit->heapMemOp)
697         load2->flags.insertWrapper = true;
698 #endif
699     return load;
700 }
701 
loadBaseDisp(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDest,OpSize size,int sReg)702 static MipsLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
703                             int displacement, int rDest, OpSize size,
704                             int sReg)
705 {
706     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
707                             size, sReg);
708 }
709 
loadBaseDispWide(CompilationUnit * cUnit,MIR * mir,int rBase,int displacement,int rDestLo,int rDestHi,int sReg)710 static MipsLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
711                                 int displacement, int rDestLo, int rDestHi,
712                                 int sReg)
713 {
714     return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
715                             kLong, sReg);
716 }
717 
storeBaseDispBody(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,int rSrcHi,OpSize size)718 static MipsLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
719                                  int displacement, int rSrc, int rSrcHi,
720                                  OpSize size)
721 {
722     MipsLIR *res;
723     MipsLIR *store = NULL;
724     MipsLIR *store2 = NULL;
725     MipsOpCode opcode = kMipsNop;
726     bool shortForm = IS_SIMM16(displacement);
727     bool pair = false;
728 
729     switch (size) {
730         case kLong:
731         case kDouble:
732             pair = true;
733             opcode = kMipsSw;
734 #ifdef __mips_hard_float
735             if (FPREG(rSrc)) {
736                 opcode = kMipsFswc1;
737                 if (DOUBLEREG(rSrc)) {
738                     rSrc = rSrc - FP_DOUBLE;
739                 } else {
740                     assert(FPREG(rSrcHi));
741                     assert(rSrc == (rSrcHi - 1));
742                 }
743                 rSrcHi = rSrc + 1;
744             }
745 #endif
746             shortForm = IS_SIMM16_2WORD(displacement);
747             assert((displacement & 0x3) == 0);
748             break;
749         case kWord:
750         case kSingle:
751             opcode = kMipsSw;
752 #ifdef __mips_hard_float
753             if (FPREG(rSrc)) {
754                 opcode = kMipsFswc1;
755                 assert(SINGLEREG(rSrc));
756             }
757 #endif
758             assert((displacement & 0x3) == 0);
759             break;
760         case kUnsignedHalf:
761         case kSignedHalf:
762             opcode = kMipsSh;
763             assert((displacement & 0x1) == 0);
764             break;
765         case kUnsignedByte:
766         case kSignedByte:
767             opcode = kMipsSb;
768             break;
769         default:
770             ALOGE("Jit: bad case in storeBaseIndexedBody");
771             dvmCompilerAbort(cUnit);
772     }
773 
774     if (shortForm) {
775         if (!pair) {
776             store = res = newLIR3(cUnit, opcode, rSrc, displacement, rBase);
777         } else {
778             store = res = newLIR3(cUnit, opcode, rSrc, displacement + LOWORD_OFFSET, rBase);
779             store2 = newLIR3(cUnit, opcode, rSrcHi, displacement + HIWORD_OFFSET, rBase);
780         }
781     } else {
782         int rScratch = dvmCompilerAllocTemp(cUnit);
783         res = opRegRegImm(cUnit, kOpAdd, rScratch, rBase, displacement);
784         if (!pair) {
785             store =  newLIR3(cUnit, opcode, rSrc, 0, rScratch);
786         } else {
787             store =  newLIR3(cUnit, opcode, rSrc, LOWORD_OFFSET, rScratch);
788             store2 = newLIR3(cUnit, opcode, rSrcHi, HIWORD_OFFSET, rScratch);
789         }
790         dvmCompilerFreeTemp(cUnit, rScratch);
791     }
792 
793     if (rBase == rFP) {
794         if (store != NULL)
795             annotateDalvikRegAccess(store, (displacement + (pair ? LOWORD_OFFSET : 0)) >> 2,
796                                     false /* isLoad */);
797         if (store2 != NULL)
798             annotateDalvikRegAccess(store2, (displacement + HIWORD_OFFSET) >> 2,
799                                     false /* isLoad */);
800     }
801 
802 #if defined(WITH_SELF_VERIFICATION)
803     if (store != NULL && cUnit->heapMemOp)
804         store->flags.insertWrapper = true;
805     if (store2 != NULL && cUnit->heapMemOp)
806         store2->flags.insertWrapper = true;
807 #endif
808     return res;
809 }
810 
storeBaseDisp(CompilationUnit * cUnit,int rBase,int displacement,int rSrc,OpSize size)811 static MipsLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
812                              int displacement, int rSrc, OpSize size)
813 {
814     return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
815 }
816 
storeBaseDispWide(CompilationUnit * cUnit,int rBase,int displacement,int rSrcLo,int rSrcHi)817 static MipsLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
818                                  int displacement, int rSrcLo, int rSrcHi)
819 {
820     return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
821 }
822 
storePair(CompilationUnit * cUnit,int base,int lowReg,int highReg)823 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
824 {
825     storeWordDisp(cUnit, base, LOWORD_OFFSET, lowReg);
826     storeWordDisp(cUnit, base, HIWORD_OFFSET, highReg);
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     loadWordDisp(cUnit, base, LOWORD_OFFSET , lowReg);
832     loadWordDisp(cUnit, base, HIWORD_OFFSET , highReg);
833 }
834 
genRegCopyNoInsert(CompilationUnit * cUnit,int rDest,int rSrc)835 static MipsLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
836 {
837     MipsLIR* res;
838     MipsOpCode opcode;
839 #ifdef __mips_hard_float
840     if (FPREG(rDest) || FPREG(rSrc))
841         return fpRegCopy(cUnit, rDest, rSrc);
842 #endif
843     res = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
844     opcode = kMipsMove;
845     assert(LOWREG(rDest) && LOWREG(rSrc));
846     res->operands[0] = rDest;
847     res->operands[1] = rSrc;
848     res->opcode = opcode;
849     setupResourceMasks(res);
850     if (rDest == rSrc) {
851         res->flags.isNop = true;
852     }
853     return res;
854 }
855 
genRegCopy(CompilationUnit * cUnit,int rDest,int rSrc)856 static MipsLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
857 {
858     MipsLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
859     dvmCompilerAppendLIR(cUnit, (LIR*)res);
860     return res;
861 }
862 
genRegCopyWide(CompilationUnit * cUnit,int destLo,int destHi,int srcLo,int srcHi)863 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
864                            int srcLo, int srcHi)
865 {
866 #ifdef __mips_hard_float
867     bool destFP = FPREG(destLo) && FPREG(destHi);
868     bool srcFP = FPREG(srcLo) && FPREG(srcHi);
869     assert(FPREG(srcLo) == FPREG(srcHi));
870     assert(FPREG(destLo) == FPREG(destHi));
871     if (destFP) {
872         if (srcFP) {
873             genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
874         } else {
875            /* note the operands are swapped for the mtc1 instr */
876             newLIR2(cUnit, kMipsMtc1, srcLo, destLo);
877             newLIR2(cUnit, kMipsMtc1, srcHi, destHi);
878         }
879     } else {
880         if (srcFP) {
881             newLIR2(cUnit, kMipsMfc1, destLo, srcLo);
882             newLIR2(cUnit, kMipsMfc1, destHi, srcHi);
883         } else {
884             // Handle overlap
885             if (srcHi == destLo) {
886                 genRegCopy(cUnit, destHi, srcHi);
887                 genRegCopy(cUnit, destLo, srcLo);
888             } else {
889                 genRegCopy(cUnit, destLo, srcLo);
890                 genRegCopy(cUnit, destHi, srcHi);
891             }
892         }
893     }
894 #else
895     // Handle overlap
896     if (srcHi == destLo) {
897         genRegCopy(cUnit, destHi, srcHi);
898         genRegCopy(cUnit, destLo, srcLo);
899     } else {
900         genRegCopy(cUnit, destLo, srcLo);
901         genRegCopy(cUnit, destHi, srcHi);
902     }
903 #endif
904 }
905 
genRegImmCheck(CompilationUnit * cUnit,MipsConditionCode cond,int reg,int checkValue,int dOffset,MipsLIR * pcrLabel)906 static inline MipsLIR *genRegImmCheck(CompilationUnit *cUnit,
907                                      MipsConditionCode cond, int reg,
908                                      int checkValue, int dOffset,
909                                      MipsLIR *pcrLabel)
910 {
911     MipsLIR *branch = NULL;
912 
913     if (checkValue == 0) {
914         MipsOpCode opc = kMipsNop;
915         if (cond == kMipsCondEq) {
916             opc = kMipsBeqz;
917 	} else if (cond == kMipsCondNe) {
918             opc = kMipsBnez;
919         } else if (cond == kMipsCondLt || cond == kMipsCondMi) {
920             opc = kMipsBltz;
921         } else if (cond == kMipsCondLe) {
922             opc = kMipsBlez;
923         } else if (cond == kMipsCondGt) {
924             opc = kMipsBgtz;
925         } else if (cond == kMipsCondGe) {
926             opc = kMipsBgez;
927         } else {
928             ALOGE("Jit: bad case in genRegImmCheck");
929             dvmCompilerAbort(cUnit);
930         }
931         branch = opCompareBranch(cUnit, opc, reg, -1);
932     } else if (IS_SIMM16(checkValue)) {
933         if (cond == kMipsCondLt) {
934             int tReg = dvmCompilerAllocTemp(cUnit);
935             newLIR3(cUnit, kMipsSlti, tReg, reg, checkValue);
936             branch = opCompareBranch(cUnit, kMipsBne, tReg, r_ZERO);
937             dvmCompilerFreeTemp(cUnit, tReg);
938         } else {
939             ALOGE("Jit: bad case in genRegImmCheck");
940             dvmCompilerAbort(cUnit);
941         }
942     } else {
943         ALOGE("Jit: bad case in genRegImmCheck");
944         dvmCompilerAbort(cUnit);
945     }
946 
947     if (cUnit->jitMode == kJitMethod) {
948         BasicBlock *bb = cUnit->curBlock;
949         if (bb->taken) {
950             MipsLIR  *exceptionLabel = (MipsLIR *) cUnit->blockLabelList;
951             exceptionLabel += bb->taken->id;
952             branch->generic.target = (LIR *) exceptionLabel;
953             return exceptionLabel;
954         } else {
955             ALOGE("Catch blocks not handled yet");
956             dvmAbort();
957             return NULL;
958         }
959     } else {
960         return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
961     }
962 }
963 
964 #if defined(WITH_SELF_VERIFICATION)
genSelfVerificationPreBranch(CompilationUnit * cUnit,MipsLIR * origLIR)965 static void genSelfVerificationPreBranch(CompilationUnit *cUnit,
966                                          MipsLIR *origLIR) {
967 // DOUGLAS - this still needs to be implemented for MIPS.
968 #if 0
969     /*
970      * We need two separate pushes, since we want r5 to be pushed first.
971      * Store multiple will push LR first.
972      */
973     MipsLIR *pushFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
974     pushFP->opcode = kThumbPush;
975     pushFP->operands[0] = 1 << r5FP;
976     setupResourceMasks(pushFP);
977     dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushFP);
978 
979     MipsLIR *pushLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
980     pushLR->opcode = kThumbPush;
981     /* Thumb push can handle LR, but is encoded differently at bit 8 */
982     pushLR->operands[0] = 1 << 8;
983     setupResourceMasks(pushLR);
984     dvmCompilerInsertLIRBefore((LIR *) origLIR, (LIR *) pushLR);
985 #endif
986 }
987 
genSelfVerificationPostBranch(CompilationUnit * cUnit,MipsLIR * origLIR)988 static void genSelfVerificationPostBranch(CompilationUnit *cUnit,
989                                          MipsLIR *origLIR) {
990 // DOUGLAS - this still needs to be implemented for MIPS.
991 #if 0
992     /*
993      * Since Thumb cannot pop memory content into LR, we have to pop LR
994      * to a temp first (r5 in this case). Then we move r5 to LR, then pop the
995      * original r5 from stack.
996      */
997     /* Pop memory content(LR) into r5 first */
998     MipsLIR *popForLR = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
999     popForLR->opcode = kThumbPop;
1000     popForLR->operands[0] = 1 << r5FP;
1001     setupResourceMasks(popForLR);
1002     dvmCompilerInsertLIRAfter((LIR *) origLIR, (LIR *) popForLR);
1003 
1004     MipsLIR *copy = genRegCopyNoInsert(cUnit, r14lr, r5FP);
1005     dvmCompilerInsertLIRAfter((LIR *) popForLR, (LIR *) copy);
1006 
1007     /* Now restore the original r5 */
1008     MipsLIR *popFP = (MipsLIR *) dvmCompilerNew(sizeof(MipsLIR), true);
1009     popFP->opcode = kThumbPop;
1010     popFP->operands[0] = 1 << r5FP;
1011     setupResourceMasks(popFP);
1012     dvmCompilerInsertLIRAfter((LIR *) copy, (LIR *) popFP);
1013 #endif
1014 }
1015 #endif
1016