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