| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 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 |  | 
| Nicolas Geoffray | f3e2cc4 | 2014-02-18 18:37:26 +0000 | [diff] [blame] | 17 | #include <string> | 
 | 18 | #include <inttypes.h> | 
 | 19 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 20 | #include "codegen_x86.h" | 
 | 21 | #include "dex/compiler_internals.h" | 
 | 22 | #include "dex/quick/mir_to_lir-inl.h" | 
| Mark Mendell | e19c91f | 2014-02-25 08:19:08 -0800 | [diff] [blame] | 23 | #include "mirror/array.h" | 
 | 24 | #include "mirror/string.h" | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 25 | #include "x86_lir.h" | 
 | 26 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 27 | namespace art { | 
 | 28 |  | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 29 | // FIXME: restore "static" when usage uncovered | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 30 | /*static*/ int core_regs[] = { | 
 | 31 |   rAX, rCX, rDX, rBX, rX86_SP, rBP, rSI, rDI | 
 | 32 | #ifdef TARGET_REX_SUPPORT | 
 | 33 |   r8, r9, r10, r11, r12, r13, r14, 15 | 
 | 34 | #endif | 
 | 35 | }; | 
 | 36 | /*static*/ int ReservedRegs[] = {rX86_SP}; | 
 | 37 | /*static*/ int core_temps[] = {rAX, rCX, rDX, rBX}; | 
 | 38 | /*static*/ int FpRegs[] = { | 
 | 39 |   fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, | 
 | 40 | #ifdef TARGET_REX_SUPPORT | 
 | 41 |   fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15 | 
 | 42 | #endif | 
 | 43 | }; | 
 | 44 | /*static*/ int fp_temps[] = { | 
 | 45 |   fr0, fr1, fr2, fr3, fr4, fr5, fr6, fr7, | 
 | 46 | #ifdef TARGET_REX_SUPPORT | 
 | 47 |   fr8, fr9, fr10, fr11, fr12, fr13, fr14, fr15 | 
 | 48 | #endif | 
 | 49 | }; | 
 | 50 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 51 | RegLocation X86Mir2Lir::LocCReturn() { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 52 |   return x86_loc_c_return; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 53 | } | 
 | 54 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 55 | RegLocation X86Mir2Lir::LocCReturnWide() { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 56 |   return x86_loc_c_return_wide; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 57 | } | 
 | 58 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 59 | RegLocation X86Mir2Lir::LocCReturnFloat() { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 60 |   return x86_loc_c_return_float; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 61 | } | 
 | 62 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 63 | RegLocation X86Mir2Lir::LocCReturnDouble() { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 64 |   return x86_loc_c_return_double; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 65 | } | 
 | 66 |  | 
 | 67 | // Return a target-dependent special register. | 
 | 68 | int X86Mir2Lir::TargetReg(SpecialTargetRegister reg) { | 
 | 69 |   int res = INVALID_REG; | 
 | 70 |   switch (reg) { | 
 | 71 |     case kSelf: res = rX86_SELF; break; | 
 | 72 |     case kSuspend: res =  rX86_SUSPEND; break; | 
 | 73 |     case kLr: res =  rX86_LR; break; | 
 | 74 |     case kPc: res =  rX86_PC; break; | 
 | 75 |     case kSp: res =  rX86_SP; break; | 
 | 76 |     case kArg0: res = rX86_ARG0; break; | 
 | 77 |     case kArg1: res = rX86_ARG1; break; | 
 | 78 |     case kArg2: res = rX86_ARG2; break; | 
 | 79 |     case kArg3: res = rX86_ARG3; break; | 
 | 80 |     case kFArg0: res = rX86_FARG0; break; | 
 | 81 |     case kFArg1: res = rX86_FARG1; break; | 
 | 82 |     case kFArg2: res = rX86_FARG2; break; | 
 | 83 |     case kFArg3: res = rX86_FARG3; break; | 
 | 84 |     case kRet0: res = rX86_RET0; break; | 
 | 85 |     case kRet1: res = rX86_RET1; break; | 
 | 86 |     case kInvokeTgt: res = rX86_INVOKE_TGT; break; | 
| Jeff Hao | 88474b4 | 2013-10-23 16:24:40 -0700 | [diff] [blame] | 87 |     case kHiddenArg: res = rAX; break; | 
 | 88 |     case kHiddenFpArg: res = fr0; break; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 89 |     case kCount: res = rX86_COUNT; break; | 
 | 90 |   } | 
 | 91 |   return res; | 
 | 92 | } | 
 | 93 |  | 
| Razvan A Lupusoru | 3bc0174 | 2014-02-06 13:18:43 -0800 | [diff] [blame] | 94 | int X86Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) { | 
 | 95 |   // For the 32-bit internal ABI, the first 3 arguments are passed in registers. | 
 | 96 |   // TODO: This is not 64-bit compliant and depends on new internal ABI. | 
 | 97 |   switch (arg_num) { | 
 | 98 |     case 0: | 
 | 99 |       return rX86_ARG1; | 
 | 100 |     case 1: | 
 | 101 |       return rX86_ARG2; | 
 | 102 |     case 2: | 
 | 103 |       return rX86_ARG3; | 
 | 104 |     default: | 
 | 105 |       return INVALID_REG; | 
 | 106 |   } | 
 | 107 | } | 
 | 108 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 109 | // Create a double from a pair of singles. | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 110 | int X86Mir2Lir::S2d(int low_reg, int high_reg) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 111 |   return X86_S2D(low_reg, high_reg); | 
 | 112 | } | 
 | 113 |  | 
 | 114 | // Return mask to strip off fp reg flags and bias. | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 115 | uint32_t X86Mir2Lir::FpRegMask() { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 116 |   return X86_FP_REG_MASK; | 
 | 117 | } | 
 | 118 |  | 
 | 119 | // True if both regs single, both core or both double. | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 120 | bool X86Mir2Lir::SameRegType(int reg1, int reg2) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 121 |   return (X86_REGTYPE(reg1) == X86_REGTYPE(reg2)); | 
 | 122 | } | 
 | 123 |  | 
 | 124 | /* | 
 | 125 |  * Decode the register id. | 
 | 126 |  */ | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 127 | uint64_t X86Mir2Lir::GetRegMaskCommon(int reg) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 128 |   uint64_t seed; | 
 | 129 |   int shift; | 
 | 130 |   int reg_id; | 
 | 131 |  | 
 | 132 |   reg_id = reg & 0xf; | 
 | 133 |   /* Double registers in x86 are just a single FP register */ | 
 | 134 |   seed = 1; | 
 | 135 |   /* FP register starts at bit position 16 */ | 
 | 136 |   shift = X86_FPREG(reg) ? kX86FPReg0 : 0; | 
 | 137 |   /* Expand the double register id into single offset */ | 
 | 138 |   shift += reg_id; | 
 | 139 |   return (seed << shift); | 
 | 140 | } | 
 | 141 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 142 | uint64_t X86Mir2Lir::GetPCUseDefEncoding() { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 143 |   /* | 
 | 144 |    * FIXME: might make sense to use a virtual resource encoding bit for pc.  Might be | 
 | 145 |    * able to clean up some of the x86/Arm_Mips differences | 
 | 146 |    */ | 
 | 147 |   LOG(FATAL) << "Unexpected call to GetPCUseDefEncoding for x86"; | 
 | 148 |   return 0ULL; | 
 | 149 | } | 
 | 150 |  | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 151 | void X86Mir2Lir::SetupTargetResourceMasks(LIR* lir, uint64_t flags) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 152 |   DCHECK_EQ(cu_->instruction_set, kX86); | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 153 |   DCHECK(!lir->flags.use_def_invalid); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 154 |  | 
 | 155 |   // X86-specific resource map setup here. | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 156 |   if (flags & REG_USE_SP) { | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 157 |     lir->u.m.use_mask |= ENCODE_X86_REG_SP; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 158 |   } | 
 | 159 |  | 
 | 160 |   if (flags & REG_DEF_SP) { | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 161 |     lir->u.m.def_mask |= ENCODE_X86_REG_SP; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 162 |   } | 
 | 163 |  | 
 | 164 |   if (flags & REG_DEFA) { | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 165 |     SetupRegMask(&lir->u.m.def_mask, rAX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 166 |   } | 
 | 167 |  | 
 | 168 |   if (flags & REG_DEFD) { | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 169 |     SetupRegMask(&lir->u.m.def_mask, rDX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 170 |   } | 
 | 171 |   if (flags & REG_USEA) { | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 172 |     SetupRegMask(&lir->u.m.use_mask, rAX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 173 |   } | 
 | 174 |  | 
 | 175 |   if (flags & REG_USEC) { | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 176 |     SetupRegMask(&lir->u.m.use_mask, rCX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 177 |   } | 
 | 178 |  | 
 | 179 |   if (flags & REG_USED) { | 
| buzbee | b48819d | 2013-09-14 16:15:25 -0700 | [diff] [blame] | 180 |     SetupRegMask(&lir->u.m.use_mask, rDX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 181 |   } | 
| Vladimir Marko | 70b797d | 2013-12-03 15:25:24 +0000 | [diff] [blame] | 182 |  | 
 | 183 |   if (flags & REG_USEB) { | 
 | 184 |     SetupRegMask(&lir->u.m.use_mask, rBX); | 
 | 185 |   } | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 186 |  | 
 | 187 |   // Fixup hard to describe instruction: Uses rAX, rCX, rDI; sets rDI. | 
 | 188 |   if (lir->opcode == kX86RepneScasw) { | 
 | 189 |     SetupRegMask(&lir->u.m.use_mask, rAX); | 
 | 190 |     SetupRegMask(&lir->u.m.use_mask, rCX); | 
 | 191 |     SetupRegMask(&lir->u.m.use_mask, rDI); | 
 | 192 |     SetupRegMask(&lir->u.m.def_mask, rDI); | 
 | 193 |   } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 194 | } | 
 | 195 |  | 
 | 196 | /* For dumping instructions */ | 
 | 197 | static const char* x86RegName[] = { | 
 | 198 |   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", | 
 | 199 |   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" | 
 | 200 | }; | 
 | 201 |  | 
 | 202 | static const char* x86CondName[] = { | 
 | 203 |   "O", | 
 | 204 |   "NO", | 
 | 205 |   "B/NAE/C", | 
 | 206 |   "NB/AE/NC", | 
 | 207 |   "Z/EQ", | 
 | 208 |   "NZ/NE", | 
 | 209 |   "BE/NA", | 
 | 210 |   "NBE/A", | 
 | 211 |   "S", | 
 | 212 |   "NS", | 
 | 213 |   "P/PE", | 
 | 214 |   "NP/PO", | 
 | 215 |   "L/NGE", | 
 | 216 |   "NL/GE", | 
 | 217 |   "LE/NG", | 
 | 218 |   "NLE/G" | 
 | 219 | }; | 
 | 220 |  | 
 | 221 | /* | 
 | 222 |  * Interpret a format string and build a string no longer than size | 
 | 223 |  * See format key in Assemble.cc. | 
 | 224 |  */ | 
 | 225 | std::string X86Mir2Lir::BuildInsnString(const char *fmt, LIR *lir, unsigned char* base_addr) { | 
 | 226 |   std::string buf; | 
 | 227 |   size_t i = 0; | 
 | 228 |   size_t fmt_len = strlen(fmt); | 
 | 229 |   while (i < fmt_len) { | 
 | 230 |     if (fmt[i] != '!') { | 
 | 231 |       buf += fmt[i]; | 
 | 232 |       i++; | 
 | 233 |     } else { | 
 | 234 |       i++; | 
 | 235 |       DCHECK_LT(i, fmt_len); | 
 | 236 |       char operand_number_ch = fmt[i]; | 
 | 237 |       i++; | 
 | 238 |       if (operand_number_ch == '!') { | 
 | 239 |         buf += "!"; | 
 | 240 |       } else { | 
 | 241 |         int operand_number = operand_number_ch - '0'; | 
 | 242 |         DCHECK_LT(operand_number, 6);  // Expect upto 6 LIR operands. | 
 | 243 |         DCHECK_LT(i, fmt_len); | 
 | 244 |         int operand = lir->operands[operand_number]; | 
 | 245 |         switch (fmt[i]) { | 
 | 246 |           case 'c': | 
 | 247 |             DCHECK_LT(static_cast<size_t>(operand), sizeof(x86CondName)); | 
 | 248 |             buf += x86CondName[operand]; | 
 | 249 |             break; | 
 | 250 |           case 'd': | 
 | 251 |             buf += StringPrintf("%d", operand); | 
 | 252 |             break; | 
 | 253 |           case 'p': { | 
| buzbee | 0d82948 | 2013-10-11 15:24:55 -0700 | [diff] [blame] | 254 |             EmbeddedData *tab_rec = reinterpret_cast<EmbeddedData*>(UnwrapPointer(operand)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 255 |             buf += StringPrintf("0x%08x", tab_rec->offset); | 
 | 256 |             break; | 
 | 257 |           } | 
 | 258 |           case 'r': | 
 | 259 |             if (X86_FPREG(operand) || X86_DOUBLEREG(operand)) { | 
 | 260 |               int fp_reg = operand & X86_FP_REG_MASK; | 
 | 261 |               buf += StringPrintf("xmm%d", fp_reg); | 
 | 262 |             } else { | 
 | 263 |               DCHECK_LT(static_cast<size_t>(operand), sizeof(x86RegName)); | 
 | 264 |               buf += x86RegName[operand]; | 
 | 265 |             } | 
 | 266 |             break; | 
 | 267 |           case 't': | 
| Ian Rogers | 107c31e | 2014-01-23 20:55:29 -0800 | [diff] [blame] | 268 |             buf += StringPrintf("0x%08" PRIxPTR " (L%p)", | 
 | 269 |                                 reinterpret_cast<uintptr_t>(base_addr) + lir->offset + operand, | 
 | 270 |                                 lir->target); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 271 |             break; | 
 | 272 |           default: | 
 | 273 |             buf += StringPrintf("DecodeError '%c'", fmt[i]); | 
 | 274 |             break; | 
 | 275 |         } | 
 | 276 |         i++; | 
 | 277 |       } | 
 | 278 |     } | 
 | 279 |   } | 
 | 280 |   return buf; | 
 | 281 | } | 
 | 282 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 283 | void X86Mir2Lir::DumpResourceMask(LIR *x86LIR, uint64_t mask, const char *prefix) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 284 |   char buf[256]; | 
 | 285 |   buf[0] = 0; | 
 | 286 |  | 
 | 287 |   if (mask == ENCODE_ALL) { | 
 | 288 |     strcpy(buf, "all"); | 
 | 289 |   } else { | 
 | 290 |     char num[8]; | 
 | 291 |     int i; | 
 | 292 |  | 
 | 293 |     for (i = 0; i < kX86RegEnd; i++) { | 
 | 294 |       if (mask & (1ULL << i)) { | 
| Ian Rogers | 988e6ea | 2014-01-08 11:30:50 -0800 | [diff] [blame] | 295 |         snprintf(num, arraysize(num), "%d ", i); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 296 |         strcat(buf, num); | 
 | 297 |       } | 
 | 298 |     } | 
 | 299 |  | 
 | 300 |     if (mask & ENCODE_CCODE) { | 
 | 301 |       strcat(buf, "cc "); | 
 | 302 |     } | 
 | 303 |     /* Memory bits */ | 
 | 304 |     if (x86LIR && (mask & ENCODE_DALVIK_REG)) { | 
| Ian Rogers | 988e6ea | 2014-01-08 11:30:50 -0800 | [diff] [blame] | 305 |       snprintf(buf + strlen(buf), arraysize(buf) - strlen(buf), "dr%d%s", | 
 | 306 |                DECODE_ALIAS_INFO_REG(x86LIR->flags.alias_info), | 
 | 307 |                (DECODE_ALIAS_INFO_WIDE(x86LIR->flags.alias_info)) ? "(+1)" : ""); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 308 |     } | 
 | 309 |     if (mask & ENCODE_LITERAL) { | 
 | 310 |       strcat(buf, "lit "); | 
 | 311 |     } | 
 | 312 |  | 
 | 313 |     if (mask & ENCODE_HEAP_REF) { | 
 | 314 |       strcat(buf, "heap "); | 
 | 315 |     } | 
 | 316 |     if (mask & ENCODE_MUST_NOT_ALIAS) { | 
 | 317 |       strcat(buf, "noalias "); | 
 | 318 |     } | 
 | 319 |   } | 
 | 320 |   if (buf[0]) { | 
 | 321 |     LOG(INFO) << prefix << ": " <<  buf; | 
 | 322 |   } | 
 | 323 | } | 
 | 324 |  | 
 | 325 | void X86Mir2Lir::AdjustSpillMask() { | 
 | 326 |   // Adjustment for LR spilling, x86 has no LR so nothing to do here | 
 | 327 |   core_spill_mask_ |= (1 << rRET); | 
 | 328 |   num_core_spills_++; | 
 | 329 | } | 
 | 330 |  | 
 | 331 | /* | 
 | 332 |  * Mark a callee-save fp register as promoted.  Note that | 
 | 333 |  * vpush/vpop uses contiguous register lists so we must | 
 | 334 |  * include any holes in the mask.  Associate holes with | 
 | 335 |  * Dalvik register INVALID_VREG (0xFFFFU). | 
 | 336 |  */ | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 337 | void X86Mir2Lir::MarkPreservedSingle(int v_reg, int reg) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 338 |   UNIMPLEMENTED(WARNING) << "MarkPreservedSingle"; | 
 | 339 | #if 0 | 
 | 340 |   LOG(FATAL) << "No support yet for promoted FP regs"; | 
 | 341 | #endif | 
 | 342 | } | 
 | 343 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 344 | void X86Mir2Lir::FlushRegWide(int reg1, int reg2) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 345 |   RegisterInfo* info1 = GetRegInfo(reg1); | 
 | 346 |   RegisterInfo* info2 = GetRegInfo(reg2); | 
 | 347 |   DCHECK(info1 && info2 && info1->pair && info2->pair && | 
 | 348 |          (info1->partner == info2->reg) && | 
 | 349 |          (info2->partner == info1->reg)); | 
 | 350 |   if ((info1->live && info1->dirty) || (info2->live && info2->dirty)) { | 
 | 351 |     if (!(info1->is_temp && info2->is_temp)) { | 
 | 352 |       /* Should not happen.  If it does, there's a problem in eval_loc */ | 
 | 353 |       LOG(FATAL) << "Long half-temp, half-promoted"; | 
 | 354 |     } | 
 | 355 |  | 
 | 356 |     info1->dirty = false; | 
 | 357 |     info2->dirty = false; | 
 | 358 |     if (mir_graph_->SRegToVReg(info2->s_reg) < mir_graph_->SRegToVReg(info1->s_reg)) | 
 | 359 |       info1 = info2; | 
 | 360 |     int v_reg = mir_graph_->SRegToVReg(info1->s_reg); | 
 | 361 |     StoreBaseDispWide(rX86_SP, VRegOffset(v_reg), info1->reg, info1->partner); | 
 | 362 |   } | 
 | 363 | } | 
 | 364 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 365 | void X86Mir2Lir::FlushReg(int reg) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 366 |   RegisterInfo* info = GetRegInfo(reg); | 
 | 367 |   if (info->live && info->dirty) { | 
 | 368 |     info->dirty = false; | 
 | 369 |     int v_reg = mir_graph_->SRegToVReg(info->s_reg); | 
 | 370 |     StoreBaseDisp(rX86_SP, VRegOffset(v_reg), reg, kWord); | 
 | 371 |   } | 
 | 372 | } | 
 | 373 |  | 
 | 374 | /* Give access to the target-dependent FP register encoding to common code */ | 
 | 375 | bool X86Mir2Lir::IsFpReg(int reg) { | 
 | 376 |   return X86_FPREG(reg); | 
 | 377 | } | 
 | 378 |  | 
 | 379 | /* Clobber all regs that might be used by an external C call */ | 
| Vladimir Marko | 31c2aac | 2013-12-09 16:31:19 +0000 | [diff] [blame] | 380 | void X86Mir2Lir::ClobberCallerSave() { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 381 |   Clobber(rAX); | 
 | 382 |   Clobber(rCX); | 
 | 383 |   Clobber(rDX); | 
| Vladimir Marko | 31c2aac | 2013-12-09 16:31:19 +0000 | [diff] [blame] | 384 |   Clobber(rBX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 385 | } | 
 | 386 |  | 
 | 387 | RegLocation X86Mir2Lir::GetReturnWideAlt() { | 
 | 388 |   RegLocation res = LocCReturnWide(); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 389 |   CHECK(res.reg.GetReg() == rAX); | 
 | 390 |   CHECK(res.reg.GetHighReg() == rDX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 391 |   Clobber(rAX); | 
 | 392 |   Clobber(rDX); | 
 | 393 |   MarkInUse(rAX); | 
 | 394 |   MarkInUse(rDX); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 395 |   MarkPair(res.reg.GetReg(), res.reg.GetHighReg()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 396 |   return res; | 
 | 397 | } | 
 | 398 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 399 | RegLocation X86Mir2Lir::GetReturnAlt() { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 400 |   RegLocation res = LocCReturn(); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 401 |   res.reg.SetReg(rDX); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 402 |   Clobber(rDX); | 
 | 403 |   MarkInUse(rDX); | 
 | 404 |   return res; | 
 | 405 | } | 
 | 406 |  | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 407 | /* To be used when explicitly managing register use */ | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 408 | void X86Mir2Lir::LockCallTemps() { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 409 |   LockTemp(rX86_ARG0); | 
 | 410 |   LockTemp(rX86_ARG1); | 
 | 411 |   LockTemp(rX86_ARG2); | 
 | 412 |   LockTemp(rX86_ARG3); | 
 | 413 | } | 
 | 414 |  | 
 | 415 | /* To be used when explicitly managing register use */ | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 416 | void X86Mir2Lir::FreeCallTemps() { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 417 |   FreeTemp(rX86_ARG0); | 
 | 418 |   FreeTemp(rX86_ARG1); | 
 | 419 |   FreeTemp(rX86_ARG2); | 
 | 420 |   FreeTemp(rX86_ARG3); | 
 | 421 | } | 
 | 422 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 423 | void X86Mir2Lir::GenMemBarrier(MemBarrierKind barrier_kind) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 424 | #if ANDROID_SMP != 0 | 
 | 425 |   // TODO: optimize fences | 
 | 426 |   NewLIR0(kX86Mfence); | 
 | 427 | #endif | 
 | 428 | } | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 429 |  | 
 | 430 | // Alloc a pair of core registers, or a double. | 
 | 431 | RegStorage X86Mir2Lir::AllocTypedTempWide(bool fp_hint, int reg_class) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 432 |   int high_reg; | 
 | 433 |   int low_reg; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 434 |  | 
 | 435 |   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) { | 
 | 436 |     low_reg = AllocTempDouble(); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 437 |     high_reg = low_reg;  // only one allocated! | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 438 |     // TODO: take advantage of 64-bit notation. | 
 | 439 |     return RegStorage(RegStorage::k64BitPair, low_reg, high_reg); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 440 |   } | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 441 |   low_reg = AllocTemp(); | 
 | 442 |   high_reg = AllocTemp(); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 443 |   return RegStorage(RegStorage::k64BitPair, low_reg, high_reg); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 444 | } | 
 | 445 |  | 
 | 446 | int X86Mir2Lir::AllocTypedTemp(bool fp_hint, int reg_class) { | 
 | 447 |   if (((reg_class == kAnyReg) && fp_hint) || (reg_class == kFPReg)) { | 
 | 448 |     return AllocTempFloat(); | 
 | 449 |   } | 
 | 450 |   return AllocTemp(); | 
 | 451 | } | 
 | 452 |  | 
 | 453 | void X86Mir2Lir::CompilerInitializeRegAlloc() { | 
 | 454 |   int num_regs = sizeof(core_regs)/sizeof(*core_regs); | 
 | 455 |   int num_reserved = sizeof(ReservedRegs)/sizeof(*ReservedRegs); | 
 | 456 |   int num_temps = sizeof(core_temps)/sizeof(*core_temps); | 
 | 457 |   int num_fp_regs = sizeof(FpRegs)/sizeof(*FpRegs); | 
 | 458 |   int num_fp_temps = sizeof(fp_temps)/sizeof(*fp_temps); | 
| Mathieu Chartier | f6c4b3b | 2013-08-24 16:11:37 -0700 | [diff] [blame] | 459 |   reg_pool_ = static_cast<RegisterPool*>(arena_->Alloc(sizeof(*reg_pool_), | 
 | 460 |                                                        ArenaAllocator::kAllocRegAlloc)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 461 |   reg_pool_->num_core_regs = num_regs; | 
 | 462 |   reg_pool_->core_regs = | 
| Mathieu Chartier | f6c4b3b | 2013-08-24 16:11:37 -0700 | [diff] [blame] | 463 |       static_cast<RegisterInfo*>(arena_->Alloc(num_regs * sizeof(*reg_pool_->core_regs), | 
 | 464 |                                                ArenaAllocator::kAllocRegAlloc)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 465 |   reg_pool_->num_fp_regs = num_fp_regs; | 
 | 466 |   reg_pool_->FPRegs = | 
| Mathieu Chartier | f6c4b3b | 2013-08-24 16:11:37 -0700 | [diff] [blame] | 467 |       static_cast<RegisterInfo *>(arena_->Alloc(num_fp_regs * sizeof(*reg_pool_->FPRegs), | 
 | 468 |                                                 ArenaAllocator::kAllocRegAlloc)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 469 |   CompilerInitPool(reg_pool_->core_regs, core_regs, reg_pool_->num_core_regs); | 
 | 470 |   CompilerInitPool(reg_pool_->FPRegs, FpRegs, reg_pool_->num_fp_regs); | 
 | 471 |   // Keep special registers from being allocated | 
 | 472 |   for (int i = 0; i < num_reserved; i++) { | 
 | 473 |     MarkInUse(ReservedRegs[i]); | 
 | 474 |   } | 
 | 475 |   // Mark temp regs - all others not in use can be used for promotion | 
 | 476 |   for (int i = 0; i < num_temps; i++) { | 
 | 477 |     MarkTemp(core_temps[i]); | 
 | 478 |   } | 
 | 479 |   for (int i = 0; i < num_fp_temps; i++) { | 
 | 480 |     MarkTemp(fp_temps[i]); | 
 | 481 |   } | 
 | 482 | } | 
 | 483 |  | 
 | 484 | void X86Mir2Lir::FreeRegLocTemps(RegLocation rl_keep, | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 485 |                      RegLocation rl_free) { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 486 |   if ((rl_free.reg.GetReg() != rl_keep.reg.GetReg()) && (rl_free.reg.GetReg() != rl_keep.reg.GetHighReg()) && | 
 | 487 |       (rl_free.reg.GetHighReg() != rl_keep.reg.GetReg()) && (rl_free.reg.GetHighReg() != rl_keep.reg.GetHighReg())) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 488 |     // No overlap, free both | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 489 |     FreeTemp(rl_free.reg.GetReg()); | 
 | 490 |     FreeTemp(rl_free.reg.GetHighReg()); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 491 |   } | 
 | 492 | } | 
 | 493 |  | 
 | 494 | void X86Mir2Lir::SpillCoreRegs() { | 
 | 495 |   if (num_core_spills_ == 0) { | 
 | 496 |     return; | 
 | 497 |   } | 
 | 498 |   // Spill mask not including fake return address register | 
 | 499 |   uint32_t mask = core_spill_mask_ & ~(1 << rRET); | 
 | 500 |   int offset = frame_size_ - (4 * num_core_spills_); | 
 | 501 |   for (int reg = 0; mask; mask >>= 1, reg++) { | 
 | 502 |     if (mask & 0x1) { | 
 | 503 |       StoreWordDisp(rX86_SP, offset, reg); | 
 | 504 |       offset += 4; | 
 | 505 |     } | 
 | 506 |   } | 
 | 507 | } | 
 | 508 |  | 
 | 509 | void X86Mir2Lir::UnSpillCoreRegs() { | 
 | 510 |   if (num_core_spills_ == 0) { | 
 | 511 |     return; | 
 | 512 |   } | 
 | 513 |   // Spill mask not including fake return address register | 
 | 514 |   uint32_t mask = core_spill_mask_ & ~(1 << rRET); | 
 | 515 |   int offset = frame_size_ - (4 * num_core_spills_); | 
 | 516 |   for (int reg = 0; mask; mask >>= 1, reg++) { | 
 | 517 |     if (mask & 0x1) { | 
 | 518 |       LoadWordDisp(rX86_SP, offset, reg); | 
 | 519 |       offset += 4; | 
 | 520 |     } | 
 | 521 |   } | 
 | 522 | } | 
 | 523 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 524 | bool X86Mir2Lir::IsUnconditionalBranch(LIR* lir) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 525 |   return (lir->opcode == kX86Jmp8 || lir->opcode == kX86Jmp32); | 
 | 526 | } | 
 | 527 |  | 
 | 528 | X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena) | 
| Mark Mendell | 55d0eac | 2014-02-06 11:02:52 -0800 | [diff] [blame] | 529 |     : Mir2Lir(cu, mir_graph, arena), | 
 | 530 |       method_address_insns_(arena, 100, kGrowableArrayMisc), | 
 | 531 |       class_type_address_insns_(arena, 100, kGrowableArrayMisc), | 
| Mark Mendell | ae9fd93 | 2014-02-10 16:14:35 -0800 | [diff] [blame] | 532 |       call_method_insns_(arena, 100, kGrowableArrayMisc), | 
 | 533 |       stack_decrement_(nullptr), stack_increment_(nullptr) { | 
| Mark Mendell | 55d0eac | 2014-02-06 11:02:52 -0800 | [diff] [blame] | 534 |   store_method_addr_used_ = false; | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 535 |   for (int i = 0; i < kX86Last; i++) { | 
 | 536 |     if (X86Mir2Lir::EncodingMap[i].opcode != i) { | 
 | 537 |       LOG(FATAL) << "Encoding order for " << X86Mir2Lir::EncodingMap[i].name | 
 | 538 |                  << " is wrong: expecting " << i << ", seeing " | 
 | 539 |                  << static_cast<int>(X86Mir2Lir::EncodingMap[i].opcode); | 
 | 540 |     } | 
 | 541 |   } | 
 | 542 | } | 
 | 543 |  | 
 | 544 | Mir2Lir* X86CodeGenerator(CompilationUnit* const cu, MIRGraph* const mir_graph, | 
 | 545 |                           ArenaAllocator* const arena) { | 
 | 546 |   return new X86Mir2Lir(cu, mir_graph, arena); | 
 | 547 | } | 
 | 548 |  | 
 | 549 | // Not used in x86 | 
| Ian Rogers | 468532e | 2013-08-05 10:56:33 -0700 | [diff] [blame] | 550 | int X86Mir2Lir::LoadHelper(ThreadOffset offset) { | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 551 |   LOG(FATAL) << "Unexpected use of LoadHelper in x86"; | 
 | 552 |   return INVALID_REG; | 
 | 553 | } | 
 | 554 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 555 | uint64_t X86Mir2Lir::GetTargetInstFlags(int opcode) { | 
| buzbee | 409fe94 | 2013-10-11 10:49:56 -0700 | [diff] [blame] | 556 |   DCHECK(!IsPseudoLirOp(opcode)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 557 |   return X86Mir2Lir::EncodingMap[opcode].flags; | 
 | 558 | } | 
 | 559 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 560 | const char* X86Mir2Lir::GetTargetInstName(int opcode) { | 
| buzbee | 409fe94 | 2013-10-11 10:49:56 -0700 | [diff] [blame] | 561 |   DCHECK(!IsPseudoLirOp(opcode)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 562 |   return X86Mir2Lir::EncodingMap[opcode].name; | 
 | 563 | } | 
 | 564 |  | 
| Brian Carlstrom | 2ce745c | 2013-07-17 17:44:30 -0700 | [diff] [blame] | 565 | const char* X86Mir2Lir::GetTargetInstFmt(int opcode) { | 
| buzbee | 409fe94 | 2013-10-11 10:49:56 -0700 | [diff] [blame] | 566 |   DCHECK(!IsPseudoLirOp(opcode)); | 
| Brian Carlstrom | 7940e44 | 2013-07-12 13:46:57 -0700 | [diff] [blame] | 567 |   return X86Mir2Lir::EncodingMap[opcode].fmt; | 
 | 568 | } | 
 | 569 |  | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 570 | /* | 
 | 571 |  * Return an updated location record with current in-register status. | 
 | 572 |  * If the value lives in live temps, reflect that fact.  No code | 
 | 573 |  * is generated.  If the live value is part of an older pair, | 
 | 574 |  * clobber both low and high. | 
 | 575 |  */ | 
 | 576 | // TODO: Reunify with common code after 'pair mess' has been fixed | 
 | 577 | RegLocation X86Mir2Lir::UpdateLocWide(RegLocation loc) { | 
 | 578 |   DCHECK(loc.wide); | 
 | 579 |   DCHECK(CheckCorePoolSanity()); | 
 | 580 |   if (loc.location != kLocPhysReg) { | 
 | 581 |     DCHECK((loc.location == kLocDalvikFrame) || | 
 | 582 |          (loc.location == kLocCompilerTemp)); | 
 | 583 |     // Are the dalvik regs already live in physical registers? | 
 | 584 |     RegisterInfo* info_lo = AllocLive(loc.s_reg_low, kAnyReg); | 
 | 585 |  | 
 | 586 |     // Handle FP registers specially on x86. | 
 | 587 |     if (info_lo && IsFpReg(info_lo->reg)) { | 
 | 588 |       bool match = true; | 
 | 589 |  | 
 | 590 |       // We can't match a FP register with a pair of Core registers. | 
 | 591 |       match = match && (info_lo->pair == 0); | 
 | 592 |  | 
 | 593 |       if (match) { | 
 | 594 |         // We can reuse;update the register usage info. | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 595 |         loc.location = kLocPhysReg; | 
 | 596 |         loc.vec_len = kVectorLength8; | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 597 |         // TODO: use k64BitVector | 
 | 598 |         loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_lo->reg); | 
 | 599 |         DCHECK(IsFpReg(loc.reg.GetReg())); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 600 |         return loc; | 
 | 601 |       } | 
 | 602 |       // We can't easily reuse; clobber and free any overlaps. | 
 | 603 |       if (info_lo) { | 
 | 604 |         Clobber(info_lo->reg); | 
 | 605 |         FreeTemp(info_lo->reg); | 
 | 606 |         if (info_lo->pair) | 
 | 607 |           Clobber(info_lo->partner); | 
 | 608 |       } | 
 | 609 |     } else { | 
 | 610 |       RegisterInfo* info_hi = AllocLive(GetSRegHi(loc.s_reg_low), kAnyReg); | 
 | 611 |       bool match = true; | 
 | 612 |       match = match && (info_lo != NULL); | 
 | 613 |       match = match && (info_hi != NULL); | 
 | 614 |       // Are they both core or both FP? | 
 | 615 |       match = match && (IsFpReg(info_lo->reg) == IsFpReg(info_hi->reg)); | 
 | 616 |       // If a pair of floating point singles, are they properly aligned? | 
 | 617 |       if (match && IsFpReg(info_lo->reg)) { | 
 | 618 |         match &= ((info_lo->reg & 0x1) == 0); | 
 | 619 |         match &= ((info_hi->reg - info_lo->reg) == 1); | 
 | 620 |       } | 
 | 621 |       // If previously used as a pair, it is the same pair? | 
 | 622 |       if (match && (info_lo->pair || info_hi->pair)) { | 
 | 623 |         match = (info_lo->pair == info_hi->pair); | 
 | 624 |         match &= ((info_lo->reg == info_hi->partner) && | 
 | 625 |               (info_hi->reg == info_lo->partner)); | 
 | 626 |       } | 
 | 627 |       if (match) { | 
 | 628 |         // Can reuse - update the register usage info | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 629 |         loc.reg = RegStorage(RegStorage::k64BitPair, info_lo->reg, info_hi->reg); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 630 |         loc.location = kLocPhysReg; | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 631 |         MarkPair(loc.reg.GetReg(), loc.reg.GetHighReg()); | 
 | 632 |         DCHECK(!IsFpReg(loc.reg.GetReg()) || ((loc.reg.GetReg() & 0x1) == 0)); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 633 |         return loc; | 
 | 634 |       } | 
 | 635 |       // Can't easily reuse - clobber and free any overlaps | 
 | 636 |       if (info_lo) { | 
 | 637 |         Clobber(info_lo->reg); | 
 | 638 |         FreeTemp(info_lo->reg); | 
 | 639 |         if (info_lo->pair) | 
 | 640 |           Clobber(info_lo->partner); | 
 | 641 |       } | 
 | 642 |       if (info_hi) { | 
 | 643 |         Clobber(info_hi->reg); | 
 | 644 |         FreeTemp(info_hi->reg); | 
 | 645 |         if (info_hi->pair) | 
 | 646 |           Clobber(info_hi->partner); | 
 | 647 |       } | 
 | 648 |     } | 
 | 649 |   } | 
 | 650 |   return loc; | 
 | 651 | } | 
 | 652 |  | 
 | 653 | // TODO: Reunify with common code after 'pair mess' has been fixed | 
 | 654 | RegLocation X86Mir2Lir::EvalLocWide(RegLocation loc, int reg_class, bool update) { | 
 | 655 |   DCHECK(loc.wide); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 656 |   int32_t low_reg; | 
 | 657 |   int32_t high_reg; | 
 | 658 |  | 
 | 659 |   loc = UpdateLocWide(loc); | 
 | 660 |  | 
 | 661 |   /* If it is already in a register, we can assume proper form.  Is it the right reg class? */ | 
 | 662 |   if (loc.location == kLocPhysReg) { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 663 |     DCHECK_EQ(IsFpReg(loc.reg.GetReg()), loc.IsVectorScalar()); | 
 | 664 |     if (!RegClassMatches(reg_class, loc.reg.GetReg())) { | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 665 |       /* It is the wrong register class.  Reallocate and copy. */ | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 666 |       if (!IsFpReg(loc.reg.GetReg())) { | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 667 |         // We want this in a FP reg, and it is in core registers. | 
 | 668 |         DCHECK(reg_class != kCoreReg); | 
 | 669 |         // Allocate this into any FP reg, and mark it with the right size. | 
 | 670 |         low_reg = AllocTypedTemp(true, reg_class); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 671 |         OpVectorRegCopyWide(low_reg, loc.reg.GetReg(), loc.reg.GetHighReg()); | 
 | 672 |         CopyRegInfo(low_reg, loc.reg.GetReg()); | 
 | 673 |         Clobber(loc.reg.GetReg()); | 
 | 674 |         Clobber(loc.reg.GetHighReg()); | 
 | 675 |         loc.reg.SetReg(low_reg); | 
 | 676 |         loc.reg.SetHighReg(low_reg);  // Play nice with existing code. | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 677 |         loc.vec_len = kVectorLength8; | 
 | 678 |       } else { | 
 | 679 |         // The value is in a FP register, and we want it in a pair of core registers. | 
 | 680 |         DCHECK_EQ(reg_class, kCoreReg); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 681 |         DCHECK_EQ(loc.reg.GetReg(), loc.reg.GetHighReg()); | 
 | 682 |         RegStorage new_regs = AllocTypedTempWide(false, kCoreReg);  // Force to core registers. | 
 | 683 |         low_reg = new_regs.GetReg(); | 
 | 684 |         high_reg = new_regs.GetHighReg(); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 685 |         DCHECK_NE(low_reg, high_reg); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 686 |         OpRegCopyWide(low_reg, high_reg, loc.reg.GetReg(), loc.reg.GetHighReg()); | 
 | 687 |         CopyRegInfo(low_reg, loc.reg.GetReg()); | 
 | 688 |         CopyRegInfo(high_reg, loc.reg.GetHighReg()); | 
 | 689 |         Clobber(loc.reg.GetReg()); | 
 | 690 |         Clobber(loc.reg.GetHighReg()); | 
 | 691 |         loc.reg = new_regs; | 
 | 692 |         MarkPair(loc.reg.GetReg(), loc.reg.GetHighReg()); | 
 | 693 |         DCHECK(!IsFpReg(loc.reg.GetReg()) || ((loc.reg.GetReg() & 0x1) == 0)); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 694 |       } | 
 | 695 |     } | 
 | 696 |     return loc; | 
 | 697 |   } | 
 | 698 |  | 
 | 699 |   DCHECK_NE(loc.s_reg_low, INVALID_SREG); | 
| Mark Mendell | e02d48f | 2014-01-15 11:19:23 -0800 | [diff] [blame] | 700 |   DCHECK_NE(GetSRegHi(loc.s_reg_low), INVALID_SREG); | 
 | 701 |  | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 702 |   loc.reg = AllocTypedTempWide(loc.fp, reg_class); | 
| Mark Mendell | e02d48f | 2014-01-15 11:19:23 -0800 | [diff] [blame] | 703 |  | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 704 |   // FIXME: take advantage of RegStorage notation. | 
 | 705 |   if (loc.reg.GetReg() == loc.reg.GetHighReg()) { | 
 | 706 |     DCHECK(IsFpReg(loc.reg.GetReg())); | 
| Mark Mendell | e02d48f | 2014-01-15 11:19:23 -0800 | [diff] [blame] | 707 |     loc.vec_len = kVectorLength8; | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 708 |   } else { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 709 |     MarkPair(loc.reg.GetReg(), loc.reg.GetHighReg()); | 
| Mark Mendell | e02d48f | 2014-01-15 11:19:23 -0800 | [diff] [blame] | 710 |   } | 
 | 711 |   if (update) { | 
 | 712 |     loc.location = kLocPhysReg; | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 713 |     MarkLive(loc.reg.GetReg(), loc.s_reg_low); | 
 | 714 |     if (loc.reg.GetReg() != loc.reg.GetHighReg()) { | 
 | 715 |       MarkLive(loc.reg.GetHighReg(), GetSRegHi(loc.s_reg_low)); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 716 |     } | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 717 |   } | 
 | 718 |   return loc; | 
 | 719 | } | 
 | 720 |  | 
 | 721 | // TODO: Reunify with common code after 'pair mess' has been fixed | 
 | 722 | RegLocation X86Mir2Lir::EvalLoc(RegLocation loc, int reg_class, bool update) { | 
 | 723 |   int new_reg; | 
 | 724 |  | 
 | 725 |   if (loc.wide) | 
 | 726 |     return EvalLocWide(loc, reg_class, update); | 
 | 727 |  | 
 | 728 |   loc = UpdateLoc(loc); | 
 | 729 |  | 
 | 730 |   if (loc.location == kLocPhysReg) { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 731 |     if (!RegClassMatches(reg_class, loc.reg.GetReg())) { | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 732 |       /* Wrong register class.  Realloc, copy and transfer ownership. */ | 
 | 733 |       new_reg = AllocTypedTemp(loc.fp, reg_class); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 734 |       OpRegCopy(new_reg, loc.reg.GetReg()); | 
 | 735 |       CopyRegInfo(new_reg, loc.reg.GetReg()); | 
 | 736 |       Clobber(loc.reg.GetReg()); | 
 | 737 |       loc.reg.SetReg(new_reg); | 
 | 738 |       if (IsFpReg(loc.reg.GetReg()) && reg_class != kCoreReg) | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 739 |         loc.vec_len = kVectorLength4; | 
 | 740 |     } | 
 | 741 |     return loc; | 
 | 742 |   } | 
 | 743 |  | 
 | 744 |   DCHECK_NE(loc.s_reg_low, INVALID_SREG); | 
 | 745 |  | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 746 |   loc.reg = RegStorage(RegStorage::k32BitSolo, AllocTypedTemp(loc.fp, reg_class)); | 
 | 747 |   if (IsFpReg(loc.reg.GetReg()) && reg_class != kCoreReg) | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 748 |     loc.vec_len = kVectorLength4; | 
 | 749 |  | 
 | 750 |   if (update) { | 
 | 751 |     loc.location = kLocPhysReg; | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 752 |     MarkLive(loc.reg.GetReg(), loc.s_reg_low); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 753 |   } | 
 | 754 |   return loc; | 
 | 755 | } | 
 | 756 |  | 
 | 757 | int X86Mir2Lir::AllocTempDouble() { | 
 | 758 |   // We really don't need a pair of registers. | 
 | 759 |   return AllocTempFloat(); | 
 | 760 | } | 
 | 761 |  | 
 | 762 | // TODO: Reunify with common code after 'pair mess' has been fixed | 
 | 763 | void X86Mir2Lir::ResetDefLocWide(RegLocation rl) { | 
 | 764 |   DCHECK(rl.wide); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 765 |   RegisterInfo* p_low = IsTemp(rl.reg.GetReg()); | 
 | 766 |   if (IsFpReg(rl.reg.GetReg())) { | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 767 |     // We are using only the low register. | 
 | 768 |     if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) { | 
 | 769 |       NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low); | 
 | 770 |     } | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 771 |     ResetDef(rl.reg.GetReg()); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 772 |   } else { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 773 |     RegisterInfo* p_high = IsTemp(rl.reg.GetHighReg()); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 774 |     if (p_low && !(cu_->disable_opt & (1 << kSuppressLoads))) { | 
 | 775 |       DCHECK(p_low->pair); | 
 | 776 |       NullifyRange(p_low->def_start, p_low->def_end, p_low->s_reg, rl.s_reg_low); | 
 | 777 |     } | 
 | 778 |     if (p_high && !(cu_->disable_opt & (1 << kSuppressLoads))) { | 
 | 779 |       DCHECK(p_high->pair); | 
 | 780 |     } | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 781 |     ResetDef(rl.reg.GetReg()); | 
 | 782 |     ResetDef(rl.reg.GetHighReg()); | 
| Bill Buzbee | d61ba4b | 2014-01-13 21:44:01 +0000 | [diff] [blame] | 783 |   } | 
 | 784 | } | 
 | 785 |  | 
 | 786 | void X86Mir2Lir::GenConstWide(RegLocation rl_dest, int64_t value) { | 
 | 787 |   // Can we do this directly to memory? | 
 | 788 |   rl_dest = UpdateLocWide(rl_dest); | 
 | 789 |   if ((rl_dest.location == kLocDalvikFrame) || | 
 | 790 |       (rl_dest.location == kLocCompilerTemp)) { | 
 | 791 |     int32_t val_lo = Low32Bits(value); | 
 | 792 |     int32_t val_hi = High32Bits(value); | 
 | 793 |     int rBase = TargetReg(kSp); | 
 | 794 |     int displacement = SRegOffset(rl_dest.s_reg_low); | 
 | 795 |  | 
 | 796 |     LIR * store = NewLIR3(kX86Mov32MI, rBase, displacement + LOWORD_OFFSET, val_lo); | 
 | 797 |     AnnotateDalvikRegAccess(store, (displacement + LOWORD_OFFSET) >> 2, | 
 | 798 |                               false /* is_load */, true /* is64bit */); | 
 | 799 |     store = NewLIR3(kX86Mov32MI, rBase, displacement + HIWORD_OFFSET, val_hi); | 
 | 800 |     AnnotateDalvikRegAccess(store, (displacement + HIWORD_OFFSET) >> 2, | 
 | 801 |                               false /* is_load */, true /* is64bit */); | 
 | 802 |     return; | 
 | 803 |   } | 
 | 804 |  | 
 | 805 |   // Just use the standard code to do the generation. | 
 | 806 |   Mir2Lir::GenConstWide(rl_dest, value); | 
 | 807 | } | 
| Mark Mendell | e02d48f | 2014-01-15 11:19:23 -0800 | [diff] [blame] | 808 |  | 
 | 809 | // TODO: Merge with existing RegLocation dumper in vreg_analysis.cc | 
 | 810 | void X86Mir2Lir::DumpRegLocation(RegLocation loc) { | 
 | 811 |   LOG(INFO)  << "location: " << loc.location << ',' | 
 | 812 |              << (loc.wide ? " w" : "  ") | 
 | 813 |              << (loc.defined ? " D" : "  ") | 
 | 814 |              << (loc.is_const ? " c" : "  ") | 
 | 815 |              << (loc.fp ? " F" : "  ") | 
 | 816 |              << (loc.core ? " C" : "  ") | 
 | 817 |              << (loc.ref ? " r" : "  ") | 
 | 818 |              << (loc.high_word ? " h" : "  ") | 
 | 819 |              << (loc.home ? " H" : "  ") | 
 | 820 |              << " vec_len: " << loc.vec_len | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 821 |              << ", low: " << static_cast<int>(loc.reg.GetReg()) | 
 | 822 |              << ", high: " << static_cast<int>(loc.reg.GetHighReg()) | 
| Mark Mendell | e02d48f | 2014-01-15 11:19:23 -0800 | [diff] [blame] | 823 |              << ", s_reg: " << loc.s_reg_low | 
 | 824 |              << ", orig: " << loc.orig_sreg; | 
 | 825 | } | 
 | 826 |  | 
| Mark Mendell | 67c39c4 | 2014-01-31 17:28:00 -0800 | [diff] [blame] | 827 | void X86Mir2Lir::Materialize() { | 
 | 828 |   // A good place to put the analysis before starting. | 
 | 829 |   AnalyzeMIR(); | 
 | 830 |  | 
 | 831 |   // Now continue with regular code generation. | 
 | 832 |   Mir2Lir::Materialize(); | 
 | 833 | } | 
 | 834 |  | 
| Mark Mendell | 55d0eac | 2014-02-06 11:02:52 -0800 | [diff] [blame] | 835 | void X86Mir2Lir::LoadMethodAddress(int dex_method_index, InvokeType type, | 
 | 836 |                                    SpecialTargetRegister symbolic_reg) { | 
 | 837 |   /* | 
 | 838 |    * For x86, just generate a 32 bit move immediate instruction, that will be filled | 
 | 839 |    * in at 'link time'.  For now, put a unique value based on target to ensure that | 
 | 840 |    * code deduplication works. | 
 | 841 |    */ | 
 | 842 |   const DexFile::MethodId& id = cu_->dex_file->GetMethodId(dex_method_index); | 
 | 843 |   uintptr_t ptr = reinterpret_cast<uintptr_t>(&id); | 
 | 844 |  | 
 | 845 |   // Generate the move instruction with the unique pointer and save index and type. | 
 | 846 |   LIR *move = RawLIR(current_dalvik_offset_, kX86Mov32RI, TargetReg(symbolic_reg), | 
 | 847 |                      static_cast<int>(ptr), dex_method_index, type); | 
 | 848 |   AppendLIR(move); | 
 | 849 |   method_address_insns_.Insert(move); | 
 | 850 | } | 
 | 851 |  | 
 | 852 | void X86Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) { | 
 | 853 |   /* | 
 | 854 |    * For x86, just generate a 32 bit move immediate instruction, that will be filled | 
 | 855 |    * in at 'link time'.  For now, put a unique value based on target to ensure that | 
 | 856 |    * code deduplication works. | 
 | 857 |    */ | 
 | 858 |   const DexFile::TypeId& id = cu_->dex_file->GetTypeId(type_idx); | 
 | 859 |   uintptr_t ptr = reinterpret_cast<uintptr_t>(&id); | 
 | 860 |  | 
 | 861 |   // Generate the move instruction with the unique pointer and save index and type. | 
 | 862 |   LIR *move = RawLIR(current_dalvik_offset_, kX86Mov32RI, TargetReg(symbolic_reg), | 
 | 863 |                      static_cast<int>(ptr), type_idx); | 
 | 864 |   AppendLIR(move); | 
 | 865 |   class_type_address_insns_.Insert(move); | 
 | 866 | } | 
 | 867 |  | 
 | 868 | LIR *X86Mir2Lir::CallWithLinkerFixup(int dex_method_index, InvokeType type) { | 
 | 869 |   /* | 
 | 870 |    * For x86, just generate a 32 bit call relative instruction, that will be filled | 
 | 871 |    * in at 'link time'.  For now, put a unique value based on target to ensure that | 
 | 872 |    * code deduplication works. | 
 | 873 |    */ | 
 | 874 |   const DexFile::MethodId& id = cu_->dex_file->GetMethodId(dex_method_index); | 
 | 875 |   uintptr_t ptr = reinterpret_cast<uintptr_t>(&id); | 
 | 876 |  | 
 | 877 |   // Generate the call instruction with the unique pointer and save index and type. | 
 | 878 |   LIR *call = RawLIR(current_dalvik_offset_, kX86CallI, static_cast<int>(ptr), dex_method_index, | 
 | 879 |                      type); | 
 | 880 |   AppendLIR(call); | 
 | 881 |   call_method_insns_.Insert(call); | 
 | 882 |   return call; | 
 | 883 | } | 
 | 884 |  | 
 | 885 | void X86Mir2Lir::InstallLiteralPools() { | 
 | 886 |   // These are handled differently for x86. | 
 | 887 |   DCHECK(code_literal_list_ == nullptr); | 
 | 888 |   DCHECK(method_literal_list_ == nullptr); | 
 | 889 |   DCHECK(class_literal_list_ == nullptr); | 
 | 890 |  | 
 | 891 |   // Handle the fixups for methods. | 
 | 892 |   for (uint32_t i = 0; i < method_address_insns_.Size(); i++) { | 
 | 893 |       LIR* p = method_address_insns_.Get(i); | 
 | 894 |       DCHECK_EQ(p->opcode, kX86Mov32RI); | 
 | 895 |       uint32_t target = p->operands[2]; | 
 | 896 |  | 
 | 897 |       // The offset to patch is the last 4 bytes of the instruction. | 
 | 898 |       int patch_offset = p->offset + p->flags.size - 4; | 
 | 899 |       cu_->compiler_driver->AddMethodPatch(cu_->dex_file, cu_->class_def_idx, | 
 | 900 |                                            cu_->method_idx, cu_->invoke_type, | 
 | 901 |                                            target, static_cast<InvokeType>(p->operands[3]), | 
 | 902 |                                            patch_offset); | 
 | 903 |   } | 
 | 904 |  | 
 | 905 |   // Handle the fixups for class types. | 
 | 906 |   for (uint32_t i = 0; i < class_type_address_insns_.Size(); i++) { | 
 | 907 |       LIR* p = class_type_address_insns_.Get(i); | 
 | 908 |       DCHECK_EQ(p->opcode, kX86Mov32RI); | 
 | 909 |       uint32_t target = p->operands[2]; | 
 | 910 |  | 
 | 911 |       // The offset to patch is the last 4 bytes of the instruction. | 
 | 912 |       int patch_offset = p->offset + p->flags.size - 4; | 
 | 913 |       cu_->compiler_driver->AddClassPatch(cu_->dex_file, cu_->class_def_idx, | 
 | 914 |                                           cu_->method_idx, target, patch_offset); | 
 | 915 |   } | 
 | 916 |  | 
 | 917 |   // And now the PC-relative calls to methods. | 
 | 918 |   for (uint32_t i = 0; i < call_method_insns_.Size(); i++) { | 
 | 919 |       LIR* p = call_method_insns_.Get(i); | 
 | 920 |       DCHECK_EQ(p->opcode, kX86CallI); | 
 | 921 |       uint32_t target = p->operands[1]; | 
 | 922 |  | 
 | 923 |       // The offset to patch is the last 4 bytes of the instruction. | 
 | 924 |       int patch_offset = p->offset + p->flags.size - 4; | 
 | 925 |       cu_->compiler_driver->AddRelativeCodePatch(cu_->dex_file, cu_->class_def_idx, | 
 | 926 |                                                  cu_->method_idx, cu_->invoke_type, target, | 
 | 927 |                                                  static_cast<InvokeType>(p->operands[2]), | 
 | 928 |                                                  patch_offset, -4 /* offset */); | 
 | 929 |   } | 
 | 930 |  | 
 | 931 |   // And do the normal processing. | 
 | 932 |   Mir2Lir::InstallLiteralPools(); | 
 | 933 | } | 
 | 934 |  | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 935 | /* | 
 | 936 |  * Fast string.index_of(I) & (II).  Inline check for simple case of char <= 0xffff, | 
 | 937 |  * otherwise bails to standard library code. | 
 | 938 |  */ | 
 | 939 | bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { | 
 | 940 |   ClobberCallerSave(); | 
 | 941 |   LockCallTemps();  // Using fixed registers | 
 | 942 |  | 
 | 943 |   // EAX: 16 bit character being searched. | 
 | 944 |   // ECX: count: number of words to be searched. | 
 | 945 |   // EDI: String being searched. | 
 | 946 |   // EDX: temporary during execution. | 
 | 947 |   // EBX: temporary during execution. | 
 | 948 |  | 
 | 949 |   RegLocation rl_obj = info->args[0]; | 
 | 950 |   RegLocation rl_char = info->args[1]; | 
| buzbee | a44d4f5 | 2014-03-05 11:26:39 -0800 | [diff] [blame^] | 951 |   RegLocation rl_start;  // Note: only present in III flavor or IndexOf. | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 952 |  | 
 | 953 |   uint32_t char_value = | 
 | 954 |     rl_char.is_const ? mir_graph_->ConstantValue(rl_char.orig_sreg) : 0; | 
 | 955 |  | 
 | 956 |   if (char_value > 0xFFFF) { | 
 | 957 |     // We have to punt to the real String.indexOf. | 
 | 958 |     return false; | 
 | 959 |   } | 
 | 960 |  | 
 | 961 |   // Okay, we are commited to inlining this. | 
 | 962 |   RegLocation rl_return = GetReturn(false); | 
 | 963 |   RegLocation rl_dest = InlineTarget(info); | 
 | 964 |  | 
 | 965 |   // Is the string non-NULL? | 
 | 966 |   LoadValueDirectFixed(rl_obj, rDX); | 
 | 967 |   GenNullCheck(rl_obj.s_reg_low, rDX, info->opt_flags); | 
 | 968 |  | 
 | 969 |   // Record that we have inlined & null checked the object. | 
 | 970 |   info->opt_flags |= (MIR_INLINED | MIR_IGNORE_NULL_CHECK); | 
 | 971 |  | 
 | 972 |   // Does the character fit in 16 bits? | 
 | 973 |   LIR* launch_pad = nullptr; | 
 | 974 |   if (rl_char.is_const) { | 
 | 975 |     // We need the value in EAX. | 
 | 976 |     LoadConstantNoClobber(rAX, char_value); | 
 | 977 |   } else { | 
 | 978 |     // Character is not a constant; compare at runtime. | 
 | 979 |     LoadValueDirectFixed(rl_char, rAX); | 
 | 980 |     launch_pad = RawLIR(0, kPseudoIntrinsicRetry, WrapPointer(info)); | 
 | 981 |     intrinsic_launchpads_.Insert(launch_pad); | 
 | 982 |     OpCmpImmBranch(kCondGt, rAX, 0xFFFF, launch_pad); | 
 | 983 |   } | 
 | 984 |  | 
 | 985 |   // From here down, we know that we are looking for a char that fits in 16 bits. | 
| Mark Mendell | e19c91f | 2014-02-25 08:19:08 -0800 | [diff] [blame] | 986 |   // Location of reference to data array within the String object. | 
 | 987 |   int value_offset = mirror::String::ValueOffset().Int32Value(); | 
 | 988 |   // Location of count within the String object. | 
 | 989 |   int count_offset = mirror::String::CountOffset().Int32Value(); | 
 | 990 |   // Starting offset within data array. | 
 | 991 |   int offset_offset = mirror::String::OffsetOffset().Int32Value(); | 
 | 992 |   // Start of char data with array_. | 
 | 993 |   int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value(); | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 994 |  | 
 | 995 |   // Character is in EAX. | 
 | 996 |   // Object pointer is in EDX. | 
 | 997 |  | 
 | 998 |   // We need to preserve EDI, but have no spare registers, so push it on the stack. | 
 | 999 |   // We have to remember that all stack addresses after this are offset by sizeof(EDI). | 
 | 1000 |   NewLIR1(kX86Push32R, rDI); | 
 | 1001 |  | 
 | 1002 |   // Compute the number of words to search in to rCX. | 
| Mark Mendell | e19c91f | 2014-02-25 08:19:08 -0800 | [diff] [blame] | 1003 |   LoadWordDisp(rDX, count_offset, rCX); | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1004 |   LIR *length_compare = nullptr; | 
 | 1005 |   int start_value = 0; | 
 | 1006 |   if (zero_based) { | 
 | 1007 |     // We have to handle an empty string.  Use special instruction JECXZ. | 
 | 1008 |     length_compare = NewLIR0(kX86Jecxz8); | 
 | 1009 |   } else { | 
| buzbee | a44d4f5 | 2014-03-05 11:26:39 -0800 | [diff] [blame^] | 1010 |     rl_start = info->args[2]; | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1011 |     // We have to offset by the start index. | 
 | 1012 |     if (rl_start.is_const) { | 
 | 1013 |       start_value = mir_graph_->ConstantValue(rl_start.orig_sreg); | 
 | 1014 |       start_value = std::max(start_value, 0); | 
 | 1015 |  | 
 | 1016 |       // Is the start > count? | 
 | 1017 |       length_compare = OpCmpImmBranch(kCondLe, rCX, start_value, nullptr); | 
 | 1018 |  | 
 | 1019 |       if (start_value != 0) { | 
 | 1020 |         OpRegImm(kOpSub, rCX, start_value); | 
 | 1021 |       } | 
 | 1022 |     } else { | 
 | 1023 |       // Runtime start index. | 
 | 1024 |       rl_start = UpdateLoc(rl_start); | 
 | 1025 |       if (rl_start.location == kLocPhysReg) { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 1026 |         length_compare = OpCmpBranch(kCondLe, rCX, rl_start.reg.GetReg(), nullptr); | 
 | 1027 |         OpRegReg(kOpSub, rCX, rl_start.reg.GetReg()); | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1028 |       } else { | 
 | 1029 |         // Compare to memory to avoid a register load.  Handle pushed EDI. | 
 | 1030 |         int displacement = SRegOffset(rl_start.s_reg_low) + sizeof(uint32_t); | 
 | 1031 |         OpRegMem(kOpCmp, rDX, rX86_SP, displacement); | 
 | 1032 |         length_compare = NewLIR2(kX86Jcc8, 0, kX86CondLe); | 
 | 1033 |         OpRegMem(kOpSub, rCX, rX86_SP, displacement); | 
 | 1034 |       } | 
 | 1035 |     } | 
 | 1036 |   } | 
 | 1037 |   DCHECK(length_compare != nullptr); | 
 | 1038 |  | 
 | 1039 |   // ECX now contains the count in words to be searched. | 
 | 1040 |  | 
 | 1041 |   // Load the address of the string into EBX. | 
| Mark Mendell | e19c91f | 2014-02-25 08:19:08 -0800 | [diff] [blame] | 1042 |   // The string starts at VALUE(String) + 2 * OFFSET(String) + DATA_OFFSET. | 
 | 1043 |   LoadWordDisp(rDX, value_offset, rDI); | 
 | 1044 |   LoadWordDisp(rDX, offset_offset, rBX); | 
 | 1045 |   OpLea(rBX, rDI, rBX, 1, data_offset); | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1046 |  | 
 | 1047 |   // Now compute into EDI where the search will start. | 
 | 1048 |   if (zero_based || rl_start.is_const) { | 
 | 1049 |     if (start_value == 0) { | 
 | 1050 |       OpRegCopy(rDI, rBX); | 
 | 1051 |     } else { | 
 | 1052 |       NewLIR3(kX86Lea32RM, rDI, rBX, 2 * start_value); | 
 | 1053 |     } | 
 | 1054 |   } else { | 
 | 1055 |     if (rl_start.location == kLocPhysReg) { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 1056 |       if (rl_start.reg.GetReg() == rDI) { | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1057 |         // We have a slight problem here.  We are already using RDI! | 
 | 1058 |         // Grab the value from the stack. | 
 | 1059 |         LoadWordDisp(rX86_SP, 0, rDX); | 
 | 1060 |         OpLea(rDI, rBX, rDX, 1, 0); | 
 | 1061 |       } else { | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 1062 |         OpLea(rDI, rBX, rl_start.reg.GetReg(), 1, 0); | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1063 |       } | 
 | 1064 |     } else { | 
 | 1065 |       OpRegCopy(rDI, rBX); | 
 | 1066 |       // Load the start index from stack, remembering that we pushed EDI. | 
 | 1067 |       int displacement = SRegOffset(rl_start.s_reg_low) + sizeof(uint32_t); | 
 | 1068 |       LoadWordDisp(rX86_SP, displacement, rDX); | 
 | 1069 |       OpLea(rDI, rBX, rDX, 1, 0); | 
 | 1070 |     } | 
 | 1071 |   } | 
 | 1072 |  | 
 | 1073 |   // EDI now contains the start of the string to be searched. | 
 | 1074 |   // We are all prepared to do the search for the character. | 
 | 1075 |   NewLIR0(kX86RepneScasw); | 
 | 1076 |  | 
 | 1077 |   // Did we find a match? | 
 | 1078 |   LIR* failed_branch = OpCondBranch(kCondNe, nullptr); | 
 | 1079 |  | 
 | 1080 |   // yes, we matched.  Compute the index of the result. | 
 | 1081 |   // index = ((curr_ptr - orig_ptr) / 2) - 1. | 
 | 1082 |   OpRegReg(kOpSub, rDI, rBX); | 
 | 1083 |   OpRegImm(kOpAsr, rDI, 1); | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 1084 |   NewLIR3(kX86Lea32RM, rl_return.reg.GetReg(), rDI, -1); | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1085 |   LIR *all_done = NewLIR1(kX86Jmp8, 0); | 
 | 1086 |  | 
 | 1087 |   // Failed to match; return -1. | 
 | 1088 |   LIR *not_found = NewLIR0(kPseudoTargetLabel); | 
 | 1089 |   length_compare->target = not_found; | 
 | 1090 |   failed_branch->target = not_found; | 
| Bill Buzbee | 00e1ec6 | 2014-02-27 23:44:13 +0000 | [diff] [blame] | 1091 |   LoadConstantNoClobber(rl_return.reg.GetReg(), -1); | 
| Mark Mendell | 4028a6c | 2014-02-19 20:06:20 -0800 | [diff] [blame] | 1092 |  | 
 | 1093 |   // And join up at the end. | 
 | 1094 |   all_done->target = NewLIR0(kPseudoTargetLabel); | 
 | 1095 |   // Restore EDI from the stack. | 
 | 1096 |   NewLIR1(kX86Pop32R, rDI); | 
 | 1097 |  | 
 | 1098 |   // Out of line code returns here. | 
 | 1099 |   if (launch_pad != nullptr) { | 
 | 1100 |     LIR *return_point = NewLIR0(kPseudoTargetLabel); | 
 | 1101 |     launch_pad->operands[2] = WrapPointer(return_point); | 
 | 1102 |   } | 
 | 1103 |  | 
 | 1104 |   StoreValue(rl_dest, rl_return); | 
 | 1105 |   return true; | 
 | 1106 | } | 
 | 1107 |  | 
| Mark Mendell | ae9fd93 | 2014-02-10 16:14:35 -0800 | [diff] [blame] | 1108 | /* | 
 | 1109 |  * @brief Enter a 32 bit quantity into the FDE buffer | 
 | 1110 |  * @param buf FDE buffer. | 
 | 1111 |  * @param data Data value. | 
 | 1112 |  */ | 
 | 1113 | static void PushWord(std::vector<uint8_t>&buf, int data) { | 
 | 1114 |   buf.push_back(data & 0xff); | 
 | 1115 |   buf.push_back((data >> 8) & 0xff); | 
 | 1116 |   buf.push_back((data >> 16) & 0xff); | 
 | 1117 |   buf.push_back((data >> 24) & 0xff); | 
 | 1118 | } | 
 | 1119 |  | 
 | 1120 | /* | 
 | 1121 |  * @brief Enter an 'advance LOC' into the FDE buffer | 
 | 1122 |  * @param buf FDE buffer. | 
 | 1123 |  * @param increment Amount by which to increase the current location. | 
 | 1124 |  */ | 
 | 1125 | static void AdvanceLoc(std::vector<uint8_t>&buf, uint32_t increment) { | 
 | 1126 |   if (increment < 64) { | 
 | 1127 |     // Encoding in opcode. | 
 | 1128 |     buf.push_back(0x1 << 6 | increment); | 
 | 1129 |   } else if (increment < 256) { | 
 | 1130 |     // Single byte delta. | 
 | 1131 |     buf.push_back(0x02); | 
 | 1132 |     buf.push_back(increment); | 
 | 1133 |   } else if (increment < 256 * 256) { | 
 | 1134 |     // Two byte delta. | 
 | 1135 |     buf.push_back(0x03); | 
 | 1136 |     buf.push_back(increment & 0xff); | 
 | 1137 |     buf.push_back((increment >> 8) & 0xff); | 
 | 1138 |   } else { | 
 | 1139 |     // Four byte delta. | 
 | 1140 |     buf.push_back(0x04); | 
 | 1141 |     PushWord(buf, increment); | 
 | 1142 |   } | 
 | 1143 | } | 
 | 1144 |  | 
 | 1145 |  | 
 | 1146 | std::vector<uint8_t>* X86CFIInitialization() { | 
 | 1147 |   return X86Mir2Lir::ReturnCommonCallFrameInformation(); | 
 | 1148 | } | 
 | 1149 |  | 
 | 1150 | std::vector<uint8_t>* X86Mir2Lir::ReturnCommonCallFrameInformation() { | 
 | 1151 |   std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>; | 
 | 1152 |  | 
 | 1153 |   // Length of the CIE (except for this field). | 
 | 1154 |   PushWord(*cfi_info, 16); | 
 | 1155 |  | 
 | 1156 |   // CIE id. | 
 | 1157 |   PushWord(*cfi_info, 0xFFFFFFFFU); | 
 | 1158 |  | 
 | 1159 |   // Version: 3. | 
 | 1160 |   cfi_info->push_back(0x03); | 
 | 1161 |  | 
 | 1162 |   // Augmentation: empty string. | 
 | 1163 |   cfi_info->push_back(0x0); | 
 | 1164 |  | 
 | 1165 |   // Code alignment: 1. | 
 | 1166 |   cfi_info->push_back(0x01); | 
 | 1167 |  | 
 | 1168 |   // Data alignment: -4. | 
 | 1169 |   cfi_info->push_back(0x7C); | 
 | 1170 |  | 
 | 1171 |   // Return address register (R8). | 
 | 1172 |   cfi_info->push_back(0x08); | 
 | 1173 |  | 
 | 1174 |   // Initial return PC is 4(ESP): DW_CFA_def_cfa R4 4. | 
 | 1175 |   cfi_info->push_back(0x0C); | 
 | 1176 |   cfi_info->push_back(0x04); | 
 | 1177 |   cfi_info->push_back(0x04); | 
 | 1178 |  | 
 | 1179 |   // Return address location: 0(SP): DW_CFA_offset R8 1 (* -4);. | 
 | 1180 |   cfi_info->push_back(0x2 << 6 | 0x08); | 
 | 1181 |   cfi_info->push_back(0x01); | 
 | 1182 |  | 
 | 1183 |   // And 2 Noops to align to 4 byte boundary. | 
 | 1184 |   cfi_info->push_back(0x0); | 
 | 1185 |   cfi_info->push_back(0x0); | 
 | 1186 |  | 
 | 1187 |   DCHECK_EQ(cfi_info->size() & 3, 0U); | 
 | 1188 |   return cfi_info; | 
 | 1189 | } | 
 | 1190 |  | 
 | 1191 | static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) { | 
 | 1192 |   uint8_t buffer[12]; | 
 | 1193 |   uint8_t *ptr = EncodeUnsignedLeb128(buffer, value); | 
 | 1194 |   for (uint8_t *p = buffer; p < ptr; p++) { | 
 | 1195 |     buf.push_back(*p); | 
 | 1196 |   } | 
 | 1197 | } | 
 | 1198 |  | 
 | 1199 | std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() { | 
 | 1200 |   std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>; | 
 | 1201 |  | 
 | 1202 |   // Generate the FDE for the method. | 
 | 1203 |   DCHECK_NE(data_offset_, 0U); | 
 | 1204 |  | 
 | 1205 |   // Length (will be filled in later in this routine). | 
 | 1206 |   PushWord(*cfi_info, 0); | 
 | 1207 |  | 
 | 1208 |   // CIE_pointer (can be filled in by linker); might be left at 0 if there is only | 
 | 1209 |   // one CIE for the whole debug_frame section. | 
 | 1210 |   PushWord(*cfi_info, 0); | 
 | 1211 |  | 
 | 1212 |   // 'initial_location' (filled in by linker). | 
 | 1213 |   PushWord(*cfi_info, 0); | 
 | 1214 |  | 
 | 1215 |   // 'address_range' (number of bytes in the method). | 
 | 1216 |   PushWord(*cfi_info, data_offset_); | 
 | 1217 |  | 
 | 1218 |   // The instructions in the FDE. | 
 | 1219 |   if (stack_decrement_ != nullptr) { | 
 | 1220 |     // Advance LOC to just past the stack decrement. | 
 | 1221 |     uint32_t pc = NEXT_LIR(stack_decrement_)->offset; | 
 | 1222 |     AdvanceLoc(*cfi_info, pc); | 
 | 1223 |  | 
 | 1224 |     // Now update the offset to the call frame: DW_CFA_def_cfa_offset frame_size. | 
 | 1225 |     cfi_info->push_back(0x0e); | 
 | 1226 |     EncodeUnsignedLeb128(*cfi_info, frame_size_); | 
 | 1227 |  | 
 | 1228 |     // We continue with that stack until the epilogue. | 
 | 1229 |     if (stack_increment_ != nullptr) { | 
 | 1230 |       uint32_t new_pc = NEXT_LIR(stack_increment_)->offset; | 
 | 1231 |       AdvanceLoc(*cfi_info, new_pc - pc); | 
 | 1232 |  | 
 | 1233 |       // We probably have code snippets after the epilogue, so save the | 
 | 1234 |       // current state: DW_CFA_remember_state. | 
 | 1235 |       cfi_info->push_back(0x0a); | 
 | 1236 |  | 
 | 1237 |       // We have now popped the stack: DW_CFA_def_cfa_offset 4.  There is only the return | 
 | 1238 |       // PC on the stack now. | 
 | 1239 |       cfi_info->push_back(0x0e); | 
 | 1240 |       EncodeUnsignedLeb128(*cfi_info, 4); | 
 | 1241 |  | 
 | 1242 |       // Everything after that is the same as before the epilogue. | 
 | 1243 |       // Stack bump was followed by RET instruction. | 
 | 1244 |       LIR *post_ret_insn = NEXT_LIR(NEXT_LIR(stack_increment_)); | 
 | 1245 |       if (post_ret_insn != nullptr) { | 
 | 1246 |         pc = new_pc; | 
 | 1247 |         new_pc = post_ret_insn->offset; | 
 | 1248 |         AdvanceLoc(*cfi_info, new_pc - pc); | 
 | 1249 |         // Restore the state: DW_CFA_restore_state. | 
 | 1250 |         cfi_info->push_back(0x0b); | 
 | 1251 |       } | 
 | 1252 |     } | 
 | 1253 |   } | 
 | 1254 |  | 
 | 1255 |   // Padding to a multiple of 4 | 
 | 1256 |   while ((cfi_info->size() & 3) != 0) { | 
 | 1257 |     // DW_CFA_nop is encoded as 0. | 
 | 1258 |     cfi_info->push_back(0); | 
 | 1259 |   } | 
 | 1260 |  | 
 | 1261 |   // Set the length of the FDE inside the generated bytes. | 
 | 1262 |   uint32_t length = cfi_info->size() - 4; | 
 | 1263 |   (*cfi_info)[0] = length; | 
 | 1264 |   (*cfi_info)[1] = length >> 8; | 
 | 1265 |   (*cfi_info)[2] = length >> 16; | 
 | 1266 |   (*cfi_info)[3] = length >> 24; | 
 | 1267 |   return cfi_info; | 
 | 1268 | } | 
 | 1269 |  | 
| Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 1270 | }  // namespace art |