target_arm.cc revision 8325296769a77ecf3ab647b5ab516f439f5b3206
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.
56RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
57  int res_reg = RegStorage::kInvalidRegVal;
58  switch (reg) {
59    case kSelf: res_reg = rARM_SELF; break;
60    case kSuspend: res_reg =  rARM_SUSPEND; break;
61    case kLr: res_reg =  rARM_LR; break;
62    case kPc: res_reg =  rARM_PC; break;
63    case kSp: res_reg =  rARM_SP; break;
64    case kArg0: res_reg = rARM_ARG0; break;
65    case kArg1: res_reg = rARM_ARG1; break;
66    case kArg2: res_reg = rARM_ARG2; break;
67    case kArg3: res_reg = rARM_ARG3; break;
68    case kFArg0: res_reg = rARM_FARG0; break;
69    case kFArg1: res_reg = rARM_FARG1; break;
70    case kFArg2: res_reg = rARM_FARG2; break;
71    case kFArg3: res_reg = rARM_FARG3; break;
72    case kRet0: res_reg = rARM_RET0; break;
73    case kRet1: res_reg = rARM_RET1; break;
74    case kInvokeTgt: res_reg = rARM_INVOKE_TGT; break;
75    case kHiddenArg: res_reg = r12; break;
76    case kHiddenFpArg: res_reg = RegStorage::kInvalidRegVal; break;
77    case kCount: res_reg = rARM_COUNT; break;
78  }
79  return RegStorage::Solo32(res_reg);
80}
81
82RegStorage 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 rs_rARM_ARG1;
87    case 1:
88      return rs_rARM_ARG2;
89    case 2:
90      return rs_rARM_ARG3;
91    default:
92      return RegStorage::InvalidReg();
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  if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
532    return AllocTempDouble();
533  } else {
534    RegStorage low_reg = AllocTemp();
535    RegStorage high_reg = AllocTemp();
536    return RegStorage::MakeRegPair(low_reg, high_reg);
537  }
538}
539
540RegStorage ArmMir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
541  if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg))
542    return AllocTempFloat();
543  return AllocTemp();
544}
545
546void ArmMir2Lir::CompilerInitializeRegAlloc() {
547  int num_regs = sizeof(core_regs)/sizeof(*core_regs);
548  int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
549  int num_temps = sizeof(core_temps)/sizeof(*core_temps);
550  int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
551  int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
552  reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
553                                                       kArenaAllocRegAlloc));
554  reg_pool_->num_core_regs = num_regs;
555  reg_pool_->core_regs = reinterpret_cast<RegisterInfo*>
556      (arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), kArenaAllocRegAlloc));
557  reg_pool_->num_fp_regs = num_fp_regs;
558  reg_pool_->FPRegs = static_cast<RegisterInfo*>
559      (arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), kArenaAllocRegAlloc));
560  CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
561  CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
562
563  // Keep special registers from being allocated
564  // Don't reserve the r4 if we are doing implicit suspend checks.
565  // TODO: re-enable this when we can safely save r4 over the suspension code path.
566  bool no_suspend = NO_SUSPEND;  // || !Runtime::Current()->ExplicitSuspendChecks();
567  for (int i = 0; i < num_reserved; i++) {
568    if (no_suspend && (ReservedRegs[i] == rARM_SUSPEND)) {
569      // Don't reserve the suspend register.
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, RegLocation rl_free) {
587  DCHECK(rl_keep.wide);
588  DCHECK(rl_free.wide);
589  if ((rl_free.reg.GetLowReg() != rl_keep.reg.GetLowReg()) &&
590      (rl_free.reg.GetLowReg() != rl_keep.reg.GetHighReg()) &&
591      (rl_free.reg.GetHighReg() != rl_keep.reg.GetLowReg()) &&
592      (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) {
593    // No overlap, free.
594    FreeTemp(rl_free.reg);
595  }
596}
597
598/*
599 * TUNING: is true leaf?  Can't just use METHOD_IS_LEAF to determine as some
600 * instructions might call out to C/assembly helper functions.  Until
601 * machinery is in place, always spill lr.
602 */
603
604void ArmMir2Lir::AdjustSpillMask() {
605  core_spill_mask_ |= (1 << rARM_LR);
606  num_core_spills_++;
607}
608
609/*
610 * Mark a callee-save fp register as promoted.  Note that
611 * vpush/vpop uses contiguous register lists so we must
612 * include any holes in the mask.  Associate holes with
613 * Dalvik register INVALID_VREG (0xFFFFU).
614 */
615void ArmMir2Lir::MarkPreservedSingle(int v_reg, int reg) {
616  DCHECK_GE(reg, ARM_FP_REG_MASK + ARM_FP_CALLEE_SAVE_BASE);
617  reg = (reg & ARM_FP_REG_MASK) - ARM_FP_CALLEE_SAVE_BASE;
618  // Ensure fp_vmap_table is large enough
619  int table_size = fp_vmap_table_.size();
620  for (int i = table_size; i < (reg + 1); i++) {
621    fp_vmap_table_.push_back(INVALID_VREG);
622  }
623  // Add the current mapping
624  fp_vmap_table_[reg] = v_reg;
625  // Size of fp_vmap_table is high-water mark, use to set mask
626  num_fp_spills_ = fp_vmap_table_.size();
627  fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
628}
629
630void ArmMir2Lir::FlushRegWide(RegStorage reg) {
631  RegisterInfo* info1 = GetRegInfo(reg.GetLowReg());
632  RegisterInfo* info2 = GetRegInfo(reg.GetHighReg());
633  DCHECK(info1 && info2 && info1->pair && info2->pair &&
634       (info1->partner == info2->reg) &&
635       (info2->partner == info1->reg));
636  if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
637    if (!(info1->is_temp && info2->is_temp)) {
638      /* Should not happen.  If it does, there's a problem in eval_loc */
639      LOG(FATAL) << "Long half-temp, half-promoted";
640    }
641
642    info1->dirty = false;
643    info2->dirty = false;
644    if (mir_graph_->SRegToVReg(info2->s_reg) <
645      mir_graph_->SRegToVReg(info1->s_reg))
646      info1 = info2;
647    int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
648    StoreBaseDispWide(rs_rARM_SP, VRegOffset(v_reg),
649                      RegStorage(RegStorage::k64BitPair, info1->reg, info1->partner));
650  }
651}
652
653void ArmMir2Lir::FlushReg(RegStorage reg) {
654  DCHECK(!reg.IsPair());
655  RegisterInfo* info = GetRegInfo(reg.GetReg());
656  if (info->live && info->dirty) {
657    info->dirty = false;
658    int v_reg = mir_graph_->SRegToVReg(info->s_reg);
659    StoreBaseDisp(rs_rARM_SP, VRegOffset(v_reg), reg, kWord);
660  }
661}
662
663/* Give access to the target-dependent FP register encoding to common code */
664bool ArmMir2Lir::IsFpReg(int reg) {
665  return ARM_FPREG(reg);
666}
667
668bool ArmMir2Lir::IsFpReg(RegStorage reg) {
669  return IsFpReg(reg.IsPair() ? reg.GetLowReg() : reg.GetReg());
670}
671
672/* Clobber all regs that might be used by an external C call */
673void ArmMir2Lir::ClobberCallerSave() {
674  Clobber(r0);
675  Clobber(r1);
676  Clobber(r2);
677  Clobber(r3);
678  Clobber(r12);
679  Clobber(r14lr);
680  Clobber(fr0);
681  Clobber(fr1);
682  Clobber(fr2);
683  Clobber(fr3);
684  Clobber(fr4);
685  Clobber(fr5);
686  Clobber(fr6);
687  Clobber(fr7);
688  Clobber(fr8);
689  Clobber(fr9);
690  Clobber(fr10);
691  Clobber(fr11);
692  Clobber(fr12);
693  Clobber(fr13);
694  Clobber(fr14);
695  Clobber(fr15);
696}
697
698RegLocation ArmMir2Lir::GetReturnWideAlt() {
699  RegLocation res = LocCReturnWide();
700  res.reg.SetReg(r2);
701  res.reg.SetHighReg(r3);
702  Clobber(r2);
703  Clobber(r3);
704  MarkInUse(r2);
705  MarkInUse(r3);
706  MarkPair(res.reg.GetLowReg(), res.reg.GetHighReg());
707  return res;
708}
709
710RegLocation ArmMir2Lir::GetReturnAlt() {
711  RegLocation res = LocCReturn();
712  res.reg.SetReg(r1);
713  Clobber(r1);
714  MarkInUse(r1);
715  return res;
716}
717
718/* To be used when explicitly managing register use */
719void ArmMir2Lir::LockCallTemps() {
720  LockTemp(r0);
721  LockTemp(r1);
722  LockTemp(r2);
723  LockTemp(r3);
724}
725
726/* To be used when explicitly managing register use */
727void ArmMir2Lir::FreeCallTemps() {
728  FreeTemp(r0);
729  FreeTemp(r1);
730  FreeTemp(r2);
731  FreeTemp(r3);
732}
733
734RegStorage ArmMir2Lir::LoadHelper(ThreadOffset<4> offset) {
735  LoadWordDisp(rs_rARM_SELF, offset.Int32Value(), rs_rARM_LR);
736  return rs_rARM_LR;
737}
738
739LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
740  RegStorage tmp = rs_r0;
741  LoadWordDisp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
742  LIR* load2 = LoadWordDisp(tmp, 0, tmp);
743  return load2;
744}
745
746uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
747  DCHECK(!IsPseudoLirOp(opcode));
748  return ArmMir2Lir::EncodingMap[opcode].flags;
749}
750
751const char* ArmMir2Lir::GetTargetInstName(int opcode) {
752  DCHECK(!IsPseudoLirOp(opcode));
753  return ArmMir2Lir::EncodingMap[opcode].name;
754}
755
756const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
757  DCHECK(!IsPseudoLirOp(opcode));
758  return ArmMir2Lir::EncodingMap[opcode].fmt;
759}
760
761}  // namespace art
762