int_x86.cc revision a1a7074eb8256d101f7b5d256cda26d7de6ce6ce
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/* This file contains codegen for the X86 ISA */ 18 19#include "codegen_x86.h" 20#include "dex/quick/mir_to_lir-inl.h" 21#include "mirror/array.h" 22#include "x86_lir.h" 23 24namespace art { 25 26/* 27 * Perform register memory operation. 28 */ 29LIR* X86Mir2Lir::GenRegMemCheck(ConditionCode c_code, 30 int reg1, int base, int offset, ThrowKind kind) { 31 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, 32 current_dalvik_offset_, reg1, base, offset); 33 OpRegMem(kOpCmp, reg1, base, offset); 34 LIR* branch = OpCondBranch(c_code, tgt); 35 // Remember branch target - will process later 36 throw_launchpads_.Insert(tgt); 37 return branch; 38} 39 40/* 41 * Perform a compare of memory to immediate value 42 */ 43LIR* X86Mir2Lir::GenMemImmedCheck(ConditionCode c_code, 44 int base, int offset, int check_value, ThrowKind kind) { 45 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, 46 current_dalvik_offset_, base, check_value, 0); 47 NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base, offset, check_value); 48 LIR* branch = OpCondBranch(c_code, tgt); 49 // Remember branch target - will process later 50 throw_launchpads_.Insert(tgt); 51 return branch; 52} 53 54/* 55 * Compare two 64-bit values 56 * x = y return 0 57 * x < y return -1 58 * x > y return 1 59 */ 60void X86Mir2Lir::GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, 61 RegLocation rl_src2) { 62 FlushAllRegs(); 63 LockCallTemps(); // Prepare for explicit register usage 64 LoadValueDirectWideFixed(rl_src1, r0, r1); 65 LoadValueDirectWideFixed(rl_src2, r2, r3); 66 // Compute (r1:r0) = (r1:r0) - (r3:r2) 67 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2 68 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF 69 NewLIR2(kX86Set8R, r2, kX86CondL); // r2 = (r1:r0) < (r3:r2) ? 1 : 0 70 NewLIR2(kX86Movzx8RR, r2, r2); 71 OpReg(kOpNeg, r2); // r2 = -r2 72 OpRegReg(kOpOr, r0, r1); // r0 = high | low - sets ZF 73 NewLIR2(kX86Set8R, r0, kX86CondNz); // r0 = (r1:r0) != (r3:r2) ? 1 : 0 74 NewLIR2(kX86Movzx8RR, r0, r0); 75 OpRegReg(kOpOr, r0, r2); // r0 = r0 | r2 76 RegLocation rl_result = LocCReturn(); 77 StoreValue(rl_dest, rl_result); 78} 79 80X86ConditionCode X86ConditionEncoding(ConditionCode cond) { 81 switch (cond) { 82 case kCondEq: return kX86CondEq; 83 case kCondNe: return kX86CondNe; 84 case kCondCs: return kX86CondC; 85 case kCondCc: return kX86CondNc; 86 case kCondUlt: return kX86CondC; 87 case kCondUge: return kX86CondNc; 88 case kCondMi: return kX86CondS; 89 case kCondPl: return kX86CondNs; 90 case kCondVs: return kX86CondO; 91 case kCondVc: return kX86CondNo; 92 case kCondHi: return kX86CondA; 93 case kCondLs: return kX86CondBe; 94 case kCondGe: return kX86CondGe; 95 case kCondLt: return kX86CondL; 96 case kCondGt: return kX86CondG; 97 case kCondLe: return kX86CondLe; 98 case kCondAl: 99 case kCondNv: LOG(FATAL) << "Should not reach here"; 100 } 101 return kX86CondO; 102} 103 104LIR* X86Mir2Lir::OpCmpBranch(ConditionCode cond, int src1, int src2, 105 LIR* target) { 106 NewLIR2(kX86Cmp32RR, src1, src2); 107 X86ConditionCode cc = X86ConditionEncoding(cond); 108 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ , 109 cc); 110 branch->target = target; 111 return branch; 112} 113 114LIR* X86Mir2Lir::OpCmpImmBranch(ConditionCode cond, int reg, 115 int check_value, LIR* target) { 116 if ((check_value == 0) && (cond == kCondEq || cond == kCondNe)) { 117 // TODO: when check_value == 0 and reg is rCX, use the jcxz/nz opcode 118 NewLIR2(kX86Test32RR, reg, reg); 119 } else { 120 NewLIR2(IS_SIMM8(check_value) ? kX86Cmp32RI8 : kX86Cmp32RI, reg, check_value); 121 } 122 X86ConditionCode cc = X86ConditionEncoding(cond); 123 LIR* branch = NewLIR2(kX86Jcc8, 0 /* lir operand for Jcc offset */ , cc); 124 branch->target = target; 125 return branch; 126} 127 128LIR* X86Mir2Lir::OpRegCopyNoInsert(int r_dest, int r_src) { 129 if (X86_FPREG(r_dest) || X86_FPREG(r_src)) 130 return OpFpRegCopy(r_dest, r_src); 131 LIR* res = RawLIR(current_dalvik_offset_, kX86Mov32RR, 132 r_dest, r_src); 133 if (!(cu_->disable_opt & (1 << kSafeOptimizations)) && r_dest == r_src) { 134 res->flags.is_nop = true; 135 } 136 return res; 137} 138 139LIR* X86Mir2Lir::OpRegCopy(int r_dest, int r_src) { 140 LIR *res = OpRegCopyNoInsert(r_dest, r_src); 141 AppendLIR(res); 142 return res; 143} 144 145void X86Mir2Lir::OpRegCopyWide(int dest_lo, int dest_hi, 146 int src_lo, int src_hi) { 147 bool dest_fp = X86_FPREG(dest_lo) && X86_FPREG(dest_hi); 148 bool src_fp = X86_FPREG(src_lo) && X86_FPREG(src_hi); 149 assert(X86_FPREG(src_lo) == X86_FPREG(src_hi)); 150 assert(X86_FPREG(dest_lo) == X86_FPREG(dest_hi)); 151 if (dest_fp) { 152 if (src_fp) { 153 OpRegCopy(S2d(dest_lo, dest_hi), S2d(src_lo, src_hi)); 154 } else { 155 // TODO: Prevent this from happening in the code. The result is often 156 // unused or could have been loaded more easily from memory. 157 NewLIR2(kX86MovdxrRR, dest_lo, src_lo); 158 dest_hi = AllocTempDouble(); 159 NewLIR2(kX86MovdxrRR, dest_hi, src_hi); 160 NewLIR2(kX86PunpckldqRR, dest_lo, dest_hi); 161 FreeTemp(dest_hi); 162 } 163 } else { 164 if (src_fp) { 165 NewLIR2(kX86MovdrxRR, dest_lo, src_lo); 166 NewLIR2(kX86PsrlqRI, src_lo, 32); 167 NewLIR2(kX86MovdrxRR, dest_hi, src_lo); 168 } else { 169 // Handle overlap 170 if (src_hi == dest_lo && src_lo == dest_hi) { 171 // Deal with cycles. 172 int temp_reg = AllocTemp(); 173 OpRegCopy(temp_reg, dest_hi); 174 OpRegCopy(dest_hi, dest_lo); 175 OpRegCopy(dest_lo, temp_reg); 176 FreeTemp(temp_reg); 177 } else if (src_hi == dest_lo) { 178 OpRegCopy(dest_hi, src_hi); 179 OpRegCopy(dest_lo, src_lo); 180 } else { 181 OpRegCopy(dest_lo, src_lo); 182 OpRegCopy(dest_hi, src_hi); 183 } 184 } 185 } 186} 187 188void X86Mir2Lir::GenSelect(BasicBlock* bb, MIR* mir) { 189 RegLocation rl_result; 190 RegLocation rl_src = mir_graph_->GetSrc(mir, 0); 191 RegLocation rl_dest = mir_graph_->GetDest(mir); 192 rl_src = LoadValue(rl_src, kCoreReg); 193 ConditionCode ccode = mir->meta.ccode; 194 195 // The kMirOpSelect has two variants, one for constants and one for moves. 196 const bool is_constant_case = (mir->ssa_rep->num_uses == 1); 197 198 if (is_constant_case) { 199 int true_val = mir->dalvikInsn.vB; 200 int false_val = mir->dalvikInsn.vC; 201 rl_result = EvalLoc(rl_dest, kCoreReg, true); 202 203 /* 204 * For ccode == kCondEq: 205 * 206 * 1) When the true case is zero and result_reg is not same as src_reg: 207 * xor result_reg, result_reg 208 * cmp $0, src_reg 209 * mov t1, $false_case 210 * cmovnz result_reg, t1 211 * 2) When the false case is zero and result_reg is not same as src_reg: 212 * xor result_reg, result_reg 213 * cmp $0, src_reg 214 * mov t1, $true_case 215 * cmovz result_reg, t1 216 * 3) All other cases (we do compare first to set eflags): 217 * cmp $0, src_reg 218 * mov result_reg, $false_case 219 * mov t1, $true_case 220 * cmovz result_reg, t1 221 */ 222 const bool result_reg_same_as_src = (rl_src.location == kLocPhysReg && rl_src.reg.GetReg() == rl_result.reg.GetReg()); 223 const bool true_zero_case = (true_val == 0 && false_val != 0 && !result_reg_same_as_src); 224 const bool false_zero_case = (false_val == 0 && true_val != 0 && !result_reg_same_as_src); 225 const bool catch_all_case = !(true_zero_case || false_zero_case); 226 227 if (true_zero_case || false_zero_case) { 228 OpRegReg(kOpXor, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 229 } 230 231 if (true_zero_case || false_zero_case || catch_all_case) { 232 OpRegImm(kOpCmp, rl_src.reg.GetReg(), 0); 233 } 234 235 if (catch_all_case) { 236 OpRegImm(kOpMov, rl_result.reg.GetReg(), false_val); 237 } 238 239 if (true_zero_case || false_zero_case || catch_all_case) { 240 ConditionCode cc = true_zero_case ? NegateComparison(ccode) : ccode; 241 int immediateForTemp = true_zero_case ? false_val : true_val; 242 int temp1_reg = AllocTemp(); 243 OpRegImm(kOpMov, temp1_reg, immediateForTemp); 244 245 OpCondRegReg(kOpCmov, cc, rl_result.reg.GetReg(), temp1_reg); 246 247 FreeTemp(temp1_reg); 248 } 249 } else { 250 RegLocation rl_true = mir_graph_->GetSrc(mir, 1); 251 RegLocation rl_false = mir_graph_->GetSrc(mir, 2); 252 rl_true = LoadValue(rl_true, kCoreReg); 253 rl_false = LoadValue(rl_false, kCoreReg); 254 rl_result = EvalLoc(rl_dest, kCoreReg, true); 255 256 /* 257 * For ccode == kCondEq: 258 * 259 * 1) When true case is already in place: 260 * cmp $0, src_reg 261 * cmovnz result_reg, false_reg 262 * 2) When false case is already in place: 263 * cmp $0, src_reg 264 * cmovz result_reg, true_reg 265 * 3) When neither cases are in place: 266 * cmp $0, src_reg 267 * mov result_reg, false_reg 268 * cmovz result_reg, true_reg 269 */ 270 271 // kMirOpSelect is generated just for conditional cases when comparison is done with zero. 272 OpRegImm(kOpCmp, rl_src.reg.GetReg(), 0); 273 274 if (rl_result.reg.GetReg() == rl_true.reg.GetReg()) { 275 OpCondRegReg(kOpCmov, NegateComparison(ccode), rl_result.reg.GetReg(), rl_false.reg.GetReg()); 276 } else if (rl_result.reg.GetReg() == rl_false.reg.GetReg()) { 277 OpCondRegReg(kOpCmov, ccode, rl_result.reg.GetReg(), rl_true.reg.GetReg()); 278 } else { 279 OpRegCopy(rl_result.reg.GetReg(), rl_false.reg.GetReg()); 280 OpCondRegReg(kOpCmov, ccode, rl_result.reg.GetReg(), rl_true.reg.GetReg()); 281 } 282 } 283 284 StoreValue(rl_dest, rl_result); 285} 286 287void X86Mir2Lir::GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) { 288 LIR* taken = &block_label_list_[bb->taken]; 289 RegLocation rl_src1 = mir_graph_->GetSrcWide(mir, 0); 290 RegLocation rl_src2 = mir_graph_->GetSrcWide(mir, 2); 291 ConditionCode ccode = mir->meta.ccode; 292 293 if (rl_src1.is_const) { 294 std::swap(rl_src1, rl_src2); 295 ccode = FlipComparisonOrder(ccode); 296 } 297 if (rl_src2.is_const) { 298 // Do special compare/branch against simple const operand 299 int64_t val = mir_graph_->ConstantValueWide(rl_src2); 300 GenFusedLongCmpImmBranch(bb, rl_src1, val, ccode); 301 return; 302 } 303 304 FlushAllRegs(); 305 LockCallTemps(); // Prepare for explicit register usage 306 LoadValueDirectWideFixed(rl_src1, r0, r1); 307 LoadValueDirectWideFixed(rl_src2, r2, r3); 308 // Swap operands and condition code to prevent use of zero flag. 309 if (ccode == kCondLe || ccode == kCondGt) { 310 // Compute (r3:r2) = (r3:r2) - (r1:r0) 311 OpRegReg(kOpSub, r2, r0); // r2 = r2 - r0 312 OpRegReg(kOpSbc, r3, r1); // r3 = r3 - r1 - CF 313 } else { 314 // Compute (r1:r0) = (r1:r0) - (r3:r2) 315 OpRegReg(kOpSub, r0, r2); // r0 = r0 - r2 316 OpRegReg(kOpSbc, r1, r3); // r1 = r1 - r3 - CF 317 } 318 switch (ccode) { 319 case kCondEq: 320 case kCondNe: 321 OpRegReg(kOpOr, r0, r1); // r0 = r0 | r1 322 break; 323 case kCondLe: 324 ccode = kCondGe; 325 break; 326 case kCondGt: 327 ccode = kCondLt; 328 break; 329 case kCondLt: 330 case kCondGe: 331 break; 332 default: 333 LOG(FATAL) << "Unexpected ccode: " << ccode; 334 } 335 OpCondBranch(ccode, taken); 336} 337 338void X86Mir2Lir::GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, 339 int64_t val, ConditionCode ccode) { 340 int32_t val_lo = Low32Bits(val); 341 int32_t val_hi = High32Bits(val); 342 LIR* taken = &block_label_list_[bb->taken]; 343 LIR* not_taken = &block_label_list_[bb->fall_through]; 344 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 345 int32_t low_reg = rl_src1.reg.GetReg(); 346 int32_t high_reg = rl_src1.reg.GetHighReg(); 347 348 if (val == 0 && (ccode == kCondEq || ccode == kCondNe)) { 349 int t_reg = AllocTemp(); 350 OpRegRegReg(kOpOr, t_reg, low_reg, high_reg); 351 FreeTemp(t_reg); 352 OpCondBranch(ccode, taken); 353 return; 354 } 355 356 OpRegImm(kOpCmp, high_reg, val_hi); 357 switch (ccode) { 358 case kCondEq: 359 case kCondNe: 360 OpCondBranch(kCondNe, (ccode == kCondEq) ? not_taken : taken); 361 break; 362 case kCondLt: 363 OpCondBranch(kCondLt, taken); 364 OpCondBranch(kCondGt, not_taken); 365 ccode = kCondUlt; 366 break; 367 case kCondLe: 368 OpCondBranch(kCondLt, taken); 369 OpCondBranch(kCondGt, not_taken); 370 ccode = kCondLs; 371 break; 372 case kCondGt: 373 OpCondBranch(kCondGt, taken); 374 OpCondBranch(kCondLt, not_taken); 375 ccode = kCondHi; 376 break; 377 case kCondGe: 378 OpCondBranch(kCondGt, taken); 379 OpCondBranch(kCondLt, not_taken); 380 ccode = kCondUge; 381 break; 382 default: 383 LOG(FATAL) << "Unexpected ccode: " << ccode; 384 } 385 OpCmpImmBranch(ccode, low_reg, val_lo, taken); 386} 387 388void X86Mir2Lir::CalculateMagicAndShift(int divisor, int& magic, int& shift) { 389 // It does not make sense to calculate magic and shift for zero divisor. 390 DCHECK_NE(divisor, 0); 391 392 /* According to H.S.Warren's Hacker's Delight Chapter 10 and 393 * T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication. 394 * The magic number M and shift S can be calculated in the following way: 395 * Let nc be the most positive value of numerator(n) such that nc = kd - 1, 396 * where divisor(d) >=2. 397 * Let nc be the most negative value of numerator(n) such that nc = kd + 1, 398 * where divisor(d) <= -2. 399 * Thus nc can be calculated like: 400 * nc = 2^31 + 2^31 % d - 1, where d >= 2 401 * nc = -2^31 + (2^31 + 1) % d, where d >= 2. 402 * 403 * So the shift p is the smallest p satisfying 404 * 2^p > nc * (d - 2^p % d), where d >= 2 405 * 2^p > nc * (d + 2^p % d), where d <= -2. 406 * 407 * the magic number M is calcuated by 408 * M = (2^p + d - 2^p % d) / d, where d >= 2 409 * M = (2^p - d - 2^p % d) / d, where d <= -2. 410 * 411 * Notice that p is always bigger than or equal to 32, so we just return 32-p as 412 * the shift number S. 413 */ 414 415 int32_t p = 31; 416 const uint32_t two31 = 0x80000000U; 417 418 // Initialize the computations. 419 uint32_t abs_d = (divisor >= 0) ? divisor : -divisor; 420 uint32_t tmp = two31 + (static_cast<uint32_t>(divisor) >> 31); 421 uint32_t abs_nc = tmp - 1 - tmp % abs_d; 422 uint32_t quotient1 = two31 / abs_nc; 423 uint32_t remainder1 = two31 % abs_nc; 424 uint32_t quotient2 = two31 / abs_d; 425 uint32_t remainder2 = two31 % abs_d; 426 427 /* 428 * To avoid handling both positive and negative divisor, Hacker's Delight 429 * introduces a method to handle these 2 cases together to avoid duplication. 430 */ 431 uint32_t delta; 432 do { 433 p++; 434 quotient1 = 2 * quotient1; 435 remainder1 = 2 * remainder1; 436 if (remainder1 >= abs_nc) { 437 quotient1++; 438 remainder1 = remainder1 - abs_nc; 439 } 440 quotient2 = 2 * quotient2; 441 remainder2 = 2 * remainder2; 442 if (remainder2 >= abs_d) { 443 quotient2++; 444 remainder2 = remainder2 - abs_d; 445 } 446 delta = abs_d - remainder2; 447 } while (quotient1 < delta || (quotient1 == delta && remainder1 == 0)); 448 449 magic = (divisor > 0) ? (quotient2 + 1) : (-quotient2 - 1); 450 shift = p - 32; 451} 452 453RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, int reg_lo, 454 int lit, bool is_div) { 455 LOG(FATAL) << "Unexpected use of GenDivRemLit for x86"; 456 return rl_dest; 457} 458 459RegLocation X86Mir2Lir::GenDivRemLit(RegLocation rl_dest, RegLocation rl_src, 460 int imm, bool is_div) { 461 // Use a multiply (and fixup) to perform an int div/rem by a constant. 462 463 // We have to use fixed registers, so flush all the temps. 464 FlushAllRegs(); 465 LockCallTemps(); // Prepare for explicit register usage. 466 467 // Assume that the result will be in EDX. 468 RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, 469 RegStorage(RegStorage::k32BitSolo, r2), INVALID_SREG, INVALID_SREG}; 470 471 // handle div/rem by 1 special case. 472 if (imm == 1) { 473 if (is_div) { 474 // x / 1 == x. 475 StoreValue(rl_result, rl_src); 476 } else { 477 // x % 1 == 0. 478 LoadConstantNoClobber(r0, 0); 479 // For this case, return the result in EAX. 480 rl_result.reg.SetReg(r0); 481 } 482 } else if (imm == -1) { // handle 0x80000000 / -1 special case. 483 if (is_div) { 484 LIR *minint_branch = 0; 485 LoadValueDirectFixed(rl_src, r0); 486 OpRegImm(kOpCmp, r0, 0x80000000); 487 minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondEq); 488 489 // for x != MIN_INT, x / -1 == -x. 490 NewLIR1(kX86Neg32R, r0); 491 492 LIR* branch_around = NewLIR1(kX86Jmp8, 0); 493 // The target for cmp/jmp above. 494 minint_branch->target = NewLIR0(kPseudoTargetLabel); 495 // EAX already contains the right value (0x80000000), 496 branch_around->target = NewLIR0(kPseudoTargetLabel); 497 } else { 498 // x % -1 == 0. 499 LoadConstantNoClobber(r0, 0); 500 } 501 // For this case, return the result in EAX. 502 rl_result.reg.SetReg(r0); 503 } else { 504 CHECK(imm <= -2 || imm >= 2); 505 // Use H.S.Warren's Hacker's Delight Chapter 10 and 506 // T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication. 507 int magic, shift; 508 CalculateMagicAndShift(imm, magic, shift); 509 510 /* 511 * For imm >= 2, 512 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n > 0 513 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1, while n < 0. 514 * For imm <= -2, 515 * int(n/imm) = ceil(n/imm) = floor(M*n/2^S) +1 , while n > 0 516 * int(n/imm) = floor(n/imm) = floor(M*n/2^S), while n < 0. 517 * We implement this algorithm in the following way: 518 * 1. multiply magic number m and numerator n, get the higher 32bit result in EDX 519 * 2. if imm > 0 and magic < 0, add numerator to EDX 520 * if imm < 0 and magic > 0, sub numerator from EDX 521 * 3. if S !=0, SAR S bits for EDX 522 * 4. add 1 to EDX if EDX < 0 523 * 5. Thus, EDX is the quotient 524 */ 525 526 // Numerator into EAX. 527 int numerator_reg = -1; 528 if (!is_div || (imm > 0 && magic < 0) || (imm < 0 && magic > 0)) { 529 // We will need the value later. 530 if (rl_src.location == kLocPhysReg) { 531 // We can use it directly. 532 DCHECK(rl_src.reg.GetReg() != r0 && rl_src.reg.GetReg() != r2); 533 numerator_reg = rl_src.reg.GetReg(); 534 } else { 535 LoadValueDirectFixed(rl_src, r1); 536 numerator_reg = r1; 537 } 538 OpRegCopy(r0, numerator_reg); 539 } else { 540 // Only need this once. Just put it into EAX. 541 LoadValueDirectFixed(rl_src, r0); 542 } 543 544 // EDX = magic. 545 LoadConstantNoClobber(r2, magic); 546 547 // EDX:EAX = magic & dividend. 548 NewLIR1(kX86Imul32DaR, r2); 549 550 if (imm > 0 && magic < 0) { 551 // Add numerator to EDX. 552 DCHECK_NE(numerator_reg, -1); 553 NewLIR2(kX86Add32RR, r2, numerator_reg); 554 } else if (imm < 0 && magic > 0) { 555 DCHECK_NE(numerator_reg, -1); 556 NewLIR2(kX86Sub32RR, r2, numerator_reg); 557 } 558 559 // Do we need the shift? 560 if (shift != 0) { 561 // Shift EDX by 'shift' bits. 562 NewLIR2(kX86Sar32RI, r2, shift); 563 } 564 565 // Add 1 to EDX if EDX < 0. 566 567 // Move EDX to EAX. 568 OpRegCopy(r0, r2); 569 570 // Move sign bit to bit 0, zeroing the rest. 571 NewLIR2(kX86Shr32RI, r2, 31); 572 573 // EDX = EDX + EAX. 574 NewLIR2(kX86Add32RR, r2, r0); 575 576 // Quotient is in EDX. 577 if (!is_div) { 578 // We need to compute the remainder. 579 // Remainder is divisor - (quotient * imm). 580 DCHECK_NE(numerator_reg, -1); 581 OpRegCopy(r0, numerator_reg); 582 583 // EAX = numerator * imm. 584 OpRegRegImm(kOpMul, r2, r2, imm); 585 586 // EDX -= EAX. 587 NewLIR2(kX86Sub32RR, r0, r2); 588 589 // For this case, return the result in EAX. 590 rl_result.reg.SetReg(r0); 591 } 592 } 593 594 return rl_result; 595} 596 597RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, int reg_lo, 598 int reg_hi, bool is_div) { 599 LOG(FATAL) << "Unexpected use of GenDivRem for x86"; 600 return rl_dest; 601} 602 603RegLocation X86Mir2Lir::GenDivRem(RegLocation rl_dest, RegLocation rl_src1, 604 RegLocation rl_src2, bool is_div, bool check_zero) { 605 // We have to use fixed registers, so flush all the temps. 606 FlushAllRegs(); 607 LockCallTemps(); // Prepare for explicit register usage. 608 609 // Load LHS into EAX. 610 LoadValueDirectFixed(rl_src1, r0); 611 612 // Load RHS into EBX. 613 LoadValueDirectFixed(rl_src2, r1); 614 615 // Copy LHS sign bit into EDX. 616 NewLIR0(kx86Cdq32Da); 617 618 if (check_zero) { 619 // Handle division by zero case. 620 GenImmedCheck(kCondEq, r1, 0, kThrowDivZero); 621 } 622 623 // Have to catch 0x80000000/-1 case, or we will get an exception! 624 OpRegImm(kOpCmp, r1, -1); 625 LIR *minus_one_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe); 626 627 // RHS is -1. 628 OpRegImm(kOpCmp, r0, 0x80000000); 629 LIR * minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondNe); 630 631 // In 0x80000000/-1 case. 632 if (!is_div) { 633 // For DIV, EAX is already right. For REM, we need EDX 0. 634 LoadConstantNoClobber(r2, 0); 635 } 636 LIR* done = NewLIR1(kX86Jmp8, 0); 637 638 // Expected case. 639 minus_one_branch->target = NewLIR0(kPseudoTargetLabel); 640 minint_branch->target = minus_one_branch->target; 641 NewLIR1(kX86Idivmod32DaR, r1); 642 done->target = NewLIR0(kPseudoTargetLabel); 643 644 // Result is in EAX for div and EDX for rem. 645 RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, 646 RegStorage(RegStorage::k32BitSolo, r0), INVALID_SREG, INVALID_SREG}; 647 if (!is_div) { 648 rl_result.reg.SetReg(r2); 649 } 650 return rl_result; 651} 652 653bool X86Mir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) { 654 DCHECK_EQ(cu_->instruction_set, kX86); 655 656 // Get the two arguments to the invoke and place them in GP registers. 657 RegLocation rl_src1 = info->args[0]; 658 RegLocation rl_src2 = info->args[1]; 659 rl_src1 = LoadValue(rl_src1, kCoreReg); 660 rl_src2 = LoadValue(rl_src2, kCoreReg); 661 662 RegLocation rl_dest = InlineTarget(info); 663 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 664 665 /* 666 * If the result register is the same as the second element, then we need to be careful. 667 * The reason is that the first copy will inadvertently clobber the second element with 668 * the first one thus yielding the wrong result. Thus we do a swap in that case. 669 */ 670 if (rl_result.reg.GetReg() == rl_src2.reg.GetReg()) { 671 std::swap(rl_src1, rl_src2); 672 } 673 674 // Pick the first integer as min/max. 675 OpRegCopy(rl_result.reg.GetReg(), rl_src1.reg.GetReg()); 676 677 // If the integers are both in the same register, then there is nothing else to do 678 // because they are equal and we have already moved one into the result. 679 if (rl_src1.reg.GetReg() != rl_src2.reg.GetReg()) { 680 // It is possible we didn't pick correctly so do the actual comparison now. 681 OpRegReg(kOpCmp, rl_src1.reg.GetReg(), rl_src2.reg.GetReg()); 682 683 // Conditionally move the other integer into the destination register. 684 ConditionCode condition_code = is_min ? kCondGt : kCondLt; 685 OpCondRegReg(kOpCmov, condition_code, rl_result.reg.GetReg(), rl_src2.reg.GetReg()); 686 } 687 688 StoreValue(rl_dest, rl_result); 689 return true; 690} 691 692bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) { 693 RegLocation rl_src_address = info->args[0]; // long address 694 rl_src_address.wide = 0; // ignore high half in info->args[1] 695 RegLocation rl_dest = size == kLong ? InlineTargetWide(info) : InlineTarget(info); 696 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 697 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 698 if (size == kLong) { 699 // Unaligned access is allowed on x86. 700 LoadBaseDispWide(rl_address.reg.GetReg(), 0, rl_result.reg.GetReg(), rl_result.reg.GetHighReg(), INVALID_SREG); 701 StoreValueWide(rl_dest, rl_result); 702 } else { 703 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord); 704 // Unaligned access is allowed on x86. 705 LoadBaseDisp(rl_address.reg.GetReg(), 0, rl_result.reg.GetReg(), size, INVALID_SREG); 706 StoreValue(rl_dest, rl_result); 707 } 708 return true; 709} 710 711bool X86Mir2Lir::GenInlinedPoke(CallInfo* info, OpSize size) { 712 RegLocation rl_src_address = info->args[0]; // long address 713 rl_src_address.wide = 0; // ignore high half in info->args[1] 714 RegLocation rl_src_value = info->args[2]; // [size] value 715 RegLocation rl_address = LoadValue(rl_src_address, kCoreReg); 716 if (size == kLong) { 717 // Unaligned access is allowed on x86. 718 RegLocation rl_value = LoadValueWide(rl_src_value, kCoreReg); 719 StoreBaseDispWide(rl_address.reg.GetReg(), 0, rl_value.reg.GetReg(), rl_value.reg.GetHighReg()); 720 } else { 721 DCHECK(size == kSignedByte || size == kSignedHalf || size == kWord); 722 // Unaligned access is allowed on x86. 723 RegLocation rl_value = LoadValue(rl_src_value, kCoreReg); 724 StoreBaseDisp(rl_address.reg.GetReg(), 0, rl_value.reg.GetReg(), size); 725 } 726 return true; 727} 728 729void X86Mir2Lir::OpLea(int rBase, int reg1, int reg2, int scale, int offset) { 730 NewLIR5(kX86Lea32RA, rBase, reg1, reg2, scale, offset); 731} 732 733void X86Mir2Lir::OpTlsCmp(ThreadOffset offset, int val) { 734 NewLIR2(kX86Cmp16TI8, offset.Int32Value(), val); 735} 736 737bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) { 738 DCHECK_EQ(cu_->instruction_set, kX86); 739 // Unused - RegLocation rl_src_unsafe = info->args[0]; 740 RegLocation rl_src_obj = info->args[1]; // Object - known non-null 741 RegLocation rl_src_offset = info->args[2]; // long low 742 rl_src_offset.wide = 0; // ignore high half in info->args[3] 743 RegLocation rl_src_expected = info->args[4]; // int, long or Object 744 // If is_long, high half is in info->args[5] 745 RegLocation rl_src_new_value = info->args[is_long ? 6 : 5]; // int, long or Object 746 // If is_long, high half is in info->args[7] 747 748 if (is_long) { 749 FlushAllRegs(); 750 LockCallTemps(); 751 LoadValueDirectWideFixed(rl_src_expected, rAX, rDX); 752 LoadValueDirectWideFixed(rl_src_new_value, rBX, rCX); 753 NewLIR1(kX86Push32R, rDI); 754 MarkTemp(rDI); 755 LockTemp(rDI); 756 NewLIR1(kX86Push32R, rSI); 757 MarkTemp(rSI); 758 LockTemp(rSI); 759 const int push_offset = 4 /* push edi */ + 4 /* push esi */; 760 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_obj.s_reg_low) + push_offset, rDI); 761 LoadWordDisp(TargetReg(kSp), SRegOffset(rl_src_offset.s_reg_low) + push_offset, rSI); 762 NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0); 763 FreeTemp(rSI); 764 UnmarkTemp(rSI); 765 NewLIR1(kX86Pop32R, rSI); 766 FreeTemp(rDI); 767 UnmarkTemp(rDI); 768 NewLIR1(kX86Pop32R, rDI); 769 FreeCallTemps(); 770 } else { 771 // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX. 772 FlushReg(r0); 773 LockTemp(r0); 774 775 // Release store semantics, get the barrier out of the way. TODO: revisit 776 GenMemBarrier(kStoreLoad); 777 778 RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg); 779 RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg); 780 781 if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) { 782 // Mark card for object assuming new value is stored. 783 FreeTemp(r0); // Temporarily release EAX for MarkGCCard(). 784 MarkGCCard(rl_new_value.reg.GetReg(), rl_object.reg.GetReg()); 785 LockTemp(r0); 786 } 787 788 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg); 789 LoadValueDirect(rl_src_expected, r0); 790 NewLIR5(kX86LockCmpxchgAR, rl_object.reg.GetReg(), rl_offset.reg.GetReg(), 0, 0, rl_new_value.reg.GetReg()); 791 792 FreeTemp(r0); 793 } 794 795 // Convert ZF to boolean 796 RegLocation rl_dest = InlineTarget(info); // boolean place for result 797 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 798 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondZ); 799 NewLIR2(kX86Movzx8RR, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 800 StoreValue(rl_dest, rl_result); 801 return true; 802} 803 804LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) { 805 CHECK(base_of_code_ != nullptr); 806 807 // Address the start of the method 808 RegLocation rl_method = mir_graph_->GetRegLocation(base_of_code_->s_reg_low); 809 LoadValueDirectFixed(rl_method, reg); 810 store_method_addr_used_ = true; 811 812 // Load the proper value from the literal area. 813 // We don't know the proper offset for the value, so pick one that will force 814 // 4 byte offset. We will fix this up in the assembler later to have the right 815 // value. 816 LIR *res = RawLIR(current_dalvik_offset_, kX86Mov32RM, reg, reg, 256, 0, 0, target); 817 res->target = target; 818 res->flags.fixup = kFixupLoad; 819 SetMemRefType(res, true, kLiteral); 820 store_method_addr_used_ = true; 821 return res; 822} 823 824LIR* X86Mir2Lir::OpVldm(int rBase, int count) { 825 LOG(FATAL) << "Unexpected use of OpVldm for x86"; 826 return NULL; 827} 828 829LIR* X86Mir2Lir::OpVstm(int rBase, int count) { 830 LOG(FATAL) << "Unexpected use of OpVstm for x86"; 831 return NULL; 832} 833 834void X86Mir2Lir::GenMultiplyByTwoBitMultiplier(RegLocation rl_src, 835 RegLocation rl_result, int lit, 836 int first_bit, int second_bit) { 837 int t_reg = AllocTemp(); 838 OpRegRegImm(kOpLsl, t_reg, rl_src.reg.GetReg(), second_bit - first_bit); 839 OpRegRegReg(kOpAdd, rl_result.reg.GetReg(), rl_src.reg.GetReg(), t_reg); 840 FreeTemp(t_reg); 841 if (first_bit != 0) { 842 OpRegRegImm(kOpLsl, rl_result.reg.GetReg(), rl_result.reg.GetReg(), first_bit); 843 } 844} 845 846void X86Mir2Lir::GenDivZeroCheck(int reg_lo, int reg_hi) { 847 // We are not supposed to clobber either of the provided registers, so allocate 848 // a temporary to use for the check. 849 int t_reg = AllocTemp(); 850 851 // Doing an OR is a quick way to check if both registers are zero. This will set the flags. 852 OpRegRegReg(kOpOr, t_reg, reg_lo, reg_hi); 853 854 // In case of zero, throw ArithmeticException. 855 GenCheck(kCondEq, kThrowDivZero); 856 857 // The temp is no longer needed so free it at this time. 858 FreeTemp(t_reg); 859} 860 861// Test suspend flag, return target of taken suspend branch 862LIR* X86Mir2Lir::OpTestSuspend(LIR* target) { 863 OpTlsCmp(Thread::ThreadFlagsOffset(), 0); 864 return OpCondBranch((target == NULL) ? kCondNe : kCondEq, target); 865} 866 867// Decrement register and branch on condition 868LIR* X86Mir2Lir::OpDecAndBranch(ConditionCode c_code, int reg, LIR* target) { 869 OpRegImm(kOpSub, reg, 1); 870 return OpCondBranch(c_code, target); 871} 872 873bool X86Mir2Lir::SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div, 874 RegLocation rl_src, RegLocation rl_dest, int lit) { 875 LOG(FATAL) << "Unexpected use of smallLiteralDive in x86"; 876 return false; 877} 878 879LIR* X86Mir2Lir::OpIT(ConditionCode cond, const char* guide) { 880 LOG(FATAL) << "Unexpected use of OpIT in x86"; 881 return NULL; 882} 883 884void X86Mir2Lir::GenImulRegImm(int dest, int src, int val) { 885 switch (val) { 886 case 0: 887 NewLIR2(kX86Xor32RR, dest, dest); 888 break; 889 case 1: 890 OpRegCopy(dest, src); 891 break; 892 default: 893 OpRegRegImm(kOpMul, dest, src, val); 894 break; 895 } 896} 897 898void X86Mir2Lir::GenImulMemImm(int dest, int sreg, int displacement, int val) { 899 LIR *m; 900 switch (val) { 901 case 0: 902 NewLIR2(kX86Xor32RR, dest, dest); 903 break; 904 case 1: 905 LoadBaseDisp(rX86_SP, displacement, dest, kWord, sreg); 906 break; 907 default: 908 m = NewLIR4(IS_SIMM8(val) ? kX86Imul32RMI8 : kX86Imul32RMI, dest, rX86_SP, 909 displacement, val); 910 AnnotateDalvikRegAccess(m, displacement >> 2, true /* is_load */, true /* is_64bit */); 911 break; 912 } 913} 914 915void X86Mir2Lir::GenMulLong(Instruction::Code, RegLocation rl_dest, RegLocation rl_src1, 916 RegLocation rl_src2) { 917 if (rl_src1.is_const) { 918 std::swap(rl_src1, rl_src2); 919 } 920 // Are we multiplying by a constant? 921 if (rl_src2.is_const) { 922 // Do special compare/branch against simple const operand 923 int64_t val = mir_graph_->ConstantValueWide(rl_src2); 924 if (val == 0) { 925 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true); 926 OpRegReg(kOpXor, rl_result.reg.GetReg(), rl_result.reg.GetReg()); 927 OpRegReg(kOpXor, rl_result.reg.GetHighReg(), rl_result.reg.GetHighReg()); 928 StoreValueWide(rl_dest, rl_result); 929 return; 930 } else if (val == 1) { 931 StoreValueWide(rl_dest, rl_src1); 932 return; 933 } else if (val == 2) { 934 GenAddLong(Instruction::ADD_LONG, rl_dest, rl_src1, rl_src1); 935 return; 936 } else if (IsPowerOfTwo(val)) { 937 int shift_amount = LowestSetBit(val); 938 if (!BadOverlap(rl_src1, rl_dest)) { 939 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 940 RegLocation rl_result = GenShiftImmOpLong(Instruction::SHL_LONG, rl_dest, 941 rl_src1, shift_amount); 942 StoreValueWide(rl_dest, rl_result); 943 return; 944 } 945 } 946 947 // Okay, just bite the bullet and do it. 948 int32_t val_lo = Low32Bits(val); 949 int32_t val_hi = High32Bits(val); 950 FlushAllRegs(); 951 LockCallTemps(); // Prepare for explicit register usage. 952 rl_src1 = UpdateLocWide(rl_src1); 953 bool src1_in_reg = rl_src1.location == kLocPhysReg; 954 int displacement = SRegOffset(rl_src1.s_reg_low); 955 956 // ECX <- 1H * 2L 957 // EAX <- 1L * 2H 958 if (src1_in_reg) { 959 GenImulRegImm(r1, rl_src1.reg.GetHighReg(), val_lo); 960 GenImulRegImm(r0, rl_src1.reg.GetReg(), val_hi); 961 } else { 962 GenImulMemImm(r1, GetSRegHi(rl_src1.s_reg_low), displacement + HIWORD_OFFSET, val_lo); 963 GenImulMemImm(r0, rl_src1.s_reg_low, displacement + LOWORD_OFFSET, val_hi); 964 } 965 966 // ECX <- ECX + EAX (2H * 1L) + (1H * 2L) 967 NewLIR2(kX86Add32RR, r1, r0); 968 969 // EAX <- 2L 970 LoadConstantNoClobber(r0, val_lo); 971 972 // EDX:EAX <- 2L * 1L (double precision) 973 if (src1_in_reg) { 974 NewLIR1(kX86Mul32DaR, rl_src1.reg.GetReg()); 975 } else { 976 LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET); 977 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2, 978 true /* is_load */, true /* is_64bit */); 979 } 980 981 // EDX <- EDX + ECX (add high words) 982 NewLIR2(kX86Add32RR, r2, r1); 983 984 // Result is EDX:EAX 985 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, 986 RegStorage(RegStorage::k64BitPair, r0, r2), 987 INVALID_SREG, INVALID_SREG}; 988 StoreValueWide(rl_dest, rl_result); 989 return; 990 } 991 992 // Nope. Do it the hard way 993 // Check for V*V. We can eliminate a multiply in that case, as 2L*1H == 2H*1L. 994 bool is_square = mir_graph_->SRegToVReg(rl_src1.s_reg_low) == 995 mir_graph_->SRegToVReg(rl_src2.s_reg_low); 996 997 FlushAllRegs(); 998 LockCallTemps(); // Prepare for explicit register usage. 999 rl_src1 = UpdateLocWide(rl_src1); 1000 rl_src2 = UpdateLocWide(rl_src2); 1001 1002 // At this point, the VRs are in their home locations. 1003 bool src1_in_reg = rl_src1.location == kLocPhysReg; 1004 bool src2_in_reg = rl_src2.location == kLocPhysReg; 1005 1006 // ECX <- 1H 1007 if (src1_in_reg) { 1008 NewLIR2(kX86Mov32RR, r1, rl_src1.reg.GetHighReg()); 1009 } else { 1010 LoadBaseDisp(rX86_SP, SRegOffset(rl_src1.s_reg_low) + HIWORD_OFFSET, r1, 1011 kWord, GetSRegHi(rl_src1.s_reg_low)); 1012 } 1013 1014 if (is_square) { 1015 // Take advantage of the fact that the values are the same. 1016 // ECX <- ECX * 2L (1H * 2L) 1017 if (src2_in_reg) { 1018 NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetReg()); 1019 } else { 1020 int displacement = SRegOffset(rl_src2.s_reg_low); 1021 LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET); 1022 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2, 1023 true /* is_load */, true /* is_64bit */); 1024 } 1025 1026 // ECX <- 2*ECX (2H * 1L) + (1H * 2L) 1027 NewLIR2(kX86Add32RR, r1, r1); 1028 } else { 1029 // EAX <- 2H 1030 if (src2_in_reg) { 1031 NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetHighReg()); 1032 } else { 1033 LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, r0, 1034 kWord, GetSRegHi(rl_src2.s_reg_low)); 1035 } 1036 1037 // EAX <- EAX * 1L (2H * 1L) 1038 if (src1_in_reg) { 1039 NewLIR2(kX86Imul32RR, r0, rl_src1.reg.GetReg()); 1040 } else { 1041 int displacement = SRegOffset(rl_src1.s_reg_low); 1042 LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET); 1043 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2, 1044 true /* is_load */, true /* is_64bit */); 1045 } 1046 1047 // ECX <- ECX * 2L (1H * 2L) 1048 if (src2_in_reg) { 1049 NewLIR2(kX86Imul32RR, r1, rl_src2.reg.GetReg()); 1050 } else { 1051 int displacement = SRegOffset(rl_src2.s_reg_low); 1052 LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET); 1053 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2, 1054 true /* is_load */, true /* is_64bit */); 1055 } 1056 1057 // ECX <- ECX + EAX (2H * 1L) + (1H * 2L) 1058 NewLIR2(kX86Add32RR, r1, r0); 1059 } 1060 1061 // EAX <- 2L 1062 if (src2_in_reg) { 1063 NewLIR2(kX86Mov32RR, r0, rl_src2.reg.GetReg()); 1064 } else { 1065 LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + LOWORD_OFFSET, r0, 1066 kWord, rl_src2.s_reg_low); 1067 } 1068 1069 // EDX:EAX <- 2L * 1L (double precision) 1070 if (src1_in_reg) { 1071 NewLIR1(kX86Mul32DaR, rl_src1.reg.GetReg()); 1072 } else { 1073 int displacement = SRegOffset(rl_src1.s_reg_low); 1074 LIR *m = NewLIR2(kX86Mul32DaM, rX86_SP, displacement + LOWORD_OFFSET); 1075 AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2, 1076 true /* is_load */, true /* is_64bit */); 1077 } 1078 1079 // EDX <- EDX + ECX (add high words) 1080 NewLIR2(kX86Add32RR, r2, r1); 1081 1082 // Result is EDX:EAX 1083 RegLocation rl_result = {kLocPhysReg, 1, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed, 1084 RegStorage(RegStorage::k64BitPair, r0, r2), INVALID_SREG, INVALID_SREG}; 1085 StoreValueWide(rl_dest, rl_result); 1086} 1087 1088void X86Mir2Lir::GenLongRegOrMemOp(RegLocation rl_dest, RegLocation rl_src, 1089 Instruction::Code op) { 1090 DCHECK_EQ(rl_dest.location, kLocPhysReg); 1091 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false); 1092 if (rl_src.location == kLocPhysReg) { 1093 // Both operands are in registers. 1094 if (rl_dest.reg.GetReg() == rl_src.reg.GetHighReg()) { 1095 // The registers are the same, so we would clobber it before the use. 1096 int temp_reg = AllocTemp(); 1097 OpRegCopy(temp_reg, rl_dest.reg.GetReg()); 1098 rl_src.reg.SetHighReg(temp_reg); 1099 } 1100 NewLIR2(x86op, rl_dest.reg.GetReg(), rl_src.reg.GetReg()); 1101 1102 x86op = GetOpcode(op, rl_dest, rl_src, true); 1103 NewLIR2(x86op, rl_dest.reg.GetHighReg(), rl_src.reg.GetHighReg()); 1104 FreeTemp(rl_src.reg.GetReg()); 1105 FreeTemp(rl_src.reg.GetHighReg()); 1106 return; 1107 } 1108 1109 // RHS is in memory. 1110 DCHECK((rl_src.location == kLocDalvikFrame) || 1111 (rl_src.location == kLocCompilerTemp)); 1112 int rBase = TargetReg(kSp); 1113 int displacement = SRegOffset(rl_src.s_reg_low); 1114 1115 LIR *lir = NewLIR3(x86op, rl_dest.reg.GetReg(), rBase, displacement + LOWORD_OFFSET); 1116 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2, 1117 true /* is_load */, true /* is64bit */); 1118 x86op = GetOpcode(op, rl_dest, rl_src, true); 1119 lir = NewLIR3(x86op, rl_dest.reg.GetHighReg(), rBase, displacement + HIWORD_OFFSET); 1120 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, 1121 true /* is_load */, true /* is64bit */); 1122} 1123 1124void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) { 1125 rl_dest = UpdateLocWide(rl_dest); 1126 if (rl_dest.location == kLocPhysReg) { 1127 // Ensure we are in a register pair 1128 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true); 1129 1130 rl_src = UpdateLocWide(rl_src); 1131 GenLongRegOrMemOp(rl_result, rl_src, op); 1132 StoreFinalValueWide(rl_dest, rl_result); 1133 return; 1134 } 1135 1136 // It wasn't in registers, so it better be in memory. 1137 DCHECK((rl_dest.location == kLocDalvikFrame) || 1138 (rl_dest.location == kLocCompilerTemp)); 1139 rl_src = LoadValueWide(rl_src, kCoreReg); 1140 1141 // Operate directly into memory. 1142 X86OpCode x86op = GetOpcode(op, rl_dest, rl_src, false); 1143 int rBase = TargetReg(kSp); 1144 int displacement = SRegOffset(rl_dest.s_reg_low); 1145 1146 LIR *lir = NewLIR3(x86op, rBase, displacement + LOWORD_OFFSET, rl_src.reg.GetReg()); 1147 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2, 1148 false /* is_load */, true /* is64bit */); 1149 x86op = GetOpcode(op, rl_dest, rl_src, true); 1150 lir = NewLIR3(x86op, rBase, displacement + HIWORD_OFFSET, rl_src.reg.GetHighReg()); 1151 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, 1152 false /* is_load */, true /* is64bit */); 1153 FreeTemp(rl_src.reg.GetReg()); 1154 FreeTemp(rl_src.reg.GetHighReg()); 1155} 1156 1157void X86Mir2Lir::GenLongArith(RegLocation rl_dest, RegLocation rl_src1, 1158 RegLocation rl_src2, Instruction::Code op, 1159 bool is_commutative) { 1160 // Is this really a 2 operand operation? 1161 switch (op) { 1162 case Instruction::ADD_LONG_2ADDR: 1163 case Instruction::SUB_LONG_2ADDR: 1164 case Instruction::AND_LONG_2ADDR: 1165 case Instruction::OR_LONG_2ADDR: 1166 case Instruction::XOR_LONG_2ADDR: 1167 GenLongArith(rl_dest, rl_src2, op); 1168 return; 1169 default: 1170 break; 1171 } 1172 1173 if (rl_dest.location == kLocPhysReg) { 1174 RegLocation rl_result = LoadValueWide(rl_src1, kCoreReg); 1175 1176 // We are about to clobber the LHS, so it needs to be a temp. 1177 rl_result = ForceTempWide(rl_result); 1178 1179 // Perform the operation using the RHS. 1180 rl_src2 = UpdateLocWide(rl_src2); 1181 GenLongRegOrMemOp(rl_result, rl_src2, op); 1182 1183 // And now record that the result is in the temp. 1184 StoreFinalValueWide(rl_dest, rl_result); 1185 return; 1186 } 1187 1188 // It wasn't in registers, so it better be in memory. 1189 DCHECK((rl_dest.location == kLocDalvikFrame) || 1190 (rl_dest.location == kLocCompilerTemp)); 1191 rl_src1 = UpdateLocWide(rl_src1); 1192 rl_src2 = UpdateLocWide(rl_src2); 1193 1194 // Get one of the source operands into temporary register. 1195 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 1196 if (IsTemp(rl_src1.reg.GetReg()) && IsTemp(rl_src1.reg.GetHighReg())) { 1197 GenLongRegOrMemOp(rl_src1, rl_src2, op); 1198 } else if (is_commutative) { 1199 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 1200 // We need at least one of them to be a temporary. 1201 if (!(IsTemp(rl_src2.reg.GetReg()) && IsTemp(rl_src2.reg.GetHighReg()))) { 1202 rl_src1 = ForceTempWide(rl_src1); 1203 } 1204 GenLongRegOrMemOp(rl_src1, rl_src2, op); 1205 } else { 1206 // Need LHS to be the temp. 1207 rl_src1 = ForceTempWide(rl_src1); 1208 GenLongRegOrMemOp(rl_src1, rl_src2, op); 1209 } 1210 1211 StoreFinalValueWide(rl_dest, rl_src1); 1212} 1213 1214void X86Mir2Lir::GenAddLong(Instruction::Code opcode, RegLocation rl_dest, 1215 RegLocation rl_src1, RegLocation rl_src2) { 1216 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true); 1217} 1218 1219void X86Mir2Lir::GenSubLong(Instruction::Code opcode, RegLocation rl_dest, 1220 RegLocation rl_src1, RegLocation rl_src2) { 1221 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, false); 1222} 1223 1224void X86Mir2Lir::GenAndLong(Instruction::Code opcode, RegLocation rl_dest, 1225 RegLocation rl_src1, RegLocation rl_src2) { 1226 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true); 1227} 1228 1229void X86Mir2Lir::GenOrLong(Instruction::Code opcode, RegLocation rl_dest, 1230 RegLocation rl_src1, RegLocation rl_src2) { 1231 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true); 1232} 1233 1234void X86Mir2Lir::GenXorLong(Instruction::Code opcode, RegLocation rl_dest, 1235 RegLocation rl_src1, RegLocation rl_src2) { 1236 GenLongArith(rl_dest, rl_src1, rl_src2, opcode, true); 1237} 1238 1239void X86Mir2Lir::GenNegLong(RegLocation rl_dest, RegLocation rl_src) { 1240 rl_src = LoadValueWide(rl_src, kCoreReg); 1241 RegLocation rl_result = ForceTempWide(rl_src); 1242 if (((rl_dest.location == kLocPhysReg) && (rl_src.location == kLocPhysReg)) && 1243 ((rl_dest.reg.GetReg() == rl_src.reg.GetHighReg()))) { 1244 // The registers are the same, so we would clobber it before the use. 1245 int temp_reg = AllocTemp(); 1246 OpRegCopy(temp_reg, rl_result.reg.GetReg()); 1247 rl_result.reg.SetHighReg(temp_reg); 1248 } 1249 OpRegReg(kOpNeg, rl_result.reg.GetReg(), rl_result.reg.GetReg()); // rLow = -rLow 1250 OpRegImm(kOpAdc, rl_result.reg.GetHighReg(), 0); // rHigh = rHigh + CF 1251 OpRegReg(kOpNeg, rl_result.reg.GetHighReg(), rl_result.reg.GetHighReg()); // rHigh = -rHigh 1252 StoreValueWide(rl_dest, rl_result); 1253} 1254 1255void X86Mir2Lir::OpRegThreadMem(OpKind op, int r_dest, ThreadOffset thread_offset) { 1256 X86OpCode opcode = kX86Bkpt; 1257 switch (op) { 1258 case kOpCmp: opcode = kX86Cmp32RT; break; 1259 case kOpMov: opcode = kX86Mov32RT; break; 1260 default: 1261 LOG(FATAL) << "Bad opcode: " << op; 1262 break; 1263 } 1264 NewLIR2(opcode, r_dest, thread_offset.Int32Value()); 1265} 1266 1267/* 1268 * Generate array load 1269 */ 1270void X86Mir2Lir::GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array, 1271 RegLocation rl_index, RegLocation rl_dest, int scale) { 1272 RegisterClass reg_class = oat_reg_class_by_size(size); 1273 int len_offset = mirror::Array::LengthOffset().Int32Value(); 1274 RegLocation rl_result; 1275 rl_array = LoadValue(rl_array, kCoreReg); 1276 1277 int data_offset; 1278 if (size == kLong || size == kDouble) { 1279 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 1280 } else { 1281 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 1282 } 1283 1284 bool constant_index = rl_index.is_const; 1285 int32_t constant_index_value = 0; 1286 if (!constant_index) { 1287 rl_index = LoadValue(rl_index, kCoreReg); 1288 } else { 1289 constant_index_value = mir_graph_->ConstantValue(rl_index); 1290 // If index is constant, just fold it into the data offset 1291 data_offset += constant_index_value << scale; 1292 // treat as non array below 1293 rl_index.reg = RegStorage(RegStorage::k32BitSolo, INVALID_REG); 1294 } 1295 1296 /* null object? */ 1297 GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags); 1298 1299 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { 1300 if (constant_index) { 1301 GenMemImmedCheck(kCondLs, rl_array.reg.GetReg(), len_offset, 1302 constant_index_value, kThrowConstantArrayBounds); 1303 } else { 1304 GenRegMemCheck(kCondUge, rl_index.reg.GetReg(), rl_array.reg.GetReg(), 1305 len_offset, kThrowArrayBounds); 1306 } 1307 } 1308 rl_result = EvalLoc(rl_dest, reg_class, true); 1309 if ((size == kLong) || (size == kDouble)) { 1310 LoadBaseIndexedDisp(rl_array.reg.GetReg(), rl_index.reg.GetReg(), scale, data_offset, rl_result.reg.GetReg(), 1311 rl_result.reg.GetHighReg(), size, INVALID_SREG); 1312 StoreValueWide(rl_dest, rl_result); 1313 } else { 1314 LoadBaseIndexedDisp(rl_array.reg.GetReg(), rl_index.reg.GetReg(), scale, 1315 data_offset, rl_result.reg.GetReg(), INVALID_REG, size, 1316 INVALID_SREG); 1317 StoreValue(rl_dest, rl_result); 1318 } 1319} 1320 1321/* 1322 * Generate array store 1323 * 1324 */ 1325void X86Mir2Lir::GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array, 1326 RegLocation rl_index, RegLocation rl_src, int scale, bool card_mark) { 1327 RegisterClass reg_class = oat_reg_class_by_size(size); 1328 int len_offset = mirror::Array::LengthOffset().Int32Value(); 1329 int data_offset; 1330 1331 if (size == kLong || size == kDouble) { 1332 data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Int32Value(); 1333 } else { 1334 data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Int32Value(); 1335 } 1336 1337 rl_array = LoadValue(rl_array, kCoreReg); 1338 bool constant_index = rl_index.is_const; 1339 int32_t constant_index_value = 0; 1340 if (!constant_index) { 1341 rl_index = LoadValue(rl_index, kCoreReg); 1342 } else { 1343 // If index is constant, just fold it into the data offset 1344 constant_index_value = mir_graph_->ConstantValue(rl_index); 1345 data_offset += constant_index_value << scale; 1346 // treat as non array below 1347 rl_index.reg = RegStorage(RegStorage::k32BitSolo, INVALID_REG); 1348 } 1349 1350 /* null object? */ 1351 GenNullCheck(rl_array.s_reg_low, rl_array.reg.GetReg(), opt_flags); 1352 1353 if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) { 1354 if (constant_index) { 1355 GenMemImmedCheck(kCondLs, rl_array.reg.GetReg(), len_offset, 1356 constant_index_value, kThrowConstantArrayBounds); 1357 } else { 1358 GenRegMemCheck(kCondUge, rl_index.reg.GetReg(), rl_array.reg.GetReg(), 1359 len_offset, kThrowArrayBounds); 1360 } 1361 } 1362 if ((size == kLong) || (size == kDouble)) { 1363 rl_src = LoadValueWide(rl_src, reg_class); 1364 } else { 1365 rl_src = LoadValue(rl_src, reg_class); 1366 } 1367 // If the src reg can't be byte accessed, move it to a temp first. 1368 if ((size == kSignedByte || size == kUnsignedByte) && rl_src.reg.GetReg() >= 4) { 1369 int temp = AllocTemp(); 1370 OpRegCopy(temp, rl_src.reg.GetReg()); 1371 StoreBaseIndexedDisp(rl_array.reg.GetReg(), rl_index.reg.GetReg(), scale, data_offset, temp, 1372 INVALID_REG, size, INVALID_SREG); 1373 } else { 1374 StoreBaseIndexedDisp(rl_array.reg.GetReg(), rl_index.reg.GetReg(), scale, data_offset, rl_src.reg.GetReg(), 1375 rl_src.wide ? rl_src.reg.GetHighReg() : INVALID_REG, size, INVALID_SREG); 1376 } 1377 if (card_mark) { 1378 // Free rl_index if its a temp. Ensures there are 2 free regs for card mark. 1379 if (!constant_index) { 1380 FreeTemp(rl_index.reg.GetReg()); 1381 } 1382 MarkGCCard(rl_src.reg.GetReg(), rl_array.reg.GetReg()); 1383 } 1384} 1385 1386RegLocation X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, 1387 RegLocation rl_src, int shift_amount) { 1388 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1389 switch (opcode) { 1390 case Instruction::SHL_LONG: 1391 case Instruction::SHL_LONG_2ADDR: 1392 DCHECK_NE(shift_amount, 1); // Prevent a double store from happening. 1393 if (shift_amount == 32) { 1394 OpRegCopy(rl_result.reg.GetHighReg(), rl_src.reg.GetReg()); 1395 LoadConstant(rl_result.reg.GetReg(), 0); 1396 } else if (shift_amount > 31) { 1397 OpRegCopy(rl_result.reg.GetHighReg(), rl_src.reg.GetReg()); 1398 FreeTemp(rl_src.reg.GetHighReg()); 1399 NewLIR2(kX86Sal32RI, rl_result.reg.GetHighReg(), shift_amount - 32); 1400 LoadConstant(rl_result.reg.GetReg(), 0); 1401 } else { 1402 OpRegCopy(rl_result.reg.GetReg(), rl_src.reg.GetReg()); 1403 OpRegCopy(rl_result.reg.GetHighReg(), rl_src.reg.GetHighReg()); 1404 NewLIR3(kX86Shld32RRI, rl_result.reg.GetHighReg(), rl_result.reg.GetReg(), shift_amount); 1405 NewLIR2(kX86Sal32RI, rl_result.reg.GetReg(), shift_amount); 1406 } 1407 break; 1408 case Instruction::SHR_LONG: 1409 case Instruction::SHR_LONG_2ADDR: 1410 if (shift_amount == 32) { 1411 OpRegCopy(rl_result.reg.GetReg(), rl_src.reg.GetHighReg()); 1412 OpRegCopy(rl_result.reg.GetHighReg(), rl_src.reg.GetHighReg()); 1413 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), 31); 1414 } else if (shift_amount > 31) { 1415 OpRegCopy(rl_result.reg.GetReg(), rl_src.reg.GetHighReg()); 1416 OpRegCopy(rl_result.reg.GetHighReg(), rl_src.reg.GetHighReg()); 1417 NewLIR2(kX86Sar32RI, rl_result.reg.GetReg(), shift_amount - 32); 1418 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), 31); 1419 } else { 1420 OpRegCopy(rl_result.reg.GetReg(), rl_src.reg.GetReg()); 1421 OpRegCopy(rl_result.reg.GetHighReg(), rl_src.reg.GetHighReg()); 1422 NewLIR3(kX86Shrd32RRI, rl_result.reg.GetReg(), rl_result.reg.GetHighReg(), shift_amount); 1423 NewLIR2(kX86Sar32RI, rl_result.reg.GetHighReg(), shift_amount); 1424 } 1425 break; 1426 case Instruction::USHR_LONG: 1427 case Instruction::USHR_LONG_2ADDR: 1428 if (shift_amount == 32) { 1429 OpRegCopy(rl_result.reg.GetReg(), rl_src.reg.GetHighReg()); 1430 LoadConstant(rl_result.reg.GetHighReg(), 0); 1431 } else if (shift_amount > 31) { 1432 OpRegCopy(rl_result.reg.GetReg(), rl_src.reg.GetHighReg()); 1433 NewLIR2(kX86Shr32RI, rl_result.reg.GetReg(), shift_amount - 32); 1434 LoadConstant(rl_result.reg.GetHighReg(), 0); 1435 } else { 1436 OpRegCopy(rl_result.reg.GetReg(), rl_src.reg.GetReg()); 1437 OpRegCopy(rl_result.reg.GetHighReg(), rl_src.reg.GetHighReg()); 1438 NewLIR3(kX86Shrd32RRI, rl_result.reg.GetReg(), rl_result.reg.GetHighReg(), shift_amount); 1439 NewLIR2(kX86Shr32RI, rl_result.reg.GetHighReg(), shift_amount); 1440 } 1441 break; 1442 default: 1443 LOG(FATAL) << "Unexpected case"; 1444 } 1445 return rl_result; 1446} 1447 1448void X86Mir2Lir::GenShiftImmOpLong(Instruction::Code opcode, RegLocation rl_dest, 1449 RegLocation rl_src, RegLocation rl_shift) { 1450 // Per spec, we only care about low 6 bits of shift amount. 1451 int shift_amount = mir_graph_->ConstantValue(rl_shift) & 0x3f; 1452 if (shift_amount == 0) { 1453 rl_src = LoadValueWide(rl_src, kCoreReg); 1454 StoreValueWide(rl_dest, rl_src); 1455 return; 1456 } else if (shift_amount == 1 && 1457 (opcode == Instruction::SHL_LONG || opcode == Instruction::SHL_LONG_2ADDR)) { 1458 // Need to handle this here to avoid calling StoreValueWide twice. 1459 GenAddLong(Instruction::ADD_LONG, rl_dest, rl_src, rl_src); 1460 return; 1461 } 1462 if (BadOverlap(rl_src, rl_dest)) { 1463 GenShiftOpLong(opcode, rl_dest, rl_src, rl_shift); 1464 return; 1465 } 1466 rl_src = LoadValueWide(rl_src, kCoreReg); 1467 RegLocation rl_result = GenShiftImmOpLong(opcode, rl_dest, rl_src, shift_amount); 1468 StoreValueWide(rl_dest, rl_result); 1469} 1470 1471void X86Mir2Lir::GenArithImmOpLong(Instruction::Code opcode, 1472 RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2) { 1473 switch (opcode) { 1474 case Instruction::ADD_LONG: 1475 case Instruction::AND_LONG: 1476 case Instruction::OR_LONG: 1477 case Instruction::XOR_LONG: 1478 if (rl_src2.is_const) { 1479 GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode); 1480 } else { 1481 DCHECK(rl_src1.is_const); 1482 GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode); 1483 } 1484 break; 1485 case Instruction::SUB_LONG: 1486 case Instruction::SUB_LONG_2ADDR: 1487 if (rl_src2.is_const) { 1488 GenLongLongImm(rl_dest, rl_src1, rl_src2, opcode); 1489 } else { 1490 GenSubLong(opcode, rl_dest, rl_src1, rl_src2); 1491 } 1492 break; 1493 case Instruction::ADD_LONG_2ADDR: 1494 case Instruction::OR_LONG_2ADDR: 1495 case Instruction::XOR_LONG_2ADDR: 1496 case Instruction::AND_LONG_2ADDR: 1497 if (rl_src2.is_const) { 1498 GenLongImm(rl_dest, rl_src2, opcode); 1499 } else { 1500 DCHECK(rl_src1.is_const); 1501 GenLongLongImm(rl_dest, rl_src2, rl_src1, opcode); 1502 } 1503 break; 1504 default: 1505 // Default - bail to non-const handler. 1506 GenArithOpLong(opcode, rl_dest, rl_src1, rl_src2); 1507 break; 1508 } 1509} 1510 1511bool X86Mir2Lir::IsNoOp(Instruction::Code op, int32_t value) { 1512 switch (op) { 1513 case Instruction::AND_LONG_2ADDR: 1514 case Instruction::AND_LONG: 1515 return value == -1; 1516 case Instruction::OR_LONG: 1517 case Instruction::OR_LONG_2ADDR: 1518 case Instruction::XOR_LONG: 1519 case Instruction::XOR_LONG_2ADDR: 1520 return value == 0; 1521 default: 1522 return false; 1523 } 1524} 1525 1526X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation dest, RegLocation rhs, 1527 bool is_high_op) { 1528 bool rhs_in_mem = rhs.location != kLocPhysReg; 1529 bool dest_in_mem = dest.location != kLocPhysReg; 1530 DCHECK(!rhs_in_mem || !dest_in_mem); 1531 switch (op) { 1532 case Instruction::ADD_LONG: 1533 case Instruction::ADD_LONG_2ADDR: 1534 if (dest_in_mem) { 1535 return is_high_op ? kX86Adc32MR : kX86Add32MR; 1536 } else if (rhs_in_mem) { 1537 return is_high_op ? kX86Adc32RM : kX86Add32RM; 1538 } 1539 return is_high_op ? kX86Adc32RR : kX86Add32RR; 1540 case Instruction::SUB_LONG: 1541 case Instruction::SUB_LONG_2ADDR: 1542 if (dest_in_mem) { 1543 return is_high_op ? kX86Sbb32MR : kX86Sub32MR; 1544 } else if (rhs_in_mem) { 1545 return is_high_op ? kX86Sbb32RM : kX86Sub32RM; 1546 } 1547 return is_high_op ? kX86Sbb32RR : kX86Sub32RR; 1548 case Instruction::AND_LONG_2ADDR: 1549 case Instruction::AND_LONG: 1550 if (dest_in_mem) { 1551 return kX86And32MR; 1552 } 1553 return rhs_in_mem ? kX86And32RM : kX86And32RR; 1554 case Instruction::OR_LONG: 1555 case Instruction::OR_LONG_2ADDR: 1556 if (dest_in_mem) { 1557 return kX86Or32MR; 1558 } 1559 return rhs_in_mem ? kX86Or32RM : kX86Or32RR; 1560 case Instruction::XOR_LONG: 1561 case Instruction::XOR_LONG_2ADDR: 1562 if (dest_in_mem) { 1563 return kX86Xor32MR; 1564 } 1565 return rhs_in_mem ? kX86Xor32RM : kX86Xor32RR; 1566 default: 1567 LOG(FATAL) << "Unexpected opcode: " << op; 1568 return kX86Add32RR; 1569 } 1570} 1571 1572X86OpCode X86Mir2Lir::GetOpcode(Instruction::Code op, RegLocation loc, bool is_high_op, 1573 int32_t value) { 1574 bool in_mem = loc.location != kLocPhysReg; 1575 bool byte_imm = IS_SIMM8(value); 1576 DCHECK(in_mem || !IsFpReg(loc.reg.GetReg())); 1577 switch (op) { 1578 case Instruction::ADD_LONG: 1579 case Instruction::ADD_LONG_2ADDR: 1580 if (byte_imm) { 1581 if (in_mem) { 1582 return is_high_op ? kX86Adc32MI8 : kX86Add32MI8; 1583 } 1584 return is_high_op ? kX86Adc32RI8 : kX86Add32RI8; 1585 } 1586 if (in_mem) { 1587 return is_high_op ? kX86Adc32MI : kX86Add32MI; 1588 } 1589 return is_high_op ? kX86Adc32RI : kX86Add32RI; 1590 case Instruction::SUB_LONG: 1591 case Instruction::SUB_LONG_2ADDR: 1592 if (byte_imm) { 1593 if (in_mem) { 1594 return is_high_op ? kX86Sbb32MI8 : kX86Sub32MI8; 1595 } 1596 return is_high_op ? kX86Sbb32RI8 : kX86Sub32RI8; 1597 } 1598 if (in_mem) { 1599 return is_high_op ? kX86Sbb32MI : kX86Sub32MI; 1600 } 1601 return is_high_op ? kX86Sbb32RI : kX86Sub32RI; 1602 case Instruction::AND_LONG_2ADDR: 1603 case Instruction::AND_LONG: 1604 if (byte_imm) { 1605 return in_mem ? kX86And32MI8 : kX86And32RI8; 1606 } 1607 return in_mem ? kX86And32MI : kX86And32RI; 1608 case Instruction::OR_LONG: 1609 case Instruction::OR_LONG_2ADDR: 1610 if (byte_imm) { 1611 return in_mem ? kX86Or32MI8 : kX86Or32RI8; 1612 } 1613 return in_mem ? kX86Or32MI : kX86Or32RI; 1614 case Instruction::XOR_LONG: 1615 case Instruction::XOR_LONG_2ADDR: 1616 if (byte_imm) { 1617 return in_mem ? kX86Xor32MI8 : kX86Xor32RI8; 1618 } 1619 return in_mem ? kX86Xor32MI : kX86Xor32RI; 1620 default: 1621 LOG(FATAL) << "Unexpected opcode: " << op; 1622 return kX86Add32MI; 1623 } 1624} 1625 1626void X86Mir2Lir::GenLongImm(RegLocation rl_dest, RegLocation rl_src, Instruction::Code op) { 1627 DCHECK(rl_src.is_const); 1628 int64_t val = mir_graph_->ConstantValueWide(rl_src); 1629 int32_t val_lo = Low32Bits(val); 1630 int32_t val_hi = High32Bits(val); 1631 rl_dest = UpdateLocWide(rl_dest); 1632 1633 // Can we just do this into memory? 1634 if ((rl_dest.location == kLocDalvikFrame) || 1635 (rl_dest.location == kLocCompilerTemp)) { 1636 int rBase = TargetReg(kSp); 1637 int displacement = SRegOffset(rl_dest.s_reg_low); 1638 1639 if (!IsNoOp(op, val_lo)) { 1640 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo); 1641 LIR *lir = NewLIR3(x86op, rBase, displacement + LOWORD_OFFSET, val_lo); 1642 AnnotateDalvikRegAccess(lir, (displacement + LOWORD_OFFSET) >> 2, 1643 false /* is_load */, true /* is64bit */); 1644 } 1645 if (!IsNoOp(op, val_hi)) { 1646 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi); 1647 LIR *lir = NewLIR3(x86op, rBase, displacement + HIWORD_OFFSET, val_hi); 1648 AnnotateDalvikRegAccess(lir, (displacement + HIWORD_OFFSET) >> 2, 1649 false /* is_load */, true /* is64bit */); 1650 } 1651 return; 1652 } 1653 1654 RegLocation rl_result = EvalLocWide(rl_dest, kCoreReg, true); 1655 DCHECK_EQ(rl_result.location, kLocPhysReg); 1656 DCHECK(!IsFpReg(rl_result.reg.GetReg())); 1657 1658 if (!IsNoOp(op, val_lo)) { 1659 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo); 1660 NewLIR2(x86op, rl_result.reg.GetReg(), val_lo); 1661 } 1662 if (!IsNoOp(op, val_hi)) { 1663 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi); 1664 NewLIR2(x86op, rl_result.reg.GetHighReg(), val_hi); 1665 } 1666 StoreValueWide(rl_dest, rl_result); 1667} 1668 1669void X86Mir2Lir::GenLongLongImm(RegLocation rl_dest, RegLocation rl_src1, 1670 RegLocation rl_src2, Instruction::Code op) { 1671 DCHECK(rl_src2.is_const); 1672 int64_t val = mir_graph_->ConstantValueWide(rl_src2); 1673 int32_t val_lo = Low32Bits(val); 1674 int32_t val_hi = High32Bits(val); 1675 rl_dest = UpdateLocWide(rl_dest); 1676 rl_src1 = UpdateLocWide(rl_src1); 1677 1678 // Can we do this directly into the destination registers? 1679 if (rl_dest.location == kLocPhysReg && rl_src1.location == kLocPhysReg && 1680 rl_dest.reg.GetReg() == rl_src1.reg.GetReg() && rl_dest.reg.GetHighReg() == rl_src1.reg.GetHighReg() && 1681 !IsFpReg(rl_dest.reg.GetReg())) { 1682 if (!IsNoOp(op, val_lo)) { 1683 X86OpCode x86op = GetOpcode(op, rl_dest, false, val_lo); 1684 NewLIR2(x86op, rl_dest.reg.GetReg(), val_lo); 1685 } 1686 if (!IsNoOp(op, val_hi)) { 1687 X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi); 1688 NewLIR2(x86op, rl_dest.reg.GetHighReg(), val_hi); 1689 } 1690 1691 StoreFinalValueWide(rl_dest, rl_dest); 1692 return; 1693 } 1694 1695 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 1696 DCHECK_EQ(rl_src1.location, kLocPhysReg); 1697 1698 // We need the values to be in a temporary 1699 RegLocation rl_result = ForceTempWide(rl_src1); 1700 if (!IsNoOp(op, val_lo)) { 1701 X86OpCode x86op = GetOpcode(op, rl_result, false, val_lo); 1702 NewLIR2(x86op, rl_result.reg.GetReg(), val_lo); 1703 } 1704 if (!IsNoOp(op, val_hi)) { 1705 X86OpCode x86op = GetOpcode(op, rl_result, true, val_hi); 1706 NewLIR2(x86op, rl_result.reg.GetHighReg(), val_hi); 1707 } 1708 1709 StoreFinalValueWide(rl_dest, rl_result); 1710} 1711 1712// For final classes there are no sub-classes to check and so we can answer the instance-of 1713// question with simple comparisons. Use compares to memory and SETEQ to optimize for x86. 1714void X86Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, 1715 RegLocation rl_dest, RegLocation rl_src) { 1716 RegLocation object = LoadValue(rl_src, kCoreReg); 1717 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1718 int result_reg = rl_result.reg.GetReg(); 1719 1720 // SETcc only works with EAX..EDX. 1721 if (result_reg == object.reg.GetReg() || result_reg >= 4) { 1722 result_reg = AllocTypedTemp(false, kCoreReg); 1723 DCHECK_LT(result_reg, 4); 1724 } 1725 1726 // Assume that there is no match. 1727 LoadConstant(result_reg, 0); 1728 LIR* null_branchover = OpCmpImmBranch(kCondEq, object.reg.GetReg(), 0, NULL); 1729 1730 int check_class = AllocTypedTemp(false, kCoreReg); 1731 1732 // If Method* is already in a register, we can save a copy. 1733 RegLocation rl_method = mir_graph_->GetMethodLoc(); 1734 int32_t offset_of_type = mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + 1735 (sizeof(mirror::Class*) * type_idx); 1736 1737 if (rl_method.location == kLocPhysReg) { 1738 if (use_declaring_class) { 1739 LoadWordDisp(rl_method.reg.GetReg(), 1740 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), 1741 check_class); 1742 } else { 1743 LoadWordDisp(rl_method.reg.GetReg(), 1744 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), 1745 check_class); 1746 LoadWordDisp(check_class, offset_of_type, check_class); 1747 } 1748 } else { 1749 LoadCurrMethodDirect(check_class); 1750 if (use_declaring_class) { 1751 LoadWordDisp(check_class, 1752 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), 1753 check_class); 1754 } else { 1755 LoadWordDisp(check_class, 1756 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), 1757 check_class); 1758 LoadWordDisp(check_class, offset_of_type, check_class); 1759 } 1760 } 1761 1762 // Compare the computed class to the class in the object. 1763 DCHECK_EQ(object.location, kLocPhysReg); 1764 OpRegMem(kOpCmp, check_class, object.reg.GetReg(), 1765 mirror::Object::ClassOffset().Int32Value()); 1766 1767 // Set the low byte of the result to 0 or 1 from the compare condition code. 1768 NewLIR2(kX86Set8R, result_reg, kX86CondEq); 1769 1770 LIR* target = NewLIR0(kPseudoTargetLabel); 1771 null_branchover->target = target; 1772 FreeTemp(check_class); 1773 if (IsTemp(result_reg)) { 1774 OpRegCopy(rl_result.reg.GetReg(), result_reg); 1775 FreeTemp(result_reg); 1776 } 1777 StoreValue(rl_dest, rl_result); 1778} 1779 1780void X86Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final, 1781 bool type_known_abstract, bool use_declaring_class, 1782 bool can_assume_type_is_in_dex_cache, 1783 uint32_t type_idx, RegLocation rl_dest, 1784 RegLocation rl_src) { 1785 FlushAllRegs(); 1786 // May generate a call - use explicit registers. 1787 LockCallTemps(); 1788 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 gets current Method*. 1789 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class*. 1790 // Reference must end up in kArg0. 1791 if (needs_access_check) { 1792 // Check we have access to type_idx and if not throw IllegalAccessError, 1793 // Caller function returns Class* in kArg0. 1794 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess), 1795 type_idx, true); 1796 OpRegCopy(class_reg, TargetReg(kRet0)); 1797 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); 1798 } else if (use_declaring_class) { 1799 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); 1800 LoadWordDisp(TargetReg(kArg1), 1801 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg); 1802 } else { 1803 // Load dex cache entry into class_reg (kArg2). 1804 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); 1805 LoadWordDisp(TargetReg(kArg1), 1806 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg); 1807 int32_t offset_of_type = 1808 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*) 1809 * type_idx); 1810 LoadWordDisp(class_reg, offset_of_type, class_reg); 1811 if (!can_assume_type_is_in_dex_cache) { 1812 // Need to test presence of type in dex cache at runtime. 1813 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL); 1814 // Type is not resolved. Call out to helper, which will return resolved type in kRet0/kArg0. 1815 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx, true); 1816 OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path. 1817 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* Reload Ref. */ 1818 // Rejoin code paths 1819 LIR* hop_target = NewLIR0(kPseudoTargetLabel); 1820 hop_branch->target = hop_target; 1821 } 1822 } 1823 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result. */ 1824 RegLocation rl_result = GetReturn(false); 1825 1826 // SETcc only works with EAX..EDX. 1827 DCHECK_LT(rl_result.reg.GetReg(), 4); 1828 1829 // Is the class NULL? 1830 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL); 1831 1832 /* Load object->klass_. */ 1833 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0); 1834 LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1)); 1835 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class. */ 1836 LIR* branchover = nullptr; 1837 if (type_known_final) { 1838 // Ensure top 3 bytes of result are 0. 1839 LoadConstant(rl_result.reg.GetReg(), 0); 1840 OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); 1841 // Set the low byte of the result to 0 or 1 from the compare condition code. 1842 NewLIR2(kX86Set8R, rl_result.reg.GetReg(), kX86CondEq); 1843 } else { 1844 if (!type_known_abstract) { 1845 LoadConstant(rl_result.reg.GetReg(), 1); // Assume result succeeds. 1846 branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL); 1847 } 1848 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); 1849 OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial)); 1850 } 1851 // TODO: only clobber when type isn't final? 1852 ClobberCallerSave(); 1853 /* Branch targets here. */ 1854 LIR* target = NewLIR0(kPseudoTargetLabel); 1855 StoreValue(rl_dest, rl_result); 1856 branch1->target = target; 1857 if (branchover != nullptr) { 1858 branchover->target = target; 1859 } 1860} 1861 1862void X86Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, 1863 RegLocation rl_lhs, RegLocation rl_rhs) { 1864 OpKind op = kOpBkpt; 1865 bool is_div_rem = false; 1866 bool unary = false; 1867 bool shift_op = false; 1868 bool is_two_addr = false; 1869 RegLocation rl_result; 1870 switch (opcode) { 1871 case Instruction::NEG_INT: 1872 op = kOpNeg; 1873 unary = true; 1874 break; 1875 case Instruction::NOT_INT: 1876 op = kOpMvn; 1877 unary = true; 1878 break; 1879 case Instruction::ADD_INT_2ADDR: 1880 is_two_addr = true; 1881 // Fallthrough 1882 case Instruction::ADD_INT: 1883 op = kOpAdd; 1884 break; 1885 case Instruction::SUB_INT_2ADDR: 1886 is_two_addr = true; 1887 // Fallthrough 1888 case Instruction::SUB_INT: 1889 op = kOpSub; 1890 break; 1891 case Instruction::MUL_INT_2ADDR: 1892 is_two_addr = true; 1893 // Fallthrough 1894 case Instruction::MUL_INT: 1895 op = kOpMul; 1896 break; 1897 case Instruction::DIV_INT_2ADDR: 1898 is_two_addr = true; 1899 // Fallthrough 1900 case Instruction::DIV_INT: 1901 op = kOpDiv; 1902 is_div_rem = true; 1903 break; 1904 /* NOTE: returns in kArg1 */ 1905 case Instruction::REM_INT_2ADDR: 1906 is_two_addr = true; 1907 // Fallthrough 1908 case Instruction::REM_INT: 1909 op = kOpRem; 1910 is_div_rem = true; 1911 break; 1912 case Instruction::AND_INT_2ADDR: 1913 is_two_addr = true; 1914 // Fallthrough 1915 case Instruction::AND_INT: 1916 op = kOpAnd; 1917 break; 1918 case Instruction::OR_INT_2ADDR: 1919 is_two_addr = true; 1920 // Fallthrough 1921 case Instruction::OR_INT: 1922 op = kOpOr; 1923 break; 1924 case Instruction::XOR_INT_2ADDR: 1925 is_two_addr = true; 1926 // Fallthrough 1927 case Instruction::XOR_INT: 1928 op = kOpXor; 1929 break; 1930 case Instruction::SHL_INT_2ADDR: 1931 is_two_addr = true; 1932 // Fallthrough 1933 case Instruction::SHL_INT: 1934 shift_op = true; 1935 op = kOpLsl; 1936 break; 1937 case Instruction::SHR_INT_2ADDR: 1938 is_two_addr = true; 1939 // Fallthrough 1940 case Instruction::SHR_INT: 1941 shift_op = true; 1942 op = kOpAsr; 1943 break; 1944 case Instruction::USHR_INT_2ADDR: 1945 is_two_addr = true; 1946 // Fallthrough 1947 case Instruction::USHR_INT: 1948 shift_op = true; 1949 op = kOpLsr; 1950 break; 1951 default: 1952 LOG(FATAL) << "Invalid word arith op: " << opcode; 1953 } 1954 1955 // Can we convert to a two address instruction? 1956 if (!is_two_addr && 1957 (mir_graph_->SRegToVReg(rl_dest.s_reg_low) == 1958 mir_graph_->SRegToVReg(rl_lhs.s_reg_low))) { 1959 is_two_addr = true; 1960 } 1961 1962 // Get the div/rem stuff out of the way. 1963 if (is_div_rem) { 1964 rl_result = GenDivRem(rl_dest, rl_lhs, rl_rhs, op == kOpDiv, true); 1965 StoreValue(rl_dest, rl_result); 1966 return; 1967 } 1968 1969 if (unary) { 1970 rl_lhs = LoadValue(rl_lhs, kCoreReg); 1971 rl_result = UpdateLoc(rl_dest); 1972 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1973 OpRegReg(op, rl_result.reg.GetReg(), rl_lhs.reg.GetReg()); 1974 } else { 1975 if (shift_op) { 1976 // X86 doesn't require masking and must use ECX. 1977 int t_reg = TargetReg(kCount); // rCX 1978 LoadValueDirectFixed(rl_rhs, t_reg); 1979 if (is_two_addr) { 1980 // Can we do this directly into memory? 1981 rl_result = UpdateLoc(rl_dest); 1982 rl_rhs = LoadValue(rl_rhs, kCoreReg); 1983 if (rl_result.location != kLocPhysReg) { 1984 // Okay, we can do this into memory 1985 OpMemReg(op, rl_result, t_reg); 1986 FreeTemp(t_reg); 1987 return; 1988 } else if (!IsFpReg(rl_result.reg.GetReg())) { 1989 // Can do this directly into the result register 1990 OpRegReg(op, rl_result.reg.GetReg(), t_reg); 1991 FreeTemp(t_reg); 1992 StoreFinalValue(rl_dest, rl_result); 1993 return; 1994 } 1995 } 1996 // Three address form, or we can't do directly. 1997 rl_lhs = LoadValue(rl_lhs, kCoreReg); 1998 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1999 OpRegRegReg(op, rl_result.reg.GetReg(), rl_lhs.reg.GetReg(), t_reg); 2000 FreeTemp(t_reg); 2001 } else { 2002 // Multiply is 3 operand only (sort of). 2003 if (is_two_addr && op != kOpMul) { 2004 // Can we do this directly into memory? 2005 rl_result = UpdateLoc(rl_dest); 2006 if (rl_result.location == kLocPhysReg) { 2007 // Can we do this from memory directly? 2008 rl_rhs = UpdateLoc(rl_rhs); 2009 if (rl_rhs.location != kLocPhysReg) { 2010 OpRegMem(op, rl_result.reg.GetReg(), rl_rhs); 2011 StoreFinalValue(rl_dest, rl_result); 2012 return; 2013 } else if (!IsFpReg(rl_rhs.reg.GetReg())) { 2014 OpRegReg(op, rl_result.reg.GetReg(), rl_rhs.reg.GetReg()); 2015 StoreFinalValue(rl_dest, rl_result); 2016 return; 2017 } 2018 } 2019 rl_rhs = LoadValue(rl_rhs, kCoreReg); 2020 if (rl_result.location != kLocPhysReg) { 2021 // Okay, we can do this into memory. 2022 OpMemReg(op, rl_result, rl_rhs.reg.GetReg()); 2023 return; 2024 } else if (!IsFpReg(rl_result.reg.GetReg())) { 2025 // Can do this directly into the result register. 2026 OpRegReg(op, rl_result.reg.GetReg(), rl_rhs.reg.GetReg()); 2027 StoreFinalValue(rl_dest, rl_result); 2028 return; 2029 } else { 2030 rl_lhs = LoadValue(rl_lhs, kCoreReg); 2031 rl_result = EvalLoc(rl_dest, kCoreReg, true); 2032 OpRegRegReg(op, rl_result.reg.GetReg(), rl_lhs.reg.GetReg(), rl_rhs.reg.GetReg()); 2033 } 2034 } else { 2035 // Try to use reg/memory instructions. 2036 rl_lhs = UpdateLoc(rl_lhs); 2037 rl_rhs = UpdateLoc(rl_rhs); 2038 // We can't optimize with FP registers. 2039 if (!IsOperationSafeWithoutTemps(rl_lhs, rl_rhs)) { 2040 // Something is difficult, so fall back to the standard case. 2041 rl_lhs = LoadValue(rl_lhs, kCoreReg); 2042 rl_rhs = LoadValue(rl_rhs, kCoreReg); 2043 rl_result = EvalLoc(rl_dest, kCoreReg, true); 2044 OpRegRegReg(op, rl_result.reg.GetReg(), rl_lhs.reg.GetReg(), rl_rhs.reg.GetReg()); 2045 } else { 2046 // We can optimize by moving to result and using memory operands. 2047 if (rl_rhs.location != kLocPhysReg) { 2048 // Force LHS into result. 2049 rl_result = EvalLoc(rl_dest, kCoreReg, true); 2050 LoadValueDirect(rl_lhs, rl_result.reg.GetReg()); 2051 OpRegMem(op, rl_result.reg.GetReg(), rl_rhs); 2052 } else if (rl_lhs.location != kLocPhysReg) { 2053 // RHS is in a register; LHS is in memory. 2054 if (op != kOpSub) { 2055 // Force RHS into result and operate on memory. 2056 rl_result = EvalLoc(rl_dest, kCoreReg, true); 2057 OpRegCopy(rl_result.reg.GetReg(), rl_rhs.reg.GetReg()); 2058 OpRegMem(op, rl_result.reg.GetReg(), rl_lhs); 2059 } else { 2060 // Subtraction isn't commutative. 2061 rl_lhs = LoadValue(rl_lhs, kCoreReg); 2062 rl_rhs = LoadValue(rl_rhs, kCoreReg); 2063 rl_result = EvalLoc(rl_dest, kCoreReg, true); 2064 OpRegRegReg(op, rl_result.reg.GetReg(), rl_lhs.reg.GetReg(), rl_rhs.reg.GetReg()); 2065 } 2066 } else { 2067 // Both are in registers. 2068 rl_lhs = LoadValue(rl_lhs, kCoreReg); 2069 rl_rhs = LoadValue(rl_rhs, kCoreReg); 2070 rl_result = EvalLoc(rl_dest, kCoreReg, true); 2071 OpRegRegReg(op, rl_result.reg.GetReg(), rl_lhs.reg.GetReg(), rl_rhs.reg.GetReg()); 2072 } 2073 } 2074 } 2075 } 2076 } 2077 StoreValue(rl_dest, rl_result); 2078} 2079 2080bool X86Mir2Lir::IsOperationSafeWithoutTemps(RegLocation rl_lhs, RegLocation rl_rhs) { 2081 // If we have non-core registers, then we can't do good things. 2082 if (rl_lhs.location == kLocPhysReg && IsFpReg(rl_lhs.reg.GetReg())) { 2083 return false; 2084 } 2085 if (rl_rhs.location == kLocPhysReg && IsFpReg(rl_rhs.reg.GetReg())) { 2086 return false; 2087 } 2088 2089 // Everything will be fine :-). 2090 return true; 2091} 2092} // namespace art 2093