target_arm.cc revision 83cc7ae96d4176533dd0391a1591d321b0a87f4f
1/*
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 "codegen_arm.h"
18
19#include <inttypes.h>
20
21#include <string>
22
23#include "dex/compiler_internals.h"
24#include "dex/quick/mir_to_lir-inl.h"
25
26namespace art {
27
28static int core_regs[] = {r0, r1, r2, r3, rARM_SUSPEND, r5, r6, r7, r8, rARM_SELF, r10,
29                         r11, r12, rARM_SP, rARM_LR, rARM_PC};
30static int ReservedRegs[] = {rARM_SUSPEND, rARM_SELF, rARM_SP, rARM_LR, rARM_PC};
31static int FpRegs[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
32                       fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15,
33                       fr16, fr17, fr18, fr19, fr20, fr21, fr22, fr23,
34                       fr24, fr25, fr26, fr27, fr28, fr29, fr30, fr31};
35static int core_temps[] = {r0, r1, r2, r3, r12};
36static int fp_temps[] = {fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
37                        fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15};
38
39RegLocation ArmMir2Lir::LocCReturn() {
40  return arm_loc_c_return;
41}
42
43RegLocation ArmMir2Lir::LocCReturnWide() {
44  return arm_loc_c_return_wide;
45}
46
47RegLocation ArmMir2Lir::LocCReturnFloat() {
48  return arm_loc_c_return_float;
49}
50
51RegLocation ArmMir2Lir::LocCReturnDouble() {
52  return arm_loc_c_return_double;
53}
54
55// Return a target-dependent special register.
56int ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
57  int res = INVALID_REG;
58  switch (reg) {
59    case kSelf: res = rARM_SELF; break;
60    case kSuspend: res =  rARM_SUSPEND; break;
61    case kLr: res =  rARM_LR; break;
62    case kPc: res =  rARM_PC; break;
63    case kSp: res =  rARM_SP; break;
64    case kArg0: res = rARM_ARG0; break;
65    case kArg1: res = rARM_ARG1; break;
66    case kArg2: res = rARM_ARG2; break;
67    case kArg3: res = rARM_ARG3; break;
68    case kFArg0: res = rARM_FARG0; break;
69    case kFArg1: res = rARM_FARG1; break;
70    case kFArg2: res = rARM_FARG2; break;
71    case kFArg3: res = rARM_FARG3; break;
72    case kRet0: res = rARM_RET0; break;
73    case kRet1: res = rARM_RET1; break;
74    case kInvokeTgt: res = rARM_INVOKE_TGT; break;
75    case kHiddenArg: res = r12; break;
76    case kHiddenFpArg: res = INVALID_REG; break;
77    case kCount: res = rARM_COUNT; break;
78  }
79  return res;
80}
81
82int ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
83  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
84  switch (arg_num) {
85    case 0:
86      return rARM_ARG1;
87    case 1:
88      return rARM_ARG2;
89    case 2:
90      return rARM_ARG3;
91    default:
92      return INVALID_REG;
93  }
94}
95
96// Create a double from a pair of singles.
97int ArmMir2Lir::S2d(int low_reg, int high_reg) {
98  return ARM_S2D(low_reg, high_reg);
99}
100
101// Return mask to strip off fp reg flags and bias.
102uint32_t ArmMir2Lir::FpRegMask() {
103  return ARM_FP_REG_MASK;
104}
105
106// True if both regs single, both core or both double.
107bool ArmMir2Lir::SameRegType(int reg1, int reg2) {
108  return (ARM_REGTYPE(reg1) == ARM_REGTYPE(reg2));
109}
110
111/*
112 * Decode the register id.
113 */
114uint64_t ArmMir2Lir::GetRegMaskCommon(int reg) {
115  uint64_t seed;
116  int shift;
117  int reg_id;
118
119
120  reg_id = reg & 0x1f;
121  /* Each double register is equal to a pair of single-precision FP registers */
122  seed = ARM_DOUBLEREG(reg) ? 3 : 1;
123  /* FP register starts at bit position 16 */
124  shift = ARM_FPREG(reg) ? kArmFPReg0 : 0;
125  /* Expand the double register id into single offset */
126  shift += reg_id;
127  return (seed << shift);
128}
129
130uint64_t ArmMir2Lir::GetPCUseDefEncoding() {
131  return ENCODE_ARM_REG_PC;
132}
133
134// Thumb2 specific setup.  TODO: inline?:
135void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) {
136  DCHECK_EQ(cu_->instruction_set, kThumb2);
137  DCHECK(!lir->flags.use_def_invalid);
138
139  int opcode = lir->opcode;
140
141  // These flags are somewhat uncommon - bypass if we can.
142  if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
143                REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
144                REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
145    if (flags & REG_DEF_SP) {
146      lir->u.m.def_mask |= ENCODE_ARM_REG_SP;
147    }
148
149    if (flags & REG_USE_SP) {
150      lir->u.m.use_mask |= ENCODE_ARM_REG_SP;
151    }
152
153    if (flags & REG_DEF_LIST0) {
154      lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
155    }
156
157    if (flags & REG_DEF_LIST1) {
158      lir->u.m.def_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
159    }
160
161    if (flags & REG_DEF_FPCS_LIST0) {
162      lir->u.m.def_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
163    }
164
165    if (flags & REG_DEF_FPCS_LIST2) {
166      for (int i = 0; i < lir->operands[2]; i++) {
167        SetupRegMask(&lir->u.m.def_mask, lir->operands[1] + i);
168      }
169    }
170
171    if (flags & REG_USE_PC) {
172      lir->u.m.use_mask |= ENCODE_ARM_REG_PC;
173    }
174
175    /* Conservatively treat the IT block */
176    if (flags & IS_IT) {
177      lir->u.m.def_mask = ENCODE_ALL;
178    }
179
180    if (flags & REG_USE_LIST0) {
181      lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[0]);
182    }
183
184    if (flags & REG_USE_LIST1) {
185      lir->u.m.use_mask |= ENCODE_ARM_REG_LIST(lir->operands[1]);
186    }
187
188    if (flags & REG_USE_FPCS_LIST0) {
189      lir->u.m.use_mask |= ENCODE_ARM_REG_FPCS_LIST(lir->operands[0]);
190    }
191
192    if (flags & REG_USE_FPCS_LIST2) {
193      for (int i = 0; i < lir->operands[2]; i++) {
194        SetupRegMask(&lir->u.m.use_mask, lir->operands[1] + i);
195      }
196    }
197    /* Fixup for kThumbPush/lr and kThumbPop/pc */
198    if (opcode == kThumbPush || opcode == kThumbPop) {
199      uint64_t r8Mask = GetRegMaskCommon(r8);
200      if ((opcode == kThumbPush) && (lir->u.m.use_mask & r8Mask)) {
201        lir->u.m.use_mask &= ~r8Mask;
202        lir->u.m.use_mask |= ENCODE_ARM_REG_LR;
203      } else if ((opcode == kThumbPop) && (lir->u.m.def_mask & r8Mask)) {
204        lir->u.m.def_mask &= ~r8Mask;
205        lir->u.m.def_mask |= ENCODE_ARM_REG_PC;
206      }
207    }
208    if (flags & REG_DEF_LR) {
209      lir->u.m.def_mask |= ENCODE_ARM_REG_LR;
210    }
211  }
212}
213
214ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
215  ArmConditionCode res;
216  switch (ccode) {
217    case kCondEq: res = kArmCondEq; break;
218    case kCondNe: res = kArmCondNe; break;
219    case kCondCs: res = kArmCondCs; break;
220    case kCondCc: res = kArmCondCc; break;
221    case kCondUlt: res = kArmCondCc; break;
222    case kCondUge: res = kArmCondCs; break;
223    case kCondMi: res = kArmCondMi; break;
224    case kCondPl: res = kArmCondPl; break;
225    case kCondVs: res = kArmCondVs; break;
226    case kCondVc: res = kArmCondVc; break;
227    case kCondHi: res = kArmCondHi; break;
228    case kCondLs: res = kArmCondLs; break;
229    case kCondGe: res = kArmCondGe; break;
230    case kCondLt: res = kArmCondLt; break;
231    case kCondGt: res = kArmCondGt; break;
232    case kCondLe: res = kArmCondLe; break;
233    case kCondAl: res = kArmCondAl; break;
234    case kCondNv: res = kArmCondNv; break;
235    default:
236      LOG(FATAL) << "Bad condition code " << ccode;
237      res = static_cast<ArmConditionCode>(0);  // Quiet gcc
238  }
239  return res;
240}
241
242static const char* core_reg_names[16] = {
243  "r0",
244  "r1",
245  "r2",
246  "r3",
247  "r4",
248  "r5",
249  "r6",
250  "r7",
251  "r8",
252  "rSELF",
253  "r10",
254  "r11",
255  "r12",
256  "sp",
257  "lr",
258  "pc",
259};
260
261
262static const char* shift_names[4] = {
263  "lsl",
264  "lsr",
265  "asr",
266  "ror"};
267
268/* Decode and print a ARM register name */
269static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
270  int i;
271  bool printed = false;
272  buf[0] = 0;
273  for (i = 0; i < 16; i++, vector >>= 1) {
274    if (vector & 0x1) {
275      int reg_id = i;
276      if (opcode == kThumbPush && i == 8) {
277        reg_id = r14lr;
278      } else if (opcode == kThumbPop && i == 8) {
279        reg_id = r15pc;
280      }
281      if (printed) {
282        snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
283      } else {
284        printed = true;
285        snprintf(buf, buf_size, "r%d", reg_id);
286      }
287    }
288  }
289  return buf;
290}
291
292static char*  DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
293  snprintf(buf, buf_size, "s%d", base);
294  for (int i = 1; i < count; i++) {
295    snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
296  }
297  return buf;
298}
299
300static int32_t ExpandImmediate(int value) {
301  int32_t mode = (value & 0xf00) >> 8;
302  uint32_t bits = value & 0xff;
303  switch (mode) {
304    case 0:
305      return bits;
306     case 1:
307      return (bits << 16) | bits;
308     case 2:
309      return (bits << 24) | (bits << 8);
310     case 3:
311      return (bits << 24) | (bits << 16) | (bits << 8) | bits;
312    default:
313      break;
314  }
315  bits = (bits | 0x80) << 24;
316  return bits >> (((value & 0xf80) >> 7) - 8);
317}
318
319const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
320                         "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
321/*
322 * Interpret a format string and build a string no longer than size
323 * See format key in Assemble.c.
324 */
325std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
326  std::string buf;
327  int i;
328  const char* fmt_end = &fmt[strlen(fmt)];
329  char tbuf[256];
330  const char* name;
331  char nc;
332  while (fmt < fmt_end) {
333    int operand;
334    if (*fmt == '!') {
335      fmt++;
336      DCHECK_LT(fmt, fmt_end);
337      nc = *fmt++;
338      if (nc == '!') {
339        strcpy(tbuf, "!");
340      } else {
341         DCHECK_LT(fmt, fmt_end);
342         DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
343         operand = lir->operands[nc-'0'];
344         switch (*fmt++) {
345           case 'H':
346             if (operand != 0) {
347               snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
348             } else {
349               strcpy(tbuf, "");
350             }
351             break;
352           case 'B':
353             switch (operand) {
354               case kSY:
355                 name = "sy";
356                 break;
357               case kST:
358                 name = "st";
359                 break;
360               case kISH:
361                 name = "ish";
362                 break;
363               case kISHST:
364                 name = "ishst";
365                 break;
366               case kNSH:
367                 name = "nsh";
368                 break;
369               case kNSHST:
370                 name = "shst";
371                 break;
372               default:
373                 name = "DecodeError2";
374                 break;
375             }
376             strcpy(tbuf, name);
377             break;
378           case 'b':
379             strcpy(tbuf, "0000");
380             for (i = 3; i >= 0; i--) {
381               tbuf[i] += operand & 1;
382               operand >>= 1;
383             }
384             break;
385           case 'n':
386             operand = ~ExpandImmediate(operand);
387             snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
388             break;
389           case 'm':
390             operand = ExpandImmediate(operand);
391             snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
392             break;
393           case 's':
394             snprintf(tbuf, arraysize(tbuf), "s%d", operand & ARM_FP_REG_MASK);
395             break;
396           case 'S':
397             snprintf(tbuf, arraysize(tbuf), "d%d", (operand & ARM_FP_REG_MASK) >> 1);
398             break;
399           case 'h':
400             snprintf(tbuf, arraysize(tbuf), "%04x", operand);
401             break;
402           case 'M':
403           case 'd':
404             snprintf(tbuf, arraysize(tbuf), "%d", operand);
405             break;
406           case 'C':
407             DCHECK_LT(operand, static_cast<int>(
408                 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
409             snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
410             break;
411           case 'E':
412             snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
413             break;
414           case 'F':
415             snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
416             break;
417           case 'c':
418             strcpy(tbuf, cc_names[operand]);
419             break;
420           case 't':
421             snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
422                 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
423                 lir->target);
424             break;
425           case 'u': {
426             int offset_1 = lir->operands[0];
427             int offset_2 = NEXT_LIR(lir)->operands[0];
428             uintptr_t target =
429                 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
430                 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
431                 0xfffffffc;
432             snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
433             break;
434          }
435
436           /* Nothing to print for BLX_2 */
437           case 'v':
438             strcpy(tbuf, "see above");
439             break;
440           case 'R':
441             DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
442             break;
443           case 'P':
444             DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
445             break;
446           case 'Q':
447             DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
448             break;
449           default:
450             strcpy(tbuf, "DecodeError1");
451             break;
452        }
453        buf += tbuf;
454      }
455    } else {
456       buf += *fmt++;
457    }
458  }
459  return buf;
460}
461
462void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, uint64_t mask, const char* prefix) {
463  char buf[256];
464  buf[0] = 0;
465
466  if (mask == ENCODE_ALL) {
467    strcpy(buf, "all");
468  } else {
469    char num[8];
470    int i;
471
472    for (i = 0; i < kArmRegEnd; i++) {
473      if (mask & (1ULL << i)) {
474        snprintf(num, arraysize(num), "%d ", i);
475        strcat(buf, num);
476      }
477    }
478
479    if (mask & ENCODE_CCODE) {
480      strcat(buf, "cc ");
481    }
482    if (mask & ENCODE_FP_STATUS) {
483      strcat(buf, "fpcc ");
484    }
485
486    /* Memory bits */
487    if (arm_lir && (mask & ENCODE_DALVIK_REG)) {
488      snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
489               DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
490               DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
491    }
492    if (mask & ENCODE_LITERAL) {
493      strcat(buf, "lit ");
494    }
495
496    if (mask & ENCODE_HEAP_REF) {
497      strcat(buf, "heap ");
498    }
499    if (mask & ENCODE_MUST_NOT_ALIAS) {
500      strcat(buf, "noalias ");
501    }
502  }
503  if (buf[0]) {
504    LOG(INFO) << prefix << ": " << buf;
505  }
506}
507
508bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
509  return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
510}
511
512ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
513    : Mir2Lir(cu, mir_graph, arena) {
514  // Sanity check - make sure encoding map lines up.
515  for (int i = 0; i < kArmLast; i++) {
516    if (ArmMir2Lir::EncodingMap[i].opcode != i) {
517      LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
518                 << " is wrong: expecting " << i << ", seeing "
519                 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
520    }
521  }
522}
523
524Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
525                          ArenaAllocator* const arena) {
526  return new ArmMir2Lir(cu, mir_graph, arena);
527}
528
529// Alloc a pair of core registers, or a double.
530RegStorage ArmMir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) {
531  int high_reg;
532  int low_reg;
533
534  if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
535    low_reg = AllocTempDouble();
536    high_reg = low_reg + 1;
537  } else {
538    low_reg = AllocTemp();
539    high_reg = AllocTemp();
540  }
541  return RegStorage(RegStorage::k64BitPair, low_reg, high_reg);
542}
543
544int ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
545  if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
546    return AllocTempFloat();
547  return AllocTemp();
548}
549
550void ArmMir2Lir::CompilerInitializeRegAlloc() {
551  int num_regs = sizeof(core_regs)/sizeof(*core_regs);
552  int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
553  int num_temps = sizeof(core_temps)/sizeof(*core_temps);
554  int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
555  int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
556  reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
557                                                       kArenaAllocRegAlloc));
558  reg_pool_->num_core_regs = num_regs;
559  reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
560      (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
561  reg_pool_->num_fp_regs = num_fp_regs;
562  reg_pool_->FPRegs = static_cast<RegisterInfo*>
563      (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
564  CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
565  CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
566  // Keep special registers from being allocated
567  for (int i = 0; i < num_reserved; i++) {
568    if (NO_SUSPEND && (ReservedRegs[i] == rARM_SUSPEND)) {
569      // To measure cost of suspend check
570      continue;
571    }
572    MarkInUse(ReservedRegs[i]);
573  }
574  // Mark temp regs - all others not in use can be used for promotion
575  for (int i = 0; i < num_temps; i++) {
576    MarkTemp(core_temps[i]);
577  }
578  for (int i = 0; i < num_fp_temps; i++) {
579    MarkTemp(fp_temps[i]);
580  }
581
582  // Start allocation at r2 in an attempt to avoid clobbering return values
583  reg_pool_->next_core_reg = r2;
584}
585
586void ArmMir2Lir::FreeRegLocTemps(RegLocation rl_keep,
587                     RegLocation rl_free) {
588  if ((rl_free.reg.GetReg() != rl_keep.reg.GetReg()) && (rl_free.reg.GetReg() != rl_keep.reg.GetHighReg()) &&
589    (rl_free.reg.GetHighReg() != rl_keep.reg.GetReg()) && (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
590    // No overlap, free both
591    FreeTemp(rl_free.reg.GetReg());
592    FreeTemp(rl_free.reg.GetHighReg());
593  }
594}
595/*
596 * TUNING: is true leaf?  Can't just use METHOD_IS_LEAF to determine as some
597 * instructions might call out to C/assembly helper functions.  Until
598 * machinery is in place, always spill lr.
599 */
600
601void ArmMir2Lir::AdjustSpillMask() {
602  core_spill_mask_ |= (1 << rARM_LR);
603  num_core_spills_++;
604}
605
606/*
607 * Mark a callee-save fp register as promoted.  Note that
608 * vpush/vpop uses contiguous register lists so we must
609 * include any holes in the mask.  Associate holes with
610 * Dalvik register INVALID_VREG (0xFFFFU).
611 */
612void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
613  DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
614  reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
615  // Ensure fp_vmap_table is large enough
616  int table_size = fp_vmap_table_.size();
617  for (int i = table_size; i < (reg + 1); i++) {
618    fp_vmap_table_.push_back(INVALID_VREG);
619  }
620  // Add the current mapping
621  fp_vmap_table_[reg] = v_reg;
622  // Size of fp_vmap_table is high-water mark, use to set mask
623  num_fp_spills_ = fp_vmap_table_.size();
624  fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
625}
626
627void ArmMir2Lir::FlushRegWide(int reg1, int reg2) {
628  RegisterInfo* info1 = GetRegInfo(reg1);
629  RegisterInfo* info2 = GetRegInfo(reg2);
630  DCHECK(info1 && info2 && info1->pair && info2->pair &&
631       (info1->partner == info2->reg) &&
632       (info2->partner == info1->reg));
633  if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
634    if (!(info1->is_temp && info2->is_temp)) {
635      /* Should not happen.  If it does, there's a problem in eval_loc */
636      LOG(FATAL) << "Long half-temp, half-promoted";
637    }
638
639    info1->dirty = false;
640    info2->dirty = false;
641    if (mir_graph_->SRegToVReg(info2->s_reg) <
642      mir_graph_->SRegToVReg(info1->s_reg))
643      info1 = info2;
644    int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
645    StoreBaseDispWide(rARM_SP, VRegOffset(v_reg), info1->reg, info1->partner);
646  }
647}
648
649void ArmMir2Lir::FlushReg(int reg) {
650  RegisterInfo* info = GetRegInfo(reg);
651  if (info->live && info->dirty) {
652    info->dirty = false;
653    int v_reg = mir_graph_->SRegToVReg(info->s_reg);
654    StoreBaseDisp(rARM_SP, VRegOffset(v_reg), reg, kWord);
655  }
656}
657
658/* Give access to the target-dependent FP register encoding to common code */
659bool ArmMir2Lir::IsFpReg(int reg) {
660  return ARM_FPREG(reg);
661}
662
663/* Clobber all regs that might be used by an external C call */
664void ArmMir2Lir::ClobberCallerSave() {
665  Clobber(r0);
666  Clobber(r1);
667  Clobber(r2);
668  Clobber(r3);
669  Clobber(r12);
670  Clobber(r14lr);
671  Clobber(fr0);
672  Clobber(fr1);
673  Clobber(fr2);
674  Clobber(fr3);
675  Clobber(fr4);
676  Clobber(fr5);
677  Clobber(fr6);
678  Clobber(fr7);
679  Clobber(fr8);
680  Clobber(fr9);
681  Clobber(fr10);
682  Clobber(fr11);
683  Clobber(fr12);
684  Clobber(fr13);
685  Clobber(fr14);
686  Clobber(fr15);
687}
688
689RegLocation ArmMir2Lir::GetReturnWideAlt() {
690  RegLocation res = LocCReturnWide();
691  res.reg.SetReg(r2);
692  res.reg.SetHighReg(r3);
693  Clobber(r2);
694  Clobber(r3);
695  MarkInUse(r2);
696  MarkInUse(r3);
697  MarkPair(res.reg.GetReg(), res.reg.GetHighReg());
698  return res;
699}
700
701RegLocation ArmMir2Lir::GetReturnAlt() {
702  RegLocation res = LocCReturn();
703  res.reg.SetReg(r1);
704  Clobber(r1);
705  MarkInUse(r1);
706  return res;
707}
708
709/* To be used when explicitly managing register use */
710void ArmMir2Lir::LockCallTemps() {
711  LockTemp(r0);
712  LockTemp(r1);
713  LockTemp(r2);
714  LockTemp(r3);
715}
716
717/* To be used when explicitly managing register use */
718void ArmMir2Lir::FreeCallTemps() {
719  FreeTemp(r0);
720  FreeTemp(r1);
721  FreeTemp(r2);
722  FreeTemp(r3);
723}
724
725int ArmMir2Lir::LoadHelper(ThreadOffset offset) {
726  LoadWordDisp(rARM_SELF, offset.Int32Value(), rARM_LR);
727  return rARM_LR;
728}
729
730uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
731  DCHECK(!IsPseudoLirOp(opcode));
732  return ArmMir2Lir::EncodingMap[opcode].flags;
733}
734
735const char* ArmMir2Lir::GetTargetInstName(int opcode) {
736  DCHECK(!IsPseudoLirOp(opcode));
737  return ArmMir2Lir::EncodingMap[opcode].name;
738}
739
740const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
741  DCHECK(!IsPseudoLirOp(opcode));
742  return ArmMir2Lir::EncodingMap[opcode].fmt;
743}
744
745}  // namespace art
746