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