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