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