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, r8, r9, r10, r11, r12};
26static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
27                        fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
28
29static int encodeImmSingle(int value)
30{
31    int res;
32    int bitA =    (value & 0x80000000) >> 31;
33    int notBitB = (value & 0x40000000) >> 30;
34    int bitB =    (value & 0x20000000) >> 29;
35    int bSmear =  (value & 0x3e000000) >> 25;
36    int slice =   (value & 0x01f80000) >> 19;
37    int zeroes =  (value & 0x0007ffff);
38    if (zeroes != 0)
39        return -1;
40    if (bitB) {
41        if ((notBitB != 0) || (bSmear != 0x1f))
42            return -1;
43    } else {
44        if ((notBitB != 1) || (bSmear != 0x0))
45            return -1;
46    }
47    res = (bitA << 7) | (bitB << 6) | slice;
48    return res;
49}
50
51static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
52                                   int value)
53{
54    int encodedImm = encodeImmSingle(value);
55    assert(SINGLEREG(rDest));
56    if (encodedImm >= 0) {
57        return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
58    }
59    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
60    if (dataTarget == NULL) {
61        dataTarget = addWordData(cUnit, value, false);
62    }
63    ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
64    loadPcRel->opCode = kThumb2Vldrs;
65    loadPcRel->generic.target = (LIR *) dataTarget;
66    loadPcRel->operands[0] = rDest;
67    loadPcRel->operands[1] = rpc;
68    setupResourceMasks(loadPcRel);
69    // Self-cosim workaround.
70    if (rDest != rlr)
71        setMemRefType(loadPcRel, true, kLiteral);
72    loadPcRel->aliasInfo = dataTarget->operands[0];
73    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
74    return loadPcRel;
75}
76
77static int leadingZeros(u4 val)
78{
79    u4 alt;
80    int n;
81    int count;
82
83    count = 16;
84    n = 32;
85    do {
86        alt = val >> count;
87        if (alt != 0) {
88            n = n - count;
89            val = alt;
90        }
91        count >>= 1;
92    } while (count);
93    return n - val;
94}
95
96/*
97 * Determine whether value can be encoded as a Thumb2 modified
98 * immediate.  If not, return -1.  If so, return i:imm3:a:bcdefgh form.
99 */
100static int modifiedImmediate(u4 value)
101{
102   int zLeading;
103   int zTrailing;
104   u4 b0 = value & 0xff;
105
106   /* Note: case of value==0 must use 0:000:0:0000000 encoding */
107   if (value <= 0xFF)
108       return b0;  // 0:000:a:bcdefgh
109   if (value == ((b0 << 16) | b0))
110       return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
111   if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
112       return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
113   b0 = (value >> 8) & 0xff;
114   if (value == ((b0 << 24) | (b0 << 8)))
115       return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
116   /* Can we do it with rotation? */
117   zLeading = leadingZeros(value);
118   zTrailing = 32 - leadingZeros(~value & (value - 1));
119   /* A run of eight or fewer active bits? */
120   if ((zLeading + zTrailing) < 24)
121       return -1;  /* No - bail */
122   /* left-justify the constant, discarding msb (known to be 1) */
123   value <<= zLeading + 1;
124   /* Create bcdefgh */
125   value >>= 25;
126   /* Put it all together */
127   return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
128}
129
130/*
131 * Load a immediate using a shortcut if possible; otherwise
132 * grab from the per-translation literal pool.
133 *
134 * No additional register clobbering operation performed. Use this version when
135 * 1) rDest is freshly returned from dvmCompilerAllocTemp or
136 * 2) The codegen is under fixed register usage
137 */
138static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
139                                     int value)
140{
141    ArmLIR *res;
142    int modImm;
143
144    if (FPREG(rDest)) {
145        return loadFPConstantValue(cUnit, rDest, value);
146    }
147
148    /* See if the value can be constructed cheaply */
149    if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
150        return newLIR2(cUnit, kThumbMovImm, rDest, value);
151    }
152    /* Check Modified immediate special cases */
153    modImm = modifiedImmediate(value);
154    if (modImm >= 0) {
155        res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
156        return res;
157    }
158    modImm = modifiedImmediate(~value);
159    if (modImm >= 0) {
160        res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
161        return res;
162    }
163    /* 16-bit immediate? */
164    if ((value & 0xffff) == value) {
165        res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
166        return res;
167    }
168    /* No shortcut - go ahead and use literal pool */
169    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
170    if (dataTarget == NULL) {
171        dataTarget = addWordData(cUnit, value, false);
172    }
173    ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
174    loadPcRel->opCode = kThumb2LdrPcRel12;
175    loadPcRel->generic.target = (LIR *) dataTarget;
176    loadPcRel->operands[0] = rDest;
177    setupResourceMasks(loadPcRel);
178    /*
179     * Special case for literal loads with a link register target.
180     * Self-cosim mode will insert calls prior to heap references
181     * after optimization, and those will destroy r14.  The easy
182     * workaround is to treat literal loads into r14 as heap references
183     * to prevent them from being hoisted.  Use of r14 in this manner
184     * is currently rare.  Revisit if that changes.
185     */
186    if (rDest != rlr)
187        setMemRefType(loadPcRel, true, kLiteral);
188    loadPcRel->aliasInfo = dataTarget->operands[0];
189    res = loadPcRel;
190    dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
191
192    /*
193     * To save space in the constant pool, we use the ADD_RRI8 instruction to
194     * add up to 255 to an existing constant value.
195     */
196    if (dataTarget->operands[0] != value) {
197        opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
198    }
199    return res;
200}
201
202/*
203 * Load an immediate value into a fixed or temp register.  Target
204 * register is clobbered, and marked inUse.
205 */
206static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
207{
208    if (dvmCompilerIsTemp(cUnit, rDest)) {
209        dvmCompilerClobber(cUnit, rDest);
210        dvmCompilerMarkInUse(cUnit, rDest);
211    }
212    return loadConstantNoClobber(cUnit, rDest, value);
213}
214
215static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
216{
217    ArmOpCode opCode = kThumbBkpt;
218    switch (op) {
219        case kOpUncondBr:
220            opCode = kThumbBUncond;
221            break;
222        default:
223            assert(0);
224    }
225    return newLIR0(cUnit, opCode);
226}
227
228static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
229{
230    return newLIR2(cUnit, kThumb2BCond, 0 /* offset to be patched */, cc);
231}
232
233static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
234{
235    ArmOpCode opCode = kThumbBkpt;
236    switch (op) {
237        case kOpPush:
238            opCode = ((value & 0xff00) != 0) ? kThumb2Push : kThumbPush;
239            break;
240        case kOpPop:
241            opCode = ((value & 0xff00) != 0) ? kThumb2Pop : kThumbPop;
242            break;
243        default:
244            assert(0);
245    }
246    return newLIR1(cUnit, opCode, value);
247}
248
249static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
250{
251    ArmOpCode opCode = kThumbBkpt;
252    switch (op) {
253        case kOpBlx:
254            opCode = kThumbBlxR;
255            break;
256        default:
257            assert(0);
258    }
259    return newLIR1(cUnit, opCode, rDestSrc);
260}
261
262static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
263                        int rSrc2, int shift)
264{
265    bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
266    ArmOpCode opCode = kThumbBkpt;
267    switch (op) {
268        case kOpAdc:
269            opCode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
270            break;
271        case kOpAnd:
272            opCode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
273            break;
274        case kOpBic:
275            opCode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
276            break;
277        case kOpCmn:
278            assert(shift == 0);
279            opCode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
280            break;
281        case kOpCmp:
282            if (thumbForm)
283                opCode = kThumbCmpRR;
284            else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
285                opCode = kThumbCmpHH;
286            else if ((shift == 0) && LOWREG(rDestSrc1))
287                opCode = kThumbCmpLH;
288            else if (shift == 0)
289                opCode = kThumbCmpHL;
290            else
291                opCode = kThumb2CmpRR;
292            break;
293        case kOpXor:
294            opCode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
295            break;
296        case kOpMov:
297            assert(shift == 0);
298            if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
299                opCode = kThumbMovRR;
300            else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
301                opCode = kThumbMovRR_H2H;
302            else if (LOWREG(rDestSrc1))
303                opCode = kThumbMovRR_H2L;
304            else
305                opCode = kThumbMovRR_L2H;
306            break;
307        case kOpMul:
308            assert(shift == 0);
309            opCode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
310            break;
311        case kOpMvn:
312            opCode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
313            break;
314        case kOpNeg:
315            assert(shift == 0);
316            opCode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
317            break;
318        case kOpOr:
319            opCode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
320            break;
321        case kOpSbc:
322            opCode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
323            break;
324        case kOpTst:
325            opCode = (thumbForm) ? kThumbTst : kThumb2TstRR;
326            break;
327        case kOpLsl:
328            assert(shift == 0);
329            opCode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
330            break;
331        case kOpLsr:
332            assert(shift == 0);
333            opCode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
334            break;
335        case kOpAsr:
336            assert(shift == 0);
337            opCode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
338            break;
339        case kOpRor:
340            assert(shift == 0);
341            opCode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
342            break;
343        case kOpAdd:
344            opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
345            break;
346        case kOpSub:
347            opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
348            break;
349        case kOp2Byte:
350            assert(shift == 0);
351            return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
352        case kOp2Short:
353            assert(shift == 0);
354            return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
355        case kOp2Char:
356            assert(shift == 0);
357            return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
358        default:
359            assert(0);
360            break;
361    }
362    assert(opCode >= 0);
363    if (EncodingMap[opCode].flags & IS_BINARY_OP)
364        return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
365    else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
366        if (EncodingMap[opCode].fieldLoc[2].kind == kFmtShift)
367            return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
368        else
369            return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
370    } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
371        return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
372    else {
373        assert(0);
374        return NULL;
375    }
376}
377
378static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
379                        int rSrc2)
380{
381    return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
382}
383
384static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
385                                int rDest, int rSrc1, int rSrc2, int shift)
386{
387    ArmOpCode opCode = kThumbBkpt;
388    bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
389                      LOWREG(rSrc2);
390    switch (op) {
391        case kOpAdd:
392            opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
393            break;
394        case kOpSub:
395            opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
396            break;
397        case kOpAdc:
398            opCode = kThumb2AdcRRR;
399            break;
400        case kOpAnd:
401            opCode = kThumb2AndRRR;
402            break;
403        case kOpBic:
404            opCode = kThumb2BicRRR;
405            break;
406        case kOpXor:
407            opCode = kThumb2EorRRR;
408            break;
409        case kOpMul:
410            assert(shift == 0);
411            opCode = kThumb2MulRRR;
412            break;
413        case kOpOr:
414            opCode = kThumb2OrrRRR;
415            break;
416        case kOpSbc:
417            opCode = kThumb2SbcRRR;
418            break;
419        case kOpLsl:
420            assert(shift == 0);
421            opCode = kThumb2LslRRR;
422            break;
423        case kOpLsr:
424            assert(shift == 0);
425            opCode = kThumb2LsrRRR;
426            break;
427        case kOpAsr:
428            assert(shift == 0);
429            opCode = kThumb2AsrRRR;
430            break;
431        case kOpRor:
432            assert(shift == 0);
433            opCode = kThumb2RorRRR;
434            break;
435        default:
436            assert(0);
437            break;
438    }
439    assert(opCode >= 0);
440    if (EncodingMap[opCode].flags & IS_QUAD_OP)
441        return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
442    else {
443        assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
444        return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
445    }
446}
447
448static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
449                           int rSrc1, int rSrc2)
450{
451    return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
452}
453
454static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
455                           int rSrc1, int value)
456{
457    ArmLIR *res;
458    bool neg = (value < 0);
459    int absValue = (neg) ? -value : value;
460    ArmOpCode opCode = kThumbBkpt;
461    ArmOpCode altOpCode = kThumbBkpt;
462    bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
463    int modImm = modifiedImmediate(value);
464    int modImmNeg = modifiedImmediate(-value);
465
466    switch(op) {
467        case kOpLsl:
468            if (allLowRegs)
469                return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
470            else
471                return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
472        case kOpLsr:
473            if (allLowRegs)
474                return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
475            else
476                return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
477        case kOpAsr:
478            if (allLowRegs)
479                return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
480            else
481                return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
482        case kOpRor:
483            return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
484        case kOpAdd:
485            if (LOWREG(rDest) && (rSrc1 == 13) &&
486                (value <= 1020) && ((value & 0x3)==0)) {
487                return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
488                               value >> 2);
489            } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
490                       (value <= 1020) && ((value & 0x3)==0)) {
491                return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
492                               value >> 2);
493            }
494            opCode = kThumb2AddRRI8;
495            altOpCode = kThumb2AddRRR;
496            // Note: intentional fallthrough
497        case kOpSub:
498            if (allLowRegs && ((absValue & 0x7) == absValue)) {
499                if (op == kOpAdd)
500                    opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
501                else
502                    opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
503                return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
504            } else if ((absValue & 0xff) == absValue) {
505                if (op == kOpAdd)
506                    opCode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
507                else
508                    opCode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
509                return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
510            }
511            if (modImmNeg >= 0) {
512                op = (op == kOpAdd) ? kOpSub : kOpAdd;
513                modImm = modImmNeg;
514            }
515            if (op == kOpSub) {
516                opCode = kThumb2SubRRI8;
517                altOpCode = kThumb2SubRRR;
518            }
519            break;
520        case kOpAdc:
521            opCode = kThumb2AdcRRI8;
522            altOpCode = kThumb2AdcRRR;
523            break;
524        case kOpSbc:
525            opCode = kThumb2SbcRRI8;
526            altOpCode = kThumb2SbcRRR;
527            break;
528        case kOpOr:
529            opCode = kThumb2OrrRRI8;
530            altOpCode = kThumb2OrrRRR;
531            break;
532        case kOpAnd:
533            opCode = kThumb2AndRRI8;
534            altOpCode = kThumb2AndRRR;
535            break;
536        case kOpXor:
537            opCode = kThumb2EorRRI8;
538            altOpCode = kThumb2EorRRR;
539            break;
540        case kOpMul:
541            //TUNING: power of 2, shift & add
542            modImm = -1;
543            altOpCode = kThumb2MulRRR;
544            break;
545        case kOpCmp: {
546            int modImm = modifiedImmediate(value);
547            ArmLIR *res;
548            if (modImm >= 0) {
549                res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
550            } else {
551                int rTmp = dvmCompilerAllocTemp(cUnit);
552                res = loadConstant(cUnit, rTmp, value);
553                opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
554                dvmCompilerFreeTemp(cUnit, rTmp);
555            }
556            return res;
557        }
558        default:
559            assert(0);
560    }
561
562    if (modImm >= 0) {
563        return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
564    } else {
565        int rScratch = dvmCompilerAllocTemp(cUnit);
566        loadConstant(cUnit, rScratch, value);
567        if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
568            res = newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
569        else
570            res = newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
571        dvmCompilerFreeTemp(cUnit, rScratch);
572        return res;
573    }
574}
575
576/* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
577static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
578                        int value)
579{
580    bool neg = (value < 0);
581    int absValue = (neg) ? -value : value;
582    bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
583    ArmOpCode opCode = kThumbBkpt;
584    switch (op) {
585        case kOpAdd:
586            if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
587                assert((value & 0x3) == 0);
588                return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
589            } else if (shortForm) {
590                opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
591            }
592            break;
593        case kOpSub:
594            if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
595                assert((value & 0x3) == 0);
596                return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
597            } else if (shortForm) {
598                opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
599            }
600            break;
601        case kOpCmp:
602            if (LOWREG(rDestSrc1) && shortForm)
603                opCode = (shortForm) ?  kThumbCmpRI8 : kThumbCmpRR;
604            else if (LOWREG(rDestSrc1))
605                opCode = kThumbCmpRR;
606            else {
607                shortForm = false;
608                opCode = kThumbCmpHL;
609            }
610            break;
611        default:
612            /* Punt to opRegRegImm - if bad case catch it there */
613            shortForm = false;
614            break;
615    }
616    if (shortForm)
617        return newLIR2(cUnit, opCode, rDestSrc1, absValue);
618    else {
619        return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
620    }
621}
622
623/*
624 * Determine whether value can be encoded as a Thumb2 floating point
625 * immediate.  If not, return -1.  If so return encoded 8-bit value.
626 */
627static int encodeImmDoubleHigh(int value)
628{
629    int res;
630    int bitA =    (value & 0x80000000) >> 31;
631    int notBitB = (value & 0x40000000) >> 30;
632    int bitB =    (value & 0x20000000) >> 29;
633    int bSmear =  (value & 0x3fc00000) >> 22;
634    int slice =   (value & 0x003f0000) >> 16;
635    int zeroes =  (value & 0x0000ffff);
636    if (zeroes != 0)
637        return -1;
638    if (bitB) {
639        if ((notBitB != 0) || (bSmear != 0x1f))
640            return -1;
641    } else {
642        if ((notBitB != 1) || (bSmear != 0x0))
643            return -1;
644    }
645    res = (bitA << 7) | (bitB << 6) | slice;
646    return res;
647}
648
649static int encodeImmDouble(int valLo, int valHi)
650{
651    int res = -1;
652    if (valLo == 0)
653        res = encodeImmDoubleHigh(valHi);
654    return res;
655}
656
657static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
658                                     int rDestHi, int valLo, int valHi)
659{
660    int encodedImm = encodeImmDouble(valLo, valHi);
661    ArmLIR *res;
662    if (FPREG(rDestLo) && (encodedImm >= 0)) {
663        res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
664                      encodedImm);
665    } else {
666        res = loadConstantNoClobber(cUnit, rDestLo, valLo);
667        loadConstantNoClobber(cUnit, rDestHi, valHi);
668    }
669    return res;
670}
671
672static int encodeShift(int code, int amount) {
673    return ((amount & 0x1f) << 2) | code;
674}
675
676static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
677                               int rIndex, int rDest, int scale, OpSize size)
678{
679    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
680    ArmLIR *load;
681    ArmOpCode opCode = kThumbBkpt;
682    bool thumbForm = (allLowRegs && (scale == 0));
683    int regPtr;
684
685    if (FPREG(rDest)) {
686        assert(SINGLEREG(rDest));
687        assert((size == kWord) || (size == kSingle));
688        opCode = kThumb2Vldrs;
689        size = kSingle;
690    } else {
691        if (size == kSingle)
692            size = kWord;
693    }
694
695    switch (size) {
696        case kSingle:
697            regPtr = dvmCompilerAllocTemp(cUnit);
698            if (scale) {
699                newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
700                        encodeShift(kArmLsl, scale));
701            } else {
702                opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
703            }
704            load = newLIR3(cUnit, opCode, rDest, regPtr, 0);
705#if defined(WITH_SELF_VERIFICATION)
706            if (cUnit->heapMemOp)
707                load->branchInsertSV = true;
708#endif
709            return load;
710        case kWord:
711            opCode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
712            break;
713        case kUnsignedHalf:
714            opCode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
715            break;
716        case kSignedHalf:
717            opCode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
718            break;
719        case kUnsignedByte:
720            opCode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
721            break;
722        case kSignedByte:
723            opCode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
724            break;
725        default:
726            assert(0);
727    }
728    if (thumbForm)
729        load = newLIR3(cUnit, opCode, rDest, rBase, rIndex);
730    else
731        load = newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
732
733#if defined(WITH_SELF_VERIFICATION)
734    if (cUnit->heapMemOp)
735        load->branchInsertSV = true;
736#endif
737    return load;
738}
739
740static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
741                                int rIndex, int rSrc, int scale, OpSize size)
742{
743    bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
744    ArmLIR *store;
745    ArmOpCode opCode = kThumbBkpt;
746    bool thumbForm = (allLowRegs && (scale == 0));
747    int regPtr;
748
749    if (FPREG(rSrc)) {
750        assert(SINGLEREG(rSrc));
751        assert((size == kWord) || (size == kSingle));
752        opCode = kThumb2Vstrs;
753        size = kSingle;
754    } else {
755        if (size == kSingle)
756            size = kWord;
757    }
758
759    switch (size) {
760        case kSingle:
761            regPtr = dvmCompilerAllocTemp(cUnit);
762            if (scale) {
763                newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
764                        encodeShift(kArmLsl, scale));
765            } else {
766                opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
767            }
768            store = newLIR3(cUnit, opCode, rSrc, regPtr, 0);
769#if defined(WITH_SELF_VERIFICATION)
770            if (cUnit->heapMemOp)
771                store->branchInsertSV = true;
772#endif
773            return store;
774        case kWord:
775            opCode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
776            break;
777        case kUnsignedHalf:
778        case kSignedHalf:
779            opCode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
780            break;
781        case kUnsignedByte:
782        case kSignedByte:
783            opCode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
784            break;
785        default:
786            assert(0);
787    }
788    if (thumbForm)
789        store = newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
790    else
791        store = newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
792
793#if defined(WITH_SELF_VERIFICATION)
794    if (cUnit->heapMemOp)
795        store->branchInsertSV = true;
796#endif
797    return store;
798}
799
800/*
801 * Load value from base + displacement.  Optionally perform null check
802 * on base (which must have an associated sReg and MIR).  If not
803 * performing null check, incoming MIR can be null.
804 */
805static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
806                                int displacement, int rDest, int rDestHi,
807                                OpSize size, int sReg)
808{
809    ArmLIR *res, *load;
810    ArmOpCode opCode = kThumbBkpt;
811    bool shortForm = false;
812    bool thumb2Form = (displacement < 4092 && displacement >= 0);
813    bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
814    int encodedDisp = displacement;
815
816    switch (size) {
817        case kDouble:
818        case kLong:
819            if (FPREG(rDest)) {
820                if (SINGLEREG(rDest)) {
821                    assert(FPREG(rDestHi));
822                    rDest = S2D(rDest, rDestHi);
823                }
824                opCode = kThumb2Vldrd;
825                if (displacement <= 1020) {
826                    shortForm = true;
827                    encodedDisp >>= 2;
828                }
829                break;
830            } else {
831                res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
832                                       -1, kWord, sReg);
833                loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
834                                 -1, kWord, INVALID_SREG);
835                return res;
836            }
837        case kSingle:
838        case kWord:
839            if (FPREG(rDest)) {
840                opCode = kThumb2Vldrs;
841                if (displacement <= 1020) {
842                    shortForm = true;
843                    encodedDisp >>= 2;
844                }
845                break;
846            }
847            if (LOWREG(rDest) && (rBase == rpc) &&
848                (displacement <= 1020) && (displacement >= 0)) {
849                shortForm = true;
850                encodedDisp >>= 2;
851                opCode = kThumbLdrPcRel;
852            } else if (LOWREG(rDest) && (rBase == r13) &&
853                      (displacement <= 1020) && (displacement >= 0)) {
854                shortForm = true;
855                encodedDisp >>= 2;
856                opCode = kThumbLdrSpRel;
857            } else if (allLowRegs && displacement < 128 && displacement >= 0) {
858                assert((displacement & 0x3) == 0);
859                shortForm = true;
860                encodedDisp >>= 2;
861                opCode = kThumbLdrRRI5;
862            } else if (thumb2Form) {
863                shortForm = true;
864                opCode = kThumb2LdrRRI12;
865            }
866            break;
867        case kUnsignedHalf:
868            if (allLowRegs && displacement < 64 && displacement >= 0) {
869                assert((displacement & 0x1) == 0);
870                shortForm = true;
871                encodedDisp >>= 1;
872                opCode = kThumbLdrhRRI5;
873            } else if (displacement < 4092 && displacement >= 0) {
874                shortForm = true;
875                opCode = kThumb2LdrhRRI12;
876            }
877            break;
878        case kSignedHalf:
879            if (thumb2Form) {
880                shortForm = true;
881                opCode = kThumb2LdrshRRI12;
882            }
883            break;
884        case kUnsignedByte:
885            if (allLowRegs && displacement < 32 && displacement >= 0) {
886                shortForm = true;
887                opCode = kThumbLdrbRRI5;
888            } else if (thumb2Form) {
889                shortForm = true;
890                opCode = kThumb2LdrbRRI12;
891            }
892            break;
893        case kSignedByte:
894            if (thumb2Form) {
895                shortForm = true;
896                opCode = kThumb2LdrsbRRI12;
897            }
898            break;
899        default:
900            assert(0);
901    }
902
903    if (shortForm) {
904        load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
905    } else {
906        int regOffset = dvmCompilerAllocTemp(cUnit);
907        res = loadConstant(cUnit, regOffset, encodedDisp);
908        load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
909        dvmCompilerFreeTemp(cUnit, regOffset);
910    }
911
912    if (rBase == rFP) {
913        annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
914    }
915#if defined(WITH_SELF_VERIFICATION)
916    if (cUnit->heapMemOp)
917        load->branchInsertSV = true;
918#endif
919    return res;
920}
921
922static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
923                            int displacement, int rDest, OpSize size,
924                            int sReg)
925{
926    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
927                            size, sReg);
928}
929
930static  ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
931                                 int displacement, int rDestLo, int rDestHi,
932                                 int sReg)
933{
934    return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
935                            kLong, sReg);
936}
937
938
939static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
940                                 int displacement, int rSrc, int rSrcHi,
941                                 OpSize size)
942{
943    ArmLIR *res, *store;
944    ArmOpCode opCode = kThumbBkpt;
945    bool shortForm = false;
946    bool thumb2Form = (displacement < 4092 && displacement >= 0);
947    bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
948    int encodedDisp = displacement;
949
950    switch (size) {
951        case kLong:
952        case kDouble:
953            if (!FPREG(rSrc)) {
954                res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
955                                        -1, kWord);
956                storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
957                                  -1, kWord);
958                return res;
959            }
960            if (SINGLEREG(rSrc)) {
961                assert(FPREG(rSrcHi));
962                rSrc = S2D(rSrc, rSrcHi);
963            }
964            opCode = kThumb2Vstrd;
965            if (displacement <= 1020) {
966                shortForm = true;
967                encodedDisp >>= 2;
968            }
969            break;
970        case kSingle:
971        case kWord:
972            if (FPREG(rSrc)) {
973                assert(SINGLEREG(rSrc));
974                opCode = kThumb2Vstrs;
975                if (displacement <= 1020) {
976                    shortForm = true;
977                    encodedDisp >>= 2;
978                }
979            break;
980            }
981            if (allLowRegs && displacement < 128 && displacement >= 0) {
982                assert((displacement & 0x3) == 0);
983                shortForm = true;
984                encodedDisp >>= 2;
985                opCode = kThumbStrRRI5;
986            } else if (thumb2Form) {
987                shortForm = true;
988                opCode = kThumb2StrRRI12;
989            }
990            break;
991        case kUnsignedHalf:
992        case kSignedHalf:
993            if (allLowRegs && displacement < 64 && displacement >= 0) {
994                assert((displacement & 0x1) == 0);
995                shortForm = true;
996                encodedDisp >>= 1;
997                opCode = kThumbStrhRRI5;
998            } else if (thumb2Form) {
999                shortForm = true;
1000                opCode = kThumb2StrhRRI12;
1001            }
1002            break;
1003        case kUnsignedByte:
1004        case kSignedByte:
1005            if (allLowRegs && displacement < 32 && displacement >= 0) {
1006                shortForm = true;
1007                opCode = kThumbStrbRRI5;
1008            } else if (thumb2Form) {
1009                shortForm = true;
1010                opCode = kThumb2StrbRRI12;
1011            }
1012            break;
1013        default:
1014            assert(0);
1015    }
1016    if (shortForm) {
1017        store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
1018    } else {
1019        int rScratch = dvmCompilerAllocTemp(cUnit);
1020        res = loadConstant(cUnit, rScratch, encodedDisp);
1021        store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
1022        dvmCompilerFreeTemp(cUnit, rScratch);
1023    }
1024
1025    if (rBase == rFP) {
1026        annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
1027    }
1028#if defined(WITH_SELF_VERIFICATION)
1029    if (cUnit->heapMemOp)
1030        store->branchInsertSV = true;
1031#endif
1032    return res;
1033}
1034
1035static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
1036                             int displacement, int rSrc, OpSize size)
1037{
1038    return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
1039}
1040
1041static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
1042                                 int displacement, int rSrcLo, int rSrcHi)
1043{
1044    return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
1045}
1046
1047static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
1048{
1049    ArmLIR *res;
1050    genBarrier(cUnit);
1051    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
1052        res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
1053    } else {
1054        res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask);
1055    }
1056#if defined(WITH_SELF_VERIFICATION)
1057    if (cUnit->heapMemOp)
1058        res->branchInsertSV = true;
1059#endif
1060    genBarrier(cUnit);
1061    return res;
1062}
1063
1064static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
1065{
1066    ArmLIR *res;
1067    genBarrier(cUnit);
1068    if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
1069        res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
1070    } else {
1071        res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask);
1072    }
1073#if defined(WITH_SELF_VERIFICATION)
1074    if (cUnit->heapMemOp)
1075        res->branchInsertSV = true;
1076#endif
1077    genBarrier(cUnit);
1078    return res;
1079}
1080
1081static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
1082{
1083    storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
1084}
1085
1086static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
1087{
1088    loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
1089}
1090
1091
1092/*
1093 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
1094 * satisfies.
1095 */
1096static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
1097                              ArmConditionCode cond, int reg,
1098                              int checkValue, int dOffset,
1099                              ArmLIR *pcrLabel)
1100{
1101    ArmLIR *branch;
1102    int modImm;
1103    if ((LOWREG(reg)) && (checkValue == 0) &&
1104       ((cond == kArmCondEq) || (cond == kArmCondNe))) {
1105        branch = newLIR2(cUnit,
1106                         (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
1107                         reg, 0);
1108    } else {
1109        modImm = modifiedImmediate(checkValue);
1110        if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
1111            newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
1112        } else if (modImm >= 0) {
1113            newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
1114        } else {
1115            int tReg = dvmCompilerAllocTemp(cUnit);
1116            loadConstant(cUnit, tReg, checkValue);
1117            opRegReg(cUnit, kOpCmp, reg, tReg);
1118        }
1119        branch = newLIR2(cUnit, kThumbBCond, 0, cond);
1120    }
1121    return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
1122}
1123
1124static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1125{
1126    ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
1127    res->operands[0] = rDest;
1128    res->operands[1] = rSrc;
1129    if (rDest == rSrc) {
1130        res->isNop = true;
1131    } else {
1132        assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
1133        if (DOUBLEREG(rDest)) {
1134            res->opCode = kThumb2Vmovd;
1135        } else {
1136            if (SINGLEREG(rDest)) {
1137                res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
1138            } else {
1139                assert(SINGLEREG(rSrc));
1140                res->opCode = kThumb2Fmrs;
1141            }
1142        }
1143        res->operands[0] = rDest;
1144        res->operands[1] = rSrc;
1145    }
1146    setupResourceMasks(res);
1147    return res;
1148}
1149
1150static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
1151{
1152    ArmLIR* res;
1153    ArmOpCode opCode;
1154    if (FPREG(rDest) || FPREG(rSrc))
1155        return fpRegCopy(cUnit, rDest, rSrc);
1156    res = dvmCompilerNew(sizeof(ArmLIR), true);
1157    if (LOWREG(rDest) && LOWREG(rSrc))
1158        opCode = kThumbMovRR;
1159    else if (!LOWREG(rDest) && !LOWREG(rSrc))
1160         opCode = kThumbMovRR_H2H;
1161    else if (LOWREG(rDest))
1162         opCode = kThumbMovRR_H2L;
1163    else
1164         opCode = kThumbMovRR_L2H;
1165
1166    res->operands[0] = rDest;
1167    res->operands[1] = rSrc;
1168    res->opCode = opCode;
1169    setupResourceMasks(res);
1170    if (rDest == rSrc) {
1171        res->isNop = true;
1172    }
1173    return res;
1174}
1175
1176static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1177{
1178    ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
1179    dvmCompilerAppendLIR(cUnit, (LIR*)res);
1180    return res;
1181}
1182
1183static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
1184                           int srcLo, int srcHi)
1185{
1186    bool destFP = FPREG(destLo) && FPREG(destHi);
1187    bool srcFP = FPREG(srcLo) && FPREG(srcHi);
1188    assert(FPREG(srcLo) == FPREG(srcHi));
1189    assert(FPREG(destLo) == FPREG(destHi));
1190    if (destFP) {
1191        if (srcFP) {
1192            genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
1193        } else {
1194            newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
1195        }
1196    } else {
1197        if (srcFP) {
1198            newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
1199        } else {
1200            // Handle overlap
1201            if (srcHi == destLo) {
1202                genRegCopy(cUnit, destHi, srcHi);
1203                genRegCopy(cUnit, destLo, srcLo);
1204            } else {
1205                genRegCopy(cUnit, destLo, srcLo);
1206                genRegCopy(cUnit, destHi, srcHi);
1207            }
1208        }
1209    }
1210}
1211