target_arm.cc revision 984305917bf57b3f8d92965e4715a0370cc5bcfb
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
28#ifdef ARM_R4_SUSPEND_FLAG
29static constexpr RegStorage core_regs_arr[] =
30    {rs_r0, rs_r1, rs_r2, rs_r3, rs_rARM_SUSPEND, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
31     rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
32#else
33static constexpr RegStorage core_regs_arr[] =
34    {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r5, rs_r6, rs_r7, rs_r8, rs_rARM_SELF,
35     rs_r10, rs_r11, rs_r12, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
36#endif
37static constexpr RegStorage sp_regs_arr[] =
38    {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
39     rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15, rs_fr16, rs_fr17, rs_fr18, rs_fr19, rs_fr20,
40     rs_fr21, rs_fr22, rs_fr23, rs_fr24, rs_fr25, rs_fr26, rs_fr27, rs_fr28, rs_fr29, rs_fr30,
41     rs_fr31};
42static constexpr RegStorage dp_regs_arr[] =
43    {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7, rs_dr8, rs_dr9, rs_dr10,
44     rs_dr11, rs_dr12, rs_dr13, rs_dr14, rs_dr15};
45#ifdef ARM_R4_SUSPEND_FLAG
46static constexpr RegStorage reserved_regs_arr[] =
47    {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
48static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
49#else
50static constexpr RegStorage reserved_regs_arr[] =
51    {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
52static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12};
53#endif
54static constexpr RegStorage sp_temps_arr[] =
55    {rs_fr0, rs_fr1, rs_fr2, rs_fr3, rs_fr4, rs_fr5, rs_fr6, rs_fr7, rs_fr8, rs_fr9, rs_fr10,
56     rs_fr11, rs_fr12, rs_fr13, rs_fr14, rs_fr15};
57static constexpr RegStorage dp_temps_arr[] =
58    {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
59
60static constexpr ArrayRef<const RegStorage> empty_pool;
61static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
62static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
63static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
64static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
65static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
66static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
67static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
68
69RegLocation ArmMir2Lir::LocCReturn() {
70  return arm_loc_c_return;
71}
72
73RegLocation ArmMir2Lir::LocCReturnRef() {
74  return arm_loc_c_return;
75}
76
77RegLocation ArmMir2Lir::LocCReturnWide() {
78  return arm_loc_c_return_wide;
79}
80
81RegLocation ArmMir2Lir::LocCReturnFloat() {
82  return arm_loc_c_return_float;
83}
84
85RegLocation ArmMir2Lir::LocCReturnDouble() {
86  return arm_loc_c_return_double;
87}
88
89// Return a target-dependent special register.
90RegStorage ArmMir2Lir::TargetReg(SpecialTargetRegister reg) {
91  RegStorage res_reg = RegStorage::InvalidReg();
92  switch (reg) {
93    case kSelf: res_reg = rs_rARM_SELF; break;
94#ifdef ARM_R4_SUSPEND_FLAG
95    case kSuspend: res_reg =  rs_rARM_SUSPEND; break;
96#else
97    case kSuspend: res_reg = RegStorage::InvalidReg(); break;
98#endif
99    case kLr: res_reg =  rs_rARM_LR; break;
100    case kPc: res_reg =  rs_rARM_PC; break;
101    case kSp: res_reg =  rs_rARM_SP; break;
102    case kArg0: res_reg = rs_r0; break;
103    case kArg1: res_reg = rs_r1; break;
104    case kArg2: res_reg = rs_r2; break;
105    case kArg3: res_reg = rs_r3; break;
106    case kFArg0: res_reg = rs_r0; break;
107    case kFArg1: res_reg = rs_r1; break;
108    case kFArg2: res_reg = rs_r2; break;
109    case kFArg3: res_reg = rs_r3; break;
110    case kRet0: res_reg = rs_r0; break;
111    case kRet1: res_reg = rs_r1; break;
112    case kInvokeTgt: res_reg = rs_rARM_LR; break;
113    case kHiddenArg: res_reg = rs_r12; break;
114    case kHiddenFpArg: res_reg = RegStorage::InvalidReg(); break;
115    case kCount: res_reg = RegStorage::InvalidReg(); break;
116    default: res_reg = RegStorage::InvalidReg();
117  }
118  return res_reg;
119}
120
121RegStorage ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
122  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
123  switch (arg_num) {
124    case 0:
125      return rs_r1;
126    case 1:
127      return rs_r2;
128    case 2:
129      return rs_r3;
130    default:
131      return RegStorage::InvalidReg();
132  }
133}
134
135/*
136 * Decode the register id.
137 */
138ResourceMask ArmMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
139  return GetRegMaskArm(reg);
140}
141
142constexpr ResourceMask ArmMir2Lir::GetRegMaskArm(RegStorage reg) {
143  return reg.IsDouble()
144      /* Each double register is equal to a pair of single-precision FP registers */
145      ? ResourceMask::TwoBits(reg.GetRegNum() * 2 + kArmFPReg0)
146      : ResourceMask::Bit(reg.IsSingle() ? reg.GetRegNum() + kArmFPReg0 : reg.GetRegNum());
147}
148
149constexpr ResourceMask ArmMir2Lir::EncodeArmRegList(int reg_list) {
150  return ResourceMask::RawMask(static_cast<uint64_t >(reg_list), 0u);
151}
152
153constexpr ResourceMask ArmMir2Lir::EncodeArmRegFpcsList(int reg_list) {
154  return ResourceMask::RawMask(static_cast<uint64_t >(reg_list) << kArmFPReg16, 0u);
155}
156
157ResourceMask ArmMir2Lir::GetPCUseDefEncoding() const {
158  return ResourceMask::Bit(kArmRegPC);
159}
160
161// Thumb2 specific setup.  TODO: inline?:
162void ArmMir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags,
163                                          ResourceMask* use_mask, ResourceMask* def_mask) {
164  DCHECK_EQ(cu_->instruction_set, kThumb2);
165  DCHECK(!lir->flags.use_def_invalid);
166
167  int opcode = lir->opcode;
168
169  // These flags are somewhat uncommon - bypass if we can.
170  if ((flags & (REG_DEF_SP | REG_USE_SP | REG_DEF_LIST0 | REG_DEF_LIST1 |
171                REG_DEF_FPCS_LIST0 | REG_DEF_FPCS_LIST2 | REG_USE_PC | IS_IT | REG_USE_LIST0 |
172                REG_USE_LIST1 | REG_USE_FPCS_LIST0 | REG_USE_FPCS_LIST2 | REG_DEF_LR)) != 0) {
173    if (flags & REG_DEF_SP) {
174      def_mask->SetBit(kArmRegSP);
175    }
176
177    if (flags & REG_USE_SP) {
178      use_mask->SetBit(kArmRegSP);
179    }
180
181    if (flags & REG_DEF_LIST0) {
182      def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
183    }
184
185    if (flags & REG_DEF_LIST1) {
186      def_mask->SetBits(EncodeArmRegList(lir->operands[1]));
187    }
188
189    if (flags & REG_DEF_FPCS_LIST0) {
190      def_mask->SetBits(EncodeArmRegList(lir->operands[0]));
191    }
192
193    if (flags & REG_DEF_FPCS_LIST2) {
194      for (int i = 0; i < lir->operands[2]; i++) {
195        SetupRegMask(def_mask, lir->operands[1] + i);
196      }
197    }
198
199    if (flags & REG_USE_PC) {
200      use_mask->SetBit(kArmRegPC);
201    }
202
203    /* Conservatively treat the IT block */
204    if (flags & IS_IT) {
205      *def_mask = kEncodeAll;
206    }
207
208    if (flags & REG_USE_LIST0) {
209      use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
210    }
211
212    if (flags & REG_USE_LIST1) {
213      use_mask->SetBits(EncodeArmRegList(lir->operands[1]));
214    }
215
216    if (flags & REG_USE_FPCS_LIST0) {
217      use_mask->SetBits(EncodeArmRegList(lir->operands[0]));
218    }
219
220    if (flags & REG_USE_FPCS_LIST2) {
221      for (int i = 0; i < lir->operands[2]; i++) {
222        SetupRegMask(use_mask, lir->operands[1] + i);
223      }
224    }
225    /* Fixup for kThumbPush/lr and kThumbPop/pc */
226    if (opcode == kThumbPush || opcode == kThumbPop) {
227      constexpr ResourceMask r8Mask = GetRegMaskArm(rs_r8);
228      if ((opcode == kThumbPush) && (use_mask->Intersects(r8Mask))) {
229        use_mask->ClearBits(r8Mask);
230        use_mask->SetBit(kArmRegLR);
231      } else if ((opcode == kThumbPop) && (def_mask->Intersects(r8Mask))) {
232        def_mask->ClearBits(r8Mask);
233        def_mask->SetBit(kArmRegPC);;
234      }
235    }
236    if (flags & REG_DEF_LR) {
237      def_mask->SetBit(kArmRegLR);
238    }
239  }
240}
241
242ArmConditionCode ArmMir2Lir::ArmConditionEncoding(ConditionCode ccode) {
243  ArmConditionCode res;
244  switch (ccode) {
245    case kCondEq: res = kArmCondEq; break;
246    case kCondNe: res = kArmCondNe; break;
247    case kCondCs: res = kArmCondCs; break;
248    case kCondCc: res = kArmCondCc; break;
249    case kCondUlt: res = kArmCondCc; break;
250    case kCondUge: res = kArmCondCs; break;
251    case kCondMi: res = kArmCondMi; break;
252    case kCondPl: res = kArmCondPl; break;
253    case kCondVs: res = kArmCondVs; break;
254    case kCondVc: res = kArmCondVc; break;
255    case kCondHi: res = kArmCondHi; break;
256    case kCondLs: res = kArmCondLs; break;
257    case kCondGe: res = kArmCondGe; break;
258    case kCondLt: res = kArmCondLt; break;
259    case kCondGt: res = kArmCondGt; break;
260    case kCondLe: res = kArmCondLe; break;
261    case kCondAl: res = kArmCondAl; break;
262    case kCondNv: res = kArmCondNv; break;
263    default:
264      LOG(FATAL) << "Bad condition code " << ccode;
265      res = static_cast<ArmConditionCode>(0);  // Quiet gcc
266  }
267  return res;
268}
269
270static const char* core_reg_names[16] = {
271  "r0",
272  "r1",
273  "r2",
274  "r3",
275  "r4",
276  "r5",
277  "r6",
278  "r7",
279  "r8",
280  "rSELF",
281  "r10",
282  "r11",
283  "r12",
284  "sp",
285  "lr",
286  "pc",
287};
288
289
290static const char* shift_names[4] = {
291  "lsl",
292  "lsr",
293  "asr",
294  "ror"};
295
296/* Decode and print a ARM register name */
297static char* DecodeRegList(int opcode, int vector, char* buf, size_t buf_size) {
298  int i;
299  bool printed = false;
300  buf[0] = 0;
301  for (i = 0; i < 16; i++, vector >>= 1) {
302    if (vector & 0x1) {
303      int reg_id = i;
304      if (opcode == kThumbPush && i == 8) {
305        reg_id = rs_rARM_LR.GetRegNum();
306      } else if (opcode == kThumbPop && i == 8) {
307        reg_id = rs_rARM_PC.GetRegNum();
308      }
309      if (printed) {
310        snprintf(buf + strlen(buf), buf_size - strlen(buf), ", r%d", reg_id);
311      } else {
312        printed = true;
313        snprintf(buf, buf_size, "r%d", reg_id);
314      }
315    }
316  }
317  return buf;
318}
319
320static char*  DecodeFPCSRegList(int count, int base, char* buf, size_t buf_size) {
321  snprintf(buf, buf_size, "s%d", base);
322  for (int i = 1; i < count; i++) {
323    snprintf(buf + strlen(buf), buf_size - strlen(buf), ", s%d", base + i);
324  }
325  return buf;
326}
327
328static int32_t ExpandImmediate(int value) {
329  int32_t mode = (value & 0xf00) >> 8;
330  uint32_t bits = value & 0xff;
331  switch (mode) {
332    case 0:
333      return bits;
334     case 1:
335      return (bits << 16) | bits;
336     case 2:
337      return (bits << 24) | (bits << 8);
338     case 3:
339      return (bits << 24) | (bits << 16) | (bits << 8) | bits;
340    default:
341      break;
342  }
343  bits = (bits | 0x80) << 24;
344  return bits >> (((value & 0xf80) >> 7) - 8);
345}
346
347const char* cc_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
348                         "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"};
349/*
350 * Interpret a format string and build a string no longer than size
351 * See format key in Assemble.c.
352 */
353std::string ArmMir2Lir::BuildInsnString(const char* fmt, LIR* lir, unsigned char* base_addr) {
354  std::string buf;
355  int i;
356  const char* fmt_end = &fmt[strlen(fmt)];
357  char tbuf[256];
358  const char* name;
359  char nc;
360  while (fmt < fmt_end) {
361    int operand;
362    if (*fmt == '!') {
363      fmt++;
364      DCHECK_LT(fmt, fmt_end);
365      nc = *fmt++;
366      if (nc == '!') {
367        strcpy(tbuf, "!");
368      } else {
369         DCHECK_LT(fmt, fmt_end);
370         DCHECK_LT(static_cast<unsigned>(nc-'0'), 4U);
371         operand = lir->operands[nc-'0'];
372         switch (*fmt++) {
373           case 'H':
374             if (operand != 0) {
375               snprintf(tbuf, arraysize(tbuf), ", %s %d", shift_names[operand & 0x3], operand >> 2);
376             } else {
377               strcpy(tbuf, "");
378             }
379             break;
380           case 'B':
381             switch (operand) {
382               case kSY:
383                 name = "sy";
384                 break;
385               case kST:
386                 name = "st";
387                 break;
388               case kISH:
389                 name = "ish";
390                 break;
391               case kISHST:
392                 name = "ishst";
393                 break;
394               case kNSH:
395                 name = "nsh";
396                 break;
397               case kNSHST:
398                 name = "shst";
399                 break;
400               default:
401                 name = "DecodeError2";
402                 break;
403             }
404             strcpy(tbuf, name);
405             break;
406           case 'b':
407             strcpy(tbuf, "0000");
408             for (i = 3; i >= 0; i--) {
409               tbuf[i] += operand & 1;
410               operand >>= 1;
411             }
412             break;
413           case 'n':
414             operand = ~ExpandImmediate(operand);
415             snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
416             break;
417           case 'm':
418             operand = ExpandImmediate(operand);
419             snprintf(tbuf, arraysize(tbuf), "%d [%#x]", operand, operand);
420             break;
421           case 's':
422             snprintf(tbuf, arraysize(tbuf), "s%d", RegStorage::RegNum(operand));
423             break;
424           case 'S':
425             snprintf(tbuf, arraysize(tbuf), "d%d", RegStorage::RegNum(operand));
426             break;
427           case 'h':
428             snprintf(tbuf, arraysize(tbuf), "%04x", operand);
429             break;
430           case 'M':
431           case 'd':
432             snprintf(tbuf, arraysize(tbuf), "%d", operand);
433             break;
434           case 'C':
435             operand = RegStorage::RegNum(operand);
436             DCHECK_LT(operand, static_cast<int>(
437                 sizeof(core_reg_names)/sizeof(core_reg_names[0])));
438             snprintf(tbuf, arraysize(tbuf), "%s", core_reg_names[operand]);
439             break;
440           case 'E':
441             snprintf(tbuf, arraysize(tbuf), "%d", operand*4);
442             break;
443           case 'F':
444             snprintf(tbuf, arraysize(tbuf), "%d", operand*2);
445             break;
446           case 'c':
447             strcpy(tbuf, cc_names[operand]);
448             break;
449           case 't':
450             snprintf(tbuf, arraysize(tbuf), "0x%08" PRIxPTR " (L%p)",
451                 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4 + (operand << 1),
452                 lir->target);
453             break;
454           case 'u': {
455             int offset_1 = lir->operands[0];
456             int offset_2 = NEXT_LIR(lir)->operands[0];
457             uintptr_t target =
458                 (((reinterpret_cast<uintptr_t>(base_addr) + lir->offset + 4) &
459                 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
460                 0xfffffffc;
461             snprintf(tbuf, arraysize(tbuf), "%p", reinterpret_cast<void *>(target));
462             break;
463          }
464
465           /* Nothing to print for BLX_2 */
466           case 'v':
467             strcpy(tbuf, "see above");
468             break;
469           case 'R':
470             DecodeRegList(lir->opcode, operand, tbuf, arraysize(tbuf));
471             break;
472           case 'P':
473             DecodeFPCSRegList(operand, 16, tbuf, arraysize(tbuf));
474             break;
475           case 'Q':
476             DecodeFPCSRegList(operand, 0, tbuf, arraysize(tbuf));
477             break;
478           default:
479             strcpy(tbuf, "DecodeError1");
480             break;
481        }
482        buf += tbuf;
483      }
484    } else {
485       buf += *fmt++;
486    }
487  }
488  return buf;
489}
490
491void ArmMir2Lir::DumpResourceMask(LIR* arm_lir, const ResourceMask& mask, const char* prefix) {
492  char buf[256];
493  buf[0] = 0;
494
495  if (mask.Equals(kEncodeAll)) {
496    strcpy(buf, "all");
497  } else {
498    char num[8];
499    int i;
500
501    for (i = 0; i < kArmRegEnd; i++) {
502      if (mask.HasBit(i)) {
503        snprintf(num, arraysize(num), "%d ", i);
504        strcat(buf, num);
505      }
506    }
507
508    if (mask.HasBit(ResourceMask::kCCode)) {
509      strcat(buf, "cc ");
510    }
511    if (mask.HasBit(ResourceMask::kFPStatus)) {
512      strcat(buf, "fpcc ");
513    }
514
515    /* Memory bits */
516    if (arm_lir && (mask.HasBit(ResourceMask::kDalvikReg))) {
517      snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s",
518               DECODE_ALIAS_INFO_REG(arm_lir->flags.alias_info),
519               DECODE_ALIAS_INFO_WIDE(arm_lir->flags.alias_info) ? "(+1)" : "");
520    }
521    if (mask.HasBit(ResourceMask::kLiteral)) {
522      strcat(buf, "lit ");
523    }
524
525    if (mask.HasBit(ResourceMask::kHeapRef)) {
526      strcat(buf, "heap ");
527    }
528    if (mask.HasBit(ResourceMask::kMustNotAlias)) {
529      strcat(buf, "noalias ");
530    }
531  }
532  if (buf[0]) {
533    LOG(INFO) << prefix << ": " << buf;
534  }
535}
536
537bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
538  return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
539}
540
541RegisterClass ArmMir2Lir::RegClassForFieldLoadStore(OpSize size, bool is_volatile) {
542  if (UNLIKELY(is_volatile)) {
543    // On arm, atomic 64-bit load/store requires a core register pair.
544    // Smaller aligned load/store is atomic for both core and fp registers.
545    if (size == k64 || size == kDouble) {
546      return kCoreReg;
547    }
548  }
549  return RegClassBySize(size);
550}
551
552ArmMir2Lir::ArmMir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
553    : Mir2Lir(cu, mir_graph, arena) {
554  // Sanity check - make sure encoding map lines up.
555  for (int i = 0; i < kArmLast; i++) {
556    if (ArmMir2Lir::EncodingMap[i].opcode != i) {
557      LOG(FATAL) << "Encoding order for " << ArmMir2Lir::EncodingMap[i].name
558                 << " is wrong: expecting " << i << ", seeing "
559                 << static_cast<int>(ArmMir2Lir::EncodingMap[i].opcode);
560    }
561  }
562}
563
564Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
565                          ArenaAllocator* const arena) {
566  return new ArmMir2Lir(cu, mir_graph, arena);
567}
568
569void ArmMir2Lir::CompilerInitializeRegAlloc() {
570  reg_pool_ = new (arena_) RegisterPool(this, arena_, core_regs, empty_pool /* core64 */, sp_regs,
571                                        dp_regs, reserved_regs, empty_pool /* reserved64 */,
572                                        core_temps, empty_pool /* core64_temps */, sp_temps,
573                                        dp_temps);
574
575  // Target-specific adjustments.
576
577  // Alias single precision floats to appropriate half of overlapping double.
578  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
579  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
580    int sp_reg_num = info->GetReg().GetRegNum();
581    int dp_reg_num = sp_reg_num >> 1;
582    RegStorage dp_reg = RegStorage::Solo64(RegStorage::kFloatingPoint | dp_reg_num);
583    RegisterInfo* dp_reg_info = GetRegInfo(dp_reg);
584    // Double precision register's master storage should refer to itself.
585    DCHECK_EQ(dp_reg_info, dp_reg_info->Master());
586    // Redirect single precision's master storage to master.
587    info->SetMaster(dp_reg_info);
588    // Singles should show a single 32-bit mask bit, at first referring to the low half.
589    DCHECK_EQ(info->StorageMask(), RegisterInfo::kLowSingleStorageMask);
590    if (sp_reg_num & 1) {
591      // For odd singles, change to use the high word of the backing double.
592      info->SetStorageMask(RegisterInfo::kHighSingleStorageMask);
593    }
594  }
595
596#ifdef ARM_R4_SUSPEND_FLAG
597  // TODO: re-enable this when we can safely save r4 over the suspension code path.
598  bool no_suspend = NO_SUSPEND;  // || !Runtime::Current()->ExplicitSuspendChecks();
599  if (no_suspend) {
600    GetRegInfo(rs_rARM_SUSPEND)->MarkFree();
601  }
602#endif
603
604  // Don't start allocating temps at r0/s0/d0 or you may clobber return regs in early-exit methods.
605  // TODO: adjust when we roll to hard float calling convention.
606  reg_pool_->next_core_reg_ = 2;
607  reg_pool_->next_sp_reg_ = 0;
608  reg_pool_->next_dp_reg_ = 0;
609}
610
611/*
612 * TUNING: is true leaf?  Can't just use METHOD_IS_LEAF to determine as some
613 * instructions might call out to C/assembly helper functions.  Until
614 * machinery is in place, always spill lr.
615 */
616
617void ArmMir2Lir::AdjustSpillMask() {
618  core_spill_mask_ |= (1 << rs_rARM_LR.GetRegNum());
619  num_core_spills_++;
620}
621
622/*
623 * Mark a callee-save fp register as promoted.  Note that
624 * vpush/vpop uses contiguous register lists so we must
625 * include any holes in the mask.  Associate holes with
626 * Dalvik register INVALID_VREG (0xFFFFU).
627 */
628void ArmMir2Lir::MarkPreservedSingle(int v_reg, RegStorage reg) {
629  DCHECK_GE(reg.GetRegNum(), ARM_FP_CALLEE_SAVE_BASE);
630  int adjusted_reg_num = reg.GetRegNum() - ARM_FP_CALLEE_SAVE_BASE;
631  // Ensure fp_vmap_table is large enough
632  int table_size = fp_vmap_table_.size();
633  for (int i = table_size; i < (adjusted_reg_num + 1); i++) {
634    fp_vmap_table_.push_back(INVALID_VREG);
635  }
636  // Add the current mapping
637  fp_vmap_table_[adjusted_reg_num] = v_reg;
638  // Size of fp_vmap_table is high-water mark, use to set mask
639  num_fp_spills_ = fp_vmap_table_.size();
640  fp_spill_mask_ = ((1 << num_fp_spills_) - 1) << ARM_FP_CALLEE_SAVE_BASE;
641}
642
643void ArmMir2Lir::MarkPreservedDouble(int v_reg, RegStorage reg) {
644  // TEMP: perform as 2 singles.
645  int reg_num = reg.GetRegNum() << 1;
646  RegStorage lo = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num);
647  RegStorage hi = RegStorage::Solo32(RegStorage::kFloatingPoint | reg_num | 1);
648  MarkPreservedSingle(v_reg, lo);
649  MarkPreservedSingle(v_reg + 1, hi);
650}
651
652/* Clobber all regs that might be used by an external C call */
653void ArmMir2Lir::ClobberCallerSave() {
654  // TODO: rework this - it's gotten even more ugly.
655  Clobber(rs_r0);
656  Clobber(rs_r1);
657  Clobber(rs_r2);
658  Clobber(rs_r3);
659  Clobber(rs_r12);
660  Clobber(rs_r14lr);
661  Clobber(rs_fr0);
662  Clobber(rs_fr1);
663  Clobber(rs_fr2);
664  Clobber(rs_fr3);
665  Clobber(rs_fr4);
666  Clobber(rs_fr5);
667  Clobber(rs_fr6);
668  Clobber(rs_fr7);
669  Clobber(rs_fr8);
670  Clobber(rs_fr9);
671  Clobber(rs_fr10);
672  Clobber(rs_fr11);
673  Clobber(rs_fr12);
674  Clobber(rs_fr13);
675  Clobber(rs_fr14);
676  Clobber(rs_fr15);
677  Clobber(rs_dr0);
678  Clobber(rs_dr1);
679  Clobber(rs_dr2);
680  Clobber(rs_dr3);
681  Clobber(rs_dr4);
682  Clobber(rs_dr5);
683  Clobber(rs_dr6);
684  Clobber(rs_dr7);
685}
686
687RegLocation ArmMir2Lir::GetReturnWideAlt() {
688  RegLocation res = LocCReturnWide();
689  res.reg.SetLowReg(rs_r2.GetReg());
690  res.reg.SetHighReg(rs_r3.GetReg());
691  Clobber(rs_r2);
692  Clobber(rs_r3);
693  MarkInUse(rs_r2);
694  MarkInUse(rs_r3);
695  MarkWide(res.reg);
696  return res;
697}
698
699RegLocation ArmMir2Lir::GetReturnAlt() {
700  RegLocation res = LocCReturn();
701  res.reg.SetReg(rs_r1.GetReg());
702  Clobber(rs_r1);
703  MarkInUse(rs_r1);
704  return res;
705}
706
707/* To be used when explicitly managing register use */
708void ArmMir2Lir::LockCallTemps() {
709  LockTemp(rs_r0);
710  LockTemp(rs_r1);
711  LockTemp(rs_r2);
712  LockTemp(rs_r3);
713}
714
715/* To be used when explicitly managing register use */
716void ArmMir2Lir::FreeCallTemps() {
717  FreeTemp(rs_r0);
718  FreeTemp(rs_r1);
719  FreeTemp(rs_r2);
720  FreeTemp(rs_r3);
721}
722
723RegStorage ArmMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
724  LoadWordDisp(rs_rARM_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rARM_LR);
725  return rs_rARM_LR;
726}
727
728LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
729  RegStorage tmp = rs_r0;
730  Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
731  LIR* load2 = Load32Disp(tmp, 0, tmp);
732  return load2;
733}
734
735uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
736  DCHECK(!IsPseudoLirOp(opcode));
737  return ArmMir2Lir::EncodingMap[opcode].flags;
738}
739
740const char* ArmMir2Lir::GetTargetInstName(int opcode) {
741  DCHECK(!IsPseudoLirOp(opcode));
742  return ArmMir2Lir::EncodingMap[opcode].name;
743}
744
745const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
746  DCHECK(!IsPseudoLirOp(opcode));
747  return ArmMir2Lir::EncodingMap[opcode].fmt;
748}
749
750/*
751 * Somewhat messy code here.  We want to allocate a pair of contiguous
752 * physical single-precision floating point registers starting with
753 * an even numbered reg.  It is possible that the paired s_reg (s_reg+1)
754 * has already been allocated - try to fit if possible.  Fail to
755 * allocate if we can't meet the requirements for the pair of
756 * s_reg<=sX[even] & (s_reg+1)<= sX+1.
757 */
758// TODO: needs rewrite to support non-backed 64-bit float regs.
759RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
760  RegStorage res;
761  int v_reg = mir_graph_->SRegToVReg(s_reg);
762  int p_map_idx = SRegToPMap(s_reg);
763  if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
764    // Upper reg is already allocated.  Can we fit?
765    int high_reg = promotion_map_[p_map_idx+1].fp_reg;
766    if ((high_reg & 1) == 0) {
767      // High reg is even - fail.
768      return res;  // Invalid.
769    }
770    // Is the low reg of the pair free?
771    // FIXME: rework.
772    RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
773    if (p->InUse() || p->IsTemp()) {
774      // Already allocated or not preserved - fail.
775      return res;  // Invalid.
776    }
777    // OK - good to go.
778    res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
779    p->MarkInUse();
780    MarkPreservedSingle(v_reg, p->GetReg());
781  } else {
782    /*
783     * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
784     * different underlying physical registers.
785     */
786    GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
787    for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
788      if (!info->IsTemp() && !info->InUse()) {
789        res = info->GetReg();
790        info->MarkInUse();
791        MarkPreservedDouble(v_reg, info->GetReg());
792        break;
793      }
794    }
795  }
796  if (res.Valid()) {
797    RegisterInfo* info = GetRegInfo(res);
798    promotion_map_[p_map_idx].fp_location = kLocPhysReg;
799    promotion_map_[p_map_idx].fp_reg =
800        info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
801    promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
802    promotion_map_[p_map_idx+1].fp_reg =
803        info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
804  }
805  return res;
806}
807
808// Reserve a callee-save sp single register.
809RegStorage ArmMir2Lir::AllocPreservedSingle(int s_reg) {
810  RegStorage res;
811  GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
812  for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
813    if (!info->IsTemp() && !info->InUse()) {
814      res = info->GetReg();
815      int p_map_idx = SRegToPMap(s_reg);
816      int v_reg = mir_graph_->SRegToVReg(s_reg);
817      GetRegInfo(res)->MarkInUse();
818      MarkPreservedSingle(v_reg, res);
819      promotion_map_[p_map_idx].fp_location = kLocPhysReg;
820      promotion_map_[p_map_idx].fp_reg = res.GetReg();
821      break;
822    }
823  }
824  return res;
825}
826
827}  // namespace art
828