blob: 5838ca799d39eac5764718a5f5c6a1af32164384 [file] [log] [blame]
buzbeeefc63692012-11-14 16:31:52 -08001/*
2 * Copyright (C) 2011 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#include "../../compiler_internals.h"
18#include "arm_lir.h"
buzbeeeaf09bc2012-11-15 14:51:41 -080019#include "../ralloc_util.h"
20#include "../codegen_util.h"
buzbeeefc63692012-11-14 16:31:52 -080021
22#include <string>
23
24namespace art {
25
26static int coreRegs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
27 r11, r12, rARM_SP, rARM_LR, rARM_PC};
28static int reservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
29static int fpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
30 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
31 fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
32 fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
33static int coreTemps[] = {r0, r1, r2, r3, r12};
34static int fpTemps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
35 fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
36
37RegLocation locCReturn()
38{
39 RegLocation res = ARM_LOC_C_RETURN;
40 return res;
41}
42
43RegLocation locCReturnWide()
44{
45 RegLocation res = ARM_LOC_C_RETURN_WIDE;
46 return res;
47}
48
49RegLocation locCReturnFloat()
50{
51 RegLocation res = ARM_LOC_C_RETURN_FLOAT;
52 return res;
53}
54
55RegLocation locCReturnDouble()
56{
57 RegLocation res = ARM_LOC_C_RETURN_DOUBLE;
58 return res;
59}
60
61// Return a target-dependent special register.
62int targetReg(SpecialTargetRegister reg) {
63 int res = INVALID_REG;
64 switch (reg) {
65 case kSelf: res = rARM_SELF; break;
66 case kSuspend: res = rARM_SUSPEND; break;
67 case kLr: res = rARM_LR; break;
68 case kPc: res = rARM_PC; break;
69 case kSp: res = rARM_SP; break;
70 case kArg0: res = rARM_ARG0; break;
71 case kArg1: res = rARM_ARG1; break;
72 case kArg2: res = rARM_ARG2; break;
73 case kArg3: res = rARM_ARG3; break;
74 case kFArg0: res = rARM_FARG0; break;
75 case kFArg1: res = rARM_FARG1; break;
76 case kFArg2: res = rARM_FARG2; break;
77 case kFArg3: res = rARM_FARG3; break;
78 case kRet0: res = rARM_RET0; break;
79 case kRet1: res = rARM_RET1; break;
80 case kInvokeTgt: res = rARM_INVOKE_TGT; break;
81 case kCount: res = rARM_COUNT; break;
82 }
83 return res;
84}
85
86
87// Create a double from a pair of singles.
88int s2d(int lowReg, int highReg)
89{
90 return ARM_S2D(lowReg, highReg);
91}
92
93// Is reg a single or double?
94bool fpReg(int reg)
95{
96 return ARM_FPREG(reg);
97}
98
99// Is reg a single?
100bool singleReg(int reg)
101{
102 return ARM_SINGLEREG(reg);
103}
104
105// Is reg a double?
106bool doubleReg(int reg)
107{
108 return ARM_DOUBLEREG(reg);
109}
110
111// Return mask to strip off fp reg flags and bias.
112uint32_t fpRegMask()
113{
114 return ARM_FP_REG_MASK;
115}
116
117// True if both regs single, both core or both double.
118bool sameRegType(int reg1, int reg2)
119{
120 return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
121}
122
123/*
124 * Decode the register id.
125 */
buzbeeeaf09bc2012-11-15 14:51:41 -0800126uint64_t getRegMaskCommon(CompilationUnit* cUnit, int reg)
buzbeeefc63692012-11-14 16:31:52 -0800127{
buzbeeeaf09bc2012-11-15 14:51:41 -0800128 uint64_t seed;
buzbeeefc63692012-11-14 16:31:52 -0800129 int shift;
130 int regId;
131
132
133 regId = reg & 0x1f;
134 /* Each double register is equal to a pair of single-precision FP registers */
135 seed = ARM_DOUBLEREG(reg) ? 3 : 1;
136 /* FP register starts at bit position 16 */
137 shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
138 /* Expand the double register id into single offset */
139 shift += regId;
140 return (seed << shift);
141}
142
143uint64_t getPCUseDefEncoding()
144{
145 return ENCODE_ARM_REG_PC;
146}
147
148void setupTargetResourceMasks(CompilationUnit* cUnit, LIR* lir)
149{
150 DCHECK_EQ(cUnit->instructionSet, kThumb2);
151
152 // Thumb2 specific setup
153 uint64_t flags = EncodingMap[lir->opcode].flags;
154 int opcode = lir->opcode;
155
156 if (flags & REG_DEF_SP) {
157 lir->defMask |= ENCODE_ARM_REG_SP;
158 }
159
160 if (flags & REG_USE_SP) {
161 lir->useMask |= ENCODE_ARM_REG_SP;
162 }
163
164 if (flags & REG_DEF_LIST0) {
165 lir->defMask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
166 }
167
168 if (flags & REG_DEF_LIST1) {
169 lir->defMask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
170 }
171
172 if (flags & REG_DEF_FPCS_LIST0) {
173 lir->defMask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
174 }
175
176 if (flags & REG_DEF_FPCS_LIST2) {
177 for (int i = 0; i < lir->operands[2]; i++) {
178 oatSetupRegMask(cUnit, &lir->defMask, lir->operands[1] + i);
179 }
180 }
181
182 if (flags & REG_USE_PC) {
183 lir->useMask |= ENCODE_ARM_REG_PC;
184 }
185
186 /* Conservatively treat the IT block */
187 if (flags & IS_IT) {
188 lir->defMask = ENCODE_ALL;
189 }
190
191 if (flags & REG_USE_LIST0) {
192 lir->useMask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
193 }
194
195 if (flags & REG_USE_LIST1) {
196 lir->useMask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
197 }
198
199 if (flags & REG_USE_FPCS_LIST0) {
200 lir->useMask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
201 }
202
203 if (flags & REG_USE_FPCS_LIST2) {
204 for (int i = 0; i < lir->operands[2]; i++) {
205 oatSetupRegMask(cUnit, &lir->useMask, lir->operands[1] + i);
206 }
207 }
208 /* Fixup for kThumbPush/lr and kThumbPop/pc */
209 if (opcode == kThumbPush || opcode == kThumbPop) {
buzbeeeaf09bc2012-11-15 14:51:41 -0800210 uint64_t r8Mask = oatGetRegMaskCommon(cUnit, r8);
buzbeeefc63692012-11-14 16:31:52 -0800211 if ((opcode == kThumbPush) && (lir->useMask & r8Mask)) {
212 lir->useMask &= ~r8Mask;
213 lir->useMask |= ENCODE_ARM_REG_LR;
214 } else if ((opcode == kThumbPop) && (lir->defMask & r8Mask)) {
215 lir->defMask &= ~r8Mask;
216 lir->defMask |= ENCODE_ARM_REG_PC;
217 }
218 }
219 if (flags & REG_DEF_LR) {
220 lir->defMask |= ENCODE_ARM_REG_LR;
221 }
222}
223
224ArmConditionCode oatArmConditionEncoding(ConditionCode code)
225{
226 ArmConditionCode res;
227 switch (code) {
228 case kCondEq: res = kArmCondEq; break;
229 case kCondNe: res = kArmCondNe; break;
230 case kCondCs: res = kArmCondCs; break;
231 case kCondCc: res = kArmCondCc; break;
232 case kCondMi: res = kArmCondMi; break;
233 case kCondPl: res = kArmCondPl; break;
234 case kCondVs: res = kArmCondVs; break;
235 case kCondVc: res = kArmCondVc; break;
236 case kCondHi: res = kArmCondHi; break;
237 case kCondLs: res = kArmCondLs; break;
238 case kCondGe: res = kArmCondGe; break;
239 case kCondLt: res = kArmCondLt; break;
240 case kCondGt: res = kArmCondGt; break;
241 case kCondLe: res = kArmCondLe; break;
242 case kCondAl: res = kArmCondAl; break;
243 case kCondNv: res = kArmCondNv; break;
244 default:
245 LOG(FATAL) << "Bad condition code" << (int)code;
246 res = (ArmConditionCode)0; // Quiet gcc
247 }
248 return res;
249}
250
251static const char* coreRegNames[16] = {
252 "r0",
253 "r1",
254 "r2",
255 "r3",
256 "r4",
257 "r5",
258 "r6",
259 "r7",
260 "r8",
261 "rSELF",
262 "r10",
263 "r11",
264 "r12",
265 "sp",
266 "lr",
267 "pc",
268};
269
270
271static const char* shiftNames[4] = {
272 "lsl",
273 "lsr",
274 "asr",
275 "ror"};
276
277/* Decode and print a ARM register name */
278char* decodeRegList(int opcode, int vector, char* buf)
279{
280 int i;
281 bool printed = false;
282 buf[0] = 0;
283 for (i = 0; i < 16; i++, vector >>= 1) {
284 if (vector & 0x1) {
285 int regId = i;
286 if (opcode == kThumbPush && i == 8) {
287 regId = r14lr;
288 } else if (opcode == kThumbPop && i == 8) {
289 regId = r15pc;
290 }
291 if (printed) {
292 sprintf(buf + strlen(buf), ", r%d", regId);
293 } else {
294 printed = true;
295 sprintf(buf, "r%d", regId);
296 }
297 }
298 }
299 return buf;
300}
301
302char* decodeFPCSRegList(int count, int base, char* buf)
303{
304 sprintf(buf, "s%d", base);
305 for (int i = 1; i < count; i++) {
306 sprintf(buf + strlen(buf), ", s%d",base + i);
307 }
308 return buf;
309}
310
311int expandImmediate(int value)
312{
313 int mode = (value & 0xf00) >> 8;
buzbeeeaf09bc2012-11-15 14:51:41 -0800314 uint32_t bits = value & 0xff;
buzbeeefc63692012-11-14 16:31:52 -0800315 switch (mode) {
316 case 0:
317 return bits;
318 case 1:
319 return (bits << 16) | bits;
320 case 2:
321 return (bits << 24) | (bits << 8);
322 case 3:
323 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
324 default:
325 break;
326 }
327 bits = (bits | 0x80) << 24;
328 return bits >> (((value & 0xf80) >> 7) - 8);
329}
330
331const char* ccNames[] = {"eq","ne","cs","cc","mi","pl","vs","vc",
332 "hi","ls","ge","lt","gt","le","al","nv"};
333/*
334 * Interpret a format string and build a string no longer than size
335 * See format key in Assemble.c.
336 */
337std::string buildInsnString(const char* fmt, LIR* lir, unsigned char* baseAddr)
338{
339 std::string buf;
340 int i;
341 const char* fmtEnd = &fmt[strlen(fmt)];
342 char tbuf[256];
343 const char* name;
344 char nc;
345 while (fmt < fmtEnd) {
346 int operand;
347 if (*fmt == '!') {
348 fmt++;
349 DCHECK_LT(fmt, fmtEnd);
350 nc = *fmt++;
351 if (nc=='!') {
352 strcpy(tbuf, "!");
353 } else {
354 DCHECK_LT(fmt, fmtEnd);
355 DCHECK_LT((unsigned)(nc-'0'), 4U);
356 operand = lir->operands[nc-'0'];
357 switch (*fmt++) {
358 case 'H':
359 if (operand != 0) {
360 sprintf(tbuf, ", %s %d",shiftNames[operand & 0x3], operand >> 2);
361 } else {
362 strcpy(tbuf,"");
363 }
364 break;
365 case 'B':
366 switch (operand) {
367 case kSY:
368 name = "sy";
369 break;
370 case kST:
371 name = "st";
372 break;
373 case kISH:
374 name = "ish";
375 break;
376 case kISHST:
377 name = "ishst";
378 break;
379 case kNSH:
380 name = "nsh";
381 break;
382 case kNSHST:
383 name = "shst";
384 break;
385 default:
386 name = "DecodeError2";
387 break;
388 }
389 strcpy(tbuf, name);
390 break;
391 case 'b':
392 strcpy(tbuf,"0000");
393 for (i=3; i>= 0; i--) {
394 tbuf[i] += operand & 1;
395 operand >>= 1;
396 }
397 break;
398 case 'n':
399 operand = ~expandImmediate(operand);
400 sprintf(tbuf,"%d [%#x]", operand, operand);
401 break;
402 case 'm':
403 operand = expandImmediate(operand);
404 sprintf(tbuf,"%d [%#x]", operand, operand);
405 break;
406 case 's':
407 sprintf(tbuf,"s%d",operand & ARM_FP_REG_MASK);
408 break;
409 case 'S':
410 sprintf(tbuf,"d%d",(operand & ARM_FP_REG_MASK) >> 1);
411 break;
412 case 'h':
413 sprintf(tbuf,"%04x", operand);
414 break;
415 case 'M':
416 case 'd':
417 sprintf(tbuf,"%d", operand);
418 break;
419 case 'C':
420 DCHECK_LT(operand, static_cast<int>(
421 sizeof(coreRegNames)/sizeof(coreRegNames[0])));
422 sprintf(tbuf,"%s",coreRegNames[operand]);
423 break;
424 case 'E':
425 sprintf(tbuf,"%d", operand*4);
426 break;
427 case 'F':
428 sprintf(tbuf,"%d", operand*2);
429 break;
430 case 'c':
431 strcpy(tbuf, ccNames[operand]);
432 break;
433 case 't':
434 sprintf(tbuf,"0x%08x (L%p)",
435 (int) baseAddr + lir->offset + 4 +
436 (operand << 1),
437 lir->target);
438 break;
439 case 'u': {
440 int offset_1 = lir->operands[0];
441 int offset_2 = NEXT_LIR(lir)->operands[0];
442 intptr_t target =
443 ((((intptr_t) baseAddr + lir->offset + 4) &
444 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
445 0xfffffffc;
446 sprintf(tbuf, "%p", (void *) target);
447 break;
448 }
449
450 /* Nothing to print for BLX_2 */
451 case 'v':
452 strcpy(tbuf, "see above");
453 break;
454 case 'R':
455 decodeRegList(lir->opcode, operand, tbuf);
456 break;
457 case 'P':
458 decodeFPCSRegList(operand, 16, tbuf);
459 break;
460 case 'Q':
461 decodeFPCSRegList(operand, 0, tbuf);
462 break;
463 default:
464 strcpy(tbuf,"DecodeError1");
465 break;
466 }
467 buf += tbuf;
468 }
469 } else {
470 buf += *fmt++;
471 }
472 }
473 return buf;
474}
475
buzbeeeaf09bc2012-11-15 14:51:41 -0800476void oatDumpResourceMask(LIR* lir, uint64_t mask, const char* prefix)
buzbeeefc63692012-11-14 16:31:52 -0800477{
478 char buf[256];
479 buf[0] = 0;
480 LIR* armLIR = (LIR*) lir;
481
482 if (mask == ENCODE_ALL) {
483 strcpy(buf, "all");
484 } else {
485 char num[8];
486 int i;
487
488 for (i = 0; i < kArmRegEnd; i++) {
489 if (mask & (1ULL << i)) {
490 sprintf(num, "%d ", i);
491 strcat(buf, num);
492 }
493 }
494
495 if (mask & ENCODE_CCODE) {
496 strcat(buf, "cc ");
497 }
498 if (mask & ENCODE_FP_STATUS) {
499 strcat(buf, "fpcc ");
500 }
501
502 /* Memory bits */
503 if (armLIR && (mask & ENCODE_DALVIK_REG)) {
504 sprintf(buf + strlen(buf), "dr%d%s", armLIR->aliasInfo & 0xffff,
505 (armLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
506 }
507 if (mask & ENCODE_LITERAL) {
508 strcat(buf, "lit ");
509 }
510
511 if (mask & ENCODE_HEAP_REF) {
512 strcat(buf, "heap ");
513 }
514 if (mask & ENCODE_MUST_NOT_ALIAS) {
515 strcat(buf, "noalias ");
516 }
517 }
518 if (buf[0]) {
519 LOG(INFO) << prefix << ": " << buf;
520 }
521}
522
523/*
524 * Nop any unconditional branches that go to the next instruction.
525 * Note: new redundant branches may be inserted later, and we'll
526 * use a check in final instruction assembly to nop those out.
527 */
528void removeRedundantBranches(CompilationUnit* cUnit)
529{
530 LIR* thisLIR;
531
532 for (thisLIR = (LIR*) cUnit->firstLIRInsn;
533 thisLIR != (LIR*) cUnit->lastLIRInsn;
534 thisLIR = NEXT_LIR(thisLIR)) {
535
536 /* Branch to the next instruction */
537 if ((thisLIR->opcode == kThumbBUncond) ||
538 (thisLIR->opcode == kThumb2BUncond)) {
539 LIR* nextLIR = thisLIR;
540
541 while (true) {
542 nextLIR = NEXT_LIR(nextLIR);
543
544 /*
545 * Is the branch target the next instruction?
546 */
547 if (nextLIR == (LIR*) thisLIR->target) {
548 thisLIR->flags.isNop = true;
549 break;
550 }
551
552 /*
553 * Found real useful stuff between the branch and the target.
554 * Need to explicitly check the lastLIRInsn here because it
555 * might be the last real instruction.
556 */
557 if (!isPseudoOpcode(nextLIR->opcode) ||
558 (nextLIR = (LIR*) cUnit->lastLIRInsn))
559 break;
560 }
561 }
562 }
563}
564
565/* Common initialization routine for an architecture family */
566bool oatArchInit()
567{
568 int i;
569
570 for (i = 0; i < kArmLast; i++) {
571 if (EncodingMap[i].opcode != i) {
572 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
573 << " is wrong: expecting " << i << ", seeing "
574 << (int)EncodingMap[i].opcode;
575 }
576 }
577
578 return oatArchVariantInit();
579}
580/*
581 * Determine the initial instruction set to be used for this trace.
582 * Later components may decide to change this.
583 */
584InstructionSet oatInstructionSet()
585{
586 return kThumb2;
587}
588
589/* Architecture-specific initializations and checks go here */
590bool oatArchVariantInit(void)
591{
592 return true;
593}
594
buzbeeefc63692012-11-14 16:31:52 -0800595/*
596 * Alloc a pair of core registers, or a double. Low reg in low byte,
597 * high reg in next byte.
598 */
599int oatAllocTypedTempPair(CompilationUnit* cUnit, bool fpHint, int regClass)
600{
601 int highReg;
602 int lowReg;
603 int res = 0;
604
605 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
606 lowReg = oatAllocTempDouble(cUnit);
607 highReg = lowReg + 1;
608 } else {
609 lowReg = oatAllocTemp(cUnit);
610 highReg = oatAllocTemp(cUnit);
611 }
612 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
613 return res;
614}
615
616int oatAllocTypedTemp(CompilationUnit* cUnit, bool fpHint, int regClass)
617{
618 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
619 return oatAllocTempFloat(cUnit);
620 return oatAllocTemp(cUnit);
621}
622
623void oatInitializeRegAlloc(CompilationUnit* cUnit)
624{
625 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
626 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
627 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
628 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
629 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
630 RegisterPool *pool = (RegisterPool *)oatNew(cUnit, sizeof(*pool), true,
631 kAllocRegAlloc);
632 cUnit->regPool = pool;
633 pool->numCoreRegs = numRegs;
634 pool->coreRegs = (RegisterInfo *)
635 oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs),
636 true, kAllocRegAlloc);
637 pool->numFPRegs = numFPRegs;
638 pool->FPRegs = (RegisterInfo *)
639 oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true,
640 kAllocRegAlloc);
641 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
642 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
643 // Keep special registers from being allocated
644 for (int i = 0; i < numReserved; i++) {
645 if (NO_SUSPEND && (reservedRegs[i] == rARM_SUSPEND)) {
646 //To measure cost of suspend check
647 continue;
648 }
649 oatMarkInUse(cUnit, reservedRegs[i]);
650 }
651 // Mark temp regs - all others not in use can be used for promotion
652 for (int i = 0; i < numTemps; i++) {
653 oatMarkTemp(cUnit, coreTemps[i]);
654 }
655 for (int i = 0; i < numFPTemps; i++) {
656 oatMarkTemp(cUnit, fpTemps[i]);
657 }
658
659 // Start allocation at r2 in an attempt to avoid clobbering return values
660 pool->nextCoreReg = r2;
661
662 // Construct the alias map.
663 cUnit->phiAliasMap = (int*)oatNew(cUnit, cUnit->numSSARegs *
664 sizeof(cUnit->phiAliasMap[0]), false,
665 kAllocDFInfo);
666 for (int i = 0; i < cUnit->numSSARegs; i++) {
667 cUnit->phiAliasMap[i] = i;
668 }
669 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
670 int defReg = phi->ssaRep->defs[0];
671 for (int i = 0; i < phi->ssaRep->numUses; i++) {
672 for (int j = 0; j < cUnit->numSSARegs; j++) {
673 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
674 cUnit->phiAliasMap[j] = defReg;
675 }
676 }
677 }
678 }
679}
680
681void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
682 RegLocation rlFree)
683{
684 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
685 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
686 // No overlap, free both
687 oatFreeTemp(cUnit, rlFree.lowReg);
688 oatFreeTemp(cUnit, rlFree.highReg);
689 }
690}
691/*
692 * TUNING: is leaf? Can't just use "hasInvoke" to determine as some
693 * instructions might call out to C/assembly helper functions. Until
694 * machinery is in place, always spill lr.
695 */
696
697void oatAdjustSpillMask(CompilationUnit* cUnit)
698{
699 cUnit->coreSpillMask |= (1 << rARM_LR);
700 cUnit->numCoreSpills++;
701}
702
703/*
704 * Mark a callee-save fp register as promoted. Note that
705 * vpush/vpop uses contiguous register lists so we must
706 * include any holes in the mask. Associate holes with
707 * Dalvik register INVALID_VREG (0xFFFFU).
708 */
709void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg)
710{
711 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
712 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
713 // Ensure fpVmapTable is large enough
714 int tableSize = cUnit->fpVmapTable.size();
715 for (int i = tableSize; i < (reg + 1); i++) {
716 cUnit->fpVmapTable.push_back(INVALID_VREG);
717 }
718 // Add the current mapping
719 cUnit->fpVmapTable[reg] = vReg;
720 // Size of fpVmapTable is high-water mark, use to set mask
721 cUnit->numFPSpills = cUnit->fpVmapTable.size();
722 cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << ARM_FP_CALLEE_SAVE_BASE;
723}
724
725void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
726{
727 RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
728 RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
729 DCHECK(info1 && info2 && info1->pair && info2->pair &&
730 (info1->partner == info2->reg) &&
731 (info2->partner == info1->reg));
732 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
733 if (!(info1->isTemp && info2->isTemp)) {
734 /* Should not happen. If it does, there's a problem in evalLoc */
735 LOG(FATAL) << "Long half-temp, half-promoted";
736 }
737
738 info1->dirty = false;
739 info2->dirty = false;
740 if (SRegToVReg(cUnit, info2->sReg) <
741 SRegToVReg(cUnit, info1->sReg))
742 info1 = info2;
743 int vReg = SRegToVReg(cUnit, info1->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800744 storeBaseDispWide(cUnit, rARM_SP, oatVRegOffset(cUnit, vReg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800745 }
746}
747
748void oatFlushReg(CompilationUnit* cUnit, int reg)
749{
750 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
751 if (info->live && info->dirty) {
752 info->dirty = false;
753 int vReg = SRegToVReg(cUnit, info->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800754 storeBaseDisp(cUnit, rARM_SP, oatVRegOffset(cUnit, vReg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800755 }
756}
757
758/* Give access to the target-dependent FP register encoding to common code */
759bool oatIsFpReg(int reg) {
760 return ARM_FPREG(reg);
761}
762
763uint32_t oatFpRegMask() {
764 return ARM_FP_REG_MASK;
765}
766
767/* Clobber all regs that might be used by an external C call */
768void oatClobberCalleeSave(CompilationUnit *cUnit)
769{
770 oatClobber(cUnit, r0);
771 oatClobber(cUnit, r1);
772 oatClobber(cUnit, r2);
773 oatClobber(cUnit, r3);
774 oatClobber(cUnit, r12);
775 oatClobber(cUnit, r14lr);
776 oatClobber(cUnit, fr0);
777 oatClobber(cUnit, fr1);
778 oatClobber(cUnit, fr2);
779 oatClobber(cUnit, fr3);
780 oatClobber(cUnit, fr4);
781 oatClobber(cUnit, fr5);
782 oatClobber(cUnit, fr6);
783 oatClobber(cUnit, fr7);
784 oatClobber(cUnit, fr8);
785 oatClobber(cUnit, fr9);
786 oatClobber(cUnit, fr10);
787 oatClobber(cUnit, fr11);
788 oatClobber(cUnit, fr12);
789 oatClobber(cUnit, fr13);
790 oatClobber(cUnit, fr14);
791 oatClobber(cUnit, fr15);
792}
793
794extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
795{
796 RegLocation res = locCReturnWide();
797 res.lowReg = r2;
798 res.highReg = r3;
799 oatClobber(cUnit, r2);
800 oatClobber(cUnit, r3);
801 oatMarkInUse(cUnit, r2);
802 oatMarkInUse(cUnit, r3);
803 oatMarkPair(cUnit, res.lowReg, res.highReg);
804 return res;
805}
806
807extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
808{
809 RegLocation res = locCReturn();
810 res.lowReg = r1;
811 oatClobber(cUnit, r1);
812 oatMarkInUse(cUnit, r1);
813 return res;
814}
815
816extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
817{
818 return ARM_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & ARM_FP_REG_MASK]
819 : &cUnit->regPool->coreRegs[reg];
820}
821
822/* To be used when explicitly managing register use */
823extern void oatLockCallTemps(CompilationUnit* cUnit)
824{
825 oatLockTemp(cUnit, r0);
826 oatLockTemp(cUnit, r1);
827 oatLockTemp(cUnit, r2);
828 oatLockTemp(cUnit, r3);
829}
830
831/* To be used when explicitly managing register use */
832extern void oatFreeCallTemps(CompilationUnit* cUnit)
833{
834 oatFreeTemp(cUnit, r0);
835 oatFreeTemp(cUnit, r1);
836 oatFreeTemp(cUnit, r2);
837 oatFreeTemp(cUnit, r3);
838}
839
840/* Convert an instruction to a NOP */
841void oatNopLIR( LIR* lir)
842{
843 ((LIR*)lir)->flags.isNop = true;
844}
845
846int loadHelper(CompilationUnit* cUnit, int offset)
847{
848 loadWordDisp(cUnit, rARM_SELF, offset, rARM_LR);
849 return rARM_LR;
850}
851
852} // namespace art