2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * This file contains codegen for the Thumb ISA and is intended to be
21 * Codegen-$(TARGET_ARCH_VARIANT).c
25 static int coreTemps[] = {r0, r1, r2, r3, r4PC, r7, r8, r9, r10, r11, r12};
26 static int corePreserved[] = {};
27 static int fpTemps[] = {fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
28 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
29 static int fpPreserved[] = {};
31 static int encodeImmSingle(int value)
34 int bitA = (value & 0x80000000) >> 31;
35 int notBitB = (value & 0x40000000) >> 30;
36 int bitB = (value & 0x20000000) >> 29;
37 int bSmear = (value & 0x3e000000) >> 25;
38 int slice = (value & 0x01f80000) >> 19;
39 int zeroes = (value & 0x0007ffff);
43 if ((notBitB != 0) || (bSmear != 0x1f))
46 if ((notBitB != 1) || (bSmear != 0x0))
49 res = (bitA << 7) | (bitB << 6) | slice;
53 static ArmLIR *loadFPConstantValue(CompilationUnit *cUnit, int rDest,
56 int encodedImm = encodeImmSingle(value);
57 assert(SINGLEREG(rDest));
58 if (encodedImm >= 0) {
59 return newLIR2(cUnit, kThumb2Vmovs_IMM8, rDest, encodedImm);
61 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
62 if (dataTarget == NULL) {
63 dataTarget = addWordData(cUnit, value, false);
65 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
66 loadPcRel->opCode = kThumb2Vldrs;
67 loadPcRel->generic.target = (LIR *) dataTarget;
68 loadPcRel->operands[0] = rDest;
69 loadPcRel->operands[1] = rpc;
70 setupResourceMasks(loadPcRel);
71 // Self-cosim workaround.
73 setMemRefType(loadPcRel, true, kLiteral);
74 loadPcRel->aliasInfo = dataTarget->operands[0];
75 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
79 static int leadingZeros(u4 val)
99 * Determine whether value can be encoded as a Thumb2 modified
100 * immediate. If not, return -1. If so, return i:imm3:a:bcdefgh form.
102 static int modifiedImmediate(u4 value)
106 u4 b0 = value & 0xff;
108 /* Note: case of value==0 must use 0:000:0:0000000 encoding */
110 return b0; // 0:000:a:bcdefgh
111 if (value == ((b0 << 16) | b0))
112 return (0x1 << 8) | b0; /* 0:001:a:bcdefgh */
113 if (value == ((b0 << 24) | (b0 << 16) | (b0 << 8) | b0))
114 return (0x3 << 8) | b0; /* 0:011:a:bcdefgh */
115 b0 = (value >> 8) & 0xff;
116 if (value == ((b0 << 24) | (b0 << 8)))
117 return (0x2 << 8) | b0; /* 0:010:a:bcdefgh */
118 /* Can we do it with rotation? */
119 zLeading = leadingZeros(value);
120 zTrailing = 32 - leadingZeros(~value & (value - 1));
121 /* A run of eight or fewer active bits? */
122 if ((zLeading + zTrailing) < 24)
123 return -1; /* No - bail */
124 /* left-justify the constant, discarding msb (known to be 1) */
125 value <<= zLeading + 1;
128 /* Put it all together */
129 return value | ((0x8 + zLeading) << 7); /* [01000..11111]:bcdefgh */
133 * Load a immediate using a shortcut if possible; otherwise
134 * grab from the per-translation literal pool.
136 * No additional register clobbering operation performed. Use this version when
137 * 1) rDest is freshly returned from dvmCompilerAllocTemp or
138 * 2) The codegen is under fixed register usage
140 static ArmLIR *loadConstantNoClobber(CompilationUnit *cUnit, int rDest,
147 return loadFPConstantValue(cUnit, rDest, value);
150 /* See if the value can be constructed cheaply */
151 if (LOWREG(rDest) && (value >= 0) && (value <= 255)) {
152 return newLIR2(cUnit, kThumbMovImm, rDest, value);
154 /* Check Modified immediate special cases */
155 modImm = modifiedImmediate(value);
157 res = newLIR2(cUnit, kThumb2MovImmShift, rDest, modImm);
160 modImm = modifiedImmediate(~value);
162 res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
165 /* 16-bit immediate? */
166 if ((value & 0xffff) == value) {
167 res = newLIR2(cUnit, kThumb2MovImm16, rDest, value);
170 /* No shortcut - go ahead and use literal pool */
171 ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
172 if (dataTarget == NULL) {
173 dataTarget = addWordData(cUnit, value, false);
175 ArmLIR *loadPcRel = dvmCompilerNew(sizeof(ArmLIR), true);
176 loadPcRel->opCode = LOWREG(rDest) ? kThumbLdrPcRel : kThumb2LdrPcRel12;
177 loadPcRel->generic.target = (LIR *) dataTarget;
178 loadPcRel->operands[0] = rDest;
179 setupResourceMasks(loadPcRel);
181 * Special case for literal loads with a link register target.
182 * Self-cosim mode will insert calls prior to heap references
183 * after optimization, and those will destroy r14. The easy
184 * workaround is to treat literal loads into r14 as heap references
185 * to prevent them from being hoisted. Use of r14 in this manner
186 * is currently rare. Revisit if that changes.
189 setMemRefType(loadPcRel, true, kLiteral);
190 loadPcRel->aliasInfo = dataTarget->operands[0];
192 dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
195 * To save space in the constant pool, we use the ADD_RRI8 instruction to
196 * add up to 255 to an existing constant value.
198 if (dataTarget->operands[0] != value) {
199 opRegImm(cUnit, kOpAdd, rDest, value - dataTarget->operands[0]);
205 * Load an immediate value into a fixed or temp register. Target
206 * register is clobbered, and marked inUse.
208 static ArmLIR *loadConstant(CompilationUnit *cUnit, int rDest, int value)
210 if (dvmCompilerIsTemp(cUnit, rDest)) {
211 dvmCompilerClobber(cUnit, rDest);
212 dvmCompilerMarkInUse(cUnit, rDest);
214 return loadConstantNoClobber(cUnit, rDest, value);
217 static ArmLIR *opNone(CompilationUnit *cUnit, OpKind op)
219 ArmOpCode opCode = kThumbBkpt;
222 opCode = kThumbBUncond;
227 return newLIR0(cUnit, opCode);
230 static ArmLIR *opCondBranch(CompilationUnit *cUnit, ArmConditionCode cc)
232 return newLIR2(cUnit, kThumbBCond, 0 /* offset to be patched */, cc);
235 static ArmLIR *opImm(CompilationUnit *cUnit, OpKind op, int value)
237 ArmOpCode opCode = kThumbBkpt;
240 opCode = ((value & 0xff00) != 0) ? kThumb2Push : kThumbPush;
243 opCode = ((value & 0xff00) != 0) ? kThumb2Pop : kThumbPop;
248 return newLIR1(cUnit, opCode, value);
251 static ArmLIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc)
253 ArmOpCode opCode = kThumbBkpt;
261 return newLIR1(cUnit, opCode, rDestSrc);
264 static ArmLIR *opRegRegShift(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
265 int rSrc2, int shift)
267 bool thumbForm = ((shift == 0) && LOWREG(rDestSrc1) && LOWREG(rSrc2));
268 ArmOpCode opCode = kThumbBkpt;
271 opCode = (thumbForm) ? kThumbAdcRR : kThumb2AdcRRR;
274 opCode = (thumbForm) ? kThumbAndRR : kThumb2AndRRR;
277 opCode = (thumbForm) ? kThumbBicRR : kThumb2BicRRR;
281 opCode = (thumbForm) ? kThumbCmnRR : kThumb2CmnRR;
285 opCode = kThumbCmpRR;
286 else if ((shift == 0) && !LOWREG(rDestSrc1) && !LOWREG(rSrc2))
287 opCode = kThumbCmpHH;
288 else if ((shift == 0) && LOWREG(rDestSrc1))
289 opCode = kThumbCmpLH;
291 opCode = kThumbCmpHL;
293 opCode = kThumb2CmpRR;
296 opCode = (thumbForm) ? kThumbEorRR : kThumb2EorRRR;
300 if (LOWREG(rDestSrc1) && LOWREG(rSrc2))
301 opCode = kThumbMovRR;
302 else if (!LOWREG(rDestSrc1) && !LOWREG(rSrc2))
303 opCode = kThumbMovRR_H2H;
304 else if (LOWREG(rDestSrc1))
305 opCode = kThumbMovRR_H2L;
307 opCode = kThumbMovRR_L2H;
311 opCode = (thumbForm) ? kThumbMul : kThumb2MulRRR;
314 opCode = (thumbForm) ? kThumbMvn : kThumb2MnvRR;
318 opCode = (thumbForm) ? kThumbNeg : kThumb2NegRR;
321 opCode = (thumbForm) ? kThumbOrr : kThumb2OrrRRR;
324 opCode = (thumbForm) ? kThumbSbc : kThumb2SbcRRR;
327 opCode = (thumbForm) ? kThumbTst : kThumb2TstRR;
331 opCode = (thumbForm) ? kThumbLslRR : kThumb2LslRRR;
335 opCode = (thumbForm) ? kThumbLsrRR : kThumb2LsrRRR;
339 opCode = (thumbForm) ? kThumbAsrRR : kThumb2AsrRRR;
343 opCode = (thumbForm) ? kThumbRorRR : kThumb2RorRRR;
346 opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
349 opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
353 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 8);
356 return newLIR4(cUnit, kThumb2Sbfx, rDestSrc1, rSrc2, 0, 16);
359 return newLIR4(cUnit, kThumb2Ubfx, rDestSrc1, rSrc2, 0, 16);
365 if (EncodingMap[opCode].flags & IS_BINARY_OP)
366 return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
367 else if (EncodingMap[opCode].flags & IS_TERTIARY_OP) {
368 if (EncodingMap[opCode].fieldLoc[2].kind == kFmtShift)
369 return newLIR3(cUnit, opCode, rDestSrc1, rSrc2, shift);
371 return newLIR3(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2);
372 } else if (EncodingMap[opCode].flags & IS_QUAD_OP)
373 return newLIR4(cUnit, opCode, rDestSrc1, rDestSrc1, rSrc2, shift);
380 static ArmLIR *opRegReg(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
383 return opRegRegShift(cUnit, op, rDestSrc1, rSrc2, 0);
386 static ArmLIR *opRegRegRegShift(CompilationUnit *cUnit, OpKind op,
387 int rDest, int rSrc1, int rSrc2, int shift)
389 ArmOpCode opCode = kThumbBkpt;
390 bool thumbForm = (shift == 0) && LOWREG(rDest) && LOWREG(rSrc1) &&
394 opCode = (thumbForm) ? kThumbAddRRR : kThumb2AddRRR;
397 opCode = (thumbForm) ? kThumbSubRRR : kThumb2SubRRR;
400 opCode = kThumb2AdcRRR;
403 opCode = kThumb2AndRRR;
406 opCode = kThumb2BicRRR;
409 opCode = kThumb2EorRRR;
413 opCode = kThumb2MulRRR;
416 opCode = kThumb2OrrRRR;
419 opCode = kThumb2SbcRRR;
423 opCode = kThumb2LslRRR;
427 opCode = kThumb2LsrRRR;
431 opCode = kThumb2AsrRRR;
435 opCode = kThumb2RorRRR;
442 if (EncodingMap[opCode].flags & IS_QUAD_OP)
443 return newLIR4(cUnit, opCode, rDest, rSrc1, rSrc2, shift);
445 assert(EncodingMap[opCode].flags & IS_TERTIARY_OP);
446 return newLIR3(cUnit, opCode, rDest, rSrc1, rSrc2);
450 static ArmLIR *opRegRegReg(CompilationUnit *cUnit, OpKind op, int rDest,
451 int rSrc1, int rSrc2)
453 return opRegRegRegShift(cUnit, op, rDest, rSrc1, rSrc2, 0);
456 static ArmLIR *opRegRegImm(CompilationUnit *cUnit, OpKind op, int rDest,
457 int rSrc1, int value)
460 bool neg = (value < 0);
461 int absValue = (neg) ? -value : value;
462 ArmOpCode opCode = kThumbBkpt;
463 ArmOpCode altOpCode = kThumbBkpt;
464 bool allLowRegs = (LOWREG(rDest) && LOWREG(rSrc1));
465 int modImm = modifiedImmediate(value);
466 int modImmNeg = modifiedImmediate(-value);
471 return newLIR3(cUnit, kThumbLslRRI5, rDest, rSrc1, value);
473 return newLIR3(cUnit, kThumb2LslRRI5, rDest, rSrc1, value);
476 return newLIR3(cUnit, kThumbLsrRRI5, rDest, rSrc1, value);
478 return newLIR3(cUnit, kThumb2LsrRRI5, rDest, rSrc1, value);
481 return newLIR3(cUnit, kThumbAsrRRI5, rDest, rSrc1, value);
483 return newLIR3(cUnit, kThumb2AsrRRI5, rDest, rSrc1, value);
485 return newLIR3(cUnit, kThumb2RorRRI5, rDest, rSrc1, value);
487 if (LOWREG(rDest) && (rSrc1 == 13) &&
488 (value <= 1020) && ((value & 0x3)==0)) {
489 return newLIR3(cUnit, kThumbAddSpRel, rDest, rSrc1,
491 } else if (LOWREG(rDest) && (rSrc1 == rpc) &&
492 (value <= 1020) && ((value & 0x3)==0)) {
493 return newLIR3(cUnit, kThumbAddPcRel, rDest, rSrc1,
496 opCode = kThumb2AddRRI8;
497 altOpCode = kThumb2AddRRR;
498 // Note: intentional fallthrough
500 if (allLowRegs && ((absValue & 0x7) == absValue)) {
502 opCode = (neg) ? kThumbSubRRI3 : kThumbAddRRI3;
504 opCode = (neg) ? kThumbAddRRI3 : kThumbSubRRI3;
505 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
506 } else if ((absValue & 0xff) == absValue) {
508 opCode = (neg) ? kThumb2SubRRI12 : kThumb2AddRRI12;
510 opCode = (neg) ? kThumb2AddRRI12 : kThumb2SubRRI12;
511 return newLIR3(cUnit, opCode, rDest, rSrc1, absValue);
513 if (modImmNeg >= 0) {
514 op = (op == kOpAdd) ? kOpSub : kOpAdd;
518 opCode = kThumb2SubRRI8;
519 altOpCode = kThumb2SubRRR;
523 opCode = kThumb2AdcRRI8;
524 altOpCode = kThumb2AdcRRR;
527 opCode = kThumb2SbcRRI8;
528 altOpCode = kThumb2SbcRRR;
531 opCode = kThumb2OrrRRI8;
532 altOpCode = kThumb2OrrRRR;
535 opCode = kThumb2AndRRI8;
536 altOpCode = kThumb2AndRRR;
539 opCode = kThumb2EorRRI8;
540 altOpCode = kThumb2EorRRR;
543 //TUNING: power of 2, shift & add
545 altOpCode = kThumb2MulRRR;
548 int modImm = modifiedImmediate(value);
551 res = newLIR2(cUnit, kThumb2CmpRI8, rSrc1, modImm);
553 int rTmp = dvmCompilerAllocTemp(cUnit);
554 res = loadConstant(cUnit, rTmp, value);
555 opRegReg(cUnit, kOpCmp, rSrc1, rTmp);
556 dvmCompilerFreeTemp(cUnit, rTmp);
565 return newLIR3(cUnit, opCode, rDest, rSrc1, modImm);
567 int rScratch = dvmCompilerAllocTemp(cUnit);
568 loadConstant(cUnit, rScratch, value);
569 if (EncodingMap[altOpCode].flags & IS_QUAD_OP)
570 res = newLIR4(cUnit, altOpCode, rDest, rSrc1, rScratch, 0);
572 res = newLIR3(cUnit, altOpCode, rDest, rSrc1, rScratch);
573 dvmCompilerFreeTemp(cUnit, rScratch);
578 /* Handle Thumb-only variants here - otherwise punt to opRegRegImm */
579 static ArmLIR *opRegImm(CompilationUnit *cUnit, OpKind op, int rDestSrc1,
583 bool neg = (value < 0);
584 int absValue = (neg) ? -value : value;
585 bool shortForm = (((absValue & 0xff) == absValue) && LOWREG(rDestSrc1));
586 ArmOpCode opCode = kThumbBkpt;
589 if ( !neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
590 assert((value & 0x3) == 0);
591 return newLIR1(cUnit, kThumbAddSpI7, value >> 2);
592 } else if (shortForm) {
593 opCode = (neg) ? kThumbSubRI8 : kThumbAddRI8;
597 if (!neg && (rDestSrc1 == 13) && (value <= 508)) { /* sp */
598 assert((value & 0x3) == 0);
599 return newLIR1(cUnit, kThumbSubSpI7, value >> 2);
600 } else if (shortForm) {
601 opCode = (neg) ? kThumbAddRI8 : kThumbSubRI8;
605 if (LOWREG(rDestSrc1) && shortForm)
606 opCode = (shortForm) ? kThumbCmpRI8 : kThumbCmpRR;
607 else if (LOWREG(rDestSrc1))
608 opCode = kThumbCmpRR;
611 opCode = kThumbCmpHL;
615 /* Punt to opRegRegImm - if bad case catch it there */
620 return newLIR2(cUnit, opCode, rDestSrc1, absValue);
622 return opRegRegImm(cUnit, op, rDestSrc1, rDestSrc1, value);
627 * Determine whether value can be encoded as a Thumb2 floating point
628 * immediate. If not, return -1. If so return encoded 8-bit value.
630 static int encodeImmDoubleHigh(int value)
633 int bitA = (value & 0x80000000) >> 31;
634 int notBitB = (value & 0x40000000) >> 30;
635 int bitB = (value & 0x20000000) >> 29;
636 int bSmear = (value & 0x3fc00000) >> 22;
637 int slice = (value & 0x003f0000) >> 16;
638 int zeroes = (value & 0x0000ffff);
642 if ((notBitB != 0) || (bSmear != 0x1f))
645 if ((notBitB != 1) || (bSmear != 0x0))
648 res = (bitA << 7) | (bitB << 6) | slice;
652 static int encodeImmDouble(int valLo, int valHi)
656 res = encodeImmDoubleHigh(valHi);
660 static ArmLIR *loadConstantValueWide(CompilationUnit *cUnit, int rDestLo,
661 int rDestHi, int valLo, int valHi)
663 int encodedImm = encodeImmDouble(valLo, valHi);
665 if (FPREG(rDestLo) && (encodedImm >= 0)) {
666 res = newLIR2(cUnit, kThumb2Vmovd_IMM8, S2D(rDestLo, rDestHi),
669 res = loadConstantNoClobber(cUnit, rDestLo, valLo);
670 loadConstantNoClobber(cUnit, rDestHi, valHi);
675 static int encodeShift(int code, int amount) {
676 return ((amount & 0x1f) << 2) | code;
679 static ArmLIR *loadBaseIndexed(CompilationUnit *cUnit, int rBase,
680 int rIndex, int rDest, int scale, OpSize size)
682 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rDest);
684 ArmOpCode opCode = kThumbBkpt;
685 bool thumbForm = (allLowRegs && (scale == 0));
689 assert(SINGLEREG(rDest));
690 assert((size == kWord) || (size == kSingle));
691 opCode = kThumb2Vldrs;
700 regPtr = dvmCompilerAllocTemp(cUnit);
702 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
703 encodeShift(kArmLsl, scale));
705 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
707 load = newLIR3(cUnit, opCode, rDest, regPtr, 0);
708 #if defined(WITH_SELF_VERIFICATION)
709 if (cUnit->heapMemOp)
710 load->branchInsertSV = true;
714 opCode = (thumbForm) ? kThumbLdrRRR : kThumb2LdrRRR;
717 opCode = (thumbForm) ? kThumbLdrhRRR : kThumb2LdrhRRR;
720 opCode = (thumbForm) ? kThumbLdrshRRR : kThumb2LdrshRRR;
723 opCode = (thumbForm) ? kThumbLdrbRRR : kThumb2LdrbRRR;
726 opCode = (thumbForm) ? kThumbLdrsbRRR : kThumb2LdrsbRRR;
732 load = newLIR3(cUnit, opCode, rDest, rBase, rIndex);
734 load = newLIR4(cUnit, opCode, rDest, rBase, rIndex, scale);
736 #if defined(WITH_SELF_VERIFICATION)
737 if (cUnit->heapMemOp)
738 load->branchInsertSV = true;
743 static ArmLIR *storeBaseIndexed(CompilationUnit *cUnit, int rBase,
744 int rIndex, int rSrc, int scale, OpSize size)
746 bool allLowRegs = LOWREG(rBase) && LOWREG(rIndex) && LOWREG(rSrc);
748 ArmOpCode opCode = kThumbBkpt;
749 bool thumbForm = (allLowRegs && (scale == 0));
753 assert(SINGLEREG(rSrc));
754 assert((size == kWord) || (size == kSingle));
755 opCode = kThumb2Vstrs;
764 regPtr = dvmCompilerAllocTemp(cUnit);
766 newLIR4(cUnit, kThumb2AddRRR, regPtr, rBase, rIndex,
767 encodeShift(kArmLsl, scale));
769 opRegRegReg(cUnit, kOpAdd, regPtr, rBase, rIndex);
771 store = newLIR3(cUnit, opCode, rSrc, regPtr, 0);
772 #if defined(WITH_SELF_VERIFICATION)
773 if (cUnit->heapMemOp)
774 store->branchInsertSV = true;
778 opCode = (thumbForm) ? kThumbStrRRR : kThumb2StrRRR;
782 opCode = (thumbForm) ? kThumbStrhRRR : kThumb2StrhRRR;
786 opCode = (thumbForm) ? kThumbStrbRRR : kThumb2StrbRRR;
792 store = newLIR3(cUnit, opCode, rSrc, rBase, rIndex);
794 store = newLIR4(cUnit, opCode, rSrc, rBase, rIndex, scale);
796 #if defined(WITH_SELF_VERIFICATION)
797 if (cUnit->heapMemOp)
798 store->branchInsertSV = true;
804 * Load value from base + displacement. Optionally perform null check
805 * on base (which must have an associated sReg and MIR). If not
806 * performing null check, incoming MIR can be null.
808 static ArmLIR *loadBaseDispBody(CompilationUnit *cUnit, MIR *mir, int rBase,
809 int displacement, int rDest, int rDestHi,
810 OpSize size, int sReg)
813 ArmOpCode opCode = kThumbBkpt;
814 bool shortForm = false;
815 bool thumb2Form = (displacement < 4092 && displacement >= 0);
817 bool allLowRegs = (LOWREG(rBase) && LOWREG(rDest));
818 int encodedDisp = displacement;
824 if (SINGLEREG(rDest)) {
825 assert(FPREG(rDestHi));
826 rDest = S2D(rDest, rDestHi);
828 opCode = kThumb2Vldrd;
829 if (displacement <= 1020) {
835 res = loadBaseDispBody(cUnit, mir, rBase, displacement, rDest,
837 loadBaseDispBody(cUnit, NULL, rBase, displacement + 4, rDestHi,
838 -1, kWord, INVALID_SREG);
844 opCode = kThumb2Vldrs;
845 if (displacement <= 1020) {
851 if (LOWREG(rDest) && (rBase == rpc) &&
852 (displacement <= 1020) && (displacement >= 0)) {
855 opCode = kThumbLdrPcRel;
856 } else if (LOWREG(rDest) && (rBase == r13) &&
857 (displacement <= 1020) && (displacement >= 0)) {
860 opCode = kThumbLdrSpRel;
861 } else if (allLowRegs && displacement < 128 && displacement >= 0) {
862 assert((displacement & 0x3) == 0);
865 opCode = kThumbLdrRRI5;
866 } else if (thumb2Form) {
868 opCode = kThumb2LdrRRI12;
872 if (allLowRegs && displacement < 64 && displacement >= 0) {
873 assert((displacement & 0x1) == 0);
876 opCode = kThumbLdrhRRI5;
877 } else if (displacement < 4092 && displacement >= 0) {
879 opCode = kThumb2LdrhRRI12;
885 opCode = kThumb2LdrshRRI12;
889 if (allLowRegs && displacement < 32 && displacement >= 0) {
891 opCode = kThumbLdrbRRI5;
892 } else if (thumb2Form) {
894 opCode = kThumb2LdrbRRI12;
900 opCode = kThumb2LdrsbRRI12;
908 load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
910 int regOffset = dvmCompilerAllocTemp(cUnit);
911 res = loadConstant(cUnit, regOffset, encodedDisp);
912 load = loadBaseIndexed(cUnit, rBase, regOffset, rDest, 0, size);
913 dvmCompilerFreeTemp(cUnit, regOffset);
917 annotateDalvikRegAccess(load, displacement >> 2, true /* isLoad */);
919 #if defined(WITH_SELF_VERIFICATION)
920 if (cUnit->heapMemOp)
921 load->branchInsertSV = true;
926 static ArmLIR *loadBaseDisp(CompilationUnit *cUnit, MIR *mir, int rBase,
927 int displacement, int rDest, OpSize size,
930 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDest, -1,
934 static ArmLIR *loadBaseDispWide(CompilationUnit *cUnit, MIR *mir, int rBase,
935 int displacement, int rDestLo, int rDestHi,
938 return loadBaseDispBody(cUnit, mir, rBase, displacement, rDestLo, rDestHi,
943 static ArmLIR *storeBaseDispBody(CompilationUnit *cUnit, int rBase,
944 int displacement, int rSrc, int rSrcHi,
948 ArmOpCode opCode = kThumbBkpt;
949 bool shortForm = false;
950 bool thumb2Form = (displacement < 4092 && displacement >= 0);
952 bool allLowRegs = (LOWREG(rBase) && LOWREG(rSrc));
953 int encodedDisp = displacement;
959 res = storeBaseDispBody(cUnit, rBase, displacement, rSrc,
961 storeBaseDispBody(cUnit, rBase, displacement + 4, rSrcHi,
965 if (SINGLEREG(rSrc)) {
966 assert(FPREG(rSrcHi));
967 rSrc = S2D(rSrc, rSrcHi);
969 opCode = kThumb2Vstrd;
970 if (displacement <= 1020) {
978 assert(SINGLEREG(rSrc));
979 opCode = kThumb2Vstrs;
980 if (displacement <= 1020) {
986 if (allLowRegs && displacement < 128 && displacement >= 0) {
987 assert((displacement & 0x3) == 0);
990 opCode = kThumbStrRRI5;
991 } else if (thumb2Form) {
993 opCode = kThumb2StrRRI12;
998 if (allLowRegs && displacement < 64 && displacement >= 0) {
999 assert((displacement & 0x1) == 0);
1002 opCode = kThumbStrhRRI5;
1003 } else if (thumb2Form) {
1005 opCode = kThumb2StrhRRI12;
1010 if (allLowRegs && displacement < 32 && displacement >= 0) {
1012 opCode = kThumbStrbRRI5;
1013 } else if (thumb2Form) {
1015 opCode = kThumb2StrbRRI12;
1022 store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
1024 int rScratch = dvmCompilerAllocTemp(cUnit);
1025 res = loadConstant(cUnit, rScratch, encodedDisp);
1026 store = storeBaseIndexed(cUnit, rBase, rScratch, rSrc, 0, size);
1027 dvmCompilerFreeTemp(cUnit, rScratch);
1031 annotateDalvikRegAccess(store, displacement >> 2, false /* isLoad */);
1033 #if defined(WITH_SELF_VERIFICATION)
1034 if (cUnit->heapMemOp)
1035 store->branchInsertSV = true;
1040 static ArmLIR *storeBaseDisp(CompilationUnit *cUnit, int rBase,
1041 int displacement, int rSrc, OpSize size)
1043 return storeBaseDispBody(cUnit, rBase, displacement, rSrc, -1, size);
1046 static ArmLIR *storeBaseDispWide(CompilationUnit *cUnit, int rBase,
1047 int displacement, int rSrcLo, int rSrcHi)
1049 return storeBaseDispBody(cUnit, rBase, displacement, rSrcLo, rSrcHi, kLong);
1052 static ArmLIR *loadMultiple(CompilationUnit *cUnit, int rBase, int rMask)
1056 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
1057 res = newLIR2(cUnit, kThumbLdmia, rBase, rMask);
1059 res = newLIR2(cUnit, kThumb2Ldmia, rBase, rMask);
1061 #if defined(WITH_SELF_VERIFICATION)
1062 if (cUnit->heapMemOp)
1063 res->branchInsertSV = true;
1069 static ArmLIR *storeMultiple(CompilationUnit *cUnit, int rBase, int rMask)
1073 if (LOWREG(rBase) && ((rMask & 0xff)==rMask)) {
1074 res = newLIR2(cUnit, kThumbStmia, rBase, rMask);
1076 res = newLIR2(cUnit, kThumb2Stmia, rBase, rMask);
1078 #if defined(WITH_SELF_VERIFICATION)
1079 if (cUnit->heapMemOp)
1080 res->branchInsertSV = true;
1086 static void storePair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
1088 storeBaseDispWide(cUnit, base, 0, lowReg, highReg);
1091 static void loadPair(CompilationUnit *cUnit, int base, int lowReg, int highReg)
1093 loadBaseDispWide(cUnit, NULL, base, 0, lowReg, highReg, INVALID_SREG);
1098 * Perform a "reg cmp imm" operation and jump to the PCR region if condition
1101 static ArmLIR *genRegImmCheck(CompilationUnit *cUnit,
1102 ArmConditionCode cond, int reg,
1103 int checkValue, int dOffset,
1109 * TODO: re-enable usage of kThumb2Cbz & kThumb2Cbnz once assembler is
1110 * enhanced to allow us to replace code patterns when instructions don't
1111 * reach. Currently, CB[N]Z is causing too many assembler aborts.
1112 * What we want to do is emit the short forms, and then replace them with
1113 * longer versions when needed.
1116 if (0 && (LOWREG(reg)) && (checkValue == 0) &&
1117 ((cond == kArmCondEq) || (cond == kArmCondNe))) {
1118 branch = newLIR2(cUnit,
1119 (cond == kArmCondEq) ? kThumb2Cbz : kThumb2Cbnz,
1122 modImm = modifiedImmediate(checkValue);
1123 if (LOWREG(reg) && ((checkValue & 0xff) == checkValue)) {
1124 newLIR2(cUnit, kThumbCmpRI8, reg, checkValue);
1125 } else if (modImm >= 0) {
1126 newLIR2(cUnit, kThumb2CmpRI8, reg, modImm);
1128 int tReg = dvmCompilerAllocTemp(cUnit);
1129 loadConstant(cUnit, tReg, checkValue);
1130 opRegReg(cUnit, kOpCmp, reg, tReg);
1132 branch = newLIR2(cUnit, kThumbBCond, 0, cond);
1134 return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
1137 static ArmLIR *fpRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1139 ArmLIR* res = dvmCompilerNew(sizeof(ArmLIR), true);
1140 res->operands[0] = rDest;
1141 res->operands[1] = rSrc;
1142 if (rDest == rSrc) {
1145 assert(DOUBLEREG(rDest) == DOUBLEREG(rSrc));
1146 if (DOUBLEREG(rDest)) {
1147 res->opCode = kThumb2Vmovd;
1149 if (SINGLEREG(rDest)) {
1150 res->opCode = SINGLEREG(rSrc) ? kThumb2Vmovs : kThumb2Fmsr;
1152 assert(SINGLEREG(rSrc));
1153 res->opCode = kThumb2Fmrs;
1156 res->operands[0] = rDest;
1157 res->operands[1] = rSrc;
1159 setupResourceMasks(res);
1163 static ArmLIR* genRegCopyNoInsert(CompilationUnit *cUnit, int rDest, int rSrc)
1167 if (FPREG(rDest) || FPREG(rSrc))
1168 return fpRegCopy(cUnit, rDest, rSrc);
1169 res = dvmCompilerNew(sizeof(ArmLIR), true);
1170 if (LOWREG(rDest) && LOWREG(rSrc))
1171 opCode = kThumbMovRR;
1172 else if (!LOWREG(rDest) && !LOWREG(rSrc))
1173 opCode = kThumbMovRR_H2H;
1174 else if (LOWREG(rDest))
1175 opCode = kThumbMovRR_H2L;
1177 opCode = kThumbMovRR_L2H;
1179 res->operands[0] = rDest;
1180 res->operands[1] = rSrc;
1181 res->opCode = opCode;
1182 setupResourceMasks(res);
1183 if (rDest == rSrc) {
1189 static ArmLIR* genRegCopy(CompilationUnit *cUnit, int rDest, int rSrc)
1191 ArmLIR *res = genRegCopyNoInsert(cUnit, rDest, rSrc);
1192 dvmCompilerAppendLIR(cUnit, (LIR*)res);
1196 static void genRegCopyWide(CompilationUnit *cUnit, int destLo, int destHi,
1197 int srcLo, int srcHi)
1199 bool destFP = FPREG(destLo) && FPREG(destHi);
1200 bool srcFP = FPREG(srcLo) && FPREG(srcHi);
1201 assert(FPREG(srcLo) == FPREG(srcHi));
1202 assert(FPREG(destLo) == FPREG(destHi));
1205 genRegCopy(cUnit, S2D(destLo, destHi), S2D(srcLo, srcHi));
1207 newLIR3(cUnit, kThumb2Fmdrr, S2D(destLo, destHi), srcLo, srcHi);
1211 newLIR3(cUnit, kThumb2Fmrrd, destLo, destHi, S2D(srcLo, srcHi));
1214 if (srcHi == destLo) {
1215 genRegCopy(cUnit, destHi, srcHi);
1216 genRegCopy(cUnit, destLo, srcLo);
1218 genRegCopy(cUnit, destLo, srcLo);
1219 genRegCopy(cUnit, destHi, srcHi);