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
25static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7};
26
27static void storePair(CompilationUnit *cUnit, int base, int lowReg,
28                      int highReg);
29static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
30static ArmLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
31                            int rDest);
32static ArmLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
33                             int displacement, int rSrc);
34static 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 */
49static 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 */
104static 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 */
117static 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
143static 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
157static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
158{
159    return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
160}
161
162static 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
179static 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
193static 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
250static 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
278static 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
373static 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
459static 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. */
469static 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. */
512static 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
549static 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
562static 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
575static 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
697static 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
705static 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
713static 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
807static 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
813static 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
819static 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
829static 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
839static 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
863static 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
870static 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
883static 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)
900static 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
920static 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