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