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