OSDN Git Service

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