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