Home | History | Annotate | Download | only in x86
      1 /*
      2  * Copyright (C) 2012 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_x86.h"
     18 #include "dex/compiler_internals.h"
     19 #include "dex/quick/mir_to_lir-inl.h"
     20 #include "x86_lir.h"
     21 
     22 #include <string>
     23 
     24 namespace art {
     25 
     26 // FIXME: restore "static" when usage uncovered
     27 /*static*/ int core_regs[] = {
     28   rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI
     29 #ifdef TARGET_REX_SUPPORT
     30   r8, r9, r10, r11, r12, r13, r14, 15
     31 #endif
     32 };
     33 /*static*/ int ReservedRegs[] = {rX86_SP};
     34 /*static*/ int core_temps[] = {rAX, rCX, rDX, rBX};
     35 /*static*/ int FpRegs[] = {
     36   fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
     37 #ifdef TARGET_REX_SUPPORT
     38   fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
     39 #endif
     40 };
     41 /*static*/ int fp_temps[] = {
     42   fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7,
     43 #ifdef TARGET_REX_SUPPORT
     44   fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15
     45 #endif
     46 };
     47 
     48 RegLocation X86Mir2Lir::LocCReturn() {
     49   RegLocation res = X86_LOC_C_RETURN;
     50   return res;
     51 }
     52 
     53 RegLocation X86Mir2Lir::LocCReturnWide() {
     54   RegLocation res = X86_LOC_C_RETURN_WIDE;
     55   return res;
     56 }
     57 
     58 RegLocation X86Mir2Lir::LocCReturnFloat() {
     59   RegLocation res = X86_LOC_C_RETURN_FLOAT;
     60   return res;
     61 }
     62 
     63 RegLocation X86Mir2Lir::LocCReturnDouble() {
     64   RegLocation res = X86_LOC_C_RETURN_DOUBLE;
     65   return res;
     66 }
     67 
     68 // Return a target-dependent special register.
     69 int X86Mir2Lir::TargetReg(SpecialTargetRegister reg) {
     70   int res = INVALID_REG;
     71   switch (reg) {
     72     case kSelf: res = rX86_SELF; break;
     73     case kSuspend: res =  rX86_SUSPEND; break;
     74     case kLr: res =  rX86_LR; break;
     75     case kPc: res =  rX86_PC; break;
     76     case kSp: res =  rX86_SP; break;
     77     case kArg0: res = rX86_ARG0; break;
     78     case kArg1: res = rX86_ARG1; break;
     79     case kArg2: res = rX86_ARG2; break;
     80     case kArg3: res = rX86_ARG3; break;
     81     case kFArg0: res = rX86_FARG0; break;
     82     case kFArg1: res = rX86_FARG1; break;
     83     case kFArg2: res = rX86_FARG2; break;
     84     case kFArg3: res = rX86_FARG3; break;
     85     case kRet0: res = rX86_RET0; break;
     86     case kRet1: res = rX86_RET1; break;
     87     case kInvokeTgt: res = rX86_INVOKE_TGT; break;
     88     case kCount: res = rX86_COUNT; break;
     89   }
     90   return res;
     91 }
     92 
     93 // Create a double from a pair of singles.
     94 int X86Mir2Lir::S2d(int low_reg, int high_reg) {
     95   return X86_S2D(low_reg, high_reg);
     96 }
     97 
     98 // Return mask to strip off fp reg flags and bias.
     99 uint32_t X86Mir2Lir::FpRegMask() {
    100   return X86_FP_REG_MASK;
    101 }
    102 
    103 // True if both regs single, both core or both double.
    104 bool X86Mir2Lir::SameRegType(int reg1, int reg2) {
    105   return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2));
    106 }
    107 
    108 /*
    109  * Decode the register id.
    110  */
    111 uint64_t X86Mir2Lir::GetRegMaskCommon(int reg) {
    112   uint64_t seed;
    113   int shift;
    114   int reg_id;
    115 
    116   reg_id = reg & 0xf;
    117   /* Double registers in x86 are just a single FP register */
    118   seed = 1;
    119   /* FP register starts at bit position 16 */
    120   shift = X86_FPREG(reg) ? kX86FPReg0 : 0;
    121   /* Expand the double register id into single offset */
    122   shift += reg_id;
    123   return (seed << shift);
    124 }
    125 
    126 uint64_t X86Mir2Lir::GetPCUseDefEncoding() {
    127   /*
    128    * FIXME: might make sense to use a virtual resource encoding bit for pc.  Might be
    129    * able to clean up some of the x86/Arm_Mips differences
    130    */
    131   LOG(FATAL) << "Unexpected call to GetPCUseDefEncoding for x86";
    132   return 0ULL;
    133 }
    134 
    135 void X86Mir2Lir::SetupTargetResourceMasks(LIR* lir) {
    136   DCHECK_EQ(cu_->instruction_set, kX86);
    137 
    138   // X86-specific resource map setup here.
    139   uint64_t flags = X86Mir2Lir::EncodingMap[lir->opcode].flags;
    140 
    141   if (flags & REG_USE_SP) {
    142     lir->use_mask |= ENCODE_X86_REG_SP;
    143   }
    144 
    145   if (flags & REG_DEF_SP) {
    146     lir->def_mask |= ENCODE_X86_REG_SP;
    147   }
    148 
    149   if (flags & REG_DEFA) {
    150     SetupRegMask(&lir->def_mask, rAX);
    151   }
    152 
    153   if (flags & REG_DEFD) {
    154     SetupRegMask(&lir->def_mask, rDX);
    155   }
    156   if (flags & REG_USEA) {
    157     SetupRegMask(&lir->use_mask, rAX);
    158   }
    159 
    160   if (flags & REG_USEC) {
    161     SetupRegMask(&lir->use_mask, rCX);
    162   }
    163 
    164   if (flags & REG_USED) {
    165     SetupRegMask(&lir->use_mask, rDX);
    166   }
    167 }
    168 
    169 /* For dumping instructions */
    170 static const char* x86RegName[] = {
    171   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
    172   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
    173 };
    174 
    175 static const char* x86CondName[] = {
    176   "O",
    177   "NO",
    178   "B/NAE/C",
    179   "NB/AE/NC",
    180   "Z/EQ",
    181   "NZ/NE",
    182   "BE/NA",
    183   "NBE/A",
    184   "S",
    185   "NS",
    186   "P/PE",
    187   "NP/PO",
    188   "L/NGE",
    189   "NL/GE",
    190   "LE/NG",
    191   "NLE/G"
    192 };
    193 
    194 /*
    195  * Interpret a format string and build a string no longer than size
    196  * See format key in Assemble.cc.
    197  */
    198 std::string X86Mir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) {
    199   std::string buf;
    200   size_t i = 0;
    201   size_t fmt_len = strlen(fmt);
    202   while (i < fmt_len) {
    203     if (fmt[i] != '!') {
    204       buf += fmt[i];
    205       i++;
    206     } else {
    207       i++;
    208       DCHECK_LT(i, fmt_len);
    209       char operand_number_ch = fmt[i];
    210       i++;
    211       if (operand_number_ch == '!') {
    212         buf += "!";
    213       } else {
    214         int operand_number = operand_number_ch - '0';
    215         DCHECK_LT(operand_number, 6);  // Expect upto 6 LIR operands.
    216         DCHECK_LT(i, fmt_len);
    217         int operand = lir->operands[operand_number];
    218         switch (fmt[i]) {
    219           case 'c':
    220             DCHECK_LT(static_cast<size_t>(operand), sizeof(x86CondName));
    221             buf += x86CondName[operand];
    222             break;
    223           case 'd':
    224             buf += StringPrintf("%d", operand);
    225             break;
    226           case 'p': {
    227             SwitchTable *tab_rec = reinterpret_cast<SwitchTable*>(operand);
    228             buf += StringPrintf("0x%08x", tab_rec->offset);
    229             break;
    230           }
    231           case 'r':
    232             if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) {
    233               int fp_reg = operand & X86_FP_REG_MASK;
    234               buf += StringPrintf("xmm%d", fp_reg);
    235             } else {
    236               DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName));
    237               buf += x86RegName[operand];
    238             }
    239             break;
    240           case 't':
    241             buf += StringPrintf("0x%08x (L%p)",
    242                                 reinterpret_cast<uint32_t>(base_addr)
    243                                 + lir->offset + operand, lir->target);
    244             break;
    245           default:
    246             buf += StringPrintf("DecodeError '%c'", fmt[i]);
    247             break;
    248         }
    249         i++;
    250       }
    251     }
    252   }
    253   return buf;
    254 }
    255 
    256 void X86Mir2Lir::DumpResourceMask(LIR *x86LIR, uint64_t mask, const char *prefix) {
    257   char buf[256];
    258   buf[0] = 0;
    259 
    260   if (mask == ENCODE_ALL) {
    261     strcpy(buf, "all");
    262   } else {
    263     char num[8];
    264     int i;
    265 
    266     for (i = 0; i < kX86RegEnd; i++) {
    267       if (mask & (1ULL << i)) {
    268         sprintf(num, "%d ", i);
    269         strcat(buf, num);
    270       }
    271     }
    272 
    273     if (mask & ENCODE_CCODE) {
    274       strcat(buf, "cc ");
    275     }
    276     /* Memory bits */
    277     if (x86LIR && (mask & ENCODE_DALVIK_REG)) {
    278       sprintf(buf + strlen(buf), "dr%d%s", x86LIR->alias_info & 0xffff,
    279               (x86LIR->alias_info & 0x80000000) ? "(+1)" : "");
    280     }
    281     if (mask & ENCODE_LITERAL) {
    282       strcat(buf, "lit ");
    283     }
    284 
    285     if (mask & ENCODE_HEAP_REF) {
    286       strcat(buf, "heap ");
    287     }
    288     if (mask & ENCODE_MUST_NOT_ALIAS) {
    289       strcat(buf, "noalias ");
    290     }
    291   }
    292   if (buf[0]) {
    293     LOG(INFO) << prefix << ": " <<  buf;
    294   }
    295 }
    296 
    297 void X86Mir2Lir::AdjustSpillMask() {
    298   // Adjustment for LR spilling, x86 has no LR so nothing to do here
    299   core_spill_mask_ |= (1 << rRET);
    300   num_core_spills_++;
    301 }
    302 
    303 /*
    304  * Mark a callee-save fp register as promoted.  Note that
    305  * vpush/vpop uses contiguous register lists so we must
    306  * include any holes in the mask.  Associate holes with
    307  * Dalvik register INVALID_VREG (0xFFFFU).
    308  */
    309 void X86Mir2Lir::MarkPreservedSingle(int v_reg, int reg) {
    310   UNIMPLEMENTED(WARNING) << "MarkPreservedSingle";
    311 #if 0
    312   LOG(FATAL) << "No support yet for promoted FP regs";
    313 #endif
    314 }
    315 
    316 void X86Mir2Lir::FlushRegWide(int reg1, int reg2) {
    317   RegisterInfo* info1 = GetRegInfo(reg1);
    318   RegisterInfo* info2 = GetRegInfo(reg2);
    319   DCHECK(info1 && info2 && info1->pair && info2->pair &&
    320          (info1->partner == info2->reg) &&
    321          (info2->partner == info1->reg));
    322   if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) {
    323     if (!(info1->is_temp && info2->is_temp)) {
    324       /* Should not happen.  If it does, there's a problem in eval_loc */
    325       LOG(FATAL) << "Long half-temp, half-promoted";
    326     }
    327 
    328     info1->dirty = false;
    329     info2->dirty = false;
    330     if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg))
    331       info1 = info2;
    332     int v_reg = mir_graph_->SRegToVReg(info1->s_reg);
    333     StoreBaseDispWide(rX86_SP, VRegOffset(v_reg), info1->reg, info1->partner);
    334   }
    335 }
    336 
    337 void X86Mir2Lir::FlushReg(int reg) {
    338   RegisterInfo* info = GetRegInfo(reg);
    339   if (info->live && info->dirty) {
    340     info->dirty = false;
    341     int v_reg = mir_graph_->SRegToVReg(info->s_reg);
    342     StoreBaseDisp(rX86_SP, VRegOffset(v_reg), reg, kWord);
    343   }
    344 }
    345 
    346 /* Give access to the target-dependent FP register encoding to common code */
    347 bool X86Mir2Lir::IsFpReg(int reg) {
    348   return X86_FPREG(reg);
    349 }
    350 
    351 /* Clobber all regs that might be used by an external C call */
    352 void X86Mir2Lir::ClobberCalleeSave() {
    353   Clobber(rAX);
    354   Clobber(rCX);
    355   Clobber(rDX);
    356 }
    357 
    358 RegLocation X86Mir2Lir::GetReturnWideAlt() {
    359   RegLocation res = LocCReturnWide();
    360   CHECK(res.low_reg == rAX);
    361   CHECK(res.high_reg == rDX);
    362   Clobber(rAX);
    363   Clobber(rDX);
    364   MarkInUse(rAX);
    365   MarkInUse(rDX);
    366   MarkPair(res.low_reg, res.high_reg);
    367   return res;
    368 }
    369 
    370 RegLocation X86Mir2Lir::GetReturnAlt() {
    371   RegLocation res = LocCReturn();
    372   res.low_reg = rDX;
    373   Clobber(rDX);
    374   MarkInUse(rDX);
    375   return res;
    376 }
    377 
    378 X86Mir2Lir::RegisterInfo* X86Mir2Lir::GetRegInfo(int reg) {
    379   return X86_FPREG(reg) ? &reg_pool_->FPRegs[reg & X86_FP_REG_MASK]
    380                     : &reg_pool_->core_regs[reg];
    381 }
    382 
    383 /* To be used when explicitly managing register use */
    384 void X86Mir2Lir::LockCallTemps() {
    385   LockTemp(rX86_ARG0);
    386   LockTemp(rX86_ARG1);
    387   LockTemp(rX86_ARG2);
    388   LockTemp(rX86_ARG3);
    389 }
    390 
    391 /* To be used when explicitly managing register use */
    392 void X86Mir2Lir::FreeCallTemps() {
    393   FreeTemp(rX86_ARG0);
    394   FreeTemp(rX86_ARG1);
    395   FreeTemp(rX86_ARG2);
    396   FreeTemp(rX86_ARG3);
    397 }
    398 
    399 void X86Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) {
    400 #if ANDROID_SMP != 0
    401   // TODO: optimize fences
    402   NewLIR0(kX86Mfence);
    403 #endif
    404 }
    405 /*
    406  * Alloc a pair of core registers, or a double.  Low reg in low byte,
    407  * high reg in next byte.
    408  */
    409 int X86Mir2Lir::AllocTypedTempPair(bool fp_hint,
    410                           int reg_class) {
    411   int high_reg;
    412   int low_reg;
    413   int res = 0;
    414 
    415   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
    416     low_reg = AllocTempDouble();
    417     high_reg = low_reg + 1;
    418     res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
    419     return res;
    420   }
    421 
    422   low_reg = AllocTemp();
    423   high_reg = AllocTemp();
    424   res = (low_reg & 0xff) | ((high_reg & 0xff) << 8);
    425   return res;
    426 }
    427 
    428 int X86Mir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) {
    429   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) {
    430     return AllocTempFloat();
    431   }
    432   return AllocTemp();
    433 }
    434 
    435 void X86Mir2Lir::CompilerInitializeRegAlloc() {
    436   int num_regs = sizeof(core_regs)/sizeof(*core_regs);
    437   int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs);
    438   int num_temps = sizeof(core_temps)/sizeof(*core_temps);
    439   int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs);
    440   int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps);
    441   reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_),
    442                                                        ArenaAllocator::kAllocRegAlloc));
    443   reg_pool_->num_core_regs = num_regs;
    444   reg_pool_->core_regs =
    445       static_cast<RegisterInfo*>(arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs),
    446                                                ArenaAllocator::kAllocRegAlloc));
    447   reg_pool_->num_fp_regs = num_fp_regs;
    448   reg_pool_->FPRegs =
    449       static_cast<RegisterInfo *>(arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs),
    450                                                 ArenaAllocator::kAllocRegAlloc));
    451   CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs);
    452   CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs);
    453   // Keep special registers from being allocated
    454   for (int i = 0; i < num_reserved; i++) {
    455     MarkInUse(ReservedRegs[i]);
    456   }
    457   // Mark temp regs - all others not in use can be used for promotion
    458   for (int i = 0; i < num_temps; i++) {
    459     MarkTemp(core_temps[i]);
    460   }
    461   for (int i = 0; i < num_fp_temps; i++) {
    462     MarkTemp(fp_temps[i]);
    463   }
    464 }
    465 
    466 void X86Mir2Lir::FreeRegLocTemps(RegLocation rl_keep,
    467                      RegLocation rl_free) {
    468   if ((rl_free.low_reg != rl_keep.low_reg) && (rl_free.low_reg != rl_keep.high_reg) &&
    469       (rl_free.high_reg != rl_keep.low_reg) && (rl_free.high_reg != rl_keep.high_reg)) {
    470     // No overlap, free both
    471     FreeTemp(rl_free.low_reg);
    472     FreeTemp(rl_free.high_reg);
    473   }
    474 }
    475 
    476 void X86Mir2Lir::SpillCoreRegs() {
    477   if (num_core_spills_ == 0) {
    478     return;
    479   }
    480   // Spill mask not including fake return address register
    481   uint32_t mask = core_spill_mask_ & ~(1 << rRET);
    482   int offset = frame_size_ - (4 * num_core_spills_);
    483   for (int reg = 0; mask; mask >>= 1, reg++) {
    484     if (mask & 0x1) {
    485       StoreWordDisp(rX86_SP, offset, reg);
    486       offset += 4;
    487     }
    488   }
    489 }
    490 
    491 void X86Mir2Lir::UnSpillCoreRegs() {
    492   if (num_core_spills_ == 0) {
    493     return;
    494   }
    495   // Spill mask not including fake return address register
    496   uint32_t mask = core_spill_mask_ & ~(1 << rRET);
    497   int offset = frame_size_ - (4 * num_core_spills_);
    498   for (int reg = 0; mask; mask >>= 1, reg++) {
    499     if (mask & 0x1) {
    500       LoadWordDisp(rX86_SP, offset, reg);
    501       offset += 4;
    502     }
    503   }
    504 }
    505 
    506 bool X86Mir2Lir::IsUnconditionalBranch(LIR* lir) {
    507   return (lir->opcode == kX86Jmp8 || lir->opcode == kX86Jmp32);
    508 }
    509 
    510 X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena)
    511     : Mir2Lir(cu, mir_graph, arena) {
    512   for (int i = 0; i < kX86Last; i++) {
    513     if (X86Mir2Lir::EncodingMap[i].opcode != i) {
    514       LOG(FATAL) << "Encoding order for " << X86Mir2Lir::EncodingMap[i].name
    515                  << " is wrong: expecting " << i << ", seeing "
    516                  << static_cast<int>(X86Mir2Lir::EncodingMap[i].opcode);
    517     }
    518   }
    519 }
    520 
    521 Mir2Lir* X86CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph,
    522                           ArenaAllocator* const arena) {
    523   return new X86Mir2Lir(cu, mir_graph, arena);
    524 }
    525 
    526 // Not used in x86
    527 int X86Mir2Lir::LoadHelper(ThreadOffset offset) {
    528   LOG(FATAL) << "Unexpected use of LoadHelper in x86";
    529   return INVALID_REG;
    530 }
    531 
    532 uint64_t X86Mir2Lir::GetTargetInstFlags(int opcode) {
    533   return X86Mir2Lir::EncodingMap[opcode].flags;
    534 }
    535 
    536 const char* X86Mir2Lir::GetTargetInstName(int opcode) {
    537   return X86Mir2Lir::EncodingMap[opcode].name;
    538 }
    539 
    540 const char* X86Mir2Lir::GetTargetInstFmt(int opcode) {
    541   return X86Mir2Lir::EncodingMap[opcode].fmt;
    542 }
    543 
    544 }  // namespace art
    545