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 "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 
     26 namespace art {
     27 
     28 #ifdef ARM_R4_SUSPEND_FLAG
     29 static 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
     33 static 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
     37 static 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};
     42 static 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
     46 static constexpr RegStorage reserved_regs_arr[] =
     47     {rs_rARM_SUSPEND, rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
     48 static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r12};
     49 #else
     50 static constexpr RegStorage reserved_regs_arr[] =
     51     {rs_rARM_SELF, rs_rARM_SP, rs_rARM_LR, rs_rARM_PC};
     52 static constexpr RegStorage core_temps_arr[] = {rs_r0, rs_r1, rs_r2, rs_r3, rs_r4, rs_r12};
     53 #endif
     54 static 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};
     57 static constexpr RegStorage dp_temps_arr[] =
     58     {rs_dr0, rs_dr1, rs_dr2, rs_dr3, rs_dr4, rs_dr5, rs_dr6, rs_dr7};
     59 
     60 static constexpr ArrayRef<const RegStorage> empty_pool;
     61 static constexpr ArrayRef<const RegStorage> core_regs(core_regs_arr);
     62 static constexpr ArrayRef<const RegStorage> sp_regs(sp_regs_arr);
     63 static constexpr ArrayRef<const RegStorage> dp_regs(dp_regs_arr);
     64 static constexpr ArrayRef<const RegStorage> reserved_regs(reserved_regs_arr);
     65 static constexpr ArrayRef<const RegStorage> core_temps(core_temps_arr);
     66 static constexpr ArrayRef<const RegStorage> sp_temps(sp_temps_arr);
     67 static constexpr ArrayRef<const RegStorage> dp_temps(dp_temps_arr);
     68 
     69 RegLocation ArmMir2Lir::LocCReturn() {
     70   return arm_loc_c_return;
     71 }
     72 
     73 RegLocation ArmMir2Lir::LocCReturnRef() {
     74   return arm_loc_c_return;
     75 }
     76 
     77 RegLocation ArmMir2Lir::LocCReturnWide() {
     78   return arm_loc_c_return_wide;
     79 }
     80 
     81 RegLocation ArmMir2Lir::LocCReturnFloat() {
     82   return arm_loc_c_return_float;
     83 }
     84 
     85 RegLocation ArmMir2Lir::LocCReturnDouble() {
     86   return arm_loc_c_return_double;
     87 }
     88 
     89 // Return a target-dependent special register.
     90 RegStorage 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 
    121 RegStorage 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  */
    138 ResourceMask ArmMir2Lir::GetRegMaskCommon(const RegStorage& reg) const {
    139   return GetRegMaskArm(reg);
    140 }
    141 
    142 constexpr 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 
    149 constexpr ResourceMask ArmMir2Lir::EncodeArmRegList(int reg_list) {
    150   return ResourceMask::RawMask(static_cast<uint64_t >(reg_list), 0u);
    151 }
    152 
    153 constexpr ResourceMask ArmMir2Lir::EncodeArmRegFpcsList(int reg_list) {
    154   return ResourceMask::RawMask(static_cast<uint64_t >(reg_list) << kArmFPReg16, 0u);
    155 }
    156 
    157 ResourceMask ArmMir2Lir::GetPCUseDefEncoding() const {
    158   return ResourceMask::Bit(kArmRegPC);
    159 }
    160 
    161 // Thumb2 specific setup.  TODO: inline?:
    162 void 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 
    242 ArmConditionCode 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 
    270 static 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 
    290 static const char* shift_names[4] = {
    291   "lsl",
    292   "lsr",
    293   "asr",
    294   "ror"};
    295 
    296 /* Decode and print a ARM register name */
    297 static 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 
    320 static 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 
    328 static 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 
    347 const 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  */
    353 std::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 
    491 void 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 
    537 bool ArmMir2Lir::IsUnconditionalBranch(LIR* lir) {
    538   return ((lir->opcode == kThumbBUncond) || (lir->opcode == kThumb2BUncond));
    539 }
    540 
    541 RegisterClass 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 
    552 ArmMir2Lir::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 
    564 Mir2Lir* ArmCodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
    565                           ArenaAllocator* const arena) {
    566   return new ArmMir2Lir(cu, mir_graph, arena);
    567 }
    568 
    569 void 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 
    617 void 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  */
    628 void 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 
    643 void 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 */
    653 void 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 
    687 RegLocation 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 
    699 RegLocation 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 */
    708 void 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 */
    716 void ArmMir2Lir::FreeCallTemps() {
    717   FreeTemp(rs_r0);
    718   FreeTemp(rs_r1);
    719   FreeTemp(rs_r2);
    720   FreeTemp(rs_r3);
    721   FreeTemp(TargetReg(kHiddenArg));
    722 }
    723 
    724 RegStorage ArmMir2Lir::LoadHelper(QuickEntrypointEnum trampoline) {
    725   LoadWordDisp(rs_rARM_SELF, GetThreadOffset<4>(trampoline).Int32Value(), rs_rARM_LR);
    726   return rs_rARM_LR;
    727 }
    728 
    729 LIR* ArmMir2Lir::CheckSuspendUsingLoad() {
    730   RegStorage tmp = rs_r0;
    731   Load32Disp(rs_rARM_SELF, Thread::ThreadSuspendTriggerOffset<4>().Int32Value(), tmp);
    732   LIR* load2 = Load32Disp(tmp, 0, tmp);
    733   return load2;
    734 }
    735 
    736 uint64_t ArmMir2Lir::GetTargetInstFlags(int opcode) {
    737   DCHECK(!IsPseudoLirOp(opcode));
    738   return ArmMir2Lir::EncodingMap[opcode].flags;
    739 }
    740 
    741 const char* ArmMir2Lir::GetTargetInstName(int opcode) {
    742   DCHECK(!IsPseudoLirOp(opcode));
    743   return ArmMir2Lir::EncodingMap[opcode].name;
    744 }
    745 
    746 const char* ArmMir2Lir::GetTargetInstFmt(int opcode) {
    747   DCHECK(!IsPseudoLirOp(opcode));
    748   return ArmMir2Lir::EncodingMap[opcode].fmt;
    749 }
    750 
    751 /*
    752  * Somewhat messy code here.  We want to allocate a pair of contiguous
    753  * physical single-precision floating point registers starting with
    754  * an even numbered reg.  It is possible that the paired s_reg (s_reg+1)
    755  * has already been allocated - try to fit if possible.  Fail to
    756  * allocate if we can't meet the requirements for the pair of
    757  * s_reg<=sX[even] & (s_reg+1)<= sX+1.
    758  */
    759 // TODO: needs rewrite to support non-backed 64-bit float regs.
    760 RegStorage ArmMir2Lir::AllocPreservedDouble(int s_reg) {
    761   RegStorage res;
    762   int v_reg = mir_graph_->SRegToVReg(s_reg);
    763   int p_map_idx = SRegToPMap(s_reg);
    764   if (promotion_map_[p_map_idx+1].fp_location == kLocPhysReg) {
    765     // Upper reg is already allocated.  Can we fit?
    766     int high_reg = promotion_map_[p_map_idx+1].fp_reg;
    767     if ((high_reg & 1) == 0) {
    768       // High reg is even - fail.
    769       return res;  // Invalid.
    770     }
    771     // Is the low reg of the pair free?
    772     // FIXME: rework.
    773     RegisterInfo* p = GetRegInfo(RegStorage::FloatSolo32(high_reg - 1));
    774     if (p->InUse() || p->IsTemp()) {
    775       // Already allocated or not preserved - fail.
    776       return res;  // Invalid.
    777     }
    778     // OK - good to go.
    779     res = RegStorage::FloatSolo64(p->GetReg().GetRegNum() >> 1);
    780     p->MarkInUse();
    781     MarkPreservedSingle(v_reg, p->GetReg());
    782   } else {
    783     /*
    784      * TODO: until runtime support is in, make sure we avoid promoting the same vreg to
    785      * different underlying physical registers.
    786      */
    787     GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->dp_regs_);
    788     for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
    789       if (!info->IsTemp() && !info->InUse()) {
    790         res = info->GetReg();
    791         info->MarkInUse();
    792         MarkPreservedDouble(v_reg, info->GetReg());
    793         break;
    794       }
    795     }
    796   }
    797   if (res.Valid()) {
    798     RegisterInfo* info = GetRegInfo(res);
    799     promotion_map_[p_map_idx].fp_location = kLocPhysReg;
    800     promotion_map_[p_map_idx].fp_reg =
    801         info->FindMatchingView(RegisterInfo::kLowSingleStorageMask)->GetReg().GetReg();
    802     promotion_map_[p_map_idx+1].fp_location = kLocPhysReg;
    803     promotion_map_[p_map_idx+1].fp_reg =
    804         info->FindMatchingView(RegisterInfo::kHighSingleStorageMask)->GetReg().GetReg();
    805   }
    806   return res;
    807 }
    808 
    809 // Reserve a callee-save sp single register.
    810 RegStorage ArmMir2Lir::AllocPreservedSingle(int s_reg) {
    811   RegStorage res;
    812   GrowableArray<RegisterInfo*>::Iterator it(&reg_pool_->sp_regs_);
    813   for (RegisterInfo* info = it.Next(); info != nullptr; info = it.Next()) {
    814     if (!info->IsTemp() && !info->InUse()) {
    815       res = info->GetReg();
    816       int p_map_idx = SRegToPMap(s_reg);
    817       int v_reg = mir_graph_->SRegToVReg(s_reg);
    818       GetRegInfo(res)->MarkInUse();
    819       MarkPreservedSingle(v_reg, res);
    820       promotion_map_[p_map_idx].fp_location = kLocPhysReg;
    821       promotion_map_[p_map_idx].fp_reg = res.GetReg();
    822       break;
    823     }
    824   }
    825   return res;
    826 }
    827 
    828 }  // namespace art
    829