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[] = {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
28static 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
32static void storePair(CompilationUnit *cUnit, int base, int lowReg,
33                      int highReg);
34static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg);
35static MipsLIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement,
36                            int rDest);
37static MipsLIR *storeWordDisp(CompilationUnit *cUnit, int rBase,
38                             int displacement, int rSrc);
39static MipsLIR *genRegRegCheck(CompilationUnit *cUnit,
40                              MipsConditionCode cond,
41                              int reg1, int reg2, int dOffset,
42                              MipsLIR *pcrLabel);
43static MipsLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value);
44
45#ifdef __mips_hard_float
46static 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 */
88static 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 */
129static 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 */
142static 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
155static 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
171static 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
184static MipsLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask);
185
186static 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
199static MipsLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
200                           int rSrc1, int value);
201static 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
234static 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
274static 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
365static 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
411static 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. */
421static 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. */
483static 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
540static 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
566static 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
592static 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
702static 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
710static 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
718static 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
811static 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
817static 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
823static 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
829static 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
835static 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
856static 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
863static 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
906static 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)
965static 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
988static 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