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