code_generator_x86.cc revision 729645a937eb9f04a311b3c22471dcf3ebe9bcec
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "code_generator_x86.h" 18 19#include "art_method.h" 20#include "code_generator_utils.h" 21#include "compiled_method.h" 22#include "entrypoints/quick/quick_entrypoints.h" 23#include "entrypoints/quick/quick_entrypoints_enum.h" 24#include "gc/accounting/card_table.h" 25#include "intrinsics.h" 26#include "intrinsics_x86.h" 27#include "mirror/array-inl.h" 28#include "mirror/class-inl.h" 29#include "pc_relative_fixups_x86.h" 30#include "thread.h" 31#include "utils/assembler.h" 32#include "utils/stack_checks.h" 33#include "utils/x86/assembler_x86.h" 34#include "utils/x86/managed_register_x86.h" 35 36namespace art { 37 38template<class MirrorType> 39class GcRoot; 40 41namespace x86 { 42 43static constexpr int kCurrentMethodStackOffset = 0; 44static constexpr Register kMethodRegisterArgument = EAX; 45 46static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI }; 47 48static constexpr int kC2ConditionMask = 0x400; 49 50static constexpr int kFakeReturnRegister = Register(8); 51 52#define __ down_cast<X86Assembler*>(codegen->GetAssembler())-> 53#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86WordSize, x).Int32Value() 54 55class NullCheckSlowPathX86 : public SlowPathCode { 56 public: 57 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {} 58 59 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 60 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 61 __ Bind(GetEntryLabel()); 62 if (instruction_->CanThrowIntoCatchBlock()) { 63 // Live registers will be restored in the catch block if caught. 64 SaveLiveRegisters(codegen, instruction_->GetLocations()); 65 } 66 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer), 67 instruction_, 68 instruction_->GetDexPc(), 69 this); 70 } 71 72 bool IsFatal() const OVERRIDE { return true; } 73 74 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathX86"; } 75 76 private: 77 HNullCheck* const instruction_; 78 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86); 79}; 80 81class DivZeroCheckSlowPathX86 : public SlowPathCode { 82 public: 83 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {} 84 85 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 86 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 87 __ Bind(GetEntryLabel()); 88 if (instruction_->CanThrowIntoCatchBlock()) { 89 // Live registers will be restored in the catch block if caught. 90 SaveLiveRegisters(codegen, instruction_->GetLocations()); 91 } 92 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero), 93 instruction_, 94 instruction_->GetDexPc(), 95 this); 96 } 97 98 bool IsFatal() const OVERRIDE { return true; } 99 100 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathX86"; } 101 102 private: 103 HDivZeroCheck* const instruction_; 104 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86); 105}; 106 107class DivRemMinusOneSlowPathX86 : public SlowPathCode { 108 public: 109 DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {} 110 111 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 112 __ Bind(GetEntryLabel()); 113 if (is_div_) { 114 __ negl(reg_); 115 } else { 116 __ movl(reg_, Immediate(0)); 117 } 118 __ jmp(GetExitLabel()); 119 } 120 121 const char* GetDescription() const OVERRIDE { return "DivRemMinusOneSlowPathX86"; } 122 123 private: 124 Register reg_; 125 bool is_div_; 126 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86); 127}; 128 129class BoundsCheckSlowPathX86 : public SlowPathCode { 130 public: 131 explicit BoundsCheckSlowPathX86(HBoundsCheck* instruction) : instruction_(instruction) {} 132 133 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 134 LocationSummary* locations = instruction_->GetLocations(); 135 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 136 __ Bind(GetEntryLabel()); 137 // We're moving two locations to locations that could overlap, so we need a parallel 138 // move resolver. 139 if (instruction_->CanThrowIntoCatchBlock()) { 140 // Live registers will be restored in the catch block if caught. 141 SaveLiveRegisters(codegen, instruction_->GetLocations()); 142 } 143 InvokeRuntimeCallingConvention calling_convention; 144 x86_codegen->EmitParallelMoves( 145 locations->InAt(0), 146 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 147 Primitive::kPrimInt, 148 locations->InAt(1), 149 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), 150 Primitive::kPrimInt); 151 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds), 152 instruction_, 153 instruction_->GetDexPc(), 154 this); 155 } 156 157 bool IsFatal() const OVERRIDE { return true; } 158 159 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathX86"; } 160 161 private: 162 HBoundsCheck* const instruction_; 163 164 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86); 165}; 166 167class SuspendCheckSlowPathX86 : public SlowPathCode { 168 public: 169 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor) 170 : instruction_(instruction), successor_(successor) {} 171 172 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 173 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 174 __ Bind(GetEntryLabel()); 175 SaveLiveRegisters(codegen, instruction_->GetLocations()); 176 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend), 177 instruction_, 178 instruction_->GetDexPc(), 179 this); 180 RestoreLiveRegisters(codegen, instruction_->GetLocations()); 181 if (successor_ == nullptr) { 182 __ jmp(GetReturnLabel()); 183 } else { 184 __ jmp(x86_codegen->GetLabelOf(successor_)); 185 } 186 } 187 188 Label* GetReturnLabel() { 189 DCHECK(successor_ == nullptr); 190 return &return_label_; 191 } 192 193 HBasicBlock* GetSuccessor() const { 194 return successor_; 195 } 196 197 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathX86"; } 198 199 private: 200 HSuspendCheck* const instruction_; 201 HBasicBlock* const successor_; 202 Label return_label_; 203 204 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86); 205}; 206 207class LoadStringSlowPathX86 : public SlowPathCode { 208 public: 209 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {} 210 211 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 212 LocationSummary* locations = instruction_->GetLocations(); 213 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 214 215 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 216 __ Bind(GetEntryLabel()); 217 SaveLiveRegisters(codegen, locations); 218 219 InvokeRuntimeCallingConvention calling_convention; 220 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex())); 221 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString), 222 instruction_, 223 instruction_->GetDexPc(), 224 this); 225 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); 226 RestoreLiveRegisters(codegen, locations); 227 228 __ jmp(GetExitLabel()); 229 } 230 231 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86"; } 232 233 private: 234 HLoadString* const instruction_; 235 236 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86); 237}; 238 239class LoadClassSlowPathX86 : public SlowPathCode { 240 public: 241 LoadClassSlowPathX86(HLoadClass* cls, 242 HInstruction* at, 243 uint32_t dex_pc, 244 bool do_clinit) 245 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { 246 DCHECK(at->IsLoadClass() || at->IsClinitCheck()); 247 } 248 249 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 250 LocationSummary* locations = at_->GetLocations(); 251 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 252 __ Bind(GetEntryLabel()); 253 SaveLiveRegisters(codegen, locations); 254 255 InvokeRuntimeCallingConvention calling_convention; 256 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex())); 257 x86_codegen->InvokeRuntime(do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage) 258 : QUICK_ENTRY_POINT(pInitializeType), 259 at_, dex_pc_, this); 260 261 // Move the class to the desired location. 262 Location out = locations->Out(); 263 if (out.IsValid()) { 264 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg())); 265 x86_codegen->Move32(out, Location::RegisterLocation(EAX)); 266 } 267 268 RestoreLiveRegisters(codegen, locations); 269 __ jmp(GetExitLabel()); 270 } 271 272 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathX86"; } 273 274 private: 275 // The class this slow path will load. 276 HLoadClass* const cls_; 277 278 // The instruction where this slow path is happening. 279 // (Might be the load class or an initialization check). 280 HInstruction* const at_; 281 282 // The dex PC of `at_`. 283 const uint32_t dex_pc_; 284 285 // Whether to initialize the class. 286 const bool do_clinit_; 287 288 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86); 289}; 290 291class TypeCheckSlowPathX86 : public SlowPathCode { 292 public: 293 TypeCheckSlowPathX86(HInstruction* instruction, bool is_fatal) 294 : instruction_(instruction), is_fatal_(is_fatal) {} 295 296 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 297 LocationSummary* locations = instruction_->GetLocations(); 298 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0) 299 : locations->Out(); 300 DCHECK(instruction_->IsCheckCast() 301 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 302 303 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 304 __ Bind(GetEntryLabel()); 305 306 if (!is_fatal_) { 307 SaveLiveRegisters(codegen, locations); 308 } 309 310 // We're moving two locations to locations that could overlap, so we need a parallel 311 // move resolver. 312 InvokeRuntimeCallingConvention calling_convention; 313 x86_codegen->EmitParallelMoves( 314 locations->InAt(1), 315 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 316 Primitive::kPrimNot, 317 object_class, 318 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), 319 Primitive::kPrimNot); 320 321 if (instruction_->IsInstanceOf()) { 322 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), 323 instruction_, 324 instruction_->GetDexPc(), 325 this); 326 CheckEntrypointTypes< 327 kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>(); 328 } else { 329 DCHECK(instruction_->IsCheckCast()); 330 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), 331 instruction_, 332 instruction_->GetDexPc(), 333 this); 334 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>(); 335 } 336 337 if (!is_fatal_) { 338 if (instruction_->IsInstanceOf()) { 339 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX)); 340 } 341 RestoreLiveRegisters(codegen, locations); 342 343 __ jmp(GetExitLabel()); 344 } 345 } 346 347 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathX86"; } 348 bool IsFatal() const OVERRIDE { return is_fatal_; } 349 350 private: 351 HInstruction* const instruction_; 352 const bool is_fatal_; 353 354 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86); 355}; 356 357class DeoptimizationSlowPathX86 : public SlowPathCode { 358 public: 359 explicit DeoptimizationSlowPathX86(HInstruction* instruction) 360 : instruction_(instruction) {} 361 362 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 363 DCHECK(instruction_->IsDeoptimize()); 364 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 365 __ Bind(GetEntryLabel()); 366 SaveLiveRegisters(codegen, instruction_->GetLocations()); 367 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), 368 instruction_, 369 instruction_->GetDexPc(), 370 this); 371 } 372 373 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathX86"; } 374 375 private: 376 HInstruction* const instruction_; 377 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86); 378}; 379 380class ArraySetSlowPathX86 : public SlowPathCode { 381 public: 382 explicit ArraySetSlowPathX86(HInstruction* instruction) : instruction_(instruction) {} 383 384 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 385 LocationSummary* locations = instruction_->GetLocations(); 386 __ Bind(GetEntryLabel()); 387 SaveLiveRegisters(codegen, locations); 388 389 InvokeRuntimeCallingConvention calling_convention; 390 HParallelMove parallel_move(codegen->GetGraph()->GetArena()); 391 parallel_move.AddMove( 392 locations->InAt(0), 393 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 394 Primitive::kPrimNot, 395 nullptr); 396 parallel_move.AddMove( 397 locations->InAt(1), 398 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), 399 Primitive::kPrimInt, 400 nullptr); 401 parallel_move.AddMove( 402 locations->InAt(2), 403 Location::RegisterLocation(calling_convention.GetRegisterAt(2)), 404 Primitive::kPrimNot, 405 nullptr); 406 codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); 407 408 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 409 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), 410 instruction_, 411 instruction_->GetDexPc(), 412 this); 413 RestoreLiveRegisters(codegen, locations); 414 __ jmp(GetExitLabel()); 415 } 416 417 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathX86"; } 418 419 private: 420 HInstruction* const instruction_; 421 422 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathX86); 423}; 424 425// Slow path generating a read barrier for a heap reference. 426class ReadBarrierForHeapReferenceSlowPathX86 : public SlowPathCode { 427 public: 428 ReadBarrierForHeapReferenceSlowPathX86(HInstruction* instruction, 429 Location out, 430 Location ref, 431 Location obj, 432 uint32_t offset, 433 Location index) 434 : instruction_(instruction), 435 out_(out), 436 ref_(ref), 437 obj_(obj), 438 offset_(offset), 439 index_(index) { 440 DCHECK(kEmitCompilerReadBarrier); 441 // If `obj` is equal to `out` or `ref`, it means the initial object 442 // has been overwritten by (or after) the heap object reference load 443 // to be instrumented, e.g.: 444 // 445 // __ movl(out, Address(out, offset)); 446 // codegen_->GenerateReadBarrier(instruction, out_loc, out_loc, out_loc, offset); 447 // 448 // In that case, we have lost the information about the original 449 // object, and the emitted read barrier cannot work properly. 450 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out; 451 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref; 452 } 453 454 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 455 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 456 LocationSummary* locations = instruction_->GetLocations(); 457 Register reg_out = out_.AsRegister<Register>(); 458 DCHECK(locations->CanCall()); 459 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out)); 460 DCHECK(!instruction_->IsInvoke() || 461 (instruction_->IsInvokeStaticOrDirect() && 462 instruction_->GetLocations()->Intrinsified())); 463 464 __ Bind(GetEntryLabel()); 465 SaveLiveRegisters(codegen, locations); 466 467 // We may have to change the index's value, but as `index_` is a 468 // constant member (like other "inputs" of this slow path), 469 // introduce a copy of it, `index`. 470 Location index = index_; 471 if (index_.IsValid()) { 472 // Handle `index_` for HArrayGet and intrinsic UnsafeGetObject. 473 if (instruction_->IsArrayGet()) { 474 // Compute the actual memory offset and store it in `index`. 475 Register index_reg = index_.AsRegister<Register>(); 476 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg)); 477 if (codegen->IsCoreCalleeSaveRegister(index_reg)) { 478 // We are about to change the value of `index_reg` (see the 479 // calls to art::x86::X86Assembler::shll and 480 // art::x86::X86Assembler::AddImmediate below), but it has 481 // not been saved by the previous call to 482 // art::SlowPathCode::SaveLiveRegisters, as it is a 483 // callee-save register -- 484 // art::SlowPathCode::SaveLiveRegisters does not consider 485 // callee-save registers, as it has been designed with the 486 // assumption that callee-save registers are supposed to be 487 // handled by the called function. So, as a callee-save 488 // register, `index_reg` _would_ eventually be saved onto 489 // the stack, but it would be too late: we would have 490 // changed its value earlier. Therefore, we manually save 491 // it here into another freely available register, 492 // `free_reg`, chosen of course among the caller-save 493 // registers (as a callee-save `free_reg` register would 494 // exhibit the same problem). 495 // 496 // Note we could have requested a temporary register from 497 // the register allocator instead; but we prefer not to, as 498 // this is a slow path, and we know we can find a 499 // caller-save register that is available. 500 Register free_reg = FindAvailableCallerSaveRegister(codegen); 501 __ movl(free_reg, index_reg); 502 index_reg = free_reg; 503 index = Location::RegisterLocation(index_reg); 504 } else { 505 // The initial register stored in `index_` has already been 506 // saved in the call to art::SlowPathCode::SaveLiveRegisters 507 // (as it is not a callee-save register), so we can freely 508 // use it. 509 } 510 // Shifting the index value contained in `index_reg` by the scale 511 // factor (2) cannot overflow in practice, as the runtime is 512 // unable to allocate object arrays with a size larger than 513 // 2^26 - 1 (that is, 2^28 - 4 bytes). 514 __ shll(index_reg, Immediate(TIMES_4)); 515 static_assert( 516 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), 517 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); 518 __ AddImmediate(index_reg, Immediate(offset_)); 519 } else { 520 DCHECK(instruction_->IsInvoke()); 521 DCHECK(instruction_->GetLocations()->Intrinsified()); 522 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) || 523 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile)) 524 << instruction_->AsInvoke()->GetIntrinsic(); 525 DCHECK_EQ(offset_, 0U); 526 DCHECK(index_.IsRegisterPair()); 527 // UnsafeGet's offset location is a register pair, the low 528 // part contains the correct offset. 529 index = index_.ToLow(); 530 } 531 } 532 533 // We're moving two or three locations to locations that could 534 // overlap, so we need a parallel move resolver. 535 InvokeRuntimeCallingConvention calling_convention; 536 HParallelMove parallel_move(codegen->GetGraph()->GetArena()); 537 parallel_move.AddMove(ref_, 538 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 539 Primitive::kPrimNot, 540 nullptr); 541 parallel_move.AddMove(obj_, 542 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), 543 Primitive::kPrimNot, 544 nullptr); 545 if (index.IsValid()) { 546 parallel_move.AddMove(index, 547 Location::RegisterLocation(calling_convention.GetRegisterAt(2)), 548 Primitive::kPrimInt, 549 nullptr); 550 codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); 551 } else { 552 codegen->GetMoveResolver()->EmitNativeCode(¶llel_move); 553 __ movl(calling_convention.GetRegisterAt(2), Immediate(offset_)); 554 } 555 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierSlow), 556 instruction_, 557 instruction_->GetDexPc(), 558 this); 559 CheckEntrypointTypes< 560 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>(); 561 x86_codegen->Move32(out_, Location::RegisterLocation(EAX)); 562 563 RestoreLiveRegisters(codegen, locations); 564 __ jmp(GetExitLabel()); 565 } 566 567 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathX86"; } 568 569 private: 570 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) { 571 size_t ref = static_cast<int>(ref_.AsRegister<Register>()); 572 size_t obj = static_cast<int>(obj_.AsRegister<Register>()); 573 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) { 574 if (i != ref && i != obj && !codegen->IsCoreCalleeSaveRegister(i)) { 575 return static_cast<Register>(i); 576 } 577 } 578 // We shall never fail to find a free caller-save register, as 579 // there are more than two core caller-save registers on x86 580 // (meaning it is possible to find one which is different from 581 // `ref` and `obj`). 582 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u); 583 LOG(FATAL) << "Could not find a free caller-save register"; 584 UNREACHABLE(); 585 } 586 587 HInstruction* const instruction_; 588 const Location out_; 589 const Location ref_; 590 const Location obj_; 591 const uint32_t offset_; 592 // An additional location containing an index to an array. 593 // Only used for HArrayGet and the UnsafeGetObject & 594 // UnsafeGetObjectVolatile intrinsics. 595 const Location index_; 596 597 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathX86); 598}; 599 600// Slow path generating a read barrier for a GC root. 601class ReadBarrierForRootSlowPathX86 : public SlowPathCode { 602 public: 603 ReadBarrierForRootSlowPathX86(HInstruction* instruction, Location out, Location root) 604 : instruction_(instruction), out_(out), root_(root) {} 605 606 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 607 LocationSummary* locations = instruction_->GetLocations(); 608 Register reg_out = out_.AsRegister<Register>(); 609 DCHECK(locations->CanCall()); 610 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out)); 611 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString()); 612 613 __ Bind(GetEntryLabel()); 614 SaveLiveRegisters(codegen, locations); 615 616 InvokeRuntimeCallingConvention calling_convention; 617 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); 618 x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_); 619 x86_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pReadBarrierForRootSlow), 620 instruction_, 621 instruction_->GetDexPc(), 622 this); 623 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>(); 624 x86_codegen->Move32(out_, Location::RegisterLocation(EAX)); 625 626 RestoreLiveRegisters(codegen, locations); 627 __ jmp(GetExitLabel()); 628 } 629 630 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathX86"; } 631 632 private: 633 HInstruction* const instruction_; 634 const Location out_; 635 const Location root_; 636 637 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathX86); 638}; 639 640#undef __ 641#define __ down_cast<X86Assembler*>(GetAssembler())-> 642 643inline Condition X86Condition(IfCondition cond) { 644 switch (cond) { 645 case kCondEQ: return kEqual; 646 case kCondNE: return kNotEqual; 647 case kCondLT: return kLess; 648 case kCondLE: return kLessEqual; 649 case kCondGT: return kGreater; 650 case kCondGE: return kGreaterEqual; 651 case kCondB: return kBelow; 652 case kCondBE: return kBelowEqual; 653 case kCondA: return kAbove; 654 case kCondAE: return kAboveEqual; 655 } 656 LOG(FATAL) << "Unreachable"; 657 UNREACHABLE(); 658} 659 660// Maps signed condition to unsigned condition and FP condition to x86 name. 661inline Condition X86UnsignedOrFPCondition(IfCondition cond) { 662 switch (cond) { 663 case kCondEQ: return kEqual; 664 case kCondNE: return kNotEqual; 665 // Signed to unsigned, and FP to x86 name. 666 case kCondLT: return kBelow; 667 case kCondLE: return kBelowEqual; 668 case kCondGT: return kAbove; 669 case kCondGE: return kAboveEqual; 670 // Unsigned remain unchanged. 671 case kCondB: return kBelow; 672 case kCondBE: return kBelowEqual; 673 case kCondA: return kAbove; 674 case kCondAE: return kAboveEqual; 675 } 676 LOG(FATAL) << "Unreachable"; 677 UNREACHABLE(); 678} 679 680void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const { 681 stream << Register(reg); 682} 683 684void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 685 stream << XmmRegister(reg); 686} 687 688size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { 689 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id)); 690 return kX86WordSize; 691} 692 693size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) { 694 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index)); 695 return kX86WordSize; 696} 697 698size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) { 699 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id)); 700 return GetFloatingPointSpillSlotSize(); 701} 702 703size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) { 704 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index)); 705 return GetFloatingPointSpillSlotSize(); 706} 707 708void CodeGeneratorX86::InvokeRuntime(QuickEntrypointEnum entrypoint, 709 HInstruction* instruction, 710 uint32_t dex_pc, 711 SlowPathCode* slow_path) { 712 InvokeRuntime(GetThreadOffset<kX86WordSize>(entrypoint).Int32Value(), 713 instruction, 714 dex_pc, 715 slow_path); 716} 717 718void CodeGeneratorX86::InvokeRuntime(int32_t entry_point_offset, 719 HInstruction* instruction, 720 uint32_t dex_pc, 721 SlowPathCode* slow_path) { 722 ValidateInvokeRuntime(instruction, slow_path); 723 __ fs()->call(Address::Absolute(entry_point_offset)); 724 RecordPcInfo(instruction, dex_pc, slow_path); 725} 726 727CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, 728 const X86InstructionSetFeatures& isa_features, 729 const CompilerOptions& compiler_options, 730 OptimizingCompilerStats* stats) 731 : CodeGenerator(graph, 732 kNumberOfCpuRegisters, 733 kNumberOfXmmRegisters, 734 kNumberOfRegisterPairs, 735 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves), 736 arraysize(kCoreCalleeSaves)) 737 | (1 << kFakeReturnRegister), 738 0, 739 compiler_options, 740 stats), 741 block_labels_(nullptr), 742 location_builder_(graph, this), 743 instruction_visitor_(graph, this), 744 move_resolver_(graph->GetArena(), this), 745 isa_features_(isa_features), 746 method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), 747 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), 748 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), 749 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) { 750 // Use a fake return address register to mimic Quick. 751 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister)); 752} 753 754Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const { 755 switch (type) { 756 case Primitive::kPrimLong: { 757 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs); 758 X86ManagedRegister pair = 759 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 760 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]); 761 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]); 762 blocked_core_registers_[pair.AsRegisterPairLow()] = true; 763 blocked_core_registers_[pair.AsRegisterPairHigh()] = true; 764 UpdateBlockedPairRegisters(); 765 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 766 } 767 768 case Primitive::kPrimByte: 769 case Primitive::kPrimBoolean: 770 case Primitive::kPrimChar: 771 case Primitive::kPrimShort: 772 case Primitive::kPrimInt: 773 case Primitive::kPrimNot: { 774 Register reg = static_cast<Register>( 775 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters)); 776 // Block all register pairs that contain `reg`. 777 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 778 X86ManagedRegister current = 779 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 780 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) { 781 blocked_register_pairs_[i] = true; 782 } 783 } 784 return Location::RegisterLocation(reg); 785 } 786 787 case Primitive::kPrimFloat: 788 case Primitive::kPrimDouble: { 789 return Location::FpuRegisterLocation( 790 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters)); 791 } 792 793 case Primitive::kPrimVoid: 794 LOG(FATAL) << "Unreachable type " << type; 795 } 796 797 return Location::NoLocation(); 798} 799 800void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const { 801 // Don't allocate the dalvik style register pair passing. 802 blocked_register_pairs_[ECX_EDX] = true; 803 804 // Stack register is always reserved. 805 blocked_core_registers_[ESP] = true; 806 807 if (is_baseline) { 808 blocked_core_registers_[EBP] = true; 809 blocked_core_registers_[ESI] = true; 810 blocked_core_registers_[EDI] = true; 811 } 812 813 UpdateBlockedPairRegisters(); 814} 815 816void CodeGeneratorX86::UpdateBlockedPairRegisters() const { 817 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 818 X86ManagedRegister current = 819 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 820 if (blocked_core_registers_[current.AsRegisterPairLow()] 821 || blocked_core_registers_[current.AsRegisterPairHigh()]) { 822 blocked_register_pairs_[i] = true; 823 } 824 } 825} 826 827InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen) 828 : HGraphVisitor(graph), 829 assembler_(codegen->GetAssembler()), 830 codegen_(codegen) {} 831 832static dwarf::Reg DWARFReg(Register reg) { 833 return dwarf::Reg::X86Core(static_cast<int>(reg)); 834} 835 836void CodeGeneratorX86::GenerateFrameEntry() { 837 __ cfi().SetCurrentCFAOffset(kX86WordSize); // return address 838 __ Bind(&frame_entry_label_); 839 bool skip_overflow_check = 840 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86); 841 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks()); 842 843 if (!skip_overflow_check) { 844 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86)))); 845 RecordPcInfo(nullptr, 0); 846 } 847 848 if (HasEmptyFrame()) { 849 return; 850 } 851 852 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) { 853 Register reg = kCoreCalleeSaves[i]; 854 if (allocated_registers_.ContainsCoreRegister(reg)) { 855 __ pushl(reg); 856 __ cfi().AdjustCFAOffset(kX86WordSize); 857 __ cfi().RelOffset(DWARFReg(reg), 0); 858 } 859 } 860 861 int adjust = GetFrameSize() - FrameEntrySpillSize(); 862 __ subl(ESP, Immediate(adjust)); 863 __ cfi().AdjustCFAOffset(adjust); 864 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument); 865} 866 867void CodeGeneratorX86::GenerateFrameExit() { 868 __ cfi().RememberState(); 869 if (!HasEmptyFrame()) { 870 int adjust = GetFrameSize() - FrameEntrySpillSize(); 871 __ addl(ESP, Immediate(adjust)); 872 __ cfi().AdjustCFAOffset(-adjust); 873 874 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) { 875 Register reg = kCoreCalleeSaves[i]; 876 if (allocated_registers_.ContainsCoreRegister(reg)) { 877 __ popl(reg); 878 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize)); 879 __ cfi().Restore(DWARFReg(reg)); 880 } 881 } 882 } 883 __ ret(); 884 __ cfi().RestoreState(); 885 __ cfi().DefCFAOffset(GetFrameSize()); 886} 887 888void CodeGeneratorX86::Bind(HBasicBlock* block) { 889 __ Bind(GetLabelOf(block)); 890} 891 892Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const { 893 switch (load->GetType()) { 894 case Primitive::kPrimLong: 895 case Primitive::kPrimDouble: 896 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 897 898 case Primitive::kPrimInt: 899 case Primitive::kPrimNot: 900 case Primitive::kPrimFloat: 901 return Location::StackSlot(GetStackSlot(load->GetLocal())); 902 903 case Primitive::kPrimBoolean: 904 case Primitive::kPrimByte: 905 case Primitive::kPrimChar: 906 case Primitive::kPrimShort: 907 case Primitive::kPrimVoid: 908 LOG(FATAL) << "Unexpected type " << load->GetType(); 909 UNREACHABLE(); 910 } 911 912 LOG(FATAL) << "Unreachable"; 913 UNREACHABLE(); 914} 915 916Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const { 917 switch (type) { 918 case Primitive::kPrimBoolean: 919 case Primitive::kPrimByte: 920 case Primitive::kPrimChar: 921 case Primitive::kPrimShort: 922 case Primitive::kPrimInt: 923 case Primitive::kPrimNot: 924 return Location::RegisterLocation(EAX); 925 926 case Primitive::kPrimLong: 927 return Location::RegisterPairLocation(EAX, EDX); 928 929 case Primitive::kPrimVoid: 930 return Location::NoLocation(); 931 932 case Primitive::kPrimDouble: 933 case Primitive::kPrimFloat: 934 return Location::FpuRegisterLocation(XMM0); 935 } 936 937 UNREACHABLE(); 938} 939 940Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const { 941 return Location::RegisterLocation(kMethodRegisterArgument); 942} 943 944Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) { 945 switch (type) { 946 case Primitive::kPrimBoolean: 947 case Primitive::kPrimByte: 948 case Primitive::kPrimChar: 949 case Primitive::kPrimShort: 950 case Primitive::kPrimInt: 951 case Primitive::kPrimNot: { 952 uint32_t index = gp_index_++; 953 stack_index_++; 954 if (index < calling_convention.GetNumberOfRegisters()) { 955 return Location::RegisterLocation(calling_convention.GetRegisterAt(index)); 956 } else { 957 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1)); 958 } 959 } 960 961 case Primitive::kPrimLong: { 962 uint32_t index = gp_index_; 963 gp_index_ += 2; 964 stack_index_ += 2; 965 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 966 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair( 967 calling_convention.GetRegisterPairAt(index)); 968 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 969 } else { 970 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2)); 971 } 972 } 973 974 case Primitive::kPrimFloat: { 975 uint32_t index = float_index_++; 976 stack_index_++; 977 if (index < calling_convention.GetNumberOfFpuRegisters()) { 978 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index)); 979 } else { 980 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1)); 981 } 982 } 983 984 case Primitive::kPrimDouble: { 985 uint32_t index = float_index_++; 986 stack_index_ += 2; 987 if (index < calling_convention.GetNumberOfFpuRegisters()) { 988 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index)); 989 } else { 990 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2)); 991 } 992 } 993 994 case Primitive::kPrimVoid: 995 LOG(FATAL) << "Unexpected parameter type " << type; 996 break; 997 } 998 return Location::NoLocation(); 999} 1000 1001void CodeGeneratorX86::Move32(Location destination, Location source) { 1002 if (source.Equals(destination)) { 1003 return; 1004 } 1005 if (destination.IsRegister()) { 1006 if (source.IsRegister()) { 1007 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>()); 1008 } else if (source.IsFpuRegister()) { 1009 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>()); 1010 } else { 1011 DCHECK(source.IsStackSlot()); 1012 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex())); 1013 } 1014 } else if (destination.IsFpuRegister()) { 1015 if (source.IsRegister()) { 1016 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>()); 1017 } else if (source.IsFpuRegister()) { 1018 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 1019 } else { 1020 DCHECK(source.IsStackSlot()); 1021 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 1022 } 1023 } else { 1024 DCHECK(destination.IsStackSlot()) << destination; 1025 if (source.IsRegister()) { 1026 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>()); 1027 } else if (source.IsFpuRegister()) { 1028 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 1029 } else if (source.IsConstant()) { 1030 HConstant* constant = source.GetConstant(); 1031 int32_t value = GetInt32ValueOf(constant); 1032 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value)); 1033 } else { 1034 DCHECK(source.IsStackSlot()); 1035 __ pushl(Address(ESP, source.GetStackIndex())); 1036 __ popl(Address(ESP, destination.GetStackIndex())); 1037 } 1038 } 1039} 1040 1041void CodeGeneratorX86::Move64(Location destination, Location source) { 1042 if (source.Equals(destination)) { 1043 return; 1044 } 1045 if (destination.IsRegisterPair()) { 1046 if (source.IsRegisterPair()) { 1047 EmitParallelMoves( 1048 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()), 1049 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()), 1050 Primitive::kPrimInt, 1051 Location::RegisterLocation(source.AsRegisterPairLow<Register>()), 1052 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()), 1053 Primitive::kPrimInt); 1054 } else if (source.IsFpuRegister()) { 1055 XmmRegister src_reg = source.AsFpuRegister<XmmRegister>(); 1056 __ movd(destination.AsRegisterPairLow<Register>(), src_reg); 1057 __ psrlq(src_reg, Immediate(32)); 1058 __ movd(destination.AsRegisterPairHigh<Register>(), src_reg); 1059 } else { 1060 // No conflict possible, so just do the moves. 1061 DCHECK(source.IsDoubleStackSlot()); 1062 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex())); 1063 __ movl(destination.AsRegisterPairHigh<Register>(), 1064 Address(ESP, source.GetHighStackIndex(kX86WordSize))); 1065 } 1066 } else if (destination.IsFpuRegister()) { 1067 if (source.IsFpuRegister()) { 1068 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 1069 } else if (source.IsDoubleStackSlot()) { 1070 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 1071 } else if (source.IsRegisterPair()) { 1072 size_t elem_size = Primitive::ComponentSize(Primitive::kPrimInt); 1073 // Create stack space for 2 elements. 1074 __ subl(ESP, Immediate(2 * elem_size)); 1075 __ movl(Address(ESP, 0), source.AsRegisterPairLow<Register>()); 1076 __ movl(Address(ESP, elem_size), source.AsRegisterPairHigh<Register>()); 1077 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0)); 1078 // And remove the temporary stack space we allocated. 1079 __ addl(ESP, Immediate(2 * elem_size)); 1080 } else { 1081 LOG(FATAL) << "Unimplemented"; 1082 } 1083 } else { 1084 DCHECK(destination.IsDoubleStackSlot()) << destination; 1085 if (source.IsRegisterPair()) { 1086 // No conflict possible, so just do the moves. 1087 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>()); 1088 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), 1089 source.AsRegisterPairHigh<Register>()); 1090 } else if (source.IsFpuRegister()) { 1091 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 1092 } else if (source.IsConstant()) { 1093 HConstant* constant = source.GetConstant(); 1094 int64_t value; 1095 if (constant->IsLongConstant()) { 1096 value = constant->AsLongConstant()->GetValue(); 1097 } else { 1098 DCHECK(constant->IsDoubleConstant()); 1099 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue()); 1100 } 1101 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value))); 1102 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value))); 1103 } else { 1104 DCHECK(source.IsDoubleStackSlot()) << source; 1105 EmitParallelMoves( 1106 Location::StackSlot(source.GetStackIndex()), 1107 Location::StackSlot(destination.GetStackIndex()), 1108 Primitive::kPrimInt, 1109 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)), 1110 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)), 1111 Primitive::kPrimInt); 1112 } 1113 } 1114} 1115 1116void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 1117 LocationSummary* locations = instruction->GetLocations(); 1118 if (instruction->IsCurrentMethod()) { 1119 Move32(location, Location::StackSlot(kCurrentMethodStackOffset)); 1120 } else if (locations != nullptr && locations->Out().Equals(location)) { 1121 return; 1122 } else if (locations != nullptr && locations->Out().IsConstant()) { 1123 HConstant* const_to_move = locations->Out().GetConstant(); 1124 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) { 1125 Immediate imm(GetInt32ValueOf(const_to_move)); 1126 if (location.IsRegister()) { 1127 __ movl(location.AsRegister<Register>(), imm); 1128 } else if (location.IsStackSlot()) { 1129 __ movl(Address(ESP, location.GetStackIndex()), imm); 1130 } else { 1131 DCHECK(location.IsConstant()); 1132 DCHECK_EQ(location.GetConstant(), const_to_move); 1133 } 1134 } else if (const_to_move->IsLongConstant()) { 1135 int64_t value = const_to_move->AsLongConstant()->GetValue(); 1136 if (location.IsRegisterPair()) { 1137 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value))); 1138 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value))); 1139 } else if (location.IsDoubleStackSlot()) { 1140 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value))); 1141 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), 1142 Immediate(High32Bits(value))); 1143 } else { 1144 DCHECK(location.IsConstant()); 1145 DCHECK_EQ(location.GetConstant(), instruction); 1146 } 1147 } 1148 } else if (instruction->IsTemporary()) { 1149 Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); 1150 if (temp_location.IsStackSlot()) { 1151 Move32(location, temp_location); 1152 } else { 1153 DCHECK(temp_location.IsDoubleStackSlot()); 1154 Move64(location, temp_location); 1155 } 1156 } else if (instruction->IsLoadLocal()) { 1157 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 1158 switch (instruction->GetType()) { 1159 case Primitive::kPrimBoolean: 1160 case Primitive::kPrimByte: 1161 case Primitive::kPrimChar: 1162 case Primitive::kPrimShort: 1163 case Primitive::kPrimInt: 1164 case Primitive::kPrimNot: 1165 case Primitive::kPrimFloat: 1166 Move32(location, Location::StackSlot(slot)); 1167 break; 1168 1169 case Primitive::kPrimLong: 1170 case Primitive::kPrimDouble: 1171 Move64(location, Location::DoubleStackSlot(slot)); 1172 break; 1173 1174 default: 1175 LOG(FATAL) << "Unimplemented local type " << instruction->GetType(); 1176 } 1177 } else { 1178 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 1179 switch (instruction->GetType()) { 1180 case Primitive::kPrimBoolean: 1181 case Primitive::kPrimByte: 1182 case Primitive::kPrimChar: 1183 case Primitive::kPrimShort: 1184 case Primitive::kPrimInt: 1185 case Primitive::kPrimNot: 1186 case Primitive::kPrimFloat: 1187 Move32(location, locations->Out()); 1188 break; 1189 1190 case Primitive::kPrimLong: 1191 case Primitive::kPrimDouble: 1192 Move64(location, locations->Out()); 1193 break; 1194 1195 default: 1196 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 1197 } 1198 } 1199} 1200 1201void CodeGeneratorX86::MoveConstant(Location location, int32_t value) { 1202 DCHECK(location.IsRegister()); 1203 __ movl(location.AsRegister<Register>(), Immediate(value)); 1204} 1205 1206void CodeGeneratorX86::MoveLocation(Location dst, Location src, Primitive::Type dst_type) { 1207 if (Primitive::Is64BitType(dst_type)) { 1208 Move64(dst, src); 1209 } else { 1210 Move32(dst, src); 1211 } 1212} 1213 1214void CodeGeneratorX86::AddLocationAsTemp(Location location, LocationSummary* locations) { 1215 if (location.IsRegister()) { 1216 locations->AddTemp(location); 1217 } else if (location.IsRegisterPair()) { 1218 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>())); 1219 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>())); 1220 } else { 1221 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location; 1222 } 1223} 1224 1225void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) { 1226 DCHECK(!successor->IsExitBlock()); 1227 1228 HBasicBlock* block = got->GetBlock(); 1229 HInstruction* previous = got->GetPrevious(); 1230 1231 HLoopInformation* info = block->GetLoopInformation(); 1232 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { 1233 GenerateSuspendCheck(info->GetSuspendCheck(), successor); 1234 return; 1235 } 1236 1237 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) { 1238 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr); 1239 } 1240 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 1241 __ jmp(codegen_->GetLabelOf(successor)); 1242 } 1243} 1244 1245void LocationsBuilderX86::VisitGoto(HGoto* got) { 1246 got->SetLocations(nullptr); 1247} 1248 1249void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) { 1250 HandleGoto(got, got->GetSuccessor()); 1251} 1252 1253void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) { 1254 try_boundary->SetLocations(nullptr); 1255} 1256 1257void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) { 1258 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor(); 1259 if (!successor->IsExitBlock()) { 1260 HandleGoto(try_boundary, successor); 1261 } 1262} 1263 1264void LocationsBuilderX86::VisitExit(HExit* exit) { 1265 exit->SetLocations(nullptr); 1266} 1267 1268void InstructionCodeGeneratorX86::VisitExit(HExit* exit ATTRIBUTE_UNUSED) { 1269} 1270 1271void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond, 1272 Label* true_label, 1273 Label* false_label) { 1274 if (cond->IsFPConditionTrueIfNaN()) { 1275 __ j(kUnordered, true_label); 1276 } else if (cond->IsFPConditionFalseIfNaN()) { 1277 __ j(kUnordered, false_label); 1278 } 1279 __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label); 1280} 1281 1282void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond, 1283 Label* true_label, 1284 Label* false_label) { 1285 LocationSummary* locations = cond->GetLocations(); 1286 Location left = locations->InAt(0); 1287 Location right = locations->InAt(1); 1288 IfCondition if_cond = cond->GetCondition(); 1289 1290 Register left_high = left.AsRegisterPairHigh<Register>(); 1291 Register left_low = left.AsRegisterPairLow<Register>(); 1292 IfCondition true_high_cond = if_cond; 1293 IfCondition false_high_cond = cond->GetOppositeCondition(); 1294 Condition final_condition = X86UnsignedOrFPCondition(if_cond); // unsigned on lower part 1295 1296 // Set the conditions for the test, remembering that == needs to be 1297 // decided using the low words. 1298 switch (if_cond) { 1299 case kCondEQ: 1300 case kCondNE: 1301 // Nothing to do. 1302 break; 1303 case kCondLT: 1304 false_high_cond = kCondGT; 1305 break; 1306 case kCondLE: 1307 true_high_cond = kCondLT; 1308 break; 1309 case kCondGT: 1310 false_high_cond = kCondLT; 1311 break; 1312 case kCondGE: 1313 true_high_cond = kCondGT; 1314 break; 1315 case kCondB: 1316 false_high_cond = kCondA; 1317 break; 1318 case kCondBE: 1319 true_high_cond = kCondB; 1320 break; 1321 case kCondA: 1322 false_high_cond = kCondB; 1323 break; 1324 case kCondAE: 1325 true_high_cond = kCondA; 1326 break; 1327 } 1328 1329 if (right.IsConstant()) { 1330 int64_t value = right.GetConstant()->AsLongConstant()->GetValue(); 1331 int32_t val_high = High32Bits(value); 1332 int32_t val_low = Low32Bits(value); 1333 1334 if (val_high == 0) { 1335 __ testl(left_high, left_high); 1336 } else { 1337 __ cmpl(left_high, Immediate(val_high)); 1338 } 1339 if (if_cond == kCondNE) { 1340 __ j(X86Condition(true_high_cond), true_label); 1341 } else if (if_cond == kCondEQ) { 1342 __ j(X86Condition(false_high_cond), false_label); 1343 } else { 1344 __ j(X86Condition(true_high_cond), true_label); 1345 __ j(X86Condition(false_high_cond), false_label); 1346 } 1347 // Must be equal high, so compare the lows. 1348 if (val_low == 0) { 1349 __ testl(left_low, left_low); 1350 } else { 1351 __ cmpl(left_low, Immediate(val_low)); 1352 } 1353 } else { 1354 Register right_high = right.AsRegisterPairHigh<Register>(); 1355 Register right_low = right.AsRegisterPairLow<Register>(); 1356 1357 __ cmpl(left_high, right_high); 1358 if (if_cond == kCondNE) { 1359 __ j(X86Condition(true_high_cond), true_label); 1360 } else if (if_cond == kCondEQ) { 1361 __ j(X86Condition(false_high_cond), false_label); 1362 } else { 1363 __ j(X86Condition(true_high_cond), true_label); 1364 __ j(X86Condition(false_high_cond), false_label); 1365 } 1366 // Must be equal high, so compare the lows. 1367 __ cmpl(left_low, right_low); 1368 } 1369 // The last comparison might be unsigned. 1370 __ j(final_condition, true_label); 1371} 1372 1373void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HCondition* condition, 1374 Label* true_target_in, 1375 Label* false_target_in) { 1376 // Generated branching requires both targets to be explicit. If either of the 1377 // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead. 1378 Label fallthrough_target; 1379 Label* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in; 1380 Label* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in; 1381 1382 LocationSummary* locations = condition->GetLocations(); 1383 Location left = locations->InAt(0); 1384 Location right = locations->InAt(1); 1385 1386 Primitive::Type type = condition->InputAt(0)->GetType(); 1387 switch (type) { 1388 case Primitive::kPrimLong: 1389 GenerateLongComparesAndJumps(condition, true_target, false_target); 1390 break; 1391 case Primitive::kPrimFloat: 1392 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); 1393 GenerateFPJumps(condition, true_target, false_target); 1394 break; 1395 case Primitive::kPrimDouble: 1396 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); 1397 GenerateFPJumps(condition, true_target, false_target); 1398 break; 1399 default: 1400 LOG(FATAL) << "Unexpected compare type " << type; 1401 } 1402 1403 if (false_target != &fallthrough_target) { 1404 __ jmp(false_target); 1405 } 1406 1407 if (fallthrough_target.IsLinked()) { 1408 __ Bind(&fallthrough_target); 1409 } 1410} 1411 1412static bool AreEflagsSetFrom(HInstruction* cond, HInstruction* branch) { 1413 // Moves may affect the eflags register (move zero uses xorl), so the EFLAGS 1414 // are set only strictly before `branch`. We can't use the eflags on long/FP 1415 // conditions if they are materialized due to the complex branching. 1416 return cond->IsCondition() && 1417 cond->GetNext() == branch && 1418 cond->InputAt(0)->GetType() != Primitive::kPrimLong && 1419 !Primitive::IsFloatingPointType(cond->InputAt(0)->GetType()); 1420} 1421 1422void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction, 1423 size_t condition_input_index, 1424 Label* true_target, 1425 Label* false_target) { 1426 HInstruction* cond = instruction->InputAt(condition_input_index); 1427 1428 if (true_target == nullptr && false_target == nullptr) { 1429 // Nothing to do. The code always falls through. 1430 return; 1431 } else if (cond->IsIntConstant()) { 1432 // Constant condition, statically compared against 1. 1433 if (cond->AsIntConstant()->IsOne()) { 1434 if (true_target != nullptr) { 1435 __ jmp(true_target); 1436 } 1437 } else { 1438 DCHECK(cond->AsIntConstant()->IsZero()); 1439 if (false_target != nullptr) { 1440 __ jmp(false_target); 1441 } 1442 } 1443 return; 1444 } 1445 1446 // The following code generates these patterns: 1447 // (1) true_target == nullptr && false_target != nullptr 1448 // - opposite condition true => branch to false_target 1449 // (2) true_target != nullptr && false_target == nullptr 1450 // - condition true => branch to true_target 1451 // (3) true_target != nullptr && false_target != nullptr 1452 // - condition true => branch to true_target 1453 // - branch to false_target 1454 if (IsBooleanValueOrMaterializedCondition(cond)) { 1455 if (AreEflagsSetFrom(cond, instruction)) { 1456 if (true_target == nullptr) { 1457 __ j(X86Condition(cond->AsCondition()->GetOppositeCondition()), false_target); 1458 } else { 1459 __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target); 1460 } 1461 } else { 1462 // Materialized condition, compare against 0. 1463 Location lhs = instruction->GetLocations()->InAt(condition_input_index); 1464 if (lhs.IsRegister()) { 1465 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); 1466 } else { 1467 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0)); 1468 } 1469 if (true_target == nullptr) { 1470 __ j(kEqual, false_target); 1471 } else { 1472 __ j(kNotEqual, true_target); 1473 } 1474 } 1475 } else { 1476 // Condition has not been materialized, use its inputs as the comparison and 1477 // its condition as the branch condition. 1478 HCondition* condition = cond->AsCondition(); 1479 1480 // If this is a long or FP comparison that has been folded into 1481 // the HCondition, generate the comparison directly. 1482 Primitive::Type type = condition->InputAt(0)->GetType(); 1483 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) { 1484 GenerateCompareTestAndBranch(condition, true_target, false_target); 1485 return; 1486 } 1487 1488 Location lhs = condition->GetLocations()->InAt(0); 1489 Location rhs = condition->GetLocations()->InAt(1); 1490 // LHS is guaranteed to be in a register (see LocationsBuilderX86::VisitCondition). 1491 if (rhs.IsRegister()) { 1492 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>()); 1493 } else if (rhs.IsConstant()) { 1494 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()); 1495 if (constant == 0) { 1496 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); 1497 } else { 1498 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant)); 1499 } 1500 } else { 1501 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); 1502 } 1503 if (true_target == nullptr) { 1504 __ j(X86Condition(condition->GetOppositeCondition()), false_target); 1505 } else { 1506 __ j(X86Condition(condition->GetCondition()), true_target); 1507 } 1508 } 1509 1510 // If neither branch falls through (case 3), the conditional branch to `true_target` 1511 // was already emitted (case 2) and we need to emit a jump to `false_target`. 1512 if (true_target != nullptr && false_target != nullptr) { 1513 __ jmp(false_target); 1514 } 1515} 1516 1517void LocationsBuilderX86::VisitIf(HIf* if_instr) { 1518 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); 1519 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) { 1520 locations->SetInAt(0, Location::Any()); 1521 } 1522} 1523 1524void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) { 1525 HBasicBlock* true_successor = if_instr->IfTrueSuccessor(); 1526 HBasicBlock* false_successor = if_instr->IfFalseSuccessor(); 1527 Label* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ? 1528 nullptr : codegen_->GetLabelOf(true_successor); 1529 Label* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ? 1530 nullptr : codegen_->GetLabelOf(false_successor); 1531 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target); 1532} 1533 1534void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) { 1535 LocationSummary* locations = new (GetGraph()->GetArena()) 1536 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath); 1537 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) { 1538 locations->SetInAt(0, Location::Any()); 1539 } 1540} 1541 1542void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) { 1543 SlowPathCode* slow_path = new (GetGraph()->GetArena()) 1544 DeoptimizationSlowPathX86(deoptimize); 1545 codegen_->AddSlowPath(slow_path); 1546 GenerateTestAndBranch(deoptimize, 1547 /* condition_input_index */ 0, 1548 slow_path->GetEntryLabel(), 1549 /* false_target */ nullptr); 1550} 1551 1552void LocationsBuilderX86::VisitLocal(HLocal* local) { 1553 local->SetLocations(nullptr); 1554} 1555 1556void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) { 1557 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 1558} 1559 1560void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) { 1561 local->SetLocations(nullptr); 1562} 1563 1564void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) { 1565 // Nothing to do, this is driven by the code generator. 1566} 1567 1568void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) { 1569 LocationSummary* locations = 1570 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 1571 switch (store->InputAt(1)->GetType()) { 1572 case Primitive::kPrimBoolean: 1573 case Primitive::kPrimByte: 1574 case Primitive::kPrimChar: 1575 case Primitive::kPrimShort: 1576 case Primitive::kPrimInt: 1577 case Primitive::kPrimNot: 1578 case Primitive::kPrimFloat: 1579 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1580 break; 1581 1582 case Primitive::kPrimLong: 1583 case Primitive::kPrimDouble: 1584 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1585 break; 1586 1587 default: 1588 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType(); 1589 } 1590} 1591 1592void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) { 1593} 1594 1595void LocationsBuilderX86::VisitCondition(HCondition* cond) { 1596 LocationSummary* locations = 1597 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall); 1598 // Handle the long/FP comparisons made in instruction simplification. 1599 switch (cond->InputAt(0)->GetType()) { 1600 case Primitive::kPrimLong: { 1601 locations->SetInAt(0, Location::RequiresRegister()); 1602 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1))); 1603 if (cond->NeedsMaterialization()) { 1604 locations->SetOut(Location::RequiresRegister()); 1605 } 1606 break; 1607 } 1608 case Primitive::kPrimFloat: 1609 case Primitive::kPrimDouble: { 1610 locations->SetInAt(0, Location::RequiresFpuRegister()); 1611 locations->SetInAt(1, Location::RequiresFpuRegister()); 1612 if (cond->NeedsMaterialization()) { 1613 locations->SetOut(Location::RequiresRegister()); 1614 } 1615 break; 1616 } 1617 default: 1618 locations->SetInAt(0, Location::RequiresRegister()); 1619 locations->SetInAt(1, Location::Any()); 1620 if (cond->NeedsMaterialization()) { 1621 // We need a byte register. 1622 locations->SetOut(Location::RegisterLocation(ECX)); 1623 } 1624 break; 1625 } 1626} 1627 1628void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) { 1629 if (!cond->NeedsMaterialization()) { 1630 return; 1631 } 1632 1633 LocationSummary* locations = cond->GetLocations(); 1634 Location lhs = locations->InAt(0); 1635 Location rhs = locations->InAt(1); 1636 Register reg = locations->Out().AsRegister<Register>(); 1637 Label true_label, false_label; 1638 1639 switch (cond->InputAt(0)->GetType()) { 1640 default: { 1641 // Integer case. 1642 1643 // Clear output register: setb only sets the low byte. 1644 __ xorl(reg, reg); 1645 1646 if (rhs.IsRegister()) { 1647 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>()); 1648 } else if (rhs.IsConstant()) { 1649 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant()); 1650 if (constant == 0) { 1651 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>()); 1652 } else { 1653 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant)); 1654 } 1655 } else { 1656 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex())); 1657 } 1658 __ setb(X86Condition(cond->GetCondition()), reg); 1659 return; 1660 } 1661 case Primitive::kPrimLong: 1662 GenerateLongComparesAndJumps(cond, &true_label, &false_label); 1663 break; 1664 case Primitive::kPrimFloat: 1665 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>()); 1666 GenerateFPJumps(cond, &true_label, &false_label); 1667 break; 1668 case Primitive::kPrimDouble: 1669 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>()); 1670 GenerateFPJumps(cond, &true_label, &false_label); 1671 break; 1672 } 1673 1674 // Convert the jumps into the result. 1675 NearLabel done_label; 1676 1677 // False case: result = 0. 1678 __ Bind(&false_label); 1679 __ xorl(reg, reg); 1680 __ jmp(&done_label); 1681 1682 // True case: result = 1. 1683 __ Bind(&true_label); 1684 __ movl(reg, Immediate(1)); 1685 __ Bind(&done_label); 1686} 1687 1688void LocationsBuilderX86::VisitEqual(HEqual* comp) { 1689 VisitCondition(comp); 1690} 1691 1692void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) { 1693 VisitCondition(comp); 1694} 1695 1696void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) { 1697 VisitCondition(comp); 1698} 1699 1700void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) { 1701 VisitCondition(comp); 1702} 1703 1704void LocationsBuilderX86::VisitLessThan(HLessThan* comp) { 1705 VisitCondition(comp); 1706} 1707 1708void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) { 1709 VisitCondition(comp); 1710} 1711 1712void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1713 VisitCondition(comp); 1714} 1715 1716void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1717 VisitCondition(comp); 1718} 1719 1720void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) { 1721 VisitCondition(comp); 1722} 1723 1724void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) { 1725 VisitCondition(comp); 1726} 1727 1728void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1729 VisitCondition(comp); 1730} 1731 1732void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1733 VisitCondition(comp); 1734} 1735 1736void LocationsBuilderX86::VisitBelow(HBelow* comp) { 1737 VisitCondition(comp); 1738} 1739 1740void InstructionCodeGeneratorX86::VisitBelow(HBelow* comp) { 1741 VisitCondition(comp); 1742} 1743 1744void LocationsBuilderX86::VisitBelowOrEqual(HBelowOrEqual* comp) { 1745 VisitCondition(comp); 1746} 1747 1748void InstructionCodeGeneratorX86::VisitBelowOrEqual(HBelowOrEqual* comp) { 1749 VisitCondition(comp); 1750} 1751 1752void LocationsBuilderX86::VisitAbove(HAbove* comp) { 1753 VisitCondition(comp); 1754} 1755 1756void InstructionCodeGeneratorX86::VisitAbove(HAbove* comp) { 1757 VisitCondition(comp); 1758} 1759 1760void LocationsBuilderX86::VisitAboveOrEqual(HAboveOrEqual* comp) { 1761 VisitCondition(comp); 1762} 1763 1764void InstructionCodeGeneratorX86::VisitAboveOrEqual(HAboveOrEqual* comp) { 1765 VisitCondition(comp); 1766} 1767 1768void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) { 1769 LocationSummary* locations = 1770 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1771 locations->SetOut(Location::ConstantLocation(constant)); 1772} 1773 1774void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) { 1775 // Will be generated at use site. 1776} 1777 1778void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) { 1779 LocationSummary* locations = 1780 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1781 locations->SetOut(Location::ConstantLocation(constant)); 1782} 1783 1784void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) { 1785 // Will be generated at use site. 1786} 1787 1788void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) { 1789 LocationSummary* locations = 1790 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1791 locations->SetOut(Location::ConstantLocation(constant)); 1792} 1793 1794void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) { 1795 // Will be generated at use site. 1796} 1797 1798void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) { 1799 LocationSummary* locations = 1800 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1801 locations->SetOut(Location::ConstantLocation(constant)); 1802} 1803 1804void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) { 1805 // Will be generated at use site. 1806} 1807 1808void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) { 1809 LocationSummary* locations = 1810 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1811 locations->SetOut(Location::ConstantLocation(constant)); 1812} 1813 1814void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant ATTRIBUTE_UNUSED) { 1815 // Will be generated at use site. 1816} 1817 1818void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) { 1819 memory_barrier->SetLocations(nullptr); 1820} 1821 1822void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) { 1823 GenerateMemoryBarrier(memory_barrier->GetBarrierKind()); 1824} 1825 1826void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) { 1827 ret->SetLocations(nullptr); 1828} 1829 1830void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) { 1831 codegen_->GenerateFrameExit(); 1832} 1833 1834void LocationsBuilderX86::VisitReturn(HReturn* ret) { 1835 LocationSummary* locations = 1836 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 1837 switch (ret->InputAt(0)->GetType()) { 1838 case Primitive::kPrimBoolean: 1839 case Primitive::kPrimByte: 1840 case Primitive::kPrimChar: 1841 case Primitive::kPrimShort: 1842 case Primitive::kPrimInt: 1843 case Primitive::kPrimNot: 1844 locations->SetInAt(0, Location::RegisterLocation(EAX)); 1845 break; 1846 1847 case Primitive::kPrimLong: 1848 locations->SetInAt( 1849 0, Location::RegisterPairLocation(EAX, EDX)); 1850 break; 1851 1852 case Primitive::kPrimFloat: 1853 case Primitive::kPrimDouble: 1854 locations->SetInAt( 1855 0, Location::FpuRegisterLocation(XMM0)); 1856 break; 1857 1858 default: 1859 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType(); 1860 } 1861} 1862 1863void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { 1864 if (kIsDebugBuild) { 1865 switch (ret->InputAt(0)->GetType()) { 1866 case Primitive::kPrimBoolean: 1867 case Primitive::kPrimByte: 1868 case Primitive::kPrimChar: 1869 case Primitive::kPrimShort: 1870 case Primitive::kPrimInt: 1871 case Primitive::kPrimNot: 1872 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX); 1873 break; 1874 1875 case Primitive::kPrimLong: 1876 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX); 1877 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX); 1878 break; 1879 1880 case Primitive::kPrimFloat: 1881 case Primitive::kPrimDouble: 1882 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0); 1883 break; 1884 1885 default: 1886 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType(); 1887 } 1888 } 1889 codegen_->GenerateFrameExit(); 1890} 1891 1892void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { 1893 // The trampoline uses the same calling convention as dex calling conventions, 1894 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain 1895 // the method_idx. 1896 HandleInvoke(invoke); 1897} 1898 1899void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { 1900 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke); 1901} 1902 1903void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { 1904 // When we do not run baseline, explicit clinit checks triggered by static 1905 // invokes must have been pruned by art::PrepareForRegisterAllocation. 1906 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); 1907 1908 IntrinsicLocationsBuilderX86 intrinsic(codegen_); 1909 if (intrinsic.TryDispatch(invoke)) { 1910 if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) { 1911 invoke->GetLocations()->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::Any()); 1912 } 1913 return; 1914 } 1915 1916 HandleInvoke(invoke); 1917 1918 // For PC-relative dex cache the invoke has an extra input, the PC-relative address base. 1919 if (invoke->HasPcRelativeDexCache()) { 1920 invoke->GetLocations()->SetInAt(invoke->GetCurrentMethodInputIndex(), 1921 Location::RequiresRegister()); 1922 } 1923 1924 if (codegen_->IsBaseline()) { 1925 // Baseline does not have enough registers if the current method also 1926 // needs a register. We therefore do not require a register for it, and let 1927 // the code generation of the invoke handle it. 1928 LocationSummary* locations = invoke->GetLocations(); 1929 Location location = locations->InAt(invoke->GetCurrentMethodInputIndex()); 1930 if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) { 1931 locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation()); 1932 } 1933 } 1934} 1935 1936static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) { 1937 if (invoke->GetLocations()->Intrinsified()) { 1938 IntrinsicCodeGeneratorX86 intrinsic(codegen); 1939 intrinsic.Dispatch(invoke); 1940 return true; 1941 } 1942 return false; 1943} 1944 1945void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { 1946 // When we do not run baseline, explicit clinit checks triggered by static 1947 // invokes must have been pruned by art::PrepareForRegisterAllocation. 1948 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); 1949 1950 if (TryGenerateIntrinsicCode(invoke, codegen_)) { 1951 return; 1952 } 1953 1954 LocationSummary* locations = invoke->GetLocations(); 1955 codegen_->GenerateStaticOrDirectCall( 1956 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation()); 1957 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1958} 1959 1960void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1961 HandleInvoke(invoke); 1962} 1963 1964void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) { 1965 InvokeDexCallingConventionVisitorX86 calling_convention_visitor; 1966 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor); 1967} 1968 1969void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1970 if (TryGenerateIntrinsicCode(invoke, codegen_)) { 1971 return; 1972 } 1973 1974 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0)); 1975 DCHECK(!codegen_->IsLeafMethod()); 1976 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1977} 1978 1979void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) { 1980 // This call to HandleInvoke allocates a temporary (core) register 1981 // which is also used to transfer the hidden argument from FP to 1982 // core register. 1983 HandleInvoke(invoke); 1984 // Add the hidden argument. 1985 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7)); 1986} 1987 1988void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) { 1989 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. 1990 LocationSummary* locations = invoke->GetLocations(); 1991 Register temp = locations->GetTemp(0).AsRegister<Register>(); 1992 XmmRegister hidden_reg = locations->GetTemp(1).AsFpuRegister<XmmRegister>(); 1993 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset( 1994 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value(); 1995 Location receiver = locations->InAt(0); 1996 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1997 1998 // Set the hidden argument. This is safe to do this here, as XMM7 1999 // won't be modified thereafter, before the `call` instruction. 2000 DCHECK_EQ(XMM7, hidden_reg); 2001 __ movl(temp, Immediate(invoke->GetDexMethodIndex())); 2002 __ movd(hidden_reg, temp); 2003 2004 if (receiver.IsStackSlot()) { 2005 __ movl(temp, Address(ESP, receiver.GetStackIndex())); 2006 // /* HeapReference<Class> */ temp = temp->klass_ 2007 __ movl(temp, Address(temp, class_offset)); 2008 } else { 2009 // /* HeapReference<Class> */ temp = receiver->klass_ 2010 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset)); 2011 } 2012 codegen_->MaybeRecordImplicitNullCheck(invoke); 2013 // Instead of simply (possibly) unpoisoning `temp` here, we should 2014 // emit a read barrier for the previous class reference load. 2015 // However this is not required in practice, as this is an 2016 // intermediate/temporary reference and because the current 2017 // concurrent copying collector keeps the from-space memory 2018 // intact/accessible until the end of the marking phase (the 2019 // concurrent copying collector may not in the future). 2020 __ MaybeUnpoisonHeapReference(temp); 2021 // temp = temp->GetImtEntryAt(method_offset); 2022 __ movl(temp, Address(temp, method_offset)); 2023 // call temp->GetEntryPoint(); 2024 __ call(Address(temp, 2025 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value())); 2026 2027 DCHECK(!codegen_->IsLeafMethod()); 2028 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 2029} 2030 2031void LocationsBuilderX86::VisitNeg(HNeg* neg) { 2032 LocationSummary* locations = 2033 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); 2034 switch (neg->GetResultType()) { 2035 case Primitive::kPrimInt: 2036 case Primitive::kPrimLong: 2037 locations->SetInAt(0, Location::RequiresRegister()); 2038 locations->SetOut(Location::SameAsFirstInput()); 2039 break; 2040 2041 case Primitive::kPrimFloat: 2042 locations->SetInAt(0, Location::RequiresFpuRegister()); 2043 locations->SetOut(Location::SameAsFirstInput()); 2044 locations->AddTemp(Location::RequiresRegister()); 2045 locations->AddTemp(Location::RequiresFpuRegister()); 2046 break; 2047 2048 case Primitive::kPrimDouble: 2049 locations->SetInAt(0, Location::RequiresFpuRegister()); 2050 locations->SetOut(Location::SameAsFirstInput()); 2051 locations->AddTemp(Location::RequiresFpuRegister()); 2052 break; 2053 2054 default: 2055 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 2056 } 2057} 2058 2059void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) { 2060 LocationSummary* locations = neg->GetLocations(); 2061 Location out = locations->Out(); 2062 Location in = locations->InAt(0); 2063 switch (neg->GetResultType()) { 2064 case Primitive::kPrimInt: 2065 DCHECK(in.IsRegister()); 2066 DCHECK(in.Equals(out)); 2067 __ negl(out.AsRegister<Register>()); 2068 break; 2069 2070 case Primitive::kPrimLong: 2071 DCHECK(in.IsRegisterPair()); 2072 DCHECK(in.Equals(out)); 2073 __ negl(out.AsRegisterPairLow<Register>()); 2074 // Negation is similar to subtraction from zero. The least 2075 // significant byte triggers a borrow when it is different from 2076 // zero; to take it into account, add 1 to the most significant 2077 // byte if the carry flag (CF) is set to 1 after the first NEGL 2078 // operation. 2079 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0)); 2080 __ negl(out.AsRegisterPairHigh<Register>()); 2081 break; 2082 2083 case Primitive::kPrimFloat: { 2084 DCHECK(in.Equals(out)); 2085 Register constant = locations->GetTemp(0).AsRegister<Register>(); 2086 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>(); 2087 // Implement float negation with an exclusive or with value 2088 // 0x80000000 (mask for bit 31, representing the sign of a 2089 // single-precision floating-point number). 2090 __ movl(constant, Immediate(INT32_C(0x80000000))); 2091 __ movd(mask, constant); 2092 __ xorps(out.AsFpuRegister<XmmRegister>(), mask); 2093 break; 2094 } 2095 2096 case Primitive::kPrimDouble: { 2097 DCHECK(in.Equals(out)); 2098 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 2099 // Implement double negation with an exclusive or with value 2100 // 0x8000000000000000 (mask for bit 63, representing the sign of 2101 // a double-precision floating-point number). 2102 __ LoadLongConstant(mask, INT64_C(0x8000000000000000)); 2103 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask); 2104 break; 2105 } 2106 2107 default: 2108 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 2109 } 2110} 2111 2112void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) { 2113 Primitive::Type result_type = conversion->GetResultType(); 2114 Primitive::Type input_type = conversion->GetInputType(); 2115 DCHECK_NE(result_type, input_type); 2116 2117 // The float-to-long and double-to-long type conversions rely on a 2118 // call to the runtime. 2119 LocationSummary::CallKind call_kind = 2120 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble) 2121 && result_type == Primitive::kPrimLong) 2122 ? LocationSummary::kCall 2123 : LocationSummary::kNoCall; 2124 LocationSummary* locations = 2125 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind); 2126 2127 // The Java language does not allow treating boolean as an integral type but 2128 // our bit representation makes it safe. 2129 2130 switch (result_type) { 2131 case Primitive::kPrimByte: 2132 switch (input_type) { 2133 case Primitive::kPrimBoolean: 2134 // Boolean input is a result of code transformations. 2135 case Primitive::kPrimShort: 2136 case Primitive::kPrimInt: 2137 case Primitive::kPrimChar: 2138 // Processing a Dex `int-to-byte' instruction. 2139 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0))); 2140 // Make the output overlap to please the register allocator. This greatly simplifies 2141 // the validation of the linear scan implementation 2142 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 2143 break; 2144 2145 default: 2146 LOG(FATAL) << "Unexpected type conversion from " << input_type 2147 << " to " << result_type; 2148 } 2149 break; 2150 2151 case Primitive::kPrimShort: 2152 switch (input_type) { 2153 case Primitive::kPrimBoolean: 2154 // Boolean input is a result of code transformations. 2155 case Primitive::kPrimByte: 2156 case Primitive::kPrimInt: 2157 case Primitive::kPrimChar: 2158 // Processing a Dex `int-to-short' instruction. 2159 locations->SetInAt(0, Location::Any()); 2160 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2161 break; 2162 2163 default: 2164 LOG(FATAL) << "Unexpected type conversion from " << input_type 2165 << " to " << result_type; 2166 } 2167 break; 2168 2169 case Primitive::kPrimInt: 2170 switch (input_type) { 2171 case Primitive::kPrimLong: 2172 // Processing a Dex `long-to-int' instruction. 2173 locations->SetInAt(0, Location::Any()); 2174 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2175 break; 2176 2177 case Primitive::kPrimFloat: 2178 // Processing a Dex `float-to-int' instruction. 2179 locations->SetInAt(0, Location::RequiresFpuRegister()); 2180 locations->SetOut(Location::RequiresRegister()); 2181 locations->AddTemp(Location::RequiresFpuRegister()); 2182 break; 2183 2184 case Primitive::kPrimDouble: 2185 // Processing a Dex `double-to-int' instruction. 2186 locations->SetInAt(0, Location::RequiresFpuRegister()); 2187 locations->SetOut(Location::RequiresRegister()); 2188 locations->AddTemp(Location::RequiresFpuRegister()); 2189 break; 2190 2191 default: 2192 LOG(FATAL) << "Unexpected type conversion from " << input_type 2193 << " to " << result_type; 2194 } 2195 break; 2196 2197 case Primitive::kPrimLong: 2198 switch (input_type) { 2199 case Primitive::kPrimBoolean: 2200 // Boolean input is a result of code transformations. 2201 case Primitive::kPrimByte: 2202 case Primitive::kPrimShort: 2203 case Primitive::kPrimInt: 2204 case Primitive::kPrimChar: 2205 // Processing a Dex `int-to-long' instruction. 2206 locations->SetInAt(0, Location::RegisterLocation(EAX)); 2207 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 2208 break; 2209 2210 case Primitive::kPrimFloat: 2211 case Primitive::kPrimDouble: { 2212 // Processing a Dex `float-to-long' or 'double-to-long' instruction. 2213 InvokeRuntimeCallingConvention calling_convention; 2214 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0); 2215 locations->SetInAt(0, Location::FpuRegisterLocation(parameter)); 2216 2217 // The runtime helper puts the result in EAX, EDX. 2218 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 2219 } 2220 break; 2221 2222 default: 2223 LOG(FATAL) << "Unexpected type conversion from " << input_type 2224 << " to " << result_type; 2225 } 2226 break; 2227 2228 case Primitive::kPrimChar: 2229 switch (input_type) { 2230 case Primitive::kPrimBoolean: 2231 // Boolean input is a result of code transformations. 2232 case Primitive::kPrimByte: 2233 case Primitive::kPrimShort: 2234 case Primitive::kPrimInt: 2235 // Processing a Dex `int-to-char' instruction. 2236 locations->SetInAt(0, Location::Any()); 2237 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2238 break; 2239 2240 default: 2241 LOG(FATAL) << "Unexpected type conversion from " << input_type 2242 << " to " << result_type; 2243 } 2244 break; 2245 2246 case Primitive::kPrimFloat: 2247 switch (input_type) { 2248 case Primitive::kPrimBoolean: 2249 // Boolean input is a result of code transformations. 2250 case Primitive::kPrimByte: 2251 case Primitive::kPrimShort: 2252 case Primitive::kPrimInt: 2253 case Primitive::kPrimChar: 2254 // Processing a Dex `int-to-float' instruction. 2255 locations->SetInAt(0, Location::RequiresRegister()); 2256 locations->SetOut(Location::RequiresFpuRegister()); 2257 break; 2258 2259 case Primitive::kPrimLong: 2260 // Processing a Dex `long-to-float' instruction. 2261 locations->SetInAt(0, Location::Any()); 2262 locations->SetOut(Location::Any()); 2263 break; 2264 2265 case Primitive::kPrimDouble: 2266 // Processing a Dex `double-to-float' instruction. 2267 locations->SetInAt(0, Location::RequiresFpuRegister()); 2268 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 2269 break; 2270 2271 default: 2272 LOG(FATAL) << "Unexpected type conversion from " << input_type 2273 << " to " << result_type; 2274 }; 2275 break; 2276 2277 case Primitive::kPrimDouble: 2278 switch (input_type) { 2279 case Primitive::kPrimBoolean: 2280 // Boolean input is a result of code transformations. 2281 case Primitive::kPrimByte: 2282 case Primitive::kPrimShort: 2283 case Primitive::kPrimInt: 2284 case Primitive::kPrimChar: 2285 // Processing a Dex `int-to-double' instruction. 2286 locations->SetInAt(0, Location::RequiresRegister()); 2287 locations->SetOut(Location::RequiresFpuRegister()); 2288 break; 2289 2290 case Primitive::kPrimLong: 2291 // Processing a Dex `long-to-double' instruction. 2292 locations->SetInAt(0, Location::Any()); 2293 locations->SetOut(Location::Any()); 2294 break; 2295 2296 case Primitive::kPrimFloat: 2297 // Processing a Dex `float-to-double' instruction. 2298 locations->SetInAt(0, Location::RequiresFpuRegister()); 2299 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 2300 break; 2301 2302 default: 2303 LOG(FATAL) << "Unexpected type conversion from " << input_type 2304 << " to " << result_type; 2305 } 2306 break; 2307 2308 default: 2309 LOG(FATAL) << "Unexpected type conversion from " << input_type 2310 << " to " << result_type; 2311 } 2312} 2313 2314void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) { 2315 LocationSummary* locations = conversion->GetLocations(); 2316 Location out = locations->Out(); 2317 Location in = locations->InAt(0); 2318 Primitive::Type result_type = conversion->GetResultType(); 2319 Primitive::Type input_type = conversion->GetInputType(); 2320 DCHECK_NE(result_type, input_type); 2321 switch (result_type) { 2322 case Primitive::kPrimByte: 2323 switch (input_type) { 2324 case Primitive::kPrimBoolean: 2325 // Boolean input is a result of code transformations. 2326 case Primitive::kPrimShort: 2327 case Primitive::kPrimInt: 2328 case Primitive::kPrimChar: 2329 // Processing a Dex `int-to-byte' instruction. 2330 if (in.IsRegister()) { 2331 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>()); 2332 } else { 2333 DCHECK(in.GetConstant()->IsIntConstant()); 2334 int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); 2335 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value))); 2336 } 2337 break; 2338 2339 default: 2340 LOG(FATAL) << "Unexpected type conversion from " << input_type 2341 << " to " << result_type; 2342 } 2343 break; 2344 2345 case Primitive::kPrimShort: 2346 switch (input_type) { 2347 case Primitive::kPrimBoolean: 2348 // Boolean input is a result of code transformations. 2349 case Primitive::kPrimByte: 2350 case Primitive::kPrimInt: 2351 case Primitive::kPrimChar: 2352 // Processing a Dex `int-to-short' instruction. 2353 if (in.IsRegister()) { 2354 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>()); 2355 } else if (in.IsStackSlot()) { 2356 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex())); 2357 } else { 2358 DCHECK(in.GetConstant()->IsIntConstant()); 2359 int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); 2360 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value))); 2361 } 2362 break; 2363 2364 default: 2365 LOG(FATAL) << "Unexpected type conversion from " << input_type 2366 << " to " << result_type; 2367 } 2368 break; 2369 2370 case Primitive::kPrimInt: 2371 switch (input_type) { 2372 case Primitive::kPrimLong: 2373 // Processing a Dex `long-to-int' instruction. 2374 if (in.IsRegisterPair()) { 2375 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>()); 2376 } else if (in.IsDoubleStackSlot()) { 2377 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex())); 2378 } else { 2379 DCHECK(in.IsConstant()); 2380 DCHECK(in.GetConstant()->IsLongConstant()); 2381 int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); 2382 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value))); 2383 } 2384 break; 2385 2386 case Primitive::kPrimFloat: { 2387 // Processing a Dex `float-to-int' instruction. 2388 XmmRegister input = in.AsFpuRegister<XmmRegister>(); 2389 Register output = out.AsRegister<Register>(); 2390 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 2391 NearLabel done, nan; 2392 2393 __ movl(output, Immediate(kPrimIntMax)); 2394 // temp = int-to-float(output) 2395 __ cvtsi2ss(temp, output); 2396 // if input >= temp goto done 2397 __ comiss(input, temp); 2398 __ j(kAboveEqual, &done); 2399 // if input == NaN goto nan 2400 __ j(kUnordered, &nan); 2401 // output = float-to-int-truncate(input) 2402 __ cvttss2si(output, input); 2403 __ jmp(&done); 2404 __ Bind(&nan); 2405 // output = 0 2406 __ xorl(output, output); 2407 __ Bind(&done); 2408 break; 2409 } 2410 2411 case Primitive::kPrimDouble: { 2412 // Processing a Dex `double-to-int' instruction. 2413 XmmRegister input = in.AsFpuRegister<XmmRegister>(); 2414 Register output = out.AsRegister<Register>(); 2415 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 2416 NearLabel done, nan; 2417 2418 __ movl(output, Immediate(kPrimIntMax)); 2419 // temp = int-to-double(output) 2420 __ cvtsi2sd(temp, output); 2421 // if input >= temp goto done 2422 __ comisd(input, temp); 2423 __ j(kAboveEqual, &done); 2424 // if input == NaN goto nan 2425 __ j(kUnordered, &nan); 2426 // output = double-to-int-truncate(input) 2427 __ cvttsd2si(output, input); 2428 __ jmp(&done); 2429 __ Bind(&nan); 2430 // output = 0 2431 __ xorl(output, output); 2432 __ Bind(&done); 2433 break; 2434 } 2435 2436 default: 2437 LOG(FATAL) << "Unexpected type conversion from " << input_type 2438 << " to " << result_type; 2439 } 2440 break; 2441 2442 case Primitive::kPrimLong: 2443 switch (input_type) { 2444 case Primitive::kPrimBoolean: 2445 // Boolean input is a result of code transformations. 2446 case Primitive::kPrimByte: 2447 case Primitive::kPrimShort: 2448 case Primitive::kPrimInt: 2449 case Primitive::kPrimChar: 2450 // Processing a Dex `int-to-long' instruction. 2451 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX); 2452 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX); 2453 DCHECK_EQ(in.AsRegister<Register>(), EAX); 2454 __ cdq(); 2455 break; 2456 2457 case Primitive::kPrimFloat: 2458 // Processing a Dex `float-to-long' instruction. 2459 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l), 2460 conversion, 2461 conversion->GetDexPc(), 2462 nullptr); 2463 break; 2464 2465 case Primitive::kPrimDouble: 2466 // Processing a Dex `double-to-long' instruction. 2467 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l), 2468 conversion, 2469 conversion->GetDexPc(), 2470 nullptr); 2471 break; 2472 2473 default: 2474 LOG(FATAL) << "Unexpected type conversion from " << input_type 2475 << " to " << result_type; 2476 } 2477 break; 2478 2479 case Primitive::kPrimChar: 2480 switch (input_type) { 2481 case Primitive::kPrimBoolean: 2482 // Boolean input is a result of code transformations. 2483 case Primitive::kPrimByte: 2484 case Primitive::kPrimShort: 2485 case Primitive::kPrimInt: 2486 // Processing a Dex `Process a Dex `int-to-char'' instruction. 2487 if (in.IsRegister()) { 2488 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>()); 2489 } else if (in.IsStackSlot()) { 2490 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex())); 2491 } else { 2492 DCHECK(in.GetConstant()->IsIntConstant()); 2493 int32_t value = in.GetConstant()->AsIntConstant()->GetValue(); 2494 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value))); 2495 } 2496 break; 2497 2498 default: 2499 LOG(FATAL) << "Unexpected type conversion from " << input_type 2500 << " to " << result_type; 2501 } 2502 break; 2503 2504 case Primitive::kPrimFloat: 2505 switch (input_type) { 2506 case Primitive::kPrimBoolean: 2507 // Boolean input is a result of code transformations. 2508 case Primitive::kPrimByte: 2509 case Primitive::kPrimShort: 2510 case Primitive::kPrimInt: 2511 case Primitive::kPrimChar: 2512 // Processing a Dex `int-to-float' instruction. 2513 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>()); 2514 break; 2515 2516 case Primitive::kPrimLong: { 2517 // Processing a Dex `long-to-float' instruction. 2518 size_t adjustment = 0; 2519 2520 // Create stack space for the call to 2521 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below. 2522 // TODO: enhance register allocator to ask for stack temporaries. 2523 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) { 2524 adjustment = Primitive::ComponentSize(Primitive::kPrimLong); 2525 __ subl(ESP, Immediate(adjustment)); 2526 } 2527 2528 // Load the value to the FP stack, using temporaries if needed. 2529 PushOntoFPStack(in, 0, adjustment, false, true); 2530 2531 if (out.IsStackSlot()) { 2532 __ fstps(Address(ESP, out.GetStackIndex() + adjustment)); 2533 } else { 2534 __ fstps(Address(ESP, 0)); 2535 Location stack_temp = Location::StackSlot(0); 2536 codegen_->Move32(out, stack_temp); 2537 } 2538 2539 // Remove the temporary stack space we allocated. 2540 if (adjustment != 0) { 2541 __ addl(ESP, Immediate(adjustment)); 2542 } 2543 break; 2544 } 2545 2546 case Primitive::kPrimDouble: 2547 // Processing a Dex `double-to-float' instruction. 2548 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>()); 2549 break; 2550 2551 default: 2552 LOG(FATAL) << "Unexpected type conversion from " << input_type 2553 << " to " << result_type; 2554 }; 2555 break; 2556 2557 case Primitive::kPrimDouble: 2558 switch (input_type) { 2559 case Primitive::kPrimBoolean: 2560 // Boolean input is a result of code transformations. 2561 case Primitive::kPrimByte: 2562 case Primitive::kPrimShort: 2563 case Primitive::kPrimInt: 2564 case Primitive::kPrimChar: 2565 // Processing a Dex `int-to-double' instruction. 2566 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>()); 2567 break; 2568 2569 case Primitive::kPrimLong: { 2570 // Processing a Dex `long-to-double' instruction. 2571 size_t adjustment = 0; 2572 2573 // Create stack space for the call to 2574 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below. 2575 // TODO: enhance register allocator to ask for stack temporaries. 2576 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) { 2577 adjustment = Primitive::ComponentSize(Primitive::kPrimLong); 2578 __ subl(ESP, Immediate(adjustment)); 2579 } 2580 2581 // Load the value to the FP stack, using temporaries if needed. 2582 PushOntoFPStack(in, 0, adjustment, false, true); 2583 2584 if (out.IsDoubleStackSlot()) { 2585 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment)); 2586 } else { 2587 __ fstpl(Address(ESP, 0)); 2588 Location stack_temp = Location::DoubleStackSlot(0); 2589 codegen_->Move64(out, stack_temp); 2590 } 2591 2592 // Remove the temporary stack space we allocated. 2593 if (adjustment != 0) { 2594 __ addl(ESP, Immediate(adjustment)); 2595 } 2596 break; 2597 } 2598 2599 case Primitive::kPrimFloat: 2600 // Processing a Dex `float-to-double' instruction. 2601 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>()); 2602 break; 2603 2604 default: 2605 LOG(FATAL) << "Unexpected type conversion from " << input_type 2606 << " to " << result_type; 2607 }; 2608 break; 2609 2610 default: 2611 LOG(FATAL) << "Unexpected type conversion from " << input_type 2612 << " to " << result_type; 2613 } 2614} 2615 2616void LocationsBuilderX86::VisitAdd(HAdd* add) { 2617 LocationSummary* locations = 2618 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 2619 switch (add->GetResultType()) { 2620 case Primitive::kPrimInt: { 2621 locations->SetInAt(0, Location::RequiresRegister()); 2622 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); 2623 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2624 break; 2625 } 2626 2627 case Primitive::kPrimLong: { 2628 locations->SetInAt(0, Location::RequiresRegister()); 2629 locations->SetInAt(1, Location::Any()); 2630 locations->SetOut(Location::SameAsFirstInput()); 2631 break; 2632 } 2633 2634 case Primitive::kPrimFloat: 2635 case Primitive::kPrimDouble: { 2636 locations->SetInAt(0, Location::RequiresFpuRegister()); 2637 locations->SetInAt(1, Location::Any()); 2638 locations->SetOut(Location::SameAsFirstInput()); 2639 break; 2640 } 2641 2642 default: 2643 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 2644 break; 2645 } 2646} 2647 2648void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) { 2649 LocationSummary* locations = add->GetLocations(); 2650 Location first = locations->InAt(0); 2651 Location second = locations->InAt(1); 2652 Location out = locations->Out(); 2653 2654 switch (add->GetResultType()) { 2655 case Primitive::kPrimInt: { 2656 if (second.IsRegister()) { 2657 if (out.AsRegister<Register>() == first.AsRegister<Register>()) { 2658 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>()); 2659 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) { 2660 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>()); 2661 } else { 2662 __ leal(out.AsRegister<Register>(), Address( 2663 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0)); 2664 } 2665 } else if (second.IsConstant()) { 2666 int32_t value = second.GetConstant()->AsIntConstant()->GetValue(); 2667 if (out.AsRegister<Register>() == first.AsRegister<Register>()) { 2668 __ addl(out.AsRegister<Register>(), Immediate(value)); 2669 } else { 2670 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value)); 2671 } 2672 } else { 2673 DCHECK(first.Equals(locations->Out())); 2674 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 2675 } 2676 break; 2677 } 2678 2679 case Primitive::kPrimLong: { 2680 if (second.IsRegisterPair()) { 2681 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 2682 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 2683 } else if (second.IsDoubleStackSlot()) { 2684 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 2685 __ adcl(first.AsRegisterPairHigh<Register>(), 2686 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 2687 } else { 2688 DCHECK(second.IsConstant()) << second; 2689 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 2690 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value))); 2691 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value))); 2692 } 2693 break; 2694 } 2695 2696 case Primitive::kPrimFloat: { 2697 if (second.IsFpuRegister()) { 2698 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2699 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) { 2700 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable(); 2701 DCHECK(!const_area->NeedsMaterialization()); 2702 __ addss(first.AsFpuRegister<XmmRegister>(), 2703 codegen_->LiteralFloatAddress( 2704 const_area->GetConstant()->AsFloatConstant()->GetValue(), 2705 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 2706 } else { 2707 DCHECK(second.IsStackSlot()); 2708 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 2709 } 2710 break; 2711 } 2712 2713 case Primitive::kPrimDouble: { 2714 if (second.IsFpuRegister()) { 2715 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2716 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) { 2717 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable(); 2718 DCHECK(!const_area->NeedsMaterialization()); 2719 __ addsd(first.AsFpuRegister<XmmRegister>(), 2720 codegen_->LiteralDoubleAddress( 2721 const_area->GetConstant()->AsDoubleConstant()->GetValue(), 2722 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 2723 } else { 2724 DCHECK(second.IsDoubleStackSlot()); 2725 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 2726 } 2727 break; 2728 } 2729 2730 default: 2731 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 2732 } 2733} 2734 2735void LocationsBuilderX86::VisitSub(HSub* sub) { 2736 LocationSummary* locations = 2737 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 2738 switch (sub->GetResultType()) { 2739 case Primitive::kPrimInt: 2740 case Primitive::kPrimLong: { 2741 locations->SetInAt(0, Location::RequiresRegister()); 2742 locations->SetInAt(1, Location::Any()); 2743 locations->SetOut(Location::SameAsFirstInput()); 2744 break; 2745 } 2746 case Primitive::kPrimFloat: 2747 case Primitive::kPrimDouble: { 2748 locations->SetInAt(0, Location::RequiresFpuRegister()); 2749 locations->SetInAt(1, Location::Any()); 2750 locations->SetOut(Location::SameAsFirstInput()); 2751 break; 2752 } 2753 2754 default: 2755 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 2756 } 2757} 2758 2759void InstructionCodeGeneratorX86::VisitSub(HSub* sub) { 2760 LocationSummary* locations = sub->GetLocations(); 2761 Location first = locations->InAt(0); 2762 Location second = locations->InAt(1); 2763 DCHECK(first.Equals(locations->Out())); 2764 switch (sub->GetResultType()) { 2765 case Primitive::kPrimInt: { 2766 if (second.IsRegister()) { 2767 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>()); 2768 } else if (second.IsConstant()) { 2769 __ subl(first.AsRegister<Register>(), 2770 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 2771 } else { 2772 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 2773 } 2774 break; 2775 } 2776 2777 case Primitive::kPrimLong: { 2778 if (second.IsRegisterPair()) { 2779 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 2780 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 2781 } else if (second.IsDoubleStackSlot()) { 2782 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 2783 __ sbbl(first.AsRegisterPairHigh<Register>(), 2784 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 2785 } else { 2786 DCHECK(second.IsConstant()) << second; 2787 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 2788 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value))); 2789 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value))); 2790 } 2791 break; 2792 } 2793 2794 case Primitive::kPrimFloat: { 2795 if (second.IsFpuRegister()) { 2796 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2797 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) { 2798 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable(); 2799 DCHECK(!const_area->NeedsMaterialization()); 2800 __ subss(first.AsFpuRegister<XmmRegister>(), 2801 codegen_->LiteralFloatAddress( 2802 const_area->GetConstant()->AsFloatConstant()->GetValue(), 2803 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 2804 } else { 2805 DCHECK(second.IsStackSlot()); 2806 __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 2807 } 2808 break; 2809 } 2810 2811 case Primitive::kPrimDouble: { 2812 if (second.IsFpuRegister()) { 2813 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2814 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) { 2815 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable(); 2816 DCHECK(!const_area->NeedsMaterialization()); 2817 __ subsd(first.AsFpuRegister<XmmRegister>(), 2818 codegen_->LiteralDoubleAddress( 2819 const_area->GetConstant()->AsDoubleConstant()->GetValue(), 2820 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 2821 } else { 2822 DCHECK(second.IsDoubleStackSlot()); 2823 __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 2824 } 2825 break; 2826 } 2827 2828 default: 2829 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 2830 } 2831} 2832 2833void LocationsBuilderX86::VisitMul(HMul* mul) { 2834 LocationSummary* locations = 2835 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); 2836 switch (mul->GetResultType()) { 2837 case Primitive::kPrimInt: 2838 locations->SetInAt(0, Location::RequiresRegister()); 2839 locations->SetInAt(1, Location::Any()); 2840 if (mul->InputAt(1)->IsIntConstant()) { 2841 // Can use 3 operand multiply. 2842 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2843 } else { 2844 locations->SetOut(Location::SameAsFirstInput()); 2845 } 2846 break; 2847 case Primitive::kPrimLong: { 2848 locations->SetInAt(0, Location::RequiresRegister()); 2849 locations->SetInAt(1, Location::Any()); 2850 locations->SetOut(Location::SameAsFirstInput()); 2851 // Needed for imul on 32bits with 64bits output. 2852 locations->AddTemp(Location::RegisterLocation(EAX)); 2853 locations->AddTemp(Location::RegisterLocation(EDX)); 2854 break; 2855 } 2856 case Primitive::kPrimFloat: 2857 case Primitive::kPrimDouble: { 2858 locations->SetInAt(0, Location::RequiresFpuRegister()); 2859 locations->SetInAt(1, Location::Any()); 2860 locations->SetOut(Location::SameAsFirstInput()); 2861 break; 2862 } 2863 2864 default: 2865 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 2866 } 2867} 2868 2869void InstructionCodeGeneratorX86::VisitMul(HMul* mul) { 2870 LocationSummary* locations = mul->GetLocations(); 2871 Location first = locations->InAt(0); 2872 Location second = locations->InAt(1); 2873 Location out = locations->Out(); 2874 2875 switch (mul->GetResultType()) { 2876 case Primitive::kPrimInt: 2877 // The constant may have ended up in a register, so test explicitly to avoid 2878 // problems where the output may not be the same as the first operand. 2879 if (mul->InputAt(1)->IsIntConstant()) { 2880 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue()); 2881 __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm); 2882 } else if (second.IsRegister()) { 2883 DCHECK(first.Equals(out)); 2884 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>()); 2885 } else { 2886 DCHECK(second.IsStackSlot()); 2887 DCHECK(first.Equals(out)); 2888 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 2889 } 2890 break; 2891 2892 case Primitive::kPrimLong: { 2893 Register in1_hi = first.AsRegisterPairHigh<Register>(); 2894 Register in1_lo = first.AsRegisterPairLow<Register>(); 2895 Register eax = locations->GetTemp(0).AsRegister<Register>(); 2896 Register edx = locations->GetTemp(1).AsRegister<Register>(); 2897 2898 DCHECK_EQ(EAX, eax); 2899 DCHECK_EQ(EDX, edx); 2900 2901 // input: in1 - 64 bits, in2 - 64 bits. 2902 // output: in1 2903 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo 2904 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32] 2905 // parts: in1.lo = (in1.lo * in2.lo)[31:0] 2906 if (second.IsConstant()) { 2907 DCHECK(second.GetConstant()->IsLongConstant()); 2908 2909 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 2910 int32_t low_value = Low32Bits(value); 2911 int32_t high_value = High32Bits(value); 2912 Immediate low(low_value); 2913 Immediate high(high_value); 2914 2915 __ movl(eax, high); 2916 // eax <- in1.lo * in2.hi 2917 __ imull(eax, in1_lo); 2918 // in1.hi <- in1.hi * in2.lo 2919 __ imull(in1_hi, low); 2920 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo 2921 __ addl(in1_hi, eax); 2922 // move in2_lo to eax to prepare for double precision 2923 __ movl(eax, low); 2924 // edx:eax <- in1.lo * in2.lo 2925 __ mull(in1_lo); 2926 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 2927 __ addl(in1_hi, edx); 2928 // in1.lo <- (in1.lo * in2.lo)[31:0]; 2929 __ movl(in1_lo, eax); 2930 } else if (second.IsRegisterPair()) { 2931 Register in2_hi = second.AsRegisterPairHigh<Register>(); 2932 Register in2_lo = second.AsRegisterPairLow<Register>(); 2933 2934 __ movl(eax, in2_hi); 2935 // eax <- in1.lo * in2.hi 2936 __ imull(eax, in1_lo); 2937 // in1.hi <- in1.hi * in2.lo 2938 __ imull(in1_hi, in2_lo); 2939 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo 2940 __ addl(in1_hi, eax); 2941 // move in1_lo to eax to prepare for double precision 2942 __ movl(eax, in1_lo); 2943 // edx:eax <- in1.lo * in2.lo 2944 __ mull(in2_lo); 2945 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 2946 __ addl(in1_hi, edx); 2947 // in1.lo <- (in1.lo * in2.lo)[31:0]; 2948 __ movl(in1_lo, eax); 2949 } else { 2950 DCHECK(second.IsDoubleStackSlot()) << second; 2951 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize)); 2952 Address in2_lo(ESP, second.GetStackIndex()); 2953 2954 __ movl(eax, in2_hi); 2955 // eax <- in1.lo * in2.hi 2956 __ imull(eax, in1_lo); 2957 // in1.hi <- in1.hi * in2.lo 2958 __ imull(in1_hi, in2_lo); 2959 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo 2960 __ addl(in1_hi, eax); 2961 // move in1_lo to eax to prepare for double precision 2962 __ movl(eax, in1_lo); 2963 // edx:eax <- in1.lo * in2.lo 2964 __ mull(in2_lo); 2965 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 2966 __ addl(in1_hi, edx); 2967 // in1.lo <- (in1.lo * in2.lo)[31:0]; 2968 __ movl(in1_lo, eax); 2969 } 2970 2971 break; 2972 } 2973 2974 case Primitive::kPrimFloat: { 2975 DCHECK(first.Equals(locations->Out())); 2976 if (second.IsFpuRegister()) { 2977 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2978 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) { 2979 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable(); 2980 DCHECK(!const_area->NeedsMaterialization()); 2981 __ mulss(first.AsFpuRegister<XmmRegister>(), 2982 codegen_->LiteralFloatAddress( 2983 const_area->GetConstant()->AsFloatConstant()->GetValue(), 2984 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 2985 } else { 2986 DCHECK(second.IsStackSlot()); 2987 __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 2988 } 2989 break; 2990 } 2991 2992 case Primitive::kPrimDouble: { 2993 DCHECK(first.Equals(locations->Out())); 2994 if (second.IsFpuRegister()) { 2995 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 2996 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) { 2997 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable(); 2998 DCHECK(!const_area->NeedsMaterialization()); 2999 __ mulsd(first.AsFpuRegister<XmmRegister>(), 3000 codegen_->LiteralDoubleAddress( 3001 const_area->GetConstant()->AsDoubleConstant()->GetValue(), 3002 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 3003 } else { 3004 DCHECK(second.IsDoubleStackSlot()); 3005 __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 3006 } 3007 break; 3008 } 3009 3010 default: 3011 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 3012 } 3013} 3014 3015void InstructionCodeGeneratorX86::PushOntoFPStack(Location source, 3016 uint32_t temp_offset, 3017 uint32_t stack_adjustment, 3018 bool is_fp, 3019 bool is_wide) { 3020 if (source.IsStackSlot()) { 3021 DCHECK(!is_wide); 3022 if (is_fp) { 3023 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment)); 3024 } else { 3025 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment)); 3026 } 3027 } else if (source.IsDoubleStackSlot()) { 3028 DCHECK(is_wide); 3029 if (is_fp) { 3030 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment)); 3031 } else { 3032 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment)); 3033 } 3034 } else { 3035 // Write the value to the temporary location on the stack and load to FP stack. 3036 if (!is_wide) { 3037 Location stack_temp = Location::StackSlot(temp_offset); 3038 codegen_->Move32(stack_temp, source); 3039 if (is_fp) { 3040 __ flds(Address(ESP, temp_offset)); 3041 } else { 3042 __ filds(Address(ESP, temp_offset)); 3043 } 3044 } else { 3045 Location stack_temp = Location::DoubleStackSlot(temp_offset); 3046 codegen_->Move64(stack_temp, source); 3047 if (is_fp) { 3048 __ fldl(Address(ESP, temp_offset)); 3049 } else { 3050 __ fildl(Address(ESP, temp_offset)); 3051 } 3052 } 3053 } 3054} 3055 3056void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) { 3057 Primitive::Type type = rem->GetResultType(); 3058 bool is_float = type == Primitive::kPrimFloat; 3059 size_t elem_size = Primitive::ComponentSize(type); 3060 LocationSummary* locations = rem->GetLocations(); 3061 Location first = locations->InAt(0); 3062 Location second = locations->InAt(1); 3063 Location out = locations->Out(); 3064 3065 // Create stack space for 2 elements. 3066 // TODO: enhance register allocator to ask for stack temporaries. 3067 __ subl(ESP, Immediate(2 * elem_size)); 3068 3069 // Load the values to the FP stack in reverse order, using temporaries if needed. 3070 const bool is_wide = !is_float; 3071 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide); 3072 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide); 3073 3074 // Loop doing FPREM until we stabilize. 3075 NearLabel retry; 3076 __ Bind(&retry); 3077 __ fprem(); 3078 3079 // Move FP status to AX. 3080 __ fstsw(); 3081 3082 // And see if the argument reduction is complete. This is signaled by the 3083 // C2 FPU flag bit set to 0. 3084 __ andl(EAX, Immediate(kC2ConditionMask)); 3085 __ j(kNotEqual, &retry); 3086 3087 // We have settled on the final value. Retrieve it into an XMM register. 3088 // Store FP top of stack to real stack. 3089 if (is_float) { 3090 __ fsts(Address(ESP, 0)); 3091 } else { 3092 __ fstl(Address(ESP, 0)); 3093 } 3094 3095 // Pop the 2 items from the FP stack. 3096 __ fucompp(); 3097 3098 // Load the value from the stack into an XMM register. 3099 DCHECK(out.IsFpuRegister()) << out; 3100 if (is_float) { 3101 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0)); 3102 } else { 3103 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0)); 3104 } 3105 3106 // And remove the temporary stack space we allocated. 3107 __ addl(ESP, Immediate(2 * elem_size)); 3108} 3109 3110 3111void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) { 3112 DCHECK(instruction->IsDiv() || instruction->IsRem()); 3113 3114 LocationSummary* locations = instruction->GetLocations(); 3115 DCHECK(locations->InAt(1).IsConstant()); 3116 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant()); 3117 3118 Register out_register = locations->Out().AsRegister<Register>(); 3119 Register input_register = locations->InAt(0).AsRegister<Register>(); 3120 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 3121 3122 DCHECK(imm == 1 || imm == -1); 3123 3124 if (instruction->IsRem()) { 3125 __ xorl(out_register, out_register); 3126 } else { 3127 __ movl(out_register, input_register); 3128 if (imm == -1) { 3129 __ negl(out_register); 3130 } 3131 } 3132} 3133 3134 3135void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) { 3136 LocationSummary* locations = instruction->GetLocations(); 3137 3138 Register out_register = locations->Out().AsRegister<Register>(); 3139 Register input_register = locations->InAt(0).AsRegister<Register>(); 3140 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 3141 3142 DCHECK(IsPowerOfTwo(std::abs(imm))); 3143 Register num = locations->GetTemp(0).AsRegister<Register>(); 3144 3145 __ leal(num, Address(input_register, std::abs(imm) - 1)); 3146 __ testl(input_register, input_register); 3147 __ cmovl(kGreaterEqual, num, input_register); 3148 int shift = CTZ(imm); 3149 __ sarl(num, Immediate(shift)); 3150 3151 if (imm < 0) { 3152 __ negl(num); 3153 } 3154 3155 __ movl(out_register, num); 3156} 3157 3158void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) { 3159 DCHECK(instruction->IsDiv() || instruction->IsRem()); 3160 3161 LocationSummary* locations = instruction->GetLocations(); 3162 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 3163 3164 Register eax = locations->InAt(0).AsRegister<Register>(); 3165 Register out = locations->Out().AsRegister<Register>(); 3166 Register num; 3167 Register edx; 3168 3169 if (instruction->IsDiv()) { 3170 edx = locations->GetTemp(0).AsRegister<Register>(); 3171 num = locations->GetTemp(1).AsRegister<Register>(); 3172 } else { 3173 edx = locations->Out().AsRegister<Register>(); 3174 num = locations->GetTemp(0).AsRegister<Register>(); 3175 } 3176 3177 DCHECK_EQ(EAX, eax); 3178 DCHECK_EQ(EDX, edx); 3179 if (instruction->IsDiv()) { 3180 DCHECK_EQ(EAX, out); 3181 } else { 3182 DCHECK_EQ(EDX, out); 3183 } 3184 3185 int64_t magic; 3186 int shift; 3187 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift); 3188 3189 NearLabel ndiv; 3190 NearLabel end; 3191 // If numerator is 0, the result is 0, no computation needed. 3192 __ testl(eax, eax); 3193 __ j(kNotEqual, &ndiv); 3194 3195 __ xorl(out, out); 3196 __ jmp(&end); 3197 3198 __ Bind(&ndiv); 3199 3200 // Save the numerator. 3201 __ movl(num, eax); 3202 3203 // EAX = magic 3204 __ movl(eax, Immediate(magic)); 3205 3206 // EDX:EAX = magic * numerator 3207 __ imull(num); 3208 3209 if (imm > 0 && magic < 0) { 3210 // EDX += num 3211 __ addl(edx, num); 3212 } else if (imm < 0 && magic > 0) { 3213 __ subl(edx, num); 3214 } 3215 3216 // Shift if needed. 3217 if (shift != 0) { 3218 __ sarl(edx, Immediate(shift)); 3219 } 3220 3221 // EDX += 1 if EDX < 0 3222 __ movl(eax, edx); 3223 __ shrl(edx, Immediate(31)); 3224 __ addl(edx, eax); 3225 3226 if (instruction->IsRem()) { 3227 __ movl(eax, num); 3228 __ imull(edx, Immediate(imm)); 3229 __ subl(eax, edx); 3230 __ movl(edx, eax); 3231 } else { 3232 __ movl(eax, edx); 3233 } 3234 __ Bind(&end); 3235} 3236 3237void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) { 3238 DCHECK(instruction->IsDiv() || instruction->IsRem()); 3239 3240 LocationSummary* locations = instruction->GetLocations(); 3241 Location out = locations->Out(); 3242 Location first = locations->InAt(0); 3243 Location second = locations->InAt(1); 3244 bool is_div = instruction->IsDiv(); 3245 3246 switch (instruction->GetResultType()) { 3247 case Primitive::kPrimInt: { 3248 DCHECK_EQ(EAX, first.AsRegister<Register>()); 3249 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>()); 3250 3251 if (second.IsConstant()) { 3252 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue(); 3253 3254 if (imm == 0) { 3255 // Do not generate anything for 0. DivZeroCheck would forbid any generated code. 3256 } else if (imm == 1 || imm == -1) { 3257 DivRemOneOrMinusOne(instruction); 3258 } else if (is_div && IsPowerOfTwo(std::abs(imm))) { 3259 DivByPowerOfTwo(instruction->AsDiv()); 3260 } else { 3261 DCHECK(imm <= -2 || imm >= 2); 3262 GenerateDivRemWithAnyConstant(instruction); 3263 } 3264 } else { 3265 SlowPathCode* slow_path = 3266 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(), 3267 is_div); 3268 codegen_->AddSlowPath(slow_path); 3269 3270 Register second_reg = second.AsRegister<Register>(); 3271 // 0x80000000/-1 triggers an arithmetic exception! 3272 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so 3273 // it's safe to just use negl instead of more complex comparisons. 3274 3275 __ cmpl(second_reg, Immediate(-1)); 3276 __ j(kEqual, slow_path->GetEntryLabel()); 3277 3278 // edx:eax <- sign-extended of eax 3279 __ cdq(); 3280 // eax = quotient, edx = remainder 3281 __ idivl(second_reg); 3282 __ Bind(slow_path->GetExitLabel()); 3283 } 3284 break; 3285 } 3286 3287 case Primitive::kPrimLong: { 3288 InvokeRuntimeCallingConvention calling_convention; 3289 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); 3290 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); 3291 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); 3292 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); 3293 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>()); 3294 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>()); 3295 3296 if (is_div) { 3297 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), 3298 instruction, 3299 instruction->GetDexPc(), 3300 nullptr); 3301 } else { 3302 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), 3303 instruction, 3304 instruction->GetDexPc(), 3305 nullptr); 3306 } 3307 break; 3308 } 3309 3310 default: 3311 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType(); 3312 } 3313} 3314 3315void LocationsBuilderX86::VisitDiv(HDiv* div) { 3316 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong) 3317 ? LocationSummary::kCall 3318 : LocationSummary::kNoCall; 3319 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind); 3320 3321 switch (div->GetResultType()) { 3322 case Primitive::kPrimInt: { 3323 locations->SetInAt(0, Location::RegisterLocation(EAX)); 3324 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1))); 3325 locations->SetOut(Location::SameAsFirstInput()); 3326 // Intel uses edx:eax as the dividend. 3327 locations->AddTemp(Location::RegisterLocation(EDX)); 3328 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way 3329 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as 3330 // output and request another temp. 3331 if (div->InputAt(1)->IsIntConstant()) { 3332 locations->AddTemp(Location::RequiresRegister()); 3333 } 3334 break; 3335 } 3336 case Primitive::kPrimLong: { 3337 InvokeRuntimeCallingConvention calling_convention; 3338 locations->SetInAt(0, Location::RegisterPairLocation( 3339 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 3340 locations->SetInAt(1, Location::RegisterPairLocation( 3341 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 3342 // Runtime helper puts the result in EAX, EDX. 3343 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 3344 break; 3345 } 3346 case Primitive::kPrimFloat: 3347 case Primitive::kPrimDouble: { 3348 locations->SetInAt(0, Location::RequiresFpuRegister()); 3349 locations->SetInAt(1, Location::Any()); 3350 locations->SetOut(Location::SameAsFirstInput()); 3351 break; 3352 } 3353 3354 default: 3355 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 3356 } 3357} 3358 3359void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { 3360 LocationSummary* locations = div->GetLocations(); 3361 Location first = locations->InAt(0); 3362 Location second = locations->InAt(1); 3363 3364 switch (div->GetResultType()) { 3365 case Primitive::kPrimInt: 3366 case Primitive::kPrimLong: { 3367 GenerateDivRemIntegral(div); 3368 break; 3369 } 3370 3371 case Primitive::kPrimFloat: { 3372 if (second.IsFpuRegister()) { 3373 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 3374 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) { 3375 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable(); 3376 DCHECK(!const_area->NeedsMaterialization()); 3377 __ divss(first.AsFpuRegister<XmmRegister>(), 3378 codegen_->LiteralFloatAddress( 3379 const_area->GetConstant()->AsFloatConstant()->GetValue(), 3380 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 3381 } else { 3382 DCHECK(second.IsStackSlot()); 3383 __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 3384 } 3385 break; 3386 } 3387 3388 case Primitive::kPrimDouble: { 3389 if (second.IsFpuRegister()) { 3390 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>()); 3391 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) { 3392 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable(); 3393 DCHECK(!const_area->NeedsMaterialization()); 3394 __ divsd(first.AsFpuRegister<XmmRegister>(), 3395 codegen_->LiteralDoubleAddress( 3396 const_area->GetConstant()->AsDoubleConstant()->GetValue(), 3397 const_area->GetLocations()->InAt(0).AsRegister<Register>())); 3398 } else { 3399 DCHECK(second.IsDoubleStackSlot()); 3400 __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex())); 3401 } 3402 break; 3403 } 3404 3405 default: 3406 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 3407 } 3408} 3409 3410void LocationsBuilderX86::VisitRem(HRem* rem) { 3411 Primitive::Type type = rem->GetResultType(); 3412 3413 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong) 3414 ? LocationSummary::kCall 3415 : LocationSummary::kNoCall; 3416 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); 3417 3418 switch (type) { 3419 case Primitive::kPrimInt: { 3420 locations->SetInAt(0, Location::RegisterLocation(EAX)); 3421 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1))); 3422 locations->SetOut(Location::RegisterLocation(EDX)); 3423 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way 3424 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as 3425 // output and request another temp. 3426 if (rem->InputAt(1)->IsIntConstant()) { 3427 locations->AddTemp(Location::RequiresRegister()); 3428 } 3429 break; 3430 } 3431 case Primitive::kPrimLong: { 3432 InvokeRuntimeCallingConvention calling_convention; 3433 locations->SetInAt(0, Location::RegisterPairLocation( 3434 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 3435 locations->SetInAt(1, Location::RegisterPairLocation( 3436 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 3437 // Runtime helper puts the result in EAX, EDX. 3438 locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); 3439 break; 3440 } 3441 case Primitive::kPrimDouble: 3442 case Primitive::kPrimFloat: { 3443 locations->SetInAt(0, Location::Any()); 3444 locations->SetInAt(1, Location::Any()); 3445 locations->SetOut(Location::RequiresFpuRegister()); 3446 locations->AddTemp(Location::RegisterLocation(EAX)); 3447 break; 3448 } 3449 3450 default: 3451 LOG(FATAL) << "Unexpected rem type " << type; 3452 } 3453} 3454 3455void InstructionCodeGeneratorX86::VisitRem(HRem* rem) { 3456 Primitive::Type type = rem->GetResultType(); 3457 switch (type) { 3458 case Primitive::kPrimInt: 3459 case Primitive::kPrimLong: { 3460 GenerateDivRemIntegral(rem); 3461 break; 3462 } 3463 case Primitive::kPrimFloat: 3464 case Primitive::kPrimDouble: { 3465 GenerateRemFP(rem); 3466 break; 3467 } 3468 default: 3469 LOG(FATAL) << "Unexpected rem type " << type; 3470 } 3471} 3472 3473void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) { 3474 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock() 3475 ? LocationSummary::kCallOnSlowPath 3476 : LocationSummary::kNoCall; 3477 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 3478 switch (instruction->GetType()) { 3479 case Primitive::kPrimByte: 3480 case Primitive::kPrimChar: 3481 case Primitive::kPrimShort: 3482 case Primitive::kPrimInt: { 3483 locations->SetInAt(0, Location::Any()); 3484 break; 3485 } 3486 case Primitive::kPrimLong: { 3487 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 3488 if (!instruction->IsConstant()) { 3489 locations->AddTemp(Location::RequiresRegister()); 3490 } 3491 break; 3492 } 3493 default: 3494 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType(); 3495 } 3496 if (instruction->HasUses()) { 3497 locations->SetOut(Location::SameAsFirstInput()); 3498 } 3499} 3500 3501void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) { 3502 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction); 3503 codegen_->AddSlowPath(slow_path); 3504 3505 LocationSummary* locations = instruction->GetLocations(); 3506 Location value = locations->InAt(0); 3507 3508 switch (instruction->GetType()) { 3509 case Primitive::kPrimByte: 3510 case Primitive::kPrimChar: 3511 case Primitive::kPrimShort: 3512 case Primitive::kPrimInt: { 3513 if (value.IsRegister()) { 3514 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>()); 3515 __ j(kEqual, slow_path->GetEntryLabel()); 3516 } else if (value.IsStackSlot()) { 3517 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0)); 3518 __ j(kEqual, slow_path->GetEntryLabel()); 3519 } else { 3520 DCHECK(value.IsConstant()) << value; 3521 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) { 3522 __ jmp(slow_path->GetEntryLabel()); 3523 } 3524 } 3525 break; 3526 } 3527 case Primitive::kPrimLong: { 3528 if (value.IsRegisterPair()) { 3529 Register temp = locations->GetTemp(0).AsRegister<Register>(); 3530 __ movl(temp, value.AsRegisterPairLow<Register>()); 3531 __ orl(temp, value.AsRegisterPairHigh<Register>()); 3532 __ j(kEqual, slow_path->GetEntryLabel()); 3533 } else { 3534 DCHECK(value.IsConstant()) << value; 3535 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) { 3536 __ jmp(slow_path->GetEntryLabel()); 3537 } 3538 } 3539 break; 3540 } 3541 default: 3542 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType(); 3543 } 3544} 3545 3546void LocationsBuilderX86::HandleShift(HBinaryOperation* op) { 3547 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); 3548 3549 LocationSummary* locations = 3550 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall); 3551 3552 switch (op->GetResultType()) { 3553 case Primitive::kPrimInt: 3554 case Primitive::kPrimLong: { 3555 // Can't have Location::Any() and output SameAsFirstInput() 3556 locations->SetInAt(0, Location::RequiresRegister()); 3557 // The shift count needs to be in CL or a constant. 3558 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1))); 3559 locations->SetOut(Location::SameAsFirstInput()); 3560 break; 3561 } 3562 default: 3563 LOG(FATAL) << "Unexpected op type " << op->GetResultType(); 3564 } 3565} 3566 3567void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) { 3568 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); 3569 3570 LocationSummary* locations = op->GetLocations(); 3571 Location first = locations->InAt(0); 3572 Location second = locations->InAt(1); 3573 DCHECK(first.Equals(locations->Out())); 3574 3575 switch (op->GetResultType()) { 3576 case Primitive::kPrimInt: { 3577 DCHECK(first.IsRegister()); 3578 Register first_reg = first.AsRegister<Register>(); 3579 if (second.IsRegister()) { 3580 Register second_reg = second.AsRegister<Register>(); 3581 DCHECK_EQ(ECX, second_reg); 3582 if (op->IsShl()) { 3583 __ shll(first_reg, second_reg); 3584 } else if (op->IsShr()) { 3585 __ sarl(first_reg, second_reg); 3586 } else { 3587 __ shrl(first_reg, second_reg); 3588 } 3589 } else { 3590 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue; 3591 if (shift == 0) { 3592 return; 3593 } 3594 Immediate imm(shift); 3595 if (op->IsShl()) { 3596 __ shll(first_reg, imm); 3597 } else if (op->IsShr()) { 3598 __ sarl(first_reg, imm); 3599 } else { 3600 __ shrl(first_reg, imm); 3601 } 3602 } 3603 break; 3604 } 3605 case Primitive::kPrimLong: { 3606 if (second.IsRegister()) { 3607 Register second_reg = second.AsRegister<Register>(); 3608 DCHECK_EQ(ECX, second_reg); 3609 if (op->IsShl()) { 3610 GenerateShlLong(first, second_reg); 3611 } else if (op->IsShr()) { 3612 GenerateShrLong(first, second_reg); 3613 } else { 3614 GenerateUShrLong(first, second_reg); 3615 } 3616 } else { 3617 // Shift by a constant. 3618 int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue; 3619 // Nothing to do if the shift is 0, as the input is already the output. 3620 if (shift != 0) { 3621 if (op->IsShl()) { 3622 GenerateShlLong(first, shift); 3623 } else if (op->IsShr()) { 3624 GenerateShrLong(first, shift); 3625 } else { 3626 GenerateUShrLong(first, shift); 3627 } 3628 } 3629 } 3630 break; 3631 } 3632 default: 3633 LOG(FATAL) << "Unexpected op type " << op->GetResultType(); 3634 } 3635} 3636 3637void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) { 3638 Register low = loc.AsRegisterPairLow<Register>(); 3639 Register high = loc.AsRegisterPairHigh<Register>(); 3640 if (shift == 1) { 3641 // This is just an addition. 3642 __ addl(low, low); 3643 __ adcl(high, high); 3644 } else if (shift == 32) { 3645 // Shift by 32 is easy. High gets low, and low gets 0. 3646 codegen_->EmitParallelMoves( 3647 loc.ToLow(), 3648 loc.ToHigh(), 3649 Primitive::kPrimInt, 3650 Location::ConstantLocation(GetGraph()->GetIntConstant(0)), 3651 loc.ToLow(), 3652 Primitive::kPrimInt); 3653 } else if (shift > 32) { 3654 // Low part becomes 0. High part is low part << (shift-32). 3655 __ movl(high, low); 3656 __ shll(high, Immediate(shift - 32)); 3657 __ xorl(low, low); 3658 } else { 3659 // Between 1 and 31. 3660 __ shld(high, low, Immediate(shift)); 3661 __ shll(low, Immediate(shift)); 3662 } 3663} 3664 3665void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) { 3666 NearLabel done; 3667 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter); 3668 __ shll(loc.AsRegisterPairLow<Register>(), shifter); 3669 __ testl(shifter, Immediate(32)); 3670 __ j(kEqual, &done); 3671 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>()); 3672 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0)); 3673 __ Bind(&done); 3674} 3675 3676void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) { 3677 Register low = loc.AsRegisterPairLow<Register>(); 3678 Register high = loc.AsRegisterPairHigh<Register>(); 3679 if (shift == 32) { 3680 // Need to copy the sign. 3681 DCHECK_NE(low, high); 3682 __ movl(low, high); 3683 __ sarl(high, Immediate(31)); 3684 } else if (shift > 32) { 3685 DCHECK_NE(low, high); 3686 // High part becomes sign. Low part is shifted by shift - 32. 3687 __ movl(low, high); 3688 __ sarl(high, Immediate(31)); 3689 __ sarl(low, Immediate(shift - 32)); 3690 } else { 3691 // Between 1 and 31. 3692 __ shrd(low, high, Immediate(shift)); 3693 __ sarl(high, Immediate(shift)); 3694 } 3695} 3696 3697void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) { 3698 NearLabel done; 3699 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter); 3700 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter); 3701 __ testl(shifter, Immediate(32)); 3702 __ j(kEqual, &done); 3703 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>()); 3704 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31)); 3705 __ Bind(&done); 3706} 3707 3708void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) { 3709 Register low = loc.AsRegisterPairLow<Register>(); 3710 Register high = loc.AsRegisterPairHigh<Register>(); 3711 if (shift == 32) { 3712 // Shift by 32 is easy. Low gets high, and high gets 0. 3713 codegen_->EmitParallelMoves( 3714 loc.ToHigh(), 3715 loc.ToLow(), 3716 Primitive::kPrimInt, 3717 Location::ConstantLocation(GetGraph()->GetIntConstant(0)), 3718 loc.ToHigh(), 3719 Primitive::kPrimInt); 3720 } else if (shift > 32) { 3721 // Low part is high >> (shift - 32). High part becomes 0. 3722 __ movl(low, high); 3723 __ shrl(low, Immediate(shift - 32)); 3724 __ xorl(high, high); 3725 } else { 3726 // Between 1 and 31. 3727 __ shrd(low, high, Immediate(shift)); 3728 __ shrl(high, Immediate(shift)); 3729 } 3730} 3731 3732void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) { 3733 NearLabel done; 3734 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter); 3735 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter); 3736 __ testl(shifter, Immediate(32)); 3737 __ j(kEqual, &done); 3738 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>()); 3739 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0)); 3740 __ Bind(&done); 3741} 3742 3743void LocationsBuilderX86::VisitShl(HShl* shl) { 3744 HandleShift(shl); 3745} 3746 3747void InstructionCodeGeneratorX86::VisitShl(HShl* shl) { 3748 HandleShift(shl); 3749} 3750 3751void LocationsBuilderX86::VisitShr(HShr* shr) { 3752 HandleShift(shr); 3753} 3754 3755void InstructionCodeGeneratorX86::VisitShr(HShr* shr) { 3756 HandleShift(shr); 3757} 3758 3759void LocationsBuilderX86::VisitUShr(HUShr* ushr) { 3760 HandleShift(ushr); 3761} 3762 3763void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) { 3764 HandleShift(ushr); 3765} 3766 3767void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) { 3768 LocationSummary* locations = 3769 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3770 locations->SetOut(Location::RegisterLocation(EAX)); 3771 InvokeRuntimeCallingConvention calling_convention; 3772 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3773 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 3774} 3775 3776void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) { 3777 // Note: if heap poisoning is enabled, the entry point takes cares 3778 // of poisoning the reference. 3779 codegen_->InvokeRuntime(instruction->GetEntrypoint(), 3780 instruction, 3781 instruction->GetDexPc(), 3782 nullptr); 3783 DCHECK(!codegen_->IsLeafMethod()); 3784} 3785 3786void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) { 3787 LocationSummary* locations = 3788 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3789 locations->SetOut(Location::RegisterLocation(EAX)); 3790 InvokeRuntimeCallingConvention calling_convention; 3791 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3792 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 3793 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 3794} 3795 3796void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) { 3797 InvokeRuntimeCallingConvention calling_convention; 3798 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex())); 3799 3800 // Note: if heap poisoning is enabled, the entry point takes cares 3801 // of poisoning the reference. 3802 codegen_->InvokeRuntime(instruction->GetEntrypoint(), 3803 instruction, 3804 instruction->GetDexPc(), 3805 nullptr); 3806 DCHECK(!codegen_->IsLeafMethod()); 3807} 3808 3809void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) { 3810 LocationSummary* locations = 3811 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3812 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 3813 if (location.IsStackSlot()) { 3814 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 3815 } else if (location.IsDoubleStackSlot()) { 3816 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 3817 } 3818 locations->SetOut(location); 3819} 3820 3821void InstructionCodeGeneratorX86::VisitParameterValue( 3822 HParameterValue* instruction ATTRIBUTE_UNUSED) { 3823} 3824 3825void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) { 3826 LocationSummary* locations = 3827 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3828 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument)); 3829} 3830 3831void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) { 3832} 3833 3834void LocationsBuilderX86::VisitNot(HNot* not_) { 3835 LocationSummary* locations = 3836 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall); 3837 locations->SetInAt(0, Location::RequiresRegister()); 3838 locations->SetOut(Location::SameAsFirstInput()); 3839} 3840 3841void InstructionCodeGeneratorX86::VisitNot(HNot* not_) { 3842 LocationSummary* locations = not_->GetLocations(); 3843 Location in = locations->InAt(0); 3844 Location out = locations->Out(); 3845 DCHECK(in.Equals(out)); 3846 switch (not_->GetResultType()) { 3847 case Primitive::kPrimInt: 3848 __ notl(out.AsRegister<Register>()); 3849 break; 3850 3851 case Primitive::kPrimLong: 3852 __ notl(out.AsRegisterPairLow<Register>()); 3853 __ notl(out.AsRegisterPairHigh<Register>()); 3854 break; 3855 3856 default: 3857 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType(); 3858 } 3859} 3860 3861void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) { 3862 LocationSummary* locations = 3863 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall); 3864 locations->SetInAt(0, Location::RequiresRegister()); 3865 locations->SetOut(Location::SameAsFirstInput()); 3866} 3867 3868void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) { 3869 LocationSummary* locations = bool_not->GetLocations(); 3870 Location in = locations->InAt(0); 3871 Location out = locations->Out(); 3872 DCHECK(in.Equals(out)); 3873 __ xorl(out.AsRegister<Register>(), Immediate(1)); 3874} 3875 3876void LocationsBuilderX86::VisitCompare(HCompare* compare) { 3877 LocationSummary* locations = 3878 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 3879 switch (compare->InputAt(0)->GetType()) { 3880 case Primitive::kPrimLong: { 3881 locations->SetInAt(0, Location::RequiresRegister()); 3882 locations->SetInAt(1, Location::Any()); 3883 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3884 break; 3885 } 3886 case Primitive::kPrimFloat: 3887 case Primitive::kPrimDouble: { 3888 locations->SetInAt(0, Location::RequiresFpuRegister()); 3889 locations->SetInAt(1, Location::RequiresFpuRegister()); 3890 locations->SetOut(Location::RequiresRegister()); 3891 break; 3892 } 3893 default: 3894 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType(); 3895 } 3896} 3897 3898void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) { 3899 LocationSummary* locations = compare->GetLocations(); 3900 Register out = locations->Out().AsRegister<Register>(); 3901 Location left = locations->InAt(0); 3902 Location right = locations->InAt(1); 3903 3904 NearLabel less, greater, done; 3905 switch (compare->InputAt(0)->GetType()) { 3906 case Primitive::kPrimLong: { 3907 Register left_low = left.AsRegisterPairLow<Register>(); 3908 Register left_high = left.AsRegisterPairHigh<Register>(); 3909 int32_t val_low = 0; 3910 int32_t val_high = 0; 3911 bool right_is_const = false; 3912 3913 if (right.IsConstant()) { 3914 DCHECK(right.GetConstant()->IsLongConstant()); 3915 right_is_const = true; 3916 int64_t val = right.GetConstant()->AsLongConstant()->GetValue(); 3917 val_low = Low32Bits(val); 3918 val_high = High32Bits(val); 3919 } 3920 3921 if (right.IsRegisterPair()) { 3922 __ cmpl(left_high, right.AsRegisterPairHigh<Register>()); 3923 } else if (right.IsDoubleStackSlot()) { 3924 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize))); 3925 } else { 3926 DCHECK(right_is_const) << right; 3927 if (val_high == 0) { 3928 __ testl(left_high, left_high); 3929 } else { 3930 __ cmpl(left_high, Immediate(val_high)); 3931 } 3932 } 3933 __ j(kLess, &less); // Signed compare. 3934 __ j(kGreater, &greater); // Signed compare. 3935 if (right.IsRegisterPair()) { 3936 __ cmpl(left_low, right.AsRegisterPairLow<Register>()); 3937 } else if (right.IsDoubleStackSlot()) { 3938 __ cmpl(left_low, Address(ESP, right.GetStackIndex())); 3939 } else { 3940 DCHECK(right_is_const) << right; 3941 if (val_low == 0) { 3942 __ testl(left_low, left_low); 3943 } else { 3944 __ cmpl(left_low, Immediate(val_low)); 3945 } 3946 } 3947 break; 3948 } 3949 case Primitive::kPrimFloat: { 3950 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); 3951 __ j(kUnordered, compare->IsGtBias() ? &greater : &less); 3952 break; 3953 } 3954 case Primitive::kPrimDouble: { 3955 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>()); 3956 __ j(kUnordered, compare->IsGtBias() ? &greater : &less); 3957 break; 3958 } 3959 default: 3960 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType(); 3961 } 3962 __ movl(out, Immediate(0)); 3963 __ j(kEqual, &done); 3964 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats). 3965 3966 __ Bind(&greater); 3967 __ movl(out, Immediate(1)); 3968 __ jmp(&done); 3969 3970 __ Bind(&less); 3971 __ movl(out, Immediate(-1)); 3972 3973 __ Bind(&done); 3974} 3975 3976void LocationsBuilderX86::VisitPhi(HPhi* instruction) { 3977 LocationSummary* locations = 3978 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3979 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 3980 locations->SetInAt(i, Location::Any()); 3981 } 3982 locations->SetOut(Location::Any()); 3983} 3984 3985void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) { 3986 LOG(FATAL) << "Unreachable"; 3987} 3988 3989void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) { 3990 /* 3991 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence. 3992 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model. 3993 * For those cases, all we need to ensure is that there is a scheduling barrier in place. 3994 */ 3995 switch (kind) { 3996 case MemBarrierKind::kAnyAny: { 3997 __ mfence(); 3998 break; 3999 } 4000 case MemBarrierKind::kAnyStore: 4001 case MemBarrierKind::kLoadAny: 4002 case MemBarrierKind::kStoreStore: { 4003 // nop 4004 break; 4005 } 4006 default: 4007 LOG(FATAL) << "Unexpected memory barrier " << kind; 4008 } 4009} 4010 4011HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch( 4012 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, 4013 MethodReference target_method ATTRIBUTE_UNUSED) { 4014 switch (desired_dispatch_info.code_ptr_location) { 4015 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup: 4016 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect: 4017 // For direct code, we actually prefer to call via the code pointer from ArtMethod*. 4018 // (Though the direct CALL ptr16:32 is available for consideration). 4019 return HInvokeStaticOrDirect::DispatchInfo { 4020 desired_dispatch_info.method_load_kind, 4021 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, 4022 desired_dispatch_info.method_load_data, 4023 0u 4024 }; 4025 default: 4026 return desired_dispatch_info; 4027 } 4028} 4029 4030Register CodeGeneratorX86::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, 4031 Register temp) { 4032 DCHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u); 4033 Location location = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex()); 4034 if (!invoke->GetLocations()->Intrinsified()) { 4035 return location.AsRegister<Register>(); 4036 } 4037 // For intrinsics we allow any location, so it may be on the stack. 4038 if (!location.IsRegister()) { 4039 __ movl(temp, Address(ESP, location.GetStackIndex())); 4040 return temp; 4041 } 4042 // For register locations, check if the register was saved. If so, get it from the stack. 4043 // Note: There is a chance that the register was saved but not overwritten, so we could 4044 // save one load. However, since this is just an intrinsic slow path we prefer this 4045 // simple and more robust approach rather that trying to determine if that's the case. 4046 SlowPathCode* slow_path = GetCurrentSlowPath(); 4047 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path. 4048 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) { 4049 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>()); 4050 __ movl(temp, Address(ESP, stack_offset)); 4051 return temp; 4052 } 4053 return location.AsRegister<Register>(); 4054} 4055 4056void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) { 4057 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp. 4058 switch (invoke->GetMethodLoadKind()) { 4059 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: 4060 // temp = thread->string_init_entrypoint 4061 __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset())); 4062 break; 4063 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive: 4064 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex()); 4065 break; 4066 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: 4067 __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress())); 4068 break; 4069 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup: 4070 __ movl(temp.AsRegister<Register>(), Immediate(0)); // Placeholder. 4071 method_patches_.emplace_back(invoke->GetTargetMethod()); 4072 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn. 4073 break; 4074 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { 4075 Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke, 4076 temp.AsRegister<Register>()); 4077 uint32_t offset = invoke->GetDexCacheArrayOffset(); 4078 __ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset)); 4079 // Add the patch entry and bind its label at the end of the instruction. 4080 pc_relative_dex_cache_patches_.emplace_back(*invoke->GetTargetMethod().dex_file, offset); 4081 __ Bind(&pc_relative_dex_cache_patches_.back().label); 4082 break; 4083 } 4084 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: { 4085 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex()); 4086 Register method_reg; 4087 Register reg = temp.AsRegister<Register>(); 4088 if (current_method.IsRegister()) { 4089 method_reg = current_method.AsRegister<Register>(); 4090 } else { 4091 DCHECK(IsBaseline() || invoke->GetLocations()->Intrinsified()); 4092 DCHECK(!current_method.IsValid()); 4093 method_reg = reg; 4094 __ movl(reg, Address(ESP, kCurrentMethodStackOffset)); 4095 } 4096 // /* ArtMethod*[] */ temp = temp.ptr_sized_fields_->dex_cache_resolved_methods_; 4097 __ movl(reg, Address(method_reg, 4098 ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value())); 4099 // temp = temp[index_in_cache] 4100 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index; 4101 __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache))); 4102 break; 4103 } 4104 } 4105 4106 switch (invoke->GetCodePtrLocation()) { 4107 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf: 4108 __ call(GetFrameEntryLabel()); 4109 break; 4110 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: { 4111 relative_call_patches_.emplace_back(invoke->GetTargetMethod()); 4112 Label* label = &relative_call_patches_.back().label; 4113 __ call(label); // Bind to the patch label, override at link time. 4114 __ Bind(label); // Bind the label at the end of the "call" insn. 4115 break; 4116 } 4117 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup: 4118 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect: 4119 // Filtered out by GetSupportedInvokeStaticOrDirectDispatch(). 4120 LOG(FATAL) << "Unsupported"; 4121 UNREACHABLE(); 4122 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod: 4123 // (callee_method + offset_of_quick_compiled_code)() 4124 __ call(Address(callee_method.AsRegister<Register>(), 4125 ArtMethod::EntryPointFromQuickCompiledCodeOffset( 4126 kX86WordSize).Int32Value())); 4127 break; 4128 } 4129 4130 DCHECK(!IsLeafMethod()); 4131} 4132 4133void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) { 4134 Register temp = temp_in.AsRegister<Register>(); 4135 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset( 4136 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value(); 4137 LocationSummary* locations = invoke->GetLocations(); 4138 Location receiver = locations->InAt(0); 4139 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 4140 DCHECK(receiver.IsRegister()); 4141 // /* HeapReference<Class> */ temp = receiver->klass_ 4142 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset)); 4143 MaybeRecordImplicitNullCheck(invoke); 4144 // Instead of simply (possibly) unpoisoning `temp` here, we should 4145 // emit a read barrier for the previous class reference load. 4146 // However this is not required in practice, as this is an 4147 // intermediate/temporary reference and because the current 4148 // concurrent copying collector keeps the from-space memory 4149 // intact/accessible until the end of the marking phase (the 4150 // concurrent copying collector may not in the future). 4151 __ MaybeUnpoisonHeapReference(temp); 4152 // temp = temp->GetMethodAt(method_offset); 4153 __ movl(temp, Address(temp, method_offset)); 4154 // call temp->GetEntryPoint(); 4155 __ call(Address( 4156 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value())); 4157} 4158 4159void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { 4160 DCHECK(linker_patches->empty()); 4161 size_t size = 4162 method_patches_.size() + 4163 relative_call_patches_.size() + 4164 pc_relative_dex_cache_patches_.size(); 4165 linker_patches->reserve(size); 4166 // The label points to the end of the "movl" insn but the literal offset for method 4167 // patch needs to point to the embedded constant which occupies the last 4 bytes. 4168 constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u; 4169 for (const MethodPatchInfo<Label>& info : method_patches_) { 4170 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment; 4171 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset, 4172 info.target_method.dex_file, 4173 info.target_method.dex_method_index)); 4174 } 4175 for (const MethodPatchInfo<Label>& info : relative_call_patches_) { 4176 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment; 4177 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset, 4178 info.target_method.dex_file, 4179 info.target_method.dex_method_index)); 4180 } 4181 for (const PcRelativeDexCacheAccessInfo& info : pc_relative_dex_cache_patches_) { 4182 uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment; 4183 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset, 4184 &info.target_dex_file, 4185 GetMethodAddressOffset(), 4186 info.element_offset)); 4187 } 4188} 4189 4190void CodeGeneratorX86::MarkGCCard(Register temp, 4191 Register card, 4192 Register object, 4193 Register value, 4194 bool value_can_be_null) { 4195 NearLabel is_null; 4196 if (value_can_be_null) { 4197 __ testl(value, value); 4198 __ j(kEqual, &is_null); 4199 } 4200 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value())); 4201 __ movl(temp, object); 4202 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift)); 4203 __ movb(Address(temp, card, TIMES_1, 0), 4204 X86ManagedRegister::FromCpuRegister(card).AsByteRegister()); 4205 if (value_can_be_null) { 4206 __ Bind(&is_null); 4207 } 4208} 4209 4210void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) { 4211 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 4212 4213 bool object_field_get_with_read_barrier = 4214 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot); 4215 LocationSummary* locations = 4216 new (GetGraph()->GetArena()) LocationSummary(instruction, 4217 kEmitCompilerReadBarrier ? 4218 LocationSummary::kCallOnSlowPath : 4219 LocationSummary::kNoCall); 4220 locations->SetInAt(0, Location::RequiresRegister()); 4221 4222 if (Primitive::IsFloatingPointType(instruction->GetType())) { 4223 locations->SetOut(Location::RequiresFpuRegister()); 4224 } else { 4225 // The output overlaps in case of long: we don't want the low move 4226 // to overwrite the object's location. Likewise, in the case of 4227 // an object field get with read barriers enabled, we do not want 4228 // the move to overwrite the object's location, as we need it to emit 4229 // the read barrier. 4230 locations->SetOut( 4231 Location::RequiresRegister(), 4232 (object_field_get_with_read_barrier || instruction->GetType() == Primitive::kPrimLong) ? 4233 Location::kOutputOverlap : 4234 Location::kNoOutputOverlap); 4235 } 4236 4237 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) { 4238 // Long values can be loaded atomically into an XMM using movsd. 4239 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM 4240 // and then copy the XMM into the output 32bits at a time). 4241 locations->AddTemp(Location::RequiresFpuRegister()); 4242 } 4243} 4244 4245void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction, 4246 const FieldInfo& field_info) { 4247 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 4248 4249 LocationSummary* locations = instruction->GetLocations(); 4250 Location base_loc = locations->InAt(0); 4251 Register base = base_loc.AsRegister<Register>(); 4252 Location out = locations->Out(); 4253 bool is_volatile = field_info.IsVolatile(); 4254 Primitive::Type field_type = field_info.GetFieldType(); 4255 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 4256 4257 switch (field_type) { 4258 case Primitive::kPrimBoolean: { 4259 __ movzxb(out.AsRegister<Register>(), Address(base, offset)); 4260 break; 4261 } 4262 4263 case Primitive::kPrimByte: { 4264 __ movsxb(out.AsRegister<Register>(), Address(base, offset)); 4265 break; 4266 } 4267 4268 case Primitive::kPrimShort: { 4269 __ movsxw(out.AsRegister<Register>(), Address(base, offset)); 4270 break; 4271 } 4272 4273 case Primitive::kPrimChar: { 4274 __ movzxw(out.AsRegister<Register>(), Address(base, offset)); 4275 break; 4276 } 4277 4278 case Primitive::kPrimInt: 4279 case Primitive::kPrimNot: { 4280 __ movl(out.AsRegister<Register>(), Address(base, offset)); 4281 break; 4282 } 4283 4284 case Primitive::kPrimLong: { 4285 if (is_volatile) { 4286 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 4287 __ movsd(temp, Address(base, offset)); 4288 codegen_->MaybeRecordImplicitNullCheck(instruction); 4289 __ movd(out.AsRegisterPairLow<Register>(), temp); 4290 __ psrlq(temp, Immediate(32)); 4291 __ movd(out.AsRegisterPairHigh<Register>(), temp); 4292 } else { 4293 DCHECK_NE(base, out.AsRegisterPairLow<Register>()); 4294 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset)); 4295 codegen_->MaybeRecordImplicitNullCheck(instruction); 4296 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset)); 4297 } 4298 break; 4299 } 4300 4301 case Primitive::kPrimFloat: { 4302 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset)); 4303 break; 4304 } 4305 4306 case Primitive::kPrimDouble: { 4307 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset)); 4308 break; 4309 } 4310 4311 case Primitive::kPrimVoid: 4312 LOG(FATAL) << "Unreachable type " << field_type; 4313 UNREACHABLE(); 4314 } 4315 4316 // Longs are handled in the switch. 4317 if (field_type != Primitive::kPrimLong) { 4318 codegen_->MaybeRecordImplicitNullCheck(instruction); 4319 } 4320 4321 if (is_volatile) { 4322 GenerateMemoryBarrier(MemBarrierKind::kLoadAny); 4323 } 4324 4325 if (field_type == Primitive::kPrimNot) { 4326 codegen_->MaybeGenerateReadBarrier(instruction, out, out, base_loc, offset); 4327 } 4328} 4329 4330void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) { 4331 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 4332 4333 LocationSummary* locations = 4334 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 4335 locations->SetInAt(0, Location::RequiresRegister()); 4336 bool is_volatile = field_info.IsVolatile(); 4337 Primitive::Type field_type = field_info.GetFieldType(); 4338 bool is_byte_type = (field_type == Primitive::kPrimBoolean) 4339 || (field_type == Primitive::kPrimByte); 4340 4341 // The register allocator does not support multiple 4342 // inputs that die at entry with one in a specific register. 4343 if (is_byte_type) { 4344 // Ensure the value is in a byte register. 4345 locations->SetInAt(1, Location::RegisterLocation(EAX)); 4346 } else if (Primitive::IsFloatingPointType(field_type)) { 4347 if (is_volatile && field_type == Primitive::kPrimDouble) { 4348 // In order to satisfy the semantics of volatile, this must be a single instruction store. 4349 locations->SetInAt(1, Location::RequiresFpuRegister()); 4350 } else { 4351 locations->SetInAt(1, Location::FpuRegisterOrConstant(instruction->InputAt(1))); 4352 } 4353 } else if (is_volatile && field_type == Primitive::kPrimLong) { 4354 // In order to satisfy the semantics of volatile, this must be a single instruction store. 4355 locations->SetInAt(1, Location::RequiresRegister()); 4356 4357 // 64bits value can be atomically written to an address with movsd and an XMM register. 4358 // We need two XMM registers because there's no easier way to (bit) copy a register pair 4359 // into a single XMM register (we copy each pair part into the XMMs and then interleave them). 4360 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the 4361 // isolated cases when we need this it isn't worth adding the extra complexity. 4362 locations->AddTemp(Location::RequiresFpuRegister()); 4363 locations->AddTemp(Location::RequiresFpuRegister()); 4364 } else { 4365 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 4366 4367 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { 4368 // Temporary registers for the write barrier. 4369 locations->AddTemp(Location::RequiresRegister()); // May be used for reference poisoning too. 4370 // Ensure the card is in a byte register. 4371 locations->AddTemp(Location::RegisterLocation(ECX)); 4372 } 4373 } 4374} 4375 4376void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction, 4377 const FieldInfo& field_info, 4378 bool value_can_be_null) { 4379 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 4380 4381 LocationSummary* locations = instruction->GetLocations(); 4382 Register base = locations->InAt(0).AsRegister<Register>(); 4383 Location value = locations->InAt(1); 4384 bool is_volatile = field_info.IsVolatile(); 4385 Primitive::Type field_type = field_info.GetFieldType(); 4386 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 4387 bool needs_write_barrier = 4388 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1)); 4389 4390 if (is_volatile) { 4391 GenerateMemoryBarrier(MemBarrierKind::kAnyStore); 4392 } 4393 4394 bool maybe_record_implicit_null_check_done = false; 4395 4396 switch (field_type) { 4397 case Primitive::kPrimBoolean: 4398 case Primitive::kPrimByte: { 4399 __ movb(Address(base, offset), value.AsRegister<ByteRegister>()); 4400 break; 4401 } 4402 4403 case Primitive::kPrimShort: 4404 case Primitive::kPrimChar: { 4405 if (value.IsConstant()) { 4406 int16_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant()); 4407 __ movw(Address(base, offset), Immediate(v)); 4408 } else { 4409 __ movw(Address(base, offset), value.AsRegister<Register>()); 4410 } 4411 break; 4412 } 4413 4414 case Primitive::kPrimInt: 4415 case Primitive::kPrimNot: { 4416 if (kPoisonHeapReferences && needs_write_barrier) { 4417 // Note that in the case where `value` is a null reference, 4418 // we do not enter this block, as the reference does not 4419 // need poisoning. 4420 DCHECK_EQ(field_type, Primitive::kPrimNot); 4421 Register temp = locations->GetTemp(0).AsRegister<Register>(); 4422 __ movl(temp, value.AsRegister<Register>()); 4423 __ PoisonHeapReference(temp); 4424 __ movl(Address(base, offset), temp); 4425 } else if (value.IsConstant()) { 4426 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant()); 4427 __ movl(Address(base, offset), Immediate(v)); 4428 } else { 4429 __ movl(Address(base, offset), value.AsRegister<Register>()); 4430 } 4431 break; 4432 } 4433 4434 case Primitive::kPrimLong: { 4435 if (is_volatile) { 4436 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>(); 4437 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>(); 4438 __ movd(temp1, value.AsRegisterPairLow<Register>()); 4439 __ movd(temp2, value.AsRegisterPairHigh<Register>()); 4440 __ punpckldq(temp1, temp2); 4441 __ movsd(Address(base, offset), temp1); 4442 codegen_->MaybeRecordImplicitNullCheck(instruction); 4443 } else if (value.IsConstant()) { 4444 int64_t v = CodeGenerator::GetInt64ValueOf(value.GetConstant()); 4445 __ movl(Address(base, offset), Immediate(Low32Bits(v))); 4446 codegen_->MaybeRecordImplicitNullCheck(instruction); 4447 __ movl(Address(base, kX86WordSize + offset), Immediate(High32Bits(v))); 4448 } else { 4449 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>()); 4450 codegen_->MaybeRecordImplicitNullCheck(instruction); 4451 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>()); 4452 } 4453 maybe_record_implicit_null_check_done = true; 4454 break; 4455 } 4456 4457 case Primitive::kPrimFloat: { 4458 if (value.IsConstant()) { 4459 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant()); 4460 __ movl(Address(base, offset), Immediate(v)); 4461 } else { 4462 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>()); 4463 } 4464 break; 4465 } 4466 4467 case Primitive::kPrimDouble: { 4468 if (value.IsConstant()) { 4469 int64_t v = CodeGenerator::GetInt64ValueOf(value.GetConstant()); 4470 __ movl(Address(base, offset), Immediate(Low32Bits(v))); 4471 codegen_->MaybeRecordImplicitNullCheck(instruction); 4472 __ movl(Address(base, kX86WordSize + offset), Immediate(High32Bits(v))); 4473 maybe_record_implicit_null_check_done = true; 4474 } else { 4475 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>()); 4476 } 4477 break; 4478 } 4479 4480 case Primitive::kPrimVoid: 4481 LOG(FATAL) << "Unreachable type " << field_type; 4482 UNREACHABLE(); 4483 } 4484 4485 if (!maybe_record_implicit_null_check_done) { 4486 codegen_->MaybeRecordImplicitNullCheck(instruction); 4487 } 4488 4489 if (needs_write_barrier) { 4490 Register temp = locations->GetTemp(0).AsRegister<Register>(); 4491 Register card = locations->GetTemp(1).AsRegister<Register>(); 4492 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null); 4493 } 4494 4495 if (is_volatile) { 4496 GenerateMemoryBarrier(MemBarrierKind::kAnyAny); 4497 } 4498} 4499 4500void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) { 4501 HandleFieldGet(instruction, instruction->GetFieldInfo()); 4502} 4503 4504void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) { 4505 HandleFieldGet(instruction, instruction->GetFieldInfo()); 4506} 4507 4508void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) { 4509 HandleFieldSet(instruction, instruction->GetFieldInfo()); 4510} 4511 4512void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) { 4513 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull()); 4514} 4515 4516void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 4517 HandleFieldSet(instruction, instruction->GetFieldInfo()); 4518} 4519 4520void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 4521 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull()); 4522} 4523 4524void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 4525 HandleFieldGet(instruction, instruction->GetFieldInfo()); 4526} 4527 4528void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 4529 HandleFieldGet(instruction, instruction->GetFieldInfo()); 4530} 4531 4532void LocationsBuilderX86::VisitUnresolvedInstanceFieldGet( 4533 HUnresolvedInstanceFieldGet* instruction) { 4534 FieldAccessCallingConventionX86 calling_convention; 4535 codegen_->CreateUnresolvedFieldLocationSummary( 4536 instruction, instruction->GetFieldType(), calling_convention); 4537} 4538 4539void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldGet( 4540 HUnresolvedInstanceFieldGet* instruction) { 4541 FieldAccessCallingConventionX86 calling_convention; 4542 codegen_->GenerateUnresolvedFieldAccess(instruction, 4543 instruction->GetFieldType(), 4544 instruction->GetFieldIndex(), 4545 instruction->GetDexPc(), 4546 calling_convention); 4547} 4548 4549void LocationsBuilderX86::VisitUnresolvedInstanceFieldSet( 4550 HUnresolvedInstanceFieldSet* instruction) { 4551 FieldAccessCallingConventionX86 calling_convention; 4552 codegen_->CreateUnresolvedFieldLocationSummary( 4553 instruction, instruction->GetFieldType(), calling_convention); 4554} 4555 4556void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldSet( 4557 HUnresolvedInstanceFieldSet* instruction) { 4558 FieldAccessCallingConventionX86 calling_convention; 4559 codegen_->GenerateUnresolvedFieldAccess(instruction, 4560 instruction->GetFieldType(), 4561 instruction->GetFieldIndex(), 4562 instruction->GetDexPc(), 4563 calling_convention); 4564} 4565 4566void LocationsBuilderX86::VisitUnresolvedStaticFieldGet( 4567 HUnresolvedStaticFieldGet* instruction) { 4568 FieldAccessCallingConventionX86 calling_convention; 4569 codegen_->CreateUnresolvedFieldLocationSummary( 4570 instruction, instruction->GetFieldType(), calling_convention); 4571} 4572 4573void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldGet( 4574 HUnresolvedStaticFieldGet* instruction) { 4575 FieldAccessCallingConventionX86 calling_convention; 4576 codegen_->GenerateUnresolvedFieldAccess(instruction, 4577 instruction->GetFieldType(), 4578 instruction->GetFieldIndex(), 4579 instruction->GetDexPc(), 4580 calling_convention); 4581} 4582 4583void LocationsBuilderX86::VisitUnresolvedStaticFieldSet( 4584 HUnresolvedStaticFieldSet* instruction) { 4585 FieldAccessCallingConventionX86 calling_convention; 4586 codegen_->CreateUnresolvedFieldLocationSummary( 4587 instruction, instruction->GetFieldType(), calling_convention); 4588} 4589 4590void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldSet( 4591 HUnresolvedStaticFieldSet* instruction) { 4592 FieldAccessCallingConventionX86 calling_convention; 4593 codegen_->GenerateUnresolvedFieldAccess(instruction, 4594 instruction->GetFieldType(), 4595 instruction->GetFieldIndex(), 4596 instruction->GetDexPc(), 4597 calling_convention); 4598} 4599 4600void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) { 4601 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock() 4602 ? LocationSummary::kCallOnSlowPath 4603 : LocationSummary::kNoCall; 4604 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 4605 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction) 4606 ? Location::RequiresRegister() 4607 : Location::Any(); 4608 locations->SetInAt(0, loc); 4609 if (instruction->HasUses()) { 4610 locations->SetOut(Location::SameAsFirstInput()); 4611 } 4612} 4613 4614void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) { 4615 if (codegen_->CanMoveNullCheckToUser(instruction)) { 4616 return; 4617 } 4618 LocationSummary* locations = instruction->GetLocations(); 4619 Location obj = locations->InAt(0); 4620 4621 __ testl(EAX, Address(obj.AsRegister<Register>(), 0)); 4622 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 4623} 4624 4625void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) { 4626 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction); 4627 codegen_->AddSlowPath(slow_path); 4628 4629 LocationSummary* locations = instruction->GetLocations(); 4630 Location obj = locations->InAt(0); 4631 4632 if (obj.IsRegister()) { 4633 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>()); 4634 } else if (obj.IsStackSlot()) { 4635 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0)); 4636 } else { 4637 DCHECK(obj.IsConstant()) << obj; 4638 DCHECK(obj.GetConstant()->IsNullConstant()); 4639 __ jmp(slow_path->GetEntryLabel()); 4640 return; 4641 } 4642 __ j(kEqual, slow_path->GetEntryLabel()); 4643} 4644 4645void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) { 4646 if (codegen_->IsImplicitNullCheckAllowed(instruction)) { 4647 GenerateImplicitNullCheck(instruction); 4648 } else { 4649 GenerateExplicitNullCheck(instruction); 4650 } 4651} 4652 4653void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) { 4654 bool object_array_get_with_read_barrier = 4655 kEmitCompilerReadBarrier && (instruction->GetType() == Primitive::kPrimNot); 4656 LocationSummary* locations = 4657 new (GetGraph()->GetArena()) LocationSummary(instruction, 4658 object_array_get_with_read_barrier ? 4659 LocationSummary::kCallOnSlowPath : 4660 LocationSummary::kNoCall); 4661 locations->SetInAt(0, Location::RequiresRegister()); 4662 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 4663 if (Primitive::IsFloatingPointType(instruction->GetType())) { 4664 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 4665 } else { 4666 // The output overlaps in case of long: we don't want the low move 4667 // to overwrite the array's location. Likewise, in the case of an 4668 // object array get with read barriers enabled, we do not want the 4669 // move to overwrite the array's location, as we need it to emit 4670 // the read barrier. 4671 locations->SetOut( 4672 Location::RequiresRegister(), 4673 (instruction->GetType() == Primitive::kPrimLong || object_array_get_with_read_barrier) ? 4674 Location::kOutputOverlap : 4675 Location::kNoOutputOverlap); 4676 } 4677} 4678 4679void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) { 4680 LocationSummary* locations = instruction->GetLocations(); 4681 Location obj_loc = locations->InAt(0); 4682 Register obj = obj_loc.AsRegister<Register>(); 4683 Location index = locations->InAt(1); 4684 4685 Primitive::Type type = instruction->GetType(); 4686 switch (type) { 4687 case Primitive::kPrimBoolean: { 4688 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 4689 Register out = locations->Out().AsRegister<Register>(); 4690 if (index.IsConstant()) { 4691 __ movzxb(out, Address(obj, 4692 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset)); 4693 } else { 4694 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset)); 4695 } 4696 break; 4697 } 4698 4699 case Primitive::kPrimByte: { 4700 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 4701 Register out = locations->Out().AsRegister<Register>(); 4702 if (index.IsConstant()) { 4703 __ movsxb(out, Address(obj, 4704 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset)); 4705 } else { 4706 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset)); 4707 } 4708 break; 4709 } 4710 4711 case Primitive::kPrimShort: { 4712 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 4713 Register out = locations->Out().AsRegister<Register>(); 4714 if (index.IsConstant()) { 4715 __ movsxw(out, Address(obj, 4716 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset)); 4717 } else { 4718 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset)); 4719 } 4720 break; 4721 } 4722 4723 case Primitive::kPrimChar: { 4724 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 4725 Register out = locations->Out().AsRegister<Register>(); 4726 if (index.IsConstant()) { 4727 __ movzxw(out, Address(obj, 4728 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset)); 4729 } else { 4730 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset)); 4731 } 4732 break; 4733 } 4734 4735 case Primitive::kPrimInt: 4736 case Primitive::kPrimNot: { 4737 static_assert( 4738 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), 4739 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); 4740 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 4741 Register out = locations->Out().AsRegister<Register>(); 4742 if (index.IsConstant()) { 4743 __ movl(out, Address(obj, 4744 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset)); 4745 } else { 4746 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset)); 4747 } 4748 break; 4749 } 4750 4751 case Primitive::kPrimLong: { 4752 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 4753 Location out = locations->Out(); 4754 DCHECK_NE(obj, out.AsRegisterPairLow<Register>()); 4755 if (index.IsConstant()) { 4756 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 4757 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset)); 4758 codegen_->MaybeRecordImplicitNullCheck(instruction); 4759 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize)); 4760 } else { 4761 __ movl(out.AsRegisterPairLow<Register>(), 4762 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset)); 4763 codegen_->MaybeRecordImplicitNullCheck(instruction); 4764 __ movl(out.AsRegisterPairHigh<Register>(), 4765 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize)); 4766 } 4767 break; 4768 } 4769 4770 case Primitive::kPrimFloat: { 4771 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 4772 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>(); 4773 if (index.IsConstant()) { 4774 __ movss(out, Address(obj, 4775 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset)); 4776 } else { 4777 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset)); 4778 } 4779 break; 4780 } 4781 4782 case Primitive::kPrimDouble: { 4783 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 4784 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>(); 4785 if (index.IsConstant()) { 4786 __ movsd(out, Address(obj, 4787 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset)); 4788 } else { 4789 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset)); 4790 } 4791 break; 4792 } 4793 4794 case Primitive::kPrimVoid: 4795 LOG(FATAL) << "Unreachable type " << type; 4796 UNREACHABLE(); 4797 } 4798 4799 if (type != Primitive::kPrimLong) { 4800 codegen_->MaybeRecordImplicitNullCheck(instruction); 4801 } 4802 4803 if (type == Primitive::kPrimNot) { 4804 static_assert( 4805 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t), 4806 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes."); 4807 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 4808 Location out = locations->Out(); 4809 if (index.IsConstant()) { 4810 uint32_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 4811 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, offset); 4812 } else { 4813 codegen_->MaybeGenerateReadBarrier(instruction, out, out, obj_loc, data_offset, index); 4814 } 4815 } 4816} 4817 4818void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) { 4819 // This location builder might end up asking to up to four registers, which is 4820 // not currently possible for baseline. The situation in which we need four 4821 // registers cannot be met by baseline though, because it has not run any 4822 // optimization. 4823 4824 Primitive::Type value_type = instruction->GetComponentType(); 4825 4826 bool needs_write_barrier = 4827 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 4828 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck(); 4829 bool object_array_set_with_read_barrier = 4830 kEmitCompilerReadBarrier && (value_type == Primitive::kPrimNot); 4831 4832 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 4833 instruction, 4834 (may_need_runtime_call_for_type_check || object_array_set_with_read_barrier) ? 4835 LocationSummary::kCallOnSlowPath : 4836 LocationSummary::kNoCall); 4837 4838 bool is_byte_type = (value_type == Primitive::kPrimBoolean) 4839 || (value_type == Primitive::kPrimByte); 4840 // We need the inputs to be different than the output in case of long operation. 4841 // In case of a byte operation, the register allocator does not support multiple 4842 // inputs that die at entry with one in a specific register. 4843 locations->SetInAt(0, Location::RequiresRegister()); 4844 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 4845 if (is_byte_type) { 4846 // Ensure the value is in a byte register. 4847 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2))); 4848 } else if (Primitive::IsFloatingPointType(value_type)) { 4849 locations->SetInAt(2, Location::FpuRegisterOrConstant(instruction->InputAt(2))); 4850 } else { 4851 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2))); 4852 } 4853 if (needs_write_barrier) { 4854 // Temporary registers for the write barrier. 4855 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too. 4856 // Ensure the card is in a byte register. 4857 locations->AddTemp(Location::RegisterLocation(ECX)); // Possibly used for read barrier too. 4858 } 4859} 4860 4861void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) { 4862 LocationSummary* locations = instruction->GetLocations(); 4863 Location array_loc = locations->InAt(0); 4864 Register array = array_loc.AsRegister<Register>(); 4865 Location index = locations->InAt(1); 4866 Location value = locations->InAt(2); 4867 Primitive::Type value_type = instruction->GetComponentType(); 4868 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 4869 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); 4870 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); 4871 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck(); 4872 bool needs_write_barrier = 4873 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 4874 4875 switch (value_type) { 4876 case Primitive::kPrimBoolean: 4877 case Primitive::kPrimByte: { 4878 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 4879 Address address = index.IsConstant() 4880 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset) 4881 : Address(array, index.AsRegister<Register>(), TIMES_1, offset); 4882 if (value.IsRegister()) { 4883 __ movb(address, value.AsRegister<ByteRegister>()); 4884 } else { 4885 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 4886 } 4887 codegen_->MaybeRecordImplicitNullCheck(instruction); 4888 break; 4889 } 4890 4891 case Primitive::kPrimShort: 4892 case Primitive::kPrimChar: { 4893 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 4894 Address address = index.IsConstant() 4895 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset) 4896 : Address(array, index.AsRegister<Register>(), TIMES_2, offset); 4897 if (value.IsRegister()) { 4898 __ movw(address, value.AsRegister<Register>()); 4899 } else { 4900 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue())); 4901 } 4902 codegen_->MaybeRecordImplicitNullCheck(instruction); 4903 break; 4904 } 4905 4906 case Primitive::kPrimNot: { 4907 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 4908 Address address = index.IsConstant() 4909 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset) 4910 : Address(array, index.AsRegister<Register>(), TIMES_4, offset); 4911 4912 if (!value.IsRegister()) { 4913 // Just setting null. 4914 DCHECK(instruction->InputAt(2)->IsNullConstant()); 4915 DCHECK(value.IsConstant()) << value; 4916 __ movl(address, Immediate(0)); 4917 codegen_->MaybeRecordImplicitNullCheck(instruction); 4918 DCHECK(!needs_write_barrier); 4919 DCHECK(!may_need_runtime_call_for_type_check); 4920 break; 4921 } 4922 4923 DCHECK(needs_write_barrier); 4924 Register register_value = value.AsRegister<Register>(); 4925 NearLabel done, not_null, do_put; 4926 SlowPathCode* slow_path = nullptr; 4927 Register temp = locations->GetTemp(0).AsRegister<Register>(); 4928 if (may_need_runtime_call_for_type_check) { 4929 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86(instruction); 4930 codegen_->AddSlowPath(slow_path); 4931 if (instruction->GetValueCanBeNull()) { 4932 __ testl(register_value, register_value); 4933 __ j(kNotEqual, ¬_null); 4934 __ movl(address, Immediate(0)); 4935 codegen_->MaybeRecordImplicitNullCheck(instruction); 4936 __ jmp(&done); 4937 __ Bind(¬_null); 4938 } 4939 4940 if (kEmitCompilerReadBarrier) { 4941 // When read barriers are enabled, the type checking 4942 // instrumentation requires two read barriers: 4943 // 4944 // __ movl(temp2, temp); 4945 // // /* HeapReference<Class> */ temp = temp->component_type_ 4946 // __ movl(temp, Address(temp, component_offset)); 4947 // codegen_->GenerateReadBarrier( 4948 // instruction, temp_loc, temp_loc, temp2_loc, component_offset); 4949 // 4950 // // /* HeapReference<Class> */ temp2 = register_value->klass_ 4951 // __ movl(temp2, Address(register_value, class_offset)); 4952 // codegen_->GenerateReadBarrier( 4953 // instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc); 4954 // 4955 // __ cmpl(temp, temp2); 4956 // 4957 // However, the second read barrier may trash `temp`, as it 4958 // is a temporary register, and as such would not be saved 4959 // along with live registers before calling the runtime (nor 4960 // restored afterwards). So in this case, we bail out and 4961 // delegate the work to the array set slow path. 4962 // 4963 // TODO: Extend the register allocator to support a new 4964 // "(locally) live temp" location so as to avoid always 4965 // going into the slow path when read barriers are enabled. 4966 __ jmp(slow_path->GetEntryLabel()); 4967 } else { 4968 // /* HeapReference<Class> */ temp = array->klass_ 4969 __ movl(temp, Address(array, class_offset)); 4970 codegen_->MaybeRecordImplicitNullCheck(instruction); 4971 __ MaybeUnpoisonHeapReference(temp); 4972 4973 // /* HeapReference<Class> */ temp = temp->component_type_ 4974 __ movl(temp, Address(temp, component_offset)); 4975 // If heap poisoning is enabled, no need to unpoison `temp` 4976 // nor the object reference in `register_value->klass`, as 4977 // we are comparing two poisoned references. 4978 __ cmpl(temp, Address(register_value, class_offset)); 4979 4980 if (instruction->StaticTypeOfArrayIsObjectArray()) { 4981 __ j(kEqual, &do_put); 4982 // If heap poisoning is enabled, the `temp` reference has 4983 // not been unpoisoned yet; unpoison it now. 4984 __ MaybeUnpoisonHeapReference(temp); 4985 4986 // /* HeapReference<Class> */ temp = temp->super_class_ 4987 __ movl(temp, Address(temp, super_offset)); 4988 // If heap poisoning is enabled, no need to unpoison 4989 // `temp`, as we are comparing against null below. 4990 __ testl(temp, temp); 4991 __ j(kNotEqual, slow_path->GetEntryLabel()); 4992 __ Bind(&do_put); 4993 } else { 4994 __ j(kNotEqual, slow_path->GetEntryLabel()); 4995 } 4996 } 4997 } 4998 4999 if (kPoisonHeapReferences) { 5000 __ movl(temp, register_value); 5001 __ PoisonHeapReference(temp); 5002 __ movl(address, temp); 5003 } else { 5004 __ movl(address, register_value); 5005 } 5006 if (!may_need_runtime_call_for_type_check) { 5007 codegen_->MaybeRecordImplicitNullCheck(instruction); 5008 } 5009 5010 Register card = locations->GetTemp(1).AsRegister<Register>(); 5011 codegen_->MarkGCCard( 5012 temp, card, array, value.AsRegister<Register>(), instruction->GetValueCanBeNull()); 5013 __ Bind(&done); 5014 5015 if (slow_path != nullptr) { 5016 __ Bind(slow_path->GetExitLabel()); 5017 } 5018 5019 break; 5020 } 5021 5022 case Primitive::kPrimInt: { 5023 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 5024 Address address = index.IsConstant() 5025 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset) 5026 : Address(array, index.AsRegister<Register>(), TIMES_4, offset); 5027 if (value.IsRegister()) { 5028 __ movl(address, value.AsRegister<Register>()); 5029 } else { 5030 DCHECK(value.IsConstant()) << value; 5031 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant()); 5032 __ movl(address, Immediate(v)); 5033 } 5034 codegen_->MaybeRecordImplicitNullCheck(instruction); 5035 break; 5036 } 5037 5038 case Primitive::kPrimLong: { 5039 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 5040 if (index.IsConstant()) { 5041 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 5042 if (value.IsRegisterPair()) { 5043 __ movl(Address(array, offset), value.AsRegisterPairLow<Register>()); 5044 codegen_->MaybeRecordImplicitNullCheck(instruction); 5045 __ movl(Address(array, offset + kX86WordSize), value.AsRegisterPairHigh<Register>()); 5046 } else { 5047 DCHECK(value.IsConstant()); 5048 int64_t val = value.GetConstant()->AsLongConstant()->GetValue(); 5049 __ movl(Address(array, offset), Immediate(Low32Bits(val))); 5050 codegen_->MaybeRecordImplicitNullCheck(instruction); 5051 __ movl(Address(array, offset + kX86WordSize), Immediate(High32Bits(val))); 5052 } 5053 } else { 5054 if (value.IsRegisterPair()) { 5055 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset), 5056 value.AsRegisterPairLow<Register>()); 5057 codegen_->MaybeRecordImplicitNullCheck(instruction); 5058 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize), 5059 value.AsRegisterPairHigh<Register>()); 5060 } else { 5061 DCHECK(value.IsConstant()); 5062 int64_t val = value.GetConstant()->AsLongConstant()->GetValue(); 5063 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset), 5064 Immediate(Low32Bits(val))); 5065 codegen_->MaybeRecordImplicitNullCheck(instruction); 5066 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize), 5067 Immediate(High32Bits(val))); 5068 } 5069 } 5070 break; 5071 } 5072 5073 case Primitive::kPrimFloat: { 5074 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 5075 Address address = index.IsConstant() 5076 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset) 5077 : Address(array, index.AsRegister<Register>(), TIMES_4, offset); 5078 if (value.IsFpuRegister()) { 5079 __ movss(address, value.AsFpuRegister<XmmRegister>()); 5080 } else { 5081 DCHECK(value.IsConstant()); 5082 int32_t v = bit_cast<int32_t, float>(value.GetConstant()->AsFloatConstant()->GetValue()); 5083 __ movl(address, Immediate(v)); 5084 } 5085 codegen_->MaybeRecordImplicitNullCheck(instruction); 5086 break; 5087 } 5088 5089 case Primitive::kPrimDouble: { 5090 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 5091 Address address = index.IsConstant() 5092 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset) 5093 : Address(array, index.AsRegister<Register>(), TIMES_8, offset); 5094 if (value.IsFpuRegister()) { 5095 __ movsd(address, value.AsFpuRegister<XmmRegister>()); 5096 } else { 5097 DCHECK(value.IsConstant()); 5098 Address address_hi = index.IsConstant() ? 5099 Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + 5100 offset + kX86WordSize) : 5101 Address(array, index.AsRegister<Register>(), TIMES_8, offset + kX86WordSize); 5102 int64_t v = bit_cast<int64_t, double>(value.GetConstant()->AsDoubleConstant()->GetValue()); 5103 __ movl(address, Immediate(Low32Bits(v))); 5104 codegen_->MaybeRecordImplicitNullCheck(instruction); 5105 __ movl(address_hi, Immediate(High32Bits(v))); 5106 } 5107 break; 5108 } 5109 5110 case Primitive::kPrimVoid: 5111 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 5112 UNREACHABLE(); 5113 } 5114} 5115 5116void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) { 5117 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 5118 locations->SetInAt(0, Location::RequiresRegister()); 5119 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 5120} 5121 5122void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) { 5123 LocationSummary* locations = instruction->GetLocations(); 5124 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 5125 Register obj = locations->InAt(0).AsRegister<Register>(); 5126 Register out = locations->Out().AsRegister<Register>(); 5127 __ movl(out, Address(obj, offset)); 5128 codegen_->MaybeRecordImplicitNullCheck(instruction); 5129} 5130 5131void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) { 5132 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock() 5133 ? LocationSummary::kCallOnSlowPath 5134 : LocationSummary::kNoCall; 5135 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 5136 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 5137 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 5138 if (instruction->HasUses()) { 5139 locations->SetOut(Location::SameAsFirstInput()); 5140 } 5141} 5142 5143void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) { 5144 LocationSummary* locations = instruction->GetLocations(); 5145 Location index_loc = locations->InAt(0); 5146 Location length_loc = locations->InAt(1); 5147 SlowPathCode* slow_path = 5148 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction); 5149 5150 if (length_loc.IsConstant()) { 5151 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant()); 5152 if (index_loc.IsConstant()) { 5153 // BCE will remove the bounds check if we are guarenteed to pass. 5154 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); 5155 if (index < 0 || index >= length) { 5156 codegen_->AddSlowPath(slow_path); 5157 __ jmp(slow_path->GetEntryLabel()); 5158 } else { 5159 // Some optimization after BCE may have generated this, and we should not 5160 // generate a bounds check if it is a valid range. 5161 } 5162 return; 5163 } 5164 5165 // We have to reverse the jump condition because the length is the constant. 5166 Register index_reg = index_loc.AsRegister<Register>(); 5167 __ cmpl(index_reg, Immediate(length)); 5168 codegen_->AddSlowPath(slow_path); 5169 __ j(kAboveEqual, slow_path->GetEntryLabel()); 5170 } else { 5171 Register length = length_loc.AsRegister<Register>(); 5172 if (index_loc.IsConstant()) { 5173 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant()); 5174 __ cmpl(length, Immediate(value)); 5175 } else { 5176 __ cmpl(length, index_loc.AsRegister<Register>()); 5177 } 5178 codegen_->AddSlowPath(slow_path); 5179 __ j(kBelowEqual, slow_path->GetEntryLabel()); 5180 } 5181} 5182 5183void LocationsBuilderX86::VisitTemporary(HTemporary* temp) { 5184 temp->SetLocations(nullptr); 5185} 5186 5187void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) { 5188 // Nothing to do, this is driven by the code generator. 5189} 5190 5191void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) { 5192 LOG(FATAL) << "Unreachable"; 5193} 5194 5195void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) { 5196 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 5197} 5198 5199void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) { 5200 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 5201} 5202 5203void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) { 5204 HBasicBlock* block = instruction->GetBlock(); 5205 if (block->GetLoopInformation() != nullptr) { 5206 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 5207 // The back edge will generate the suspend check. 5208 return; 5209 } 5210 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 5211 // The goto will generate the suspend check. 5212 return; 5213 } 5214 GenerateSuspendCheck(instruction, nullptr); 5215} 5216 5217void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction, 5218 HBasicBlock* successor) { 5219 SuspendCheckSlowPathX86* slow_path = 5220 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath()); 5221 if (slow_path == nullptr) { 5222 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor); 5223 instruction->SetSlowPath(slow_path); 5224 codegen_->AddSlowPath(slow_path); 5225 if (successor != nullptr) { 5226 DCHECK(successor->IsLoopHeader()); 5227 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction); 5228 } 5229 } else { 5230 DCHECK_EQ(slow_path->GetSuccessor(), successor); 5231 } 5232 5233 __ fs()->cmpw(Address::Absolute( 5234 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0)); 5235 if (successor == nullptr) { 5236 __ j(kNotEqual, slow_path->GetEntryLabel()); 5237 __ Bind(slow_path->GetReturnLabel()); 5238 } else { 5239 __ j(kEqual, codegen_->GetLabelOf(successor)); 5240 __ jmp(slow_path->GetEntryLabel()); 5241 } 5242} 5243 5244X86Assembler* ParallelMoveResolverX86::GetAssembler() const { 5245 return codegen_->GetAssembler(); 5246} 5247 5248void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) { 5249 ScratchRegisterScope ensure_scratch( 5250 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 5251 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister()); 5252 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 5253 __ movl(temp_reg, Address(ESP, src + stack_offset)); 5254 __ movl(Address(ESP, dst + stack_offset), temp_reg); 5255} 5256 5257void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) { 5258 ScratchRegisterScope ensure_scratch( 5259 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 5260 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister()); 5261 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 5262 __ movl(temp_reg, Address(ESP, src + stack_offset)); 5263 __ movl(Address(ESP, dst + stack_offset), temp_reg); 5264 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize)); 5265 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg); 5266} 5267 5268void ParallelMoveResolverX86::EmitMove(size_t index) { 5269 MoveOperands* move = moves_[index]; 5270 Location source = move->GetSource(); 5271 Location destination = move->GetDestination(); 5272 5273 if (source.IsRegister()) { 5274 if (destination.IsRegister()) { 5275 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>()); 5276 } else { 5277 DCHECK(destination.IsStackSlot()); 5278 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>()); 5279 } 5280 } else if (source.IsFpuRegister()) { 5281 if (destination.IsFpuRegister()) { 5282 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 5283 } else if (destination.IsStackSlot()) { 5284 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 5285 } else { 5286 DCHECK(destination.IsDoubleStackSlot()); 5287 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>()); 5288 } 5289 } else if (source.IsStackSlot()) { 5290 if (destination.IsRegister()) { 5291 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex())); 5292 } else if (destination.IsFpuRegister()) { 5293 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 5294 } else { 5295 DCHECK(destination.IsStackSlot()); 5296 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex()); 5297 } 5298 } else if (source.IsDoubleStackSlot()) { 5299 if (destination.IsFpuRegister()) { 5300 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex())); 5301 } else { 5302 DCHECK(destination.IsDoubleStackSlot()) << destination; 5303 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex()); 5304 } 5305 } else if (source.IsConstant()) { 5306 HConstant* constant = source.GetConstant(); 5307 if (constant->IsIntConstant() || constant->IsNullConstant()) { 5308 int32_t value = CodeGenerator::GetInt32ValueOf(constant); 5309 if (destination.IsRegister()) { 5310 if (value == 0) { 5311 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>()); 5312 } else { 5313 __ movl(destination.AsRegister<Register>(), Immediate(value)); 5314 } 5315 } else { 5316 DCHECK(destination.IsStackSlot()) << destination; 5317 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value)); 5318 } 5319 } else if (constant->IsFloatConstant()) { 5320 float fp_value = constant->AsFloatConstant()->GetValue(); 5321 int32_t value = bit_cast<int32_t, float>(fp_value); 5322 Immediate imm(value); 5323 if (destination.IsFpuRegister()) { 5324 XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); 5325 if (value == 0) { 5326 // Easy handling of 0.0. 5327 __ xorps(dest, dest); 5328 } else { 5329 ScratchRegisterScope ensure_scratch( 5330 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 5331 Register temp = static_cast<Register>(ensure_scratch.GetRegister()); 5332 __ movl(temp, Immediate(value)); 5333 __ movd(dest, temp); 5334 } 5335 } else { 5336 DCHECK(destination.IsStackSlot()) << destination; 5337 __ movl(Address(ESP, destination.GetStackIndex()), imm); 5338 } 5339 } else if (constant->IsLongConstant()) { 5340 int64_t value = constant->AsLongConstant()->GetValue(); 5341 int32_t low_value = Low32Bits(value); 5342 int32_t high_value = High32Bits(value); 5343 Immediate low(low_value); 5344 Immediate high(high_value); 5345 if (destination.IsDoubleStackSlot()) { 5346 __ movl(Address(ESP, destination.GetStackIndex()), low); 5347 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high); 5348 } else { 5349 __ movl(destination.AsRegisterPairLow<Register>(), low); 5350 __ movl(destination.AsRegisterPairHigh<Register>(), high); 5351 } 5352 } else { 5353 DCHECK(constant->IsDoubleConstant()); 5354 double dbl_value = constant->AsDoubleConstant()->GetValue(); 5355 int64_t value = bit_cast<int64_t, double>(dbl_value); 5356 int32_t low_value = Low32Bits(value); 5357 int32_t high_value = High32Bits(value); 5358 Immediate low(low_value); 5359 Immediate high(high_value); 5360 if (destination.IsFpuRegister()) { 5361 XmmRegister dest = destination.AsFpuRegister<XmmRegister>(); 5362 if (value == 0) { 5363 // Easy handling of 0.0. 5364 __ xorpd(dest, dest); 5365 } else { 5366 __ pushl(high); 5367 __ pushl(low); 5368 __ movsd(dest, Address(ESP, 0)); 5369 __ addl(ESP, Immediate(8)); 5370 } 5371 } else { 5372 DCHECK(destination.IsDoubleStackSlot()) << destination; 5373 __ movl(Address(ESP, destination.GetStackIndex()), low); 5374 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high); 5375 } 5376 } 5377 } else { 5378 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source; 5379 } 5380} 5381 5382void ParallelMoveResolverX86::Exchange(Register reg, int mem) { 5383 Register suggested_scratch = reg == EAX ? EBX : EAX; 5384 ScratchRegisterScope ensure_scratch( 5385 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters()); 5386 5387 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 5388 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset)); 5389 __ movl(Address(ESP, mem + stack_offset), reg); 5390 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister())); 5391} 5392 5393void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) { 5394 ScratchRegisterScope ensure_scratch( 5395 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 5396 5397 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister()); 5398 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0; 5399 __ movl(temp_reg, Address(ESP, mem + stack_offset)); 5400 __ movss(Address(ESP, mem + stack_offset), reg); 5401 __ movd(reg, temp_reg); 5402} 5403 5404void ParallelMoveResolverX86::Exchange(int mem1, int mem2) { 5405 ScratchRegisterScope ensure_scratch1( 5406 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters()); 5407 5408 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX; 5409 ScratchRegisterScope ensure_scratch2( 5410 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters()); 5411 5412 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0; 5413 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0; 5414 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset)); 5415 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset)); 5416 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister())); 5417 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister())); 5418} 5419 5420void ParallelMoveResolverX86::EmitSwap(size_t index) { 5421 MoveOperands* move = moves_[index]; 5422 Location source = move->GetSource(); 5423 Location destination = move->GetDestination(); 5424 5425 if (source.IsRegister() && destination.IsRegister()) { 5426 // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary. 5427 DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>()); 5428 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>()); 5429 __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>()); 5430 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>()); 5431 } else if (source.IsRegister() && destination.IsStackSlot()) { 5432 Exchange(source.AsRegister<Register>(), destination.GetStackIndex()); 5433 } else if (source.IsStackSlot() && destination.IsRegister()) { 5434 Exchange(destination.AsRegister<Register>(), source.GetStackIndex()); 5435 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 5436 Exchange(destination.GetStackIndex(), source.GetStackIndex()); 5437 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { 5438 // Use XOR Swap algorithm to avoid a temporary. 5439 DCHECK_NE(source.reg(), destination.reg()); 5440 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 5441 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>()); 5442 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>()); 5443 } else if (source.IsFpuRegister() && destination.IsStackSlot()) { 5444 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex()); 5445 } else if (destination.IsFpuRegister() && source.IsStackSlot()) { 5446 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex()); 5447 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) { 5448 // Take advantage of the 16 bytes in the XMM register. 5449 XmmRegister reg = source.AsFpuRegister<XmmRegister>(); 5450 Address stack(ESP, destination.GetStackIndex()); 5451 // Load the double into the high doubleword. 5452 __ movhpd(reg, stack); 5453 5454 // Store the low double into the destination. 5455 __ movsd(stack, reg); 5456 5457 // Move the high double to the low double. 5458 __ psrldq(reg, Immediate(8)); 5459 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) { 5460 // Take advantage of the 16 bytes in the XMM register. 5461 XmmRegister reg = destination.AsFpuRegister<XmmRegister>(); 5462 Address stack(ESP, source.GetStackIndex()); 5463 // Load the double into the high doubleword. 5464 __ movhpd(reg, stack); 5465 5466 // Store the low double into the destination. 5467 __ movsd(stack, reg); 5468 5469 // Move the high double to the low double. 5470 __ psrldq(reg, Immediate(8)); 5471 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) { 5472 Exchange(destination.GetStackIndex(), source.GetStackIndex()); 5473 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize)); 5474 } else { 5475 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination; 5476 } 5477} 5478 5479void ParallelMoveResolverX86::SpillScratch(int reg) { 5480 __ pushl(static_cast<Register>(reg)); 5481} 5482 5483void ParallelMoveResolverX86::RestoreScratch(int reg) { 5484 __ popl(static_cast<Register>(reg)); 5485} 5486 5487void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) { 5488 InvokeRuntimeCallingConvention calling_convention; 5489 CodeGenerator::CreateLoadClassLocationSummary( 5490 cls, 5491 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 5492 Location::RegisterLocation(EAX), 5493 /* code_generator_supports_read_barrier */ true); 5494} 5495 5496void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { 5497 LocationSummary* locations = cls->GetLocations(); 5498 if (cls->NeedsAccessCheck()) { 5499 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex()); 5500 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess), 5501 cls, 5502 cls->GetDexPc(), 5503 nullptr); 5504 return; 5505 } 5506 5507 Location out_loc = locations->Out(); 5508 Register out = out_loc.AsRegister<Register>(); 5509 Register current_method = locations->InAt(0).AsRegister<Register>(); 5510 5511 if (cls->IsReferrersClass()) { 5512 DCHECK(!cls->CanCallRuntime()); 5513 DCHECK(!cls->MustGenerateClinitCheck()); 5514 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value(); 5515 if (kEmitCompilerReadBarrier) { 5516 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_) 5517 __ leal(out, Address(current_method, declaring_class_offset)); 5518 // /* mirror::Class* */ out = out->Read() 5519 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc); 5520 } else { 5521 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_ 5522 __ movl(out, Address(current_method, declaring_class_offset)); 5523 } 5524 } else { 5525 DCHECK(cls->CanCallRuntime()); 5526 // /* GcRoot<mirror::Class>[] */ out = 5527 // current_method.ptr_sized_fields_->dex_cache_resolved_types_ 5528 __ movl(out, Address(current_method, 5529 ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value())); 5530 5531 size_t cache_offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex()); 5532 if (kEmitCompilerReadBarrier) { 5533 // /* GcRoot<mirror::Class>* */ out = &out[type_index] 5534 __ leal(out, Address(out, cache_offset)); 5535 // /* mirror::Class* */ out = out->Read() 5536 codegen_->GenerateReadBarrierForRoot(cls, out_loc, out_loc); 5537 } else { 5538 // /* GcRoot<mirror::Class> */ out = out[type_index] 5539 __ movl(out, Address(out, cache_offset)); 5540 } 5541 5542 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86( 5543 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); 5544 codegen_->AddSlowPath(slow_path); 5545 __ testl(out, out); 5546 __ j(kEqual, slow_path->GetEntryLabel()); 5547 if (cls->MustGenerateClinitCheck()) { 5548 GenerateClassInitializationCheck(slow_path, out); 5549 } else { 5550 __ Bind(slow_path->GetExitLabel()); 5551 } 5552 } 5553} 5554 5555void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) { 5556 LocationSummary* locations = 5557 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); 5558 locations->SetInAt(0, Location::RequiresRegister()); 5559 if (check->HasUses()) { 5560 locations->SetOut(Location::SameAsFirstInput()); 5561 } 5562} 5563 5564void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) { 5565 // We assume the class to not be null. 5566 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86( 5567 check->GetLoadClass(), check, check->GetDexPc(), true); 5568 codegen_->AddSlowPath(slow_path); 5569 GenerateClassInitializationCheck(slow_path, 5570 check->GetLocations()->InAt(0).AsRegister<Register>()); 5571} 5572 5573void InstructionCodeGeneratorX86::GenerateClassInitializationCheck( 5574 SlowPathCode* slow_path, Register class_reg) { 5575 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()), 5576 Immediate(mirror::Class::kStatusInitialized)); 5577 __ j(kLess, slow_path->GetEntryLabel()); 5578 __ Bind(slow_path->GetExitLabel()); 5579 // No need for memory fence, thanks to the X86 memory model. 5580} 5581 5582void LocationsBuilderX86::VisitLoadString(HLoadString* load) { 5583 LocationSummary* locations = 5584 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); 5585 locations->SetInAt(0, Location::RequiresRegister()); 5586 locations->SetOut(Location::RequiresRegister()); 5587} 5588 5589void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) { 5590 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load); 5591 codegen_->AddSlowPath(slow_path); 5592 5593 LocationSummary* locations = load->GetLocations(); 5594 Location out_loc = locations->Out(); 5595 Register out = out_loc.AsRegister<Register>(); 5596 Register current_method = locations->InAt(0).AsRegister<Register>(); 5597 5598 uint32_t declaring_class_offset = ArtMethod::DeclaringClassOffset().Int32Value(); 5599 if (kEmitCompilerReadBarrier) { 5600 // /* GcRoot<mirror::Class>* */ out = &(current_method->declaring_class_) 5601 __ leal(out, Address(current_method, declaring_class_offset)); 5602 // /* mirror::Class* */ out = out->Read() 5603 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc); 5604 } else { 5605 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_ 5606 __ movl(out, Address(current_method, declaring_class_offset)); 5607 } 5608 5609 // /* GcRoot<mirror::String>[] */ out = out->dex_cache_strings_ 5610 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value())); 5611 5612 size_t cache_offset = CodeGenerator::GetCacheOffset(load->GetStringIndex()); 5613 if (kEmitCompilerReadBarrier) { 5614 // /* GcRoot<mirror::String>* */ out = &out[string_index] 5615 __ leal(out, Address(out, cache_offset)); 5616 // /* mirror::String* */ out = out->Read() 5617 codegen_->GenerateReadBarrierForRoot(load, out_loc, out_loc); 5618 } else { 5619 // /* GcRoot<mirror::String> */ out = out[string_index] 5620 __ movl(out, Address(out, cache_offset)); 5621 } 5622 5623 __ testl(out, out); 5624 __ j(kEqual, slow_path->GetEntryLabel()); 5625 __ Bind(slow_path->GetExitLabel()); 5626} 5627 5628static Address GetExceptionTlsAddress() { 5629 return Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value()); 5630} 5631 5632void LocationsBuilderX86::VisitLoadException(HLoadException* load) { 5633 LocationSummary* locations = 5634 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); 5635 locations->SetOut(Location::RequiresRegister()); 5636} 5637 5638void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) { 5639 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress()); 5640} 5641 5642void LocationsBuilderX86::VisitClearException(HClearException* clear) { 5643 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall); 5644} 5645 5646void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) { 5647 __ fs()->movl(GetExceptionTlsAddress(), Immediate(0)); 5648} 5649 5650void LocationsBuilderX86::VisitThrow(HThrow* instruction) { 5651 LocationSummary* locations = 5652 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 5653 InvokeRuntimeCallingConvention calling_convention; 5654 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 5655} 5656 5657void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) { 5658 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException), 5659 instruction, 5660 instruction->GetDexPc(), 5661 nullptr); 5662} 5663 5664void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) { 5665 LocationSummary::CallKind call_kind = LocationSummary::kNoCall; 5666 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind(); 5667 switch (type_check_kind) { 5668 case TypeCheckKind::kExactCheck: 5669 case TypeCheckKind::kAbstractClassCheck: 5670 case TypeCheckKind::kClassHierarchyCheck: 5671 case TypeCheckKind::kArrayObjectCheck: 5672 call_kind = 5673 kEmitCompilerReadBarrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall; 5674 break; 5675 case TypeCheckKind::kArrayCheck: 5676 case TypeCheckKind::kUnresolvedCheck: 5677 case TypeCheckKind::kInterfaceCheck: 5678 call_kind = LocationSummary::kCallOnSlowPath; 5679 break; 5680 } 5681 5682 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 5683 locations->SetInAt(0, Location::RequiresRegister()); 5684 locations->SetInAt(1, Location::Any()); 5685 // Note that TypeCheckSlowPathX86 uses this "out" register too. 5686 locations->SetOut(Location::RequiresRegister()); 5687 // When read barriers are enabled, we need a temporary register for 5688 // some cases. 5689 if (kEmitCompilerReadBarrier && 5690 (type_check_kind == TypeCheckKind::kAbstractClassCheck || 5691 type_check_kind == TypeCheckKind::kClassHierarchyCheck || 5692 type_check_kind == TypeCheckKind::kArrayObjectCheck)) { 5693 locations->AddTemp(Location::RequiresRegister()); 5694 } 5695} 5696 5697void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) { 5698 LocationSummary* locations = instruction->GetLocations(); 5699 Location obj_loc = locations->InAt(0); 5700 Register obj = obj_loc.AsRegister<Register>(); 5701 Location cls = locations->InAt(1); 5702 Location out_loc = locations->Out(); 5703 Register out = out_loc.AsRegister<Register>(); 5704 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 5705 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); 5706 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); 5707 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); 5708 SlowPathCode* slow_path = nullptr; 5709 NearLabel done, zero; 5710 5711 // Return 0 if `obj` is null. 5712 // Avoid null check if we know obj is not null. 5713 if (instruction->MustDoNullCheck()) { 5714 __ testl(obj, obj); 5715 __ j(kEqual, &zero); 5716 } 5717 5718 // /* HeapReference<Class> */ out = obj->klass_ 5719 __ movl(out, Address(obj, class_offset)); 5720 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, obj_loc, class_offset); 5721 5722 switch (instruction->GetTypeCheckKind()) { 5723 case TypeCheckKind::kExactCheck: { 5724 if (cls.IsRegister()) { 5725 __ cmpl(out, cls.AsRegister<Register>()); 5726 } else { 5727 DCHECK(cls.IsStackSlot()) << cls; 5728 __ cmpl(out, Address(ESP, cls.GetStackIndex())); 5729 } 5730 5731 // Classes must be equal for the instanceof to succeed. 5732 __ j(kNotEqual, &zero); 5733 __ movl(out, Immediate(1)); 5734 __ jmp(&done); 5735 break; 5736 } 5737 5738 case TypeCheckKind::kAbstractClassCheck: { 5739 // If the class is abstract, we eagerly fetch the super class of the 5740 // object to avoid doing a comparison we know will fail. 5741 NearLabel loop; 5742 __ Bind(&loop); 5743 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation(); 5744 if (kEmitCompilerReadBarrier) { 5745 // Save the value of `out` into `temp` before overwriting it 5746 // in the following move operation, as we will need it for the 5747 // read barrier below. 5748 Register temp = temp_loc.AsRegister<Register>(); 5749 __ movl(temp, out); 5750 } 5751 // /* HeapReference<Class> */ out = out->super_class_ 5752 __ movl(out, Address(out, super_offset)); 5753 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset); 5754 __ testl(out, out); 5755 // If `out` is null, we use it for the result, and jump to `done`. 5756 __ j(kEqual, &done); 5757 if (cls.IsRegister()) { 5758 __ cmpl(out, cls.AsRegister<Register>()); 5759 } else { 5760 DCHECK(cls.IsStackSlot()) << cls; 5761 __ cmpl(out, Address(ESP, cls.GetStackIndex())); 5762 } 5763 __ j(kNotEqual, &loop); 5764 __ movl(out, Immediate(1)); 5765 if (zero.IsLinked()) { 5766 __ jmp(&done); 5767 } 5768 break; 5769 } 5770 5771 case TypeCheckKind::kClassHierarchyCheck: { 5772 // Walk over the class hierarchy to find a match. 5773 NearLabel loop, success; 5774 __ Bind(&loop); 5775 if (cls.IsRegister()) { 5776 __ cmpl(out, cls.AsRegister<Register>()); 5777 } else { 5778 DCHECK(cls.IsStackSlot()) << cls; 5779 __ cmpl(out, Address(ESP, cls.GetStackIndex())); 5780 } 5781 __ j(kEqual, &success); 5782 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation(); 5783 if (kEmitCompilerReadBarrier) { 5784 // Save the value of `out` into `temp` before overwriting it 5785 // in the following move operation, as we will need it for the 5786 // read barrier below. 5787 Register temp = temp_loc.AsRegister<Register>(); 5788 __ movl(temp, out); 5789 } 5790 // /* HeapReference<Class> */ out = out->super_class_ 5791 __ movl(out, Address(out, super_offset)); 5792 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, super_offset); 5793 __ testl(out, out); 5794 __ j(kNotEqual, &loop); 5795 // If `out` is null, we use it for the result, and jump to `done`. 5796 __ jmp(&done); 5797 __ Bind(&success); 5798 __ movl(out, Immediate(1)); 5799 if (zero.IsLinked()) { 5800 __ jmp(&done); 5801 } 5802 break; 5803 } 5804 5805 case TypeCheckKind::kArrayObjectCheck: { 5806 // Do an exact check. 5807 NearLabel exact_check; 5808 if (cls.IsRegister()) { 5809 __ cmpl(out, cls.AsRegister<Register>()); 5810 } else { 5811 DCHECK(cls.IsStackSlot()) << cls; 5812 __ cmpl(out, Address(ESP, cls.GetStackIndex())); 5813 } 5814 __ j(kEqual, &exact_check); 5815 // Otherwise, we need to check that the object's class is a non-primitive array. 5816 Location temp_loc = kEmitCompilerReadBarrier ? locations->GetTemp(0) : Location::NoLocation(); 5817 if (kEmitCompilerReadBarrier) { 5818 // Save the value of `out` into `temp` before overwriting it 5819 // in the following move operation, as we will need it for the 5820 // read barrier below. 5821 Register temp = temp_loc.AsRegister<Register>(); 5822 __ movl(temp, out); 5823 } 5824 // /* HeapReference<Class> */ out = out->component_type_ 5825 __ movl(out, Address(out, component_offset)); 5826 codegen_->MaybeGenerateReadBarrier(instruction, out_loc, out_loc, temp_loc, component_offset); 5827 __ testl(out, out); 5828 // If `out` is null, we use it for the result, and jump to `done`. 5829 __ j(kEqual, &done); 5830 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot)); 5831 __ j(kNotEqual, &zero); 5832 __ Bind(&exact_check); 5833 __ movl(out, Immediate(1)); 5834 __ jmp(&done); 5835 break; 5836 } 5837 5838 case TypeCheckKind::kArrayCheck: { 5839 if (cls.IsRegister()) { 5840 __ cmpl(out, cls.AsRegister<Register>()); 5841 } else { 5842 DCHECK(cls.IsStackSlot()) << cls; 5843 __ cmpl(out, Address(ESP, cls.GetStackIndex())); 5844 } 5845 DCHECK(locations->OnlyCallsOnSlowPath()); 5846 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(instruction, 5847 /* is_fatal */ false); 5848 codegen_->AddSlowPath(slow_path); 5849 __ j(kNotEqual, slow_path->GetEntryLabel()); 5850 __ movl(out, Immediate(1)); 5851 if (zero.IsLinked()) { 5852 __ jmp(&done); 5853 } 5854 break; 5855 } 5856 5857 case TypeCheckKind::kUnresolvedCheck: 5858 case TypeCheckKind::kInterfaceCheck: { 5859 // Note that we indeed only call on slow path, but we always go 5860 // into the slow path for the unresolved & interface check 5861 // cases. 5862 // 5863 // We cannot directly call the InstanceofNonTrivial runtime 5864 // entry point without resorting to a type checking slow path 5865 // here (i.e. by calling InvokeRuntime directly), as it would 5866 // require to assign fixed registers for the inputs of this 5867 // HInstanceOf instruction (following the runtime calling 5868 // convention), which might be cluttered by the potential first 5869 // read barrier emission at the beginning of this method. 5870 DCHECK(locations->OnlyCallsOnSlowPath()); 5871 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(instruction, 5872 /* is_fatal */ false); 5873 codegen_->AddSlowPath(slow_path); 5874 __ jmp(slow_path->GetEntryLabel()); 5875 if (zero.IsLinked()) { 5876 __ jmp(&done); 5877 } 5878 break; 5879 } 5880 } 5881 5882 if (zero.IsLinked()) { 5883 __ Bind(&zero); 5884 __ xorl(out, out); 5885 } 5886 5887 if (done.IsLinked()) { 5888 __ Bind(&done); 5889 } 5890 5891 if (slow_path != nullptr) { 5892 __ Bind(slow_path->GetExitLabel()); 5893 } 5894} 5895 5896void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) { 5897 LocationSummary::CallKind call_kind = LocationSummary::kNoCall; 5898 bool throws_into_catch = instruction->CanThrowIntoCatchBlock(); 5899 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind(); 5900 switch (type_check_kind) { 5901 case TypeCheckKind::kExactCheck: 5902 case TypeCheckKind::kAbstractClassCheck: 5903 case TypeCheckKind::kClassHierarchyCheck: 5904 case TypeCheckKind::kArrayObjectCheck: 5905 call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ? 5906 LocationSummary::kCallOnSlowPath : 5907 LocationSummary::kNoCall; // In fact, call on a fatal (non-returning) slow path. 5908 break; 5909 case TypeCheckKind::kArrayCheck: 5910 case TypeCheckKind::kUnresolvedCheck: 5911 case TypeCheckKind::kInterfaceCheck: 5912 call_kind = LocationSummary::kCallOnSlowPath; 5913 break; 5914 } 5915 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 5916 locations->SetInAt(0, Location::RequiresRegister()); 5917 locations->SetInAt(1, Location::Any()); 5918 // Note that TypeCheckSlowPathX86 uses this "temp" register too. 5919 locations->AddTemp(Location::RequiresRegister()); 5920 // When read barriers are enabled, we need an additional temporary 5921 // register for some cases. 5922 if (kEmitCompilerReadBarrier && 5923 (type_check_kind == TypeCheckKind::kAbstractClassCheck || 5924 type_check_kind == TypeCheckKind::kClassHierarchyCheck || 5925 type_check_kind == TypeCheckKind::kArrayObjectCheck)) { 5926 locations->AddTemp(Location::RequiresRegister()); 5927 } 5928} 5929 5930void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) { 5931 LocationSummary* locations = instruction->GetLocations(); 5932 Location obj_loc = locations->InAt(0); 5933 Register obj = obj_loc.AsRegister<Register>(); 5934 Location cls = locations->InAt(1); 5935 Location temp_loc = locations->GetTemp(0); 5936 Register temp = temp_loc.AsRegister<Register>(); 5937 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 5938 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); 5939 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); 5940 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); 5941 5942 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind(); 5943 bool is_type_check_slow_path_fatal = 5944 (type_check_kind == TypeCheckKind::kExactCheck || 5945 type_check_kind == TypeCheckKind::kAbstractClassCheck || 5946 type_check_kind == TypeCheckKind::kClassHierarchyCheck || 5947 type_check_kind == TypeCheckKind::kArrayObjectCheck) && 5948 !instruction->CanThrowIntoCatchBlock(); 5949 SlowPathCode* type_check_slow_path = 5950 new (GetGraph()->GetArena()) TypeCheckSlowPathX86(instruction, 5951 is_type_check_slow_path_fatal); 5952 codegen_->AddSlowPath(type_check_slow_path); 5953 5954 NearLabel done; 5955 // Avoid null check if we know obj is not null. 5956 if (instruction->MustDoNullCheck()) { 5957 __ testl(obj, obj); 5958 __ j(kEqual, &done); 5959 } 5960 5961 // /* HeapReference<Class> */ temp = obj->klass_ 5962 __ movl(temp, Address(obj, class_offset)); 5963 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset); 5964 5965 switch (type_check_kind) { 5966 case TypeCheckKind::kExactCheck: 5967 case TypeCheckKind::kArrayCheck: { 5968 if (cls.IsRegister()) { 5969 __ cmpl(temp, cls.AsRegister<Register>()); 5970 } else { 5971 DCHECK(cls.IsStackSlot()) << cls; 5972 __ cmpl(temp, Address(ESP, cls.GetStackIndex())); 5973 } 5974 // Jump to slow path for throwing the exception or doing a 5975 // more involved array check. 5976 __ j(kNotEqual, type_check_slow_path->GetEntryLabel()); 5977 break; 5978 } 5979 5980 case TypeCheckKind::kAbstractClassCheck: { 5981 // If the class is abstract, we eagerly fetch the super class of the 5982 // object to avoid doing a comparison we know will fail. 5983 NearLabel loop, compare_classes; 5984 __ Bind(&loop); 5985 Location temp2_loc = 5986 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation(); 5987 if (kEmitCompilerReadBarrier) { 5988 // Save the value of `temp` into `temp2` before overwriting it 5989 // in the following move operation, as we will need it for the 5990 // read barrier below. 5991 Register temp2 = temp2_loc.AsRegister<Register>(); 5992 __ movl(temp2, temp); 5993 } 5994 // /* HeapReference<Class> */ temp = temp->super_class_ 5995 __ movl(temp, Address(temp, super_offset)); 5996 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset); 5997 5998 // If the class reference currently in `temp` is not null, jump 5999 // to the `compare_classes` label to compare it with the checked 6000 // class. 6001 __ testl(temp, temp); 6002 __ j(kNotEqual, &compare_classes); 6003 // Otherwise, jump to the slow path to throw the exception. 6004 // 6005 // But before, move back the object's class into `temp` before 6006 // going into the slow path, as it has been overwritten in the 6007 // meantime. 6008 // /* HeapReference<Class> */ temp = obj->klass_ 6009 __ movl(temp, Address(obj, class_offset)); 6010 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset); 6011 __ jmp(type_check_slow_path->GetEntryLabel()); 6012 6013 __ Bind(&compare_classes); 6014 if (cls.IsRegister()) { 6015 __ cmpl(temp, cls.AsRegister<Register>()); 6016 } else { 6017 DCHECK(cls.IsStackSlot()) << cls; 6018 __ cmpl(temp, Address(ESP, cls.GetStackIndex())); 6019 } 6020 __ j(kNotEqual, &loop); 6021 break; 6022 } 6023 6024 case TypeCheckKind::kClassHierarchyCheck: { 6025 // Walk over the class hierarchy to find a match. 6026 NearLabel loop; 6027 __ Bind(&loop); 6028 if (cls.IsRegister()) { 6029 __ cmpl(temp, cls.AsRegister<Register>()); 6030 } else { 6031 DCHECK(cls.IsStackSlot()) << cls; 6032 __ cmpl(temp, Address(ESP, cls.GetStackIndex())); 6033 } 6034 __ j(kEqual, &done); 6035 6036 Location temp2_loc = 6037 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation(); 6038 if (kEmitCompilerReadBarrier) { 6039 // Save the value of `temp` into `temp2` before overwriting it 6040 // in the following move operation, as we will need it for the 6041 // read barrier below. 6042 Register temp2 = temp2_loc.AsRegister<Register>(); 6043 __ movl(temp2, temp); 6044 } 6045 // /* HeapReference<Class> */ temp = temp->super_class_ 6046 __ movl(temp, Address(temp, super_offset)); 6047 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, temp2_loc, super_offset); 6048 6049 // If the class reference currently in `temp` is not null, jump 6050 // back at the beginning of the loop. 6051 __ testl(temp, temp); 6052 __ j(kNotEqual, &loop); 6053 // Otherwise, jump to the slow path to throw the exception. 6054 // 6055 // But before, move back the object's class into `temp` before 6056 // going into the slow path, as it has been overwritten in the 6057 // meantime. 6058 // /* HeapReference<Class> */ temp = obj->klass_ 6059 __ movl(temp, Address(obj, class_offset)); 6060 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset); 6061 __ jmp(type_check_slow_path->GetEntryLabel()); 6062 break; 6063 } 6064 6065 case TypeCheckKind::kArrayObjectCheck: { 6066 // Do an exact check. 6067 NearLabel check_non_primitive_component_type; 6068 if (cls.IsRegister()) { 6069 __ cmpl(temp, cls.AsRegister<Register>()); 6070 } else { 6071 DCHECK(cls.IsStackSlot()) << cls; 6072 __ cmpl(temp, Address(ESP, cls.GetStackIndex())); 6073 } 6074 __ j(kEqual, &done); 6075 6076 // Otherwise, we need to check that the object's class is a non-primitive array. 6077 Location temp2_loc = 6078 kEmitCompilerReadBarrier ? locations->GetTemp(1) : Location::NoLocation(); 6079 if (kEmitCompilerReadBarrier) { 6080 // Save the value of `temp` into `temp2` before overwriting it 6081 // in the following move operation, as we will need it for the 6082 // read barrier below. 6083 Register temp2 = temp2_loc.AsRegister<Register>(); 6084 __ movl(temp2, temp); 6085 } 6086 // /* HeapReference<Class> */ temp = temp->component_type_ 6087 __ movl(temp, Address(temp, component_offset)); 6088 codegen_->MaybeGenerateReadBarrier( 6089 instruction, temp_loc, temp_loc, temp2_loc, component_offset); 6090 6091 // If the component type is not null (i.e. the object is indeed 6092 // an array), jump to label `check_non_primitive_component_type` 6093 // to further check that this component type is not a primitive 6094 // type. 6095 __ testl(temp, temp); 6096 __ j(kNotEqual, &check_non_primitive_component_type); 6097 // Otherwise, jump to the slow path to throw the exception. 6098 // 6099 // But before, move back the object's class into `temp` before 6100 // going into the slow path, as it has been overwritten in the 6101 // meantime. 6102 // /* HeapReference<Class> */ temp = obj->klass_ 6103 __ movl(temp, Address(obj, class_offset)); 6104 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset); 6105 __ jmp(type_check_slow_path->GetEntryLabel()); 6106 6107 __ Bind(&check_non_primitive_component_type); 6108 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot)); 6109 __ j(kEqual, &done); 6110 // Same comment as above regarding `temp` and the slow path. 6111 // /* HeapReference<Class> */ temp = obj->klass_ 6112 __ movl(temp, Address(obj, class_offset)); 6113 codegen_->MaybeGenerateReadBarrier(instruction, temp_loc, temp_loc, obj_loc, class_offset); 6114 __ jmp(type_check_slow_path->GetEntryLabel()); 6115 break; 6116 } 6117 6118 case TypeCheckKind::kUnresolvedCheck: 6119 case TypeCheckKind::kInterfaceCheck: 6120 // We always go into the type check slow path for the unresolved & 6121 // interface check cases. 6122 // 6123 // We cannot directly call the CheckCast runtime entry point 6124 // without resorting to a type checking slow path here (i.e. by 6125 // calling InvokeRuntime directly), as it would require to 6126 // assign fixed registers for the inputs of this HInstanceOf 6127 // instruction (following the runtime calling convention), which 6128 // might be cluttered by the potential first read barrier 6129 // emission at the beginning of this method. 6130 __ jmp(type_check_slow_path->GetEntryLabel()); 6131 break; 6132 } 6133 __ Bind(&done); 6134 6135 __ Bind(type_check_slow_path->GetExitLabel()); 6136} 6137 6138void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) { 6139 LocationSummary* locations = 6140 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 6141 InvokeRuntimeCallingConvention calling_convention; 6142 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 6143} 6144 6145void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) { 6146 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject) 6147 : QUICK_ENTRY_POINT(pUnlockObject), 6148 instruction, 6149 instruction->GetDexPc(), 6150 nullptr); 6151} 6152 6153void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } 6154void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } 6155void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } 6156 6157void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) { 6158 LocationSummary* locations = 6159 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 6160 DCHECK(instruction->GetResultType() == Primitive::kPrimInt 6161 || instruction->GetResultType() == Primitive::kPrimLong); 6162 locations->SetInAt(0, Location::RequiresRegister()); 6163 locations->SetInAt(1, Location::Any()); 6164 locations->SetOut(Location::SameAsFirstInput()); 6165} 6166 6167void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) { 6168 HandleBitwiseOperation(instruction); 6169} 6170 6171void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) { 6172 HandleBitwiseOperation(instruction); 6173} 6174 6175void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) { 6176 HandleBitwiseOperation(instruction); 6177} 6178 6179void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) { 6180 LocationSummary* locations = instruction->GetLocations(); 6181 Location first = locations->InAt(0); 6182 Location second = locations->InAt(1); 6183 DCHECK(first.Equals(locations->Out())); 6184 6185 if (instruction->GetResultType() == Primitive::kPrimInt) { 6186 if (second.IsRegister()) { 6187 if (instruction->IsAnd()) { 6188 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>()); 6189 } else if (instruction->IsOr()) { 6190 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>()); 6191 } else { 6192 DCHECK(instruction->IsXor()); 6193 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>()); 6194 } 6195 } else if (second.IsConstant()) { 6196 if (instruction->IsAnd()) { 6197 __ andl(first.AsRegister<Register>(), 6198 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 6199 } else if (instruction->IsOr()) { 6200 __ orl(first.AsRegister<Register>(), 6201 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 6202 } else { 6203 DCHECK(instruction->IsXor()); 6204 __ xorl(first.AsRegister<Register>(), 6205 Immediate(second.GetConstant()->AsIntConstant()->GetValue())); 6206 } 6207 } else { 6208 if (instruction->IsAnd()) { 6209 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 6210 } else if (instruction->IsOr()) { 6211 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 6212 } else { 6213 DCHECK(instruction->IsXor()); 6214 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex())); 6215 } 6216 } 6217 } else { 6218 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); 6219 if (second.IsRegisterPair()) { 6220 if (instruction->IsAnd()) { 6221 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 6222 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 6223 } else if (instruction->IsOr()) { 6224 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 6225 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 6226 } else { 6227 DCHECK(instruction->IsXor()); 6228 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>()); 6229 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>()); 6230 } 6231 } else if (second.IsDoubleStackSlot()) { 6232 if (instruction->IsAnd()) { 6233 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 6234 __ andl(first.AsRegisterPairHigh<Register>(), 6235 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 6236 } else if (instruction->IsOr()) { 6237 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 6238 __ orl(first.AsRegisterPairHigh<Register>(), 6239 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 6240 } else { 6241 DCHECK(instruction->IsXor()); 6242 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex())); 6243 __ xorl(first.AsRegisterPairHigh<Register>(), 6244 Address(ESP, second.GetHighStackIndex(kX86WordSize))); 6245 } 6246 } else { 6247 DCHECK(second.IsConstant()) << second; 6248 int64_t value = second.GetConstant()->AsLongConstant()->GetValue(); 6249 int32_t low_value = Low32Bits(value); 6250 int32_t high_value = High32Bits(value); 6251 Immediate low(low_value); 6252 Immediate high(high_value); 6253 Register first_low = first.AsRegisterPairLow<Register>(); 6254 Register first_high = first.AsRegisterPairHigh<Register>(); 6255 if (instruction->IsAnd()) { 6256 if (low_value == 0) { 6257 __ xorl(first_low, first_low); 6258 } else if (low_value != -1) { 6259 __ andl(first_low, low); 6260 } 6261 if (high_value == 0) { 6262 __ xorl(first_high, first_high); 6263 } else if (high_value != -1) { 6264 __ andl(first_high, high); 6265 } 6266 } else if (instruction->IsOr()) { 6267 if (low_value != 0) { 6268 __ orl(first_low, low); 6269 } 6270 if (high_value != 0) { 6271 __ orl(first_high, high); 6272 } 6273 } else { 6274 DCHECK(instruction->IsXor()); 6275 if (low_value != 0) { 6276 __ xorl(first_low, low); 6277 } 6278 if (high_value != 0) { 6279 __ xorl(first_high, high); 6280 } 6281 } 6282 } 6283 } 6284} 6285 6286void CodeGeneratorX86::GenerateReadBarrier(HInstruction* instruction, 6287 Location out, 6288 Location ref, 6289 Location obj, 6290 uint32_t offset, 6291 Location index) { 6292 DCHECK(kEmitCompilerReadBarrier); 6293 6294 // If heap poisoning is enabled, the unpoisoning of the loaded 6295 // reference will be carried out by the runtime within the slow 6296 // path. 6297 // 6298 // Note that `ref` currently does not get unpoisoned (when heap 6299 // poisoning is enabled), which is alright as the `ref` argument is 6300 // not used by the artReadBarrierSlow entry point. 6301 // 6302 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow. 6303 SlowPathCode* slow_path = new (GetGraph()->GetArena()) 6304 ReadBarrierForHeapReferenceSlowPathX86(instruction, out, ref, obj, offset, index); 6305 AddSlowPath(slow_path); 6306 6307 // TODO: When read barrier has a fast path, add it here. 6308 /* Currently the read barrier call is inserted after the original load. 6309 * However, if we have a fast path, we need to perform the load of obj.LockWord *before* the 6310 * original load. This load-load ordering is required by the read barrier. 6311 * The fast path/slow path (for Baker's algorithm) should look like: 6312 * 6313 * bool isGray = obj.LockWord & kReadBarrierMask; 6314 * lfence; // load fence or artificial data dependence to prevent load-load reordering 6315 * ref = obj.field; // this is the original load 6316 * if (isGray) { 6317 * ref = Mark(ref); // ideally the slow path just does Mark(ref) 6318 * } 6319 */ 6320 6321 __ jmp(slow_path->GetEntryLabel()); 6322 __ Bind(slow_path->GetExitLabel()); 6323} 6324 6325void CodeGeneratorX86::MaybeGenerateReadBarrier(HInstruction* instruction, 6326 Location out, 6327 Location ref, 6328 Location obj, 6329 uint32_t offset, 6330 Location index) { 6331 if (kEmitCompilerReadBarrier) { 6332 // If heap poisoning is enabled, unpoisoning will be taken care of 6333 // by the runtime within the slow path. 6334 GenerateReadBarrier(instruction, out, ref, obj, offset, index); 6335 } else if (kPoisonHeapReferences) { 6336 __ UnpoisonHeapReference(out.AsRegister<Register>()); 6337 } 6338} 6339 6340void CodeGeneratorX86::GenerateReadBarrierForRoot(HInstruction* instruction, 6341 Location out, 6342 Location root) { 6343 DCHECK(kEmitCompilerReadBarrier); 6344 6345 // Note that GC roots are not affected by heap poisoning, so we do 6346 // not need to do anything special for this here. 6347 SlowPathCode* slow_path = 6348 new (GetGraph()->GetArena()) ReadBarrierForRootSlowPathX86(instruction, out, root); 6349 AddSlowPath(slow_path); 6350 6351 // TODO: Implement a fast path for ReadBarrierForRoot, performing 6352 // the following operation (for Baker's algorithm): 6353 // 6354 // if (thread.tls32_.is_gc_marking) { 6355 // root = Mark(root); 6356 // } 6357 6358 __ jmp(slow_path->GetEntryLabel()); 6359 __ Bind(slow_path->GetExitLabel()); 6360} 6361 6362void LocationsBuilderX86::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) { 6363 // Nothing to do, this should be removed during prepare for register allocator. 6364 LOG(FATAL) << "Unreachable"; 6365} 6366 6367void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) { 6368 // Nothing to do, this should be removed during prepare for register allocator. 6369 LOG(FATAL) << "Unreachable"; 6370} 6371 6372void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) { 6373 DCHECK(codegen_->IsBaseline()); 6374 LocationSummary* locations = 6375 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 6376 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant())); 6377} 6378 6379void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) { 6380 DCHECK(codegen_->IsBaseline()); 6381 // Will be generated at use site. 6382} 6383 6384// Simple implementation of packed switch - generate cascaded compare/jumps. 6385void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) { 6386 LocationSummary* locations = 6387 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall); 6388 locations->SetInAt(0, Location::RequiresRegister()); 6389} 6390 6391void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) { 6392 int32_t lower_bound = switch_instr->GetStartValue(); 6393 int32_t num_entries = switch_instr->GetNumEntries(); 6394 LocationSummary* locations = switch_instr->GetLocations(); 6395 Register value_reg = locations->InAt(0).AsRegister<Register>(); 6396 HBasicBlock* default_block = switch_instr->GetDefaultBlock(); 6397 6398 // Create a series of compare/jumps. 6399 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors(); 6400 for (int i = 0; i < num_entries; i++) { 6401 int32_t case_value = lower_bound + i; 6402 if (case_value == 0) { 6403 __ testl(value_reg, value_reg); 6404 } else { 6405 __ cmpl(value_reg, Immediate(case_value)); 6406 } 6407 __ j(kEqual, codegen_->GetLabelOf(successors[i])); 6408 } 6409 6410 // And the default for any other value. 6411 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) { 6412 __ jmp(codegen_->GetLabelOf(default_block)); 6413 } 6414} 6415 6416void LocationsBuilderX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) { 6417 LocationSummary* locations = 6418 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall); 6419 locations->SetInAt(0, Location::RequiresRegister()); 6420 6421 // Constant area pointer. 6422 locations->SetInAt(1, Location::RequiresRegister()); 6423 6424 // And the temporary we need. 6425 locations->AddTemp(Location::RequiresRegister()); 6426} 6427 6428void InstructionCodeGeneratorX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) { 6429 int32_t lower_bound = switch_instr->GetStartValue(); 6430 int32_t num_entries = switch_instr->GetNumEntries(); 6431 LocationSummary* locations = switch_instr->GetLocations(); 6432 Register value_reg = locations->InAt(0).AsRegister<Register>(); 6433 HBasicBlock* default_block = switch_instr->GetDefaultBlock(); 6434 6435 // Optimizing has a jump area. 6436 Register temp_reg = locations->GetTemp(0).AsRegister<Register>(); 6437 Register constant_area = locations->InAt(1).AsRegister<Register>(); 6438 6439 // Remove the bias, if needed. 6440 if (lower_bound != 0) { 6441 __ leal(temp_reg, Address(value_reg, -lower_bound)); 6442 value_reg = temp_reg; 6443 } 6444 6445 // Is the value in range? 6446 DCHECK_GE(num_entries, 1); 6447 __ cmpl(value_reg, Immediate(num_entries - 1)); 6448 __ j(kAbove, codegen_->GetLabelOf(default_block)); 6449 6450 // We are in the range of the table. 6451 // Load (target-constant_area) from the jump table, indexing by the value. 6452 __ movl(temp_reg, codegen_->LiteralCaseTable(switch_instr, constant_area, value_reg)); 6453 6454 // Compute the actual target address by adding in constant_area. 6455 __ addl(temp_reg, constant_area); 6456 6457 // And jump. 6458 __ jmp(temp_reg); 6459} 6460 6461void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress( 6462 HX86ComputeBaseMethodAddress* insn) { 6463 LocationSummary* locations = 6464 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall); 6465 locations->SetOut(Location::RequiresRegister()); 6466} 6467 6468void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress( 6469 HX86ComputeBaseMethodAddress* insn) { 6470 LocationSummary* locations = insn->GetLocations(); 6471 Register reg = locations->Out().AsRegister<Register>(); 6472 6473 // Generate call to next instruction. 6474 Label next_instruction; 6475 __ call(&next_instruction); 6476 __ Bind(&next_instruction); 6477 6478 // Remember this offset for later use with constant area. 6479 codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize()); 6480 6481 // Grab the return address off the stack. 6482 __ popl(reg); 6483} 6484 6485void LocationsBuilderX86::VisitX86LoadFromConstantTable( 6486 HX86LoadFromConstantTable* insn) { 6487 LocationSummary* locations = 6488 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall); 6489 6490 locations->SetInAt(0, Location::RequiresRegister()); 6491 locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant())); 6492 6493 // If we don't need to be materialized, we only need the inputs to be set. 6494 if (!insn->NeedsMaterialization()) { 6495 return; 6496 } 6497 6498 switch (insn->GetType()) { 6499 case Primitive::kPrimFloat: 6500 case Primitive::kPrimDouble: 6501 locations->SetOut(Location::RequiresFpuRegister()); 6502 break; 6503 6504 case Primitive::kPrimInt: 6505 locations->SetOut(Location::RequiresRegister()); 6506 break; 6507 6508 default: 6509 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType(); 6510 } 6511} 6512 6513void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) { 6514 if (!insn->NeedsMaterialization()) { 6515 return; 6516 } 6517 6518 LocationSummary* locations = insn->GetLocations(); 6519 Location out = locations->Out(); 6520 Register const_area = locations->InAt(0).AsRegister<Register>(); 6521 HConstant *value = insn->GetConstant(); 6522 6523 switch (insn->GetType()) { 6524 case Primitive::kPrimFloat: 6525 __ movss(out.AsFpuRegister<XmmRegister>(), 6526 codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area)); 6527 break; 6528 6529 case Primitive::kPrimDouble: 6530 __ movsd(out.AsFpuRegister<XmmRegister>(), 6531 codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area)); 6532 break; 6533 6534 case Primitive::kPrimInt: 6535 __ movl(out.AsRegister<Register>(), 6536 codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area)); 6537 break; 6538 6539 default: 6540 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType(); 6541 } 6542} 6543 6544/** 6545 * Class to handle late fixup of offsets into constant area. 6546 */ 6547class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> { 6548 public: 6549 RIPFixup(CodeGeneratorX86& codegen, size_t offset) 6550 : codegen_(&codegen), offset_into_constant_area_(offset) {} 6551 6552 protected: 6553 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; } 6554 6555 CodeGeneratorX86* codegen_; 6556 6557 private: 6558 void Process(const MemoryRegion& region, int pos) OVERRIDE { 6559 // Patch the correct offset for the instruction. The place to patch is the 6560 // last 4 bytes of the instruction. 6561 // The value to patch is the distance from the offset in the constant area 6562 // from the address computed by the HX86ComputeBaseMethodAddress instruction. 6563 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_; 6564 int32_t relative_position = constant_offset - codegen_->GetMethodAddressOffset();; 6565 6566 // Patch in the right value. 6567 region.StoreUnaligned<int32_t>(pos - 4, relative_position); 6568 } 6569 6570 // Location in constant area that the fixup refers to. 6571 int32_t offset_into_constant_area_; 6572}; 6573 6574/** 6575 * Class to handle late fixup of offsets to a jump table that will be created in the 6576 * constant area. 6577 */ 6578class JumpTableRIPFixup : public RIPFixup { 6579 public: 6580 JumpTableRIPFixup(CodeGeneratorX86& codegen, HX86PackedSwitch* switch_instr) 6581 : RIPFixup(codegen, static_cast<size_t>(-1)), switch_instr_(switch_instr) {} 6582 6583 void CreateJumpTable() { 6584 X86Assembler* assembler = codegen_->GetAssembler(); 6585 6586 // Ensure that the reference to the jump table has the correct offset. 6587 const int32_t offset_in_constant_table = assembler->ConstantAreaSize(); 6588 SetOffset(offset_in_constant_table); 6589 6590 // The label values in the jump table are computed relative to the 6591 // instruction addressing the constant area. 6592 const int32_t relative_offset = codegen_->GetMethodAddressOffset(); 6593 6594 // Populate the jump table with the correct values for the jump table. 6595 int32_t num_entries = switch_instr_->GetNumEntries(); 6596 HBasicBlock* block = switch_instr_->GetBlock(); 6597 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors(); 6598 // The value that we want is the target offset - the position of the table. 6599 for (int32_t i = 0; i < num_entries; i++) { 6600 HBasicBlock* b = successors[i]; 6601 Label* l = codegen_->GetLabelOf(b); 6602 DCHECK(l->IsBound()); 6603 int32_t offset_to_block = l->Position() - relative_offset; 6604 assembler->AppendInt32(offset_to_block); 6605 } 6606 } 6607 6608 private: 6609 const HX86PackedSwitch* switch_instr_; 6610}; 6611 6612void CodeGeneratorX86::Finalize(CodeAllocator* allocator) { 6613 // Generate the constant area if needed. 6614 X86Assembler* assembler = GetAssembler(); 6615 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) { 6616 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8 6617 // byte values. 6618 assembler->Align(4, 0); 6619 constant_area_start_ = assembler->CodeSize(); 6620 6621 // Populate any jump tables. 6622 for (auto jump_table : fixups_to_jump_tables_) { 6623 jump_table->CreateJumpTable(); 6624 } 6625 6626 // And now add the constant area to the generated code. 6627 assembler->AddConstantArea(); 6628 } 6629 6630 // And finish up. 6631 CodeGenerator::Finalize(allocator); 6632} 6633 6634Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) { 6635 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v)); 6636 return Address(reg, kDummy32BitOffset, fixup); 6637} 6638 6639Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) { 6640 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v)); 6641 return Address(reg, kDummy32BitOffset, fixup); 6642} 6643 6644Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) { 6645 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v)); 6646 return Address(reg, kDummy32BitOffset, fixup); 6647} 6648 6649Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) { 6650 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v)); 6651 return Address(reg, kDummy32BitOffset, fixup); 6652} 6653 6654Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr, 6655 Register reg, 6656 Register value) { 6657 // Create a fixup to be used to create and address the jump table. 6658 JumpTableRIPFixup* table_fixup = 6659 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr); 6660 6661 // We have to populate the jump tables. 6662 fixups_to_jump_tables_.push_back(table_fixup); 6663 6664 // We want a scaled address, as we are extracting the correct offset from the table. 6665 return Address(reg, value, TIMES_4, kDummy32BitOffset, table_fixup); 6666} 6667 6668// TODO: target as memory. 6669void CodeGeneratorX86::MoveFromReturnRegister(Location target, Primitive::Type type) { 6670 if (!target.IsValid()) { 6671 DCHECK(type == Primitive::kPrimVoid); 6672 return; 6673 } 6674 6675 DCHECK_NE(type, Primitive::kPrimVoid); 6676 6677 Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type); 6678 if (target.Equals(return_loc)) { 6679 return; 6680 } 6681 6682 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged 6683 // with the else branch. 6684 if (type == Primitive::kPrimLong) { 6685 HParallelMove parallel_move(GetGraph()->GetArena()); 6686 parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), Primitive::kPrimInt, nullptr); 6687 parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), Primitive::kPrimInt, nullptr); 6688 GetMoveResolver()->EmitNativeCode(¶llel_move); 6689 } else { 6690 // Let the parallel move resolver take care of all of this. 6691 HParallelMove parallel_move(GetGraph()->GetArena()); 6692 parallel_move.AddMove(return_loc, target, type, nullptr); 6693 GetMoveResolver()->EmitNativeCode(¶llel_move); 6694 } 6695} 6696 6697#undef __ 6698 6699} // namespace x86 6700} // namespace art 6701