OSDN Git Service

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