blob: 6640707f6aee2e378b89a92416ea58fe9ba53328 [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
buzbeecbd6d442012-11-17 14:11:25 -0800224ArmConditionCode oatArmConditionEncoding(ConditionCode ccode)
buzbeeefc63692012-11-14 16:31:52 -0800225{
226 ArmConditionCode res;
buzbeecbd6d442012-11-17 14:11:25 -0800227 switch (ccode) {
buzbeeefc63692012-11-14 16:31:52 -0800228 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:
buzbeecbd6d442012-11-17 14:11:25 -0800245 LOG(FATAL) << "Bad condition code " << ccode;
246 res = static_cast<ArmConditionCode>(0); // Quiet gcc
buzbeeefc63692012-11-14 16:31:52 -0800247 }
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);
buzbeecbd6d442012-11-17 14:11:25 -0800355 DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
buzbeeefc63692012-11-14 16:31:52 -0800356 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)",
buzbeecbd6d442012-11-17 14:11:25 -0800435 reinterpret_cast<uintptr_t>(baseAddr) + lir->offset + 4 +
buzbeeefc63692012-11-14 16:31:52 -0800436 (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];
buzbeecbd6d442012-11-17 14:11:25 -0800442 uintptr_t target =
443 (((reinterpret_cast<uintptr_t>(baseAddr) + lir->offset + 4) &
buzbeeefc63692012-11-14 16:31:52 -0800444 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
445 0xfffffffc;
buzbeecbd6d442012-11-17 14:11:25 -0800446 sprintf(tbuf, "%p", reinterpret_cast<void *>(target));
buzbeeefc63692012-11-14 16:31:52 -0800447 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
buzbeecbd6d442012-11-17 14:11:25 -0800476void oatDumpResourceMask(LIR* armLIR, uint64_t mask, const char* prefix)
buzbeeefc63692012-11-14 16:31:52 -0800477{
478 char buf[256];
479 buf[0] = 0;
buzbeeefc63692012-11-14 16:31:52 -0800480
481 if (mask == ENCODE_ALL) {
482 strcpy(buf, "all");
483 } else {
484 char num[8];
485 int i;
486
487 for (i = 0; i < kArmRegEnd; i++) {
488 if (mask & (1ULL << i)) {
489 sprintf(num, "%d ", i);
490 strcat(buf, num);
491 }
492 }
493
494 if (mask & ENCODE_CCODE) {
495 strcat(buf, "cc ");
496 }
497 if (mask & ENCODE_FP_STATUS) {
498 strcat(buf, "fpcc ");
499 }
500
501 /* Memory bits */
502 if (armLIR && (mask & ENCODE_DALVIK_REG)) {
503 sprintf(buf + strlen(buf), "dr%d%s", armLIR->aliasInfo & 0xffff,
504 (armLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
505 }
506 if (mask & ENCODE_LITERAL) {
507 strcat(buf, "lit ");
508 }
509
510 if (mask & ENCODE_HEAP_REF) {
511 strcat(buf, "heap ");
512 }
513 if (mask & ENCODE_MUST_NOT_ALIAS) {
514 strcat(buf, "noalias ");
515 }
516 }
517 if (buf[0]) {
518 LOG(INFO) << prefix << ": " << buf;
519 }
520}
521
buzbeecbd6d442012-11-17 14:11:25 -0800522bool branchUnconditional(LIR* lir)
buzbeeefc63692012-11-14 16:31:52 -0800523{
buzbeecbd6d442012-11-17 14:11:25 -0800524 return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
buzbeeefc63692012-11-14 16:31:52 -0800525}
526
527/* Common initialization routine for an architecture family */
528bool oatArchInit()
529{
530 int i;
531
532 for (i = 0; i < kArmLast; i++) {
533 if (EncodingMap[i].opcode != i) {
534 LOG(FATAL) << "Encoding order for " << EncodingMap[i].name
535 << " is wrong: expecting " << i << ", seeing "
buzbeecbd6d442012-11-17 14:11:25 -0800536 << static_cast<int>(EncodingMap[i].opcode);
buzbeeefc63692012-11-14 16:31:52 -0800537 }
538 }
539
540 return oatArchVariantInit();
541}
542/*
543 * Determine the initial instruction set to be used for this trace.
544 * Later components may decide to change this.
545 */
546InstructionSet oatInstructionSet()
547{
548 return kThumb2;
549}
550
551/* Architecture-specific initializations and checks go here */
552bool oatArchVariantInit(void)
553{
554 return true;
555}
556
buzbeeefc63692012-11-14 16:31:52 -0800557/*
558 * Alloc a pair of core registers, or a double. Low reg in low byte,
559 * high reg in next byte.
560 */
561int oatAllocTypedTempPair(CompilationUnit* cUnit, bool fpHint, int regClass)
562{
563 int highReg;
564 int lowReg;
565 int res = 0;
566
567 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg)) {
568 lowReg = oatAllocTempDouble(cUnit);
569 highReg = lowReg + 1;
570 } else {
571 lowReg = oatAllocTemp(cUnit);
572 highReg = oatAllocTemp(cUnit);
573 }
574 res = (lowReg & 0xff) | ((highReg & 0xff) << 8);
575 return res;
576}
577
578int oatAllocTypedTemp(CompilationUnit* cUnit, bool fpHint, int regClass)
579{
580 if (((regClass == kAnyReg) && fpHint) || (regClass == kFPReg))
581 return oatAllocTempFloat(cUnit);
582 return oatAllocTemp(cUnit);
583}
584
585void oatInitializeRegAlloc(CompilationUnit* cUnit)
586{
587 int numRegs = sizeof(coreRegs)/sizeof(*coreRegs);
588 int numReserved = sizeof(reservedRegs)/sizeof(*reservedRegs);
589 int numTemps = sizeof(coreTemps)/sizeof(*coreTemps);
590 int numFPRegs = sizeof(fpRegs)/sizeof(*fpRegs);
591 int numFPTemps = sizeof(fpTemps)/sizeof(*fpTemps);
buzbeecbd6d442012-11-17 14:11:25 -0800592 RegisterPool *pool =
593 static_cast<RegisterPool*>(oatNew(cUnit, sizeof(*pool), true, kAllocRegAlloc));
buzbeeefc63692012-11-14 16:31:52 -0800594 cUnit->regPool = pool;
595 pool->numCoreRegs = numRegs;
buzbeecbd6d442012-11-17 14:11:25 -0800596 pool->coreRegs = reinterpret_cast<RegisterInfo*>
597 (oatNew(cUnit, numRegs * sizeof(*cUnit->regPool->coreRegs), true, kAllocRegAlloc));
buzbeeefc63692012-11-14 16:31:52 -0800598 pool->numFPRegs = numFPRegs;
buzbeecbd6d442012-11-17 14:11:25 -0800599 pool->FPRegs = static_cast<RegisterInfo*>
600 (oatNew(cUnit, numFPRegs * sizeof(*cUnit->regPool->FPRegs), true, kAllocRegAlloc));
buzbeeefc63692012-11-14 16:31:52 -0800601 oatInitPool(pool->coreRegs, coreRegs, pool->numCoreRegs);
602 oatInitPool(pool->FPRegs, fpRegs, pool->numFPRegs);
603 // Keep special registers from being allocated
604 for (int i = 0; i < numReserved; i++) {
605 if (NO_SUSPEND && (reservedRegs[i] == rARM_SUSPEND)) {
606 //To measure cost of suspend check
607 continue;
608 }
609 oatMarkInUse(cUnit, reservedRegs[i]);
610 }
611 // Mark temp regs - all others not in use can be used for promotion
612 for (int i = 0; i < numTemps; i++) {
613 oatMarkTemp(cUnit, coreTemps[i]);
614 }
615 for (int i = 0; i < numFPTemps; i++) {
616 oatMarkTemp(cUnit, fpTemps[i]);
617 }
618
619 // Start allocation at r2 in an attempt to avoid clobbering return values
620 pool->nextCoreReg = r2;
621
622 // Construct the alias map.
buzbeecbd6d442012-11-17 14:11:25 -0800623 cUnit->phiAliasMap = static_cast<int*>
624 (oatNew(cUnit, cUnit->numSSARegs * sizeof(cUnit->phiAliasMap[0]), false, kAllocDFInfo));
buzbeeefc63692012-11-14 16:31:52 -0800625 for (int i = 0; i < cUnit->numSSARegs; i++) {
626 cUnit->phiAliasMap[i] = i;
627 }
628 for (MIR* phi = cUnit->phiList; phi; phi = phi->meta.phiNext) {
629 int defReg = phi->ssaRep->defs[0];
630 for (int i = 0; i < phi->ssaRep->numUses; i++) {
631 for (int j = 0; j < cUnit->numSSARegs; j++) {
632 if (cUnit->phiAliasMap[j] == phi->ssaRep->uses[i]) {
633 cUnit->phiAliasMap[j] = defReg;
634 }
635 }
636 }
637 }
638}
639
640void freeRegLocTemps(CompilationUnit* cUnit, RegLocation rlKeep,
641 RegLocation rlFree)
642{
643 if ((rlFree.lowReg != rlKeep.lowReg) && (rlFree.lowReg != rlKeep.highReg) &&
644 (rlFree.highReg != rlKeep.lowReg) && (rlFree.highReg != rlKeep.highReg)) {
645 // No overlap, free both
646 oatFreeTemp(cUnit, rlFree.lowReg);
647 oatFreeTemp(cUnit, rlFree.highReg);
648 }
649}
650/*
651 * TUNING: is leaf? Can't just use "hasInvoke" to determine as some
652 * instructions might call out to C/assembly helper functions. Until
653 * machinery is in place, always spill lr.
654 */
655
656void oatAdjustSpillMask(CompilationUnit* cUnit)
657{
658 cUnit->coreSpillMask |= (1 << rARM_LR);
659 cUnit->numCoreSpills++;
660}
661
662/*
663 * Mark a callee-save fp register as promoted. Note that
664 * vpush/vpop uses contiguous register lists so we must
665 * include any holes in the mask. Associate holes with
666 * Dalvik register INVALID_VREG (0xFFFFU).
667 */
668void oatMarkPreservedSingle(CompilationUnit* cUnit, int vReg, int reg)
669{
670 DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
671 reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
672 // Ensure fpVmapTable is large enough
673 int tableSize = cUnit->fpVmapTable.size();
674 for (int i = tableSize; i < (reg + 1); i++) {
675 cUnit->fpVmapTable.push_back(INVALID_VREG);
676 }
677 // Add the current mapping
678 cUnit->fpVmapTable[reg] = vReg;
679 // Size of fpVmapTable is high-water mark, use to set mask
680 cUnit->numFPSpills = cUnit->fpVmapTable.size();
681 cUnit->fpSpillMask = ((1 << cUnit->numFPSpills) - 1) << ARM_FP_CALLEE_SAVE_BASE;
682}
683
684void oatFlushRegWide(CompilationUnit* cUnit, int reg1, int reg2)
685{
686 RegisterInfo* info1 = oatGetRegInfo(cUnit, reg1);
687 RegisterInfo* info2 = oatGetRegInfo(cUnit, reg2);
688 DCHECK(info1 && info2 && info1->pair && info2->pair &&
689 (info1->partner == info2->reg) &&
690 (info2->partner == info1->reg));
691 if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
692 if (!(info1->isTemp && info2->isTemp)) {
693 /* Should not happen. If it does, there's a problem in evalLoc */
694 LOG(FATAL) << "Long half-temp, half-promoted";
695 }
696
697 info1->dirty = false;
698 info2->dirty = false;
699 if (SRegToVReg(cUnit, info2->sReg) <
700 SRegToVReg(cUnit, info1->sReg))
701 info1 = info2;
702 int vReg = SRegToVReg(cUnit, info1->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800703 storeBaseDispWide(cUnit, rARM_SP, oatVRegOffset(cUnit, vReg), info1->reg, info1->partner);
buzbeeefc63692012-11-14 16:31:52 -0800704 }
705}
706
707void oatFlushReg(CompilationUnit* cUnit, int reg)
708{
709 RegisterInfo* info = oatGetRegInfo(cUnit, reg);
710 if (info->live && info->dirty) {
711 info->dirty = false;
712 int vReg = SRegToVReg(cUnit, info->sReg);
buzbeeeaf09bc2012-11-15 14:51:41 -0800713 storeBaseDisp(cUnit, rARM_SP, oatVRegOffset(cUnit, vReg), reg, kWord);
buzbeeefc63692012-11-14 16:31:52 -0800714 }
715}
716
717/* Give access to the target-dependent FP register encoding to common code */
718bool oatIsFpReg(int reg) {
719 return ARM_FPREG(reg);
720}
721
722uint32_t oatFpRegMask() {
723 return ARM_FP_REG_MASK;
724}
725
726/* Clobber all regs that might be used by an external C call */
727void oatClobberCalleeSave(CompilationUnit *cUnit)
728{
729 oatClobber(cUnit, r0);
730 oatClobber(cUnit, r1);
731 oatClobber(cUnit, r2);
732 oatClobber(cUnit, r3);
733 oatClobber(cUnit, r12);
734 oatClobber(cUnit, r14lr);
735 oatClobber(cUnit, fr0);
736 oatClobber(cUnit, fr1);
737 oatClobber(cUnit, fr2);
738 oatClobber(cUnit, fr3);
739 oatClobber(cUnit, fr4);
740 oatClobber(cUnit, fr5);
741 oatClobber(cUnit, fr6);
742 oatClobber(cUnit, fr7);
743 oatClobber(cUnit, fr8);
744 oatClobber(cUnit, fr9);
745 oatClobber(cUnit, fr10);
746 oatClobber(cUnit, fr11);
747 oatClobber(cUnit, fr12);
748 oatClobber(cUnit, fr13);
749 oatClobber(cUnit, fr14);
750 oatClobber(cUnit, fr15);
751}
752
753extern RegLocation oatGetReturnWideAlt(CompilationUnit* cUnit)
754{
755 RegLocation res = locCReturnWide();
756 res.lowReg = r2;
757 res.highReg = r3;
758 oatClobber(cUnit, r2);
759 oatClobber(cUnit, r3);
760 oatMarkInUse(cUnit, r2);
761 oatMarkInUse(cUnit, r3);
762 oatMarkPair(cUnit, res.lowReg, res.highReg);
763 return res;
764}
765
766extern RegLocation oatGetReturnAlt(CompilationUnit* cUnit)
767{
768 RegLocation res = locCReturn();
769 res.lowReg = r1;
770 oatClobber(cUnit, r1);
771 oatMarkInUse(cUnit, r1);
772 return res;
773}
774
775extern RegisterInfo* oatGetRegInfo(CompilationUnit* cUnit, int reg)
776{
777 return ARM_FPREG(reg) ? &cUnit->regPool->FPRegs[reg & ARM_FP_REG_MASK]
778 : &cUnit->regPool->coreRegs[reg];
779}
780
781/* To be used when explicitly managing register use */
782extern void oatLockCallTemps(CompilationUnit* cUnit)
783{
784 oatLockTemp(cUnit, r0);
785 oatLockTemp(cUnit, r1);
786 oatLockTemp(cUnit, r2);
787 oatLockTemp(cUnit, r3);
788}
789
790/* To be used when explicitly managing register use */
791extern void oatFreeCallTemps(CompilationUnit* cUnit)
792{
793 oatFreeTemp(cUnit, r0);
794 oatFreeTemp(cUnit, r1);
795 oatFreeTemp(cUnit, r2);
796 oatFreeTemp(cUnit, r3);
797}
798
buzbeeefc63692012-11-14 16:31:52 -0800799int loadHelper(CompilationUnit* cUnit, int offset)
800{
801 loadWordDisp(cUnit, rARM_SELF, offset, rARM_LR);
802 return rARM_LR;
803}
804
805} // namespace art