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 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_ 18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_ 19 20 #include "arch/x86/instruction_set_features_x86.h" 21 #include "base/enums.h" 22 #include "code_generator.h" 23 #include "dex/dex_file_types.h" 24 #include "driver/compiler_options.h" 25 #include "nodes.h" 26 #include "parallel_move_resolver.h" 27 #include "utils/x86/assembler_x86.h" 28 29 namespace art { 30 namespace x86 { 31 32 // Use a local definition to prevent copying mistakes. 33 static constexpr size_t kX86WordSize = static_cast<size_t>(kX86PointerSize); 34 35 class CodeGeneratorX86; 36 37 static constexpr Register kParameterCoreRegisters[] = { ECX, EDX, EBX }; 38 static constexpr RegisterPair kParameterCorePairRegisters[] = { ECX_EDX, EDX_EBX }; 39 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 40 static constexpr XmmRegister kParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 }; 41 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters); 42 43 static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX, EBX }; 44 static constexpr size_t kRuntimeParameterCoreRegistersLength = 45 arraysize(kRuntimeParameterCoreRegisters); 46 static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 }; 47 static constexpr size_t kRuntimeParameterFpuRegistersLength = 48 arraysize(kRuntimeParameterFpuRegisters); 49 50 class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> { 51 public: InvokeRuntimeCallingConvention()52 InvokeRuntimeCallingConvention() 53 : CallingConvention(kRuntimeParameterCoreRegisters, 54 kRuntimeParameterCoreRegistersLength, 55 kRuntimeParameterFpuRegisters, 56 kRuntimeParameterFpuRegistersLength, 57 kX86PointerSize) {} 58 59 private: 60 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 61 }; 62 63 class InvokeDexCallingConvention : public CallingConvention<Register, XmmRegister> { 64 public: InvokeDexCallingConvention()65 InvokeDexCallingConvention() : CallingConvention( 66 kParameterCoreRegisters, 67 kParameterCoreRegistersLength, 68 kParameterFpuRegisters, 69 kParameterFpuRegistersLength, 70 kX86PointerSize) {} 71 GetRegisterPairAt(size_t argument_index)72 RegisterPair GetRegisterPairAt(size_t argument_index) { 73 DCHECK_LT(argument_index + 1, GetNumberOfRegisters()); 74 return kParameterCorePairRegisters[argument_index]; 75 } 76 77 private: 78 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); 79 }; 80 81 class InvokeDexCallingConventionVisitorX86 : public InvokeDexCallingConventionVisitor { 82 public: InvokeDexCallingConventionVisitorX86()83 InvokeDexCallingConventionVisitorX86() {} ~InvokeDexCallingConventionVisitorX86()84 virtual ~InvokeDexCallingConventionVisitorX86() {} 85 86 Location GetNextLocation(DataType::Type type) override; 87 Location GetReturnLocation(DataType::Type type) const override; 88 Location GetMethodLocation() const override; 89 90 private: 91 InvokeDexCallingConvention calling_convention; 92 93 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorX86); 94 }; 95 96 class CriticalNativeCallingConventionVisitorX86 : public InvokeDexCallingConventionVisitor { 97 public: CriticalNativeCallingConventionVisitorX86(bool for_register_allocation)98 explicit CriticalNativeCallingConventionVisitorX86(bool for_register_allocation) 99 : for_register_allocation_(for_register_allocation) {} 100 ~CriticalNativeCallingConventionVisitorX86()101 virtual ~CriticalNativeCallingConventionVisitorX86() {} 102 103 Location GetNextLocation(DataType::Type type) override; 104 Location GetReturnLocation(DataType::Type type) const override; 105 Location GetMethodLocation() const override; 106 GetStackOffset()107 size_t GetStackOffset() const { return stack_offset_; } 108 109 private: 110 // Register allocator does not support adjusting frame size, so we cannot provide final locations 111 // of stack arguments for register allocation. We ask the register allocator for any location and 112 // move these arguments to the right place after adjusting the SP when generating the call. 113 const bool for_register_allocation_; 114 size_t stack_offset_ = 0u; 115 116 DISALLOW_COPY_AND_ASSIGN(CriticalNativeCallingConventionVisitorX86); 117 }; 118 119 class FieldAccessCallingConventionX86 : public FieldAccessCallingConvention { 120 public: FieldAccessCallingConventionX86()121 FieldAccessCallingConventionX86() {} 122 GetObjectLocation()123 Location GetObjectLocation() const override { 124 return Location::RegisterLocation(ECX); 125 } GetFieldIndexLocation()126 Location GetFieldIndexLocation() const override { 127 return Location::RegisterLocation(EAX); 128 } GetReturnLocation(DataType::Type type)129 Location GetReturnLocation(DataType::Type type) const override { 130 return DataType::Is64BitType(type) 131 ? Location::RegisterPairLocation(EAX, EDX) 132 : Location::RegisterLocation(EAX); 133 } GetSetValueLocation(DataType::Type type,bool is_instance)134 Location GetSetValueLocation(DataType::Type type, bool is_instance) const override { 135 return DataType::Is64BitType(type) 136 ? (is_instance 137 ? Location::RegisterPairLocation(EDX, EBX) 138 : Location::RegisterPairLocation(ECX, EDX)) 139 : (is_instance 140 ? Location::RegisterLocation(EDX) 141 : Location::RegisterLocation(ECX)); 142 } GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED)143 Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const override { 144 return Location::FpuRegisterLocation(XMM0); 145 } 146 147 private: 148 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionX86); 149 }; 150 151 class ParallelMoveResolverX86 : public ParallelMoveResolverWithSwap { 152 public: ParallelMoveResolverX86(ArenaAllocator * allocator,CodeGeneratorX86 * codegen)153 ParallelMoveResolverX86(ArenaAllocator* allocator, CodeGeneratorX86* codegen) 154 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {} 155 156 void EmitMove(size_t index) override; 157 void EmitSwap(size_t index) override; 158 void SpillScratch(int reg) override; 159 void RestoreScratch(int reg) override; 160 161 X86Assembler* GetAssembler() const; 162 163 private: 164 void Exchange(Register reg, int mem); 165 void Exchange32(XmmRegister reg, int mem); 166 void Exchange128(XmmRegister reg, int mem); 167 void ExchangeMemory(int mem1, int mem2, int number_of_words); 168 void MoveMemoryToMemory(int dst, int src, int number_of_words); 169 170 CodeGeneratorX86* const codegen_; 171 172 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverX86); 173 }; 174 175 class LocationsBuilderX86 : public HGraphVisitor { 176 public: LocationsBuilderX86(HGraph * graph,CodeGeneratorX86 * codegen)177 LocationsBuilderX86(HGraph* graph, CodeGeneratorX86* codegen) 178 : HGraphVisitor(graph), codegen_(codegen) {} 179 180 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 181 void Visit##name(H##name* instr) override; 182 183 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)184 FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION) 185 FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(DECLARE_VISIT_INSTRUCTION) 186 187 #undef DECLARE_VISIT_INSTRUCTION 188 189 void VisitInstruction(HInstruction* instruction) override { 190 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 191 << " (id " << instruction->GetId() << ")"; 192 } 193 194 private: 195 void HandleBitwiseOperation(HBinaryOperation* instruction); 196 void HandleInvoke(HInvoke* invoke); 197 void HandleCondition(HCondition* condition); 198 void HandleShift(HBinaryOperation* instruction); 199 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info); 200 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 201 bool CpuHasAvxFeatureFlag(); 202 bool CpuHasAvx2FeatureFlag(); 203 204 CodeGeneratorX86* const codegen_; 205 InvokeDexCallingConventionVisitorX86 parameter_visitor_; 206 207 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderX86); 208 }; 209 210 class InstructionCodeGeneratorX86 : public InstructionCodeGenerator { 211 public: 212 InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen); 213 214 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 215 void Visit##name(H##name* instr) override; 216 217 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION)218 FOR_EACH_CONCRETE_INSTRUCTION_X86(DECLARE_VISIT_INSTRUCTION) 219 FOR_EACH_CONCRETE_INSTRUCTION_X86_COMMON(DECLARE_VISIT_INSTRUCTION) 220 221 #undef DECLARE_VISIT_INSTRUCTION 222 223 void VisitInstruction(HInstruction* instruction) override { 224 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 225 << " (id " << instruction->GetId() << ")"; 226 } 227 GetAssembler()228 X86Assembler* GetAssembler() const { return assembler_; } 229 230 // The compare/jump sequence will generate about (1.5 * num_entries) instructions. A jump 231 // table version generates 7 instructions and num_entries literals. Compare/jump sequence will 232 // generates less code/data with a small num_entries. 233 static constexpr uint32_t kPackedSwitchJumpTableThreshold = 5; 234 235 // Generate a GC root reference load: 236 // 237 // root <- *address 238 // 239 // while honoring read barriers based on read_barrier_option. 240 void GenerateGcRootFieldLoad(HInstruction* instruction, 241 Location root, 242 const Address& address, 243 Label* fixup_label, 244 ReadBarrierOption read_barrier_option); 245 246 void HandleFieldSet(HInstruction* instruction, 247 uint32_t value_index, 248 DataType::Type type, 249 Address field_addr, 250 Register base, 251 bool is_volatile, 252 bool value_can_be_null); 253 254 private: 255 // Generate code for the given suspend check. If not null, `successor` 256 // is the block to branch to if the suspend check is not needed, and after 257 // the suspend call. 258 void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); 259 void GenerateClassInitializationCheck(SlowPathCode* slow_path, Register class_reg); 260 void GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check, Register temp); 261 void HandleBitwiseOperation(HBinaryOperation* instruction); 262 void GenerateDivRemIntegral(HBinaryOperation* instruction); 263 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 264 void DivByPowerOfTwo(HDiv* instruction); 265 void RemByPowerOfTwo(HRem* instruction); 266 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 267 void GenerateRemFP(HRem* rem); 268 void HandleCondition(HCondition* condition); 269 void HandleShift(HBinaryOperation* instruction); 270 void GenerateShlLong(const Location& loc, Register shifter); 271 void GenerateShrLong(const Location& loc, Register shifter); 272 void GenerateUShrLong(const Location& loc, Register shifter); 273 void GenerateShlLong(const Location& loc, int shift); 274 void GenerateShrLong(const Location& loc, int shift); 275 void GenerateUShrLong(const Location& loc, int shift); 276 void GenerateMinMaxInt(LocationSummary* locations, bool is_min, DataType::Type type); 277 void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type); 278 void GenerateMinMax(HBinaryOperation* minmax, bool is_min); 279 280 void HandleFieldSet(HInstruction* instruction, 281 const FieldInfo& field_info, 282 bool value_can_be_null); 283 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 284 285 // Generate a heap reference load using one register `out`: 286 // 287 // out <- *(out + offset) 288 // 289 // while honoring heap poisoning and/or read barriers (if any). 290 // 291 // Location `maybe_temp` is used when generating a read barrier and 292 // shall be a register in that case; it may be an invalid location 293 // otherwise. 294 void GenerateReferenceLoadOneRegister(HInstruction* instruction, 295 Location out, 296 uint32_t offset, 297 Location maybe_temp, 298 ReadBarrierOption read_barrier_option); 299 // Generate a heap reference load using two different registers 300 // `out` and `obj`: 301 // 302 // out <- *(obj + offset) 303 // 304 // while honoring heap poisoning and/or read barriers (if any). 305 // 306 // Location `maybe_temp` is used when generating a Baker's (fast 307 // path) read barrier and shall be a register in that case; it may 308 // be an invalid location otherwise. 309 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction, 310 Location out, 311 Location obj, 312 uint32_t offset, 313 ReadBarrierOption read_barrier_option); 314 315 // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not. 316 // `is_wide` specifies whether it is long/double or not. 317 void PushOntoFPStack(Location source, uint32_t temp_offset, 318 uint32_t stack_adjustment, bool is_fp, bool is_wide); 319 320 template<class LabelType> 321 void GenerateTestAndBranch(HInstruction* instruction, 322 size_t condition_input_index, 323 LabelType* true_target, 324 LabelType* false_target); 325 template<class LabelType> 326 void GenerateCompareTestAndBranch(HCondition* condition, 327 LabelType* true_target, 328 LabelType* false_target); 329 template<class LabelType> 330 void GenerateFPJumps(HCondition* cond, LabelType* true_label, LabelType* false_label); 331 template<class LabelType> 332 void GenerateLongComparesAndJumps(HCondition* cond, 333 LabelType* true_label, 334 LabelType* false_label); 335 336 void HandleGoto(HInstruction* got, HBasicBlock* successor); 337 void GenPackedSwitchWithCompares(Register value_reg, 338 int32_t lower_bound, 339 uint32_t num_entries, 340 HBasicBlock* switch_block, 341 HBasicBlock* default_block); 342 343 void GenerateFPCompare(Location lhs, Location rhs, HInstruction* insn, bool is_double); 344 bool CpuHasAvxFeatureFlag(); 345 bool CpuHasAvx2FeatureFlag(); 346 347 void GenerateMethodEntryExitHook(HInstruction* instruction); 348 349 X86Assembler* const assembler_; 350 CodeGeneratorX86* const codegen_; 351 352 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86); 353 }; 354 355 class JumpTableRIPFixup; 356 357 class CodeGeneratorX86 : public CodeGenerator { 358 public: 359 CodeGeneratorX86(HGraph* graph, 360 const CompilerOptions& compiler_options, 361 OptimizingCompilerStats* stats = nullptr); ~CodeGeneratorX86()362 virtual ~CodeGeneratorX86() {} 363 364 void GenerateFrameEntry() override; 365 void GenerateFrameExit() override; 366 void Bind(HBasicBlock* block) override; 367 void MoveConstant(Location destination, int32_t value) override; 368 void MoveLocation(Location dst, Location src, DataType::Type dst_type) override; 369 void AddLocationAsTemp(Location location, LocationSummary* locations) override; 370 371 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) override; 372 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) override; 373 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) override; 374 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) override; 375 376 // Generate code to invoke a runtime entry point. 377 void InvokeRuntime(QuickEntrypointEnum entrypoint, 378 HInstruction* instruction, 379 uint32_t dex_pc, 380 SlowPathCode* slow_path = nullptr) override; 381 382 // Generate code to invoke a runtime entry point, but do not record 383 // PC-related information in a stack map. 384 void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset, 385 HInstruction* instruction, 386 SlowPathCode* slow_path); 387 388 void GenerateInvokeRuntime(int32_t entry_point_offset); 389 GetWordSize()390 size_t GetWordSize() const override { 391 return kX86WordSize; 392 } 393 GetSlowPathFPWidth()394 size_t GetSlowPathFPWidth() const override { 395 return GetGraph()->HasSIMD() 396 ? GetSIMDRegisterWidth() 397 : 2 * kX86WordSize; // 8 bytes == 2 words for each spill 398 } 399 GetCalleePreservedFPWidth()400 size_t GetCalleePreservedFPWidth() const override { 401 return 2 * kX86WordSize; 402 } 403 GetSIMDRegisterWidth()404 size_t GetSIMDRegisterWidth() const override { 405 return 4 * kX86WordSize; 406 } 407 GetLocationBuilder()408 HGraphVisitor* GetLocationBuilder() override { 409 return &location_builder_; 410 } 411 GetInstructionVisitor()412 HGraphVisitor* GetInstructionVisitor() override { 413 return &instruction_visitor_; 414 } 415 GetAssembler()416 X86Assembler* GetAssembler() override { 417 return &assembler_; 418 } 419 GetAssembler()420 const X86Assembler& GetAssembler() const override { 421 return assembler_; 422 } 423 GetAddressOf(HBasicBlock * block)424 uintptr_t GetAddressOf(HBasicBlock* block) override { 425 return GetLabelOf(block)->Position(); 426 } 427 428 void SetupBlockedRegisters() const override; 429 430 void DumpCoreRegister(std::ostream& stream, int reg) const override; 431 void DumpFloatingPointRegister(std::ostream& stream, int reg) const override; 432 GetMoveResolver()433 ParallelMoveResolverX86* GetMoveResolver() override { 434 return &move_resolver_; 435 } 436 GetInstructionSet()437 InstructionSet GetInstructionSet() const override { 438 return InstructionSet::kX86; 439 } 440 441 const X86InstructionSetFeatures& GetInstructionSetFeatures() const; 442 443 // Helper method to move a 32bits value between two locations. 444 void Move32(Location destination, Location source); 445 // Helper method to move a 64bits value between two locations. 446 void Move64(Location destination, Location source); 447 // Helper method to load a value from an address to a register. 448 void LoadFromMemoryNoBarrier(DataType::Type dst_type, 449 Location dst, 450 Address src, 451 HInstruction* instr = nullptr, 452 XmmRegister temp = kNoXmmRegister, 453 bool is_atomic_load = false); 454 // Helper method to move a primitive value from a location to an address. 455 void MoveToMemory(DataType::Type src_type, 456 Location src, 457 Register dst_base, 458 Register dst_index = Register::kNoRegister, 459 ScaleFactor dst_scale = TIMES_1, 460 int32_t dst_disp = 0); 461 462 // Check if the desired_string_load_kind is supported. If it is, return it, 463 // otherwise return a fall-back kind that should be used instead. 464 HLoadString::LoadKind GetSupportedLoadStringKind( 465 HLoadString::LoadKind desired_string_load_kind) override; 466 467 // Check if the desired_class_load_kind is supported. If it is, return it, 468 // otherwise return a fall-back kind that should be used instead. 469 HLoadClass::LoadKind GetSupportedLoadClassKind( 470 HLoadClass::LoadKind desired_class_load_kind) override; 471 472 // Check if the desired_dispatch_info is supported. If it is, return it, 473 // otherwise return a fall-back info that should be used instead. 474 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( 475 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, 476 ArtMethod* method) override; 477 478 void LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke); 479 // Generate a call to a static or direct method. 480 void GenerateStaticOrDirectCall( 481 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override; 482 // Generate a call to a virtual method. 483 void GenerateVirtualCall( 484 HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) override; 485 486 void RecordBootImageIntrinsicPatch(HX86ComputeBaseMethodAddress* method_address, 487 uint32_t intrinsic_data); 488 void RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress* method_address, 489 uint32_t boot_image_offset); 490 void RecordBootImageMethodPatch(HInvoke* invoke); 491 void RecordMethodBssEntryPatch(HInvoke* invoke); 492 void RecordBootImageTypePatch(HLoadClass* load_class); 493 Label* NewTypeBssEntryPatch(HLoadClass* load_class); 494 void RecordBootImageStringPatch(HLoadString* load_string); 495 Label* NewStringBssEntryPatch(HLoadString* load_string); 496 void RecordBootImageJniEntrypointPatch(HInvokeStaticOrDirect* invoke); 497 498 void LoadBootImageAddress(Register reg, 499 uint32_t boot_image_reference, 500 HInvokeStaticOrDirect* invoke); 501 void LoadIntrinsicDeclaringClass(Register reg, HInvokeStaticOrDirect* invoke); 502 503 Label* NewJitRootStringPatch(const DexFile& dex_file, 504 dex::StringIndex string_index, 505 Handle<mirror::String> handle); 506 Label* NewJitRootClassPatch(const DexFile& dex_file, 507 dex::TypeIndex type_index, 508 Handle<mirror::Class> handle); 509 510 void MoveFromReturnRegister(Location trg, DataType::Type type) override; 511 512 // Emit linker patches. 513 void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) override; 514 515 void PatchJitRootUse(uint8_t* code, 516 const uint8_t* roots_data, 517 const PatchInfo<Label>& info, 518 uint64_t index_in_table) const; 519 void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) override; 520 521 // Emit a write barrier. 522 void MarkGCCard(Register temp, 523 Register card, 524 Register object, 525 Register value, 526 bool value_can_be_null); 527 528 void GenerateMemoryBarrier(MemBarrierKind kind); 529 GetLabelOf(HBasicBlock * block)530 Label* GetLabelOf(HBasicBlock* block) const { 531 return CommonGetLabelOf<Label>(block_labels_, block); 532 } 533 Initialize()534 void Initialize() override { 535 block_labels_ = CommonInitializeLabels<Label>(); 536 } 537 NeedsTwoRegisters(DataType::Type type)538 bool NeedsTwoRegisters(DataType::Type type) const override { 539 return type == DataType::Type::kInt64; 540 } 541 ShouldSplitLongMoves()542 bool ShouldSplitLongMoves() const override { return true; } 543 GetFrameEntryLabel()544 Label* GetFrameEntryLabel() { return &frame_entry_label_; } 545 AddMethodAddressOffset(HX86ComputeBaseMethodAddress * method_base,int32_t offset)546 void AddMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base, int32_t offset) { 547 method_address_offset_.Put(method_base->GetId(), offset); 548 } 549 GetMethodAddressOffset(HX86ComputeBaseMethodAddress * method_base)550 int32_t GetMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base) const { 551 return method_address_offset_.Get(method_base->GetId()); 552 } 553 ConstantAreaStart()554 int32_t ConstantAreaStart() const { 555 return constant_area_start_; 556 } 557 558 Address LiteralDoubleAddress(double v, HX86ComputeBaseMethodAddress* method_base, Register reg); 559 Address LiteralFloatAddress(float v, HX86ComputeBaseMethodAddress* method_base, Register reg); 560 Address LiteralInt32Address(int32_t v, HX86ComputeBaseMethodAddress* method_base, Register reg); 561 Address LiteralInt64Address(int64_t v, HX86ComputeBaseMethodAddress* method_base, Register reg); 562 563 // Load a 32-bit value into a register in the most efficient manner. 564 void Load32BitValue(Register dest, int32_t value); 565 566 // Compare a register with a 32-bit value in the most efficient manner. 567 void Compare32BitValue(Register dest, int32_t value); 568 569 // Compare int values. Supports only register locations for `lhs`. 570 void GenerateIntCompare(Location lhs, Location rhs); 571 void GenerateIntCompare(Register lhs, Location rhs); 572 573 // Construct address for array access. 574 static Address ArrayAddress(Register obj, 575 Location index, 576 ScaleFactor scale, 577 uint32_t data_offset); 578 579 Address LiteralCaseTable(HX86PackedSwitch* switch_instr, Register reg, Register value); 580 581 void Finalize(CodeAllocator* allocator) override; 582 583 // Fast path implementation of ReadBarrier::Barrier for a heap 584 // reference field load when Baker's read barriers are used. 585 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, 586 Location ref, 587 Register obj, 588 uint32_t offset, 589 bool needs_null_check); 590 // Fast path implementation of ReadBarrier::Barrier for a heap 591 // reference array load when Baker's read barriers are used. 592 void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, 593 Location ref, 594 Register obj, 595 uint32_t data_offset, 596 Location index, 597 bool needs_null_check); 598 // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier, 599 // GenerateArrayLoadWithBakerReadBarrier and some intrinsics. 600 // 601 // Load the object reference located at address `src`, held by 602 // object `obj`, into `ref`, and mark it if needed. The base of 603 // address `src` must be `obj`. 604 // 605 // If `always_update_field` is true, the value of the reference is 606 // atomically updated in the holder (`obj`). This operation 607 // requires a temporary register, which must be provided as a 608 // non-null pointer (`temp`). 609 void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, 610 Location ref, 611 Register obj, 612 const Address& src, 613 bool needs_null_check, 614 bool always_update_field = false, 615 Register* temp = nullptr); 616 617 // Generate a read barrier for a heap reference within `instruction` 618 // using a slow path. 619 // 620 // A read barrier for an object reference read from the heap is 621 // implemented as a call to the artReadBarrierSlow runtime entry 622 // point, which is passed the values in locations `ref`, `obj`, and 623 // `offset`: 624 // 625 // mirror::Object* artReadBarrierSlow(mirror::Object* ref, 626 // mirror::Object* obj, 627 // uint32_t offset); 628 // 629 // The `out` location contains the value returned by 630 // artReadBarrierSlow. 631 // 632 // When `index` is provided (i.e. for array accesses), the offset 633 // value passed to artReadBarrierSlow is adjusted to take `index` 634 // into account. 635 void GenerateReadBarrierSlow(HInstruction* instruction, 636 Location out, 637 Location ref, 638 Location obj, 639 uint32_t offset, 640 Location index = Location::NoLocation()); 641 642 // If read barriers are enabled, generate a read barrier for a heap 643 // reference using a slow path. If heap poisoning is enabled, also 644 // unpoison the reference in `out`. 645 void MaybeGenerateReadBarrierSlow(HInstruction* instruction, 646 Location out, 647 Location ref, 648 Location obj, 649 uint32_t offset, 650 Location index = Location::NoLocation()); 651 652 // Generate a read barrier for a GC root within `instruction` using 653 // a slow path. 654 // 655 // A read barrier for an object reference GC root is implemented as 656 // a call to the artReadBarrierForRootSlow runtime entry point, 657 // which is passed the value in location `root`: 658 // 659 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); 660 // 661 // The `out` location contains the value returned by 662 // artReadBarrierForRootSlow. 663 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root); 664 665 // Ensure that prior stores complete to memory before subsequent loads. 666 // The locked add implementation will avoid serializing device memory, but will 667 // touch (but not change) the top of the stack. 668 // The 'non_temporal' parameter should be used to ensure ordering of non-temporal stores. 669 void MemoryFence(bool non_temporal = false) { 670 if (!non_temporal) { 671 assembler_.lock()->addl(Address(ESP, 0), Immediate(0)); 672 } else { 673 assembler_.mfence(); 674 } 675 } 676 677 void IncreaseFrame(size_t adjustment) override; 678 void DecreaseFrame(size_t adjustment) override; 679 680 void GenerateNop() override; 681 void GenerateImplicitNullCheck(HNullCheck* instruction) override; 682 void GenerateExplicitNullCheck(HNullCheck* instruction) override; 683 684 void MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass); 685 void MaybeIncrementHotness(bool is_frame_entry); 686 687 // When we don't know the proper offset for the value, we use kPlaceholder32BitOffset. 688 // The correct value will be inserted when processing Assembler fixups. 689 static constexpr int32_t kPlaceholder32BitOffset = 256; 690 691 private: 692 struct X86PcRelativePatchInfo : PatchInfo<Label> { X86PcRelativePatchInfoX86PcRelativePatchInfo693 X86PcRelativePatchInfo(HX86ComputeBaseMethodAddress* address, 694 const DexFile* target_dex_file, 695 uint32_t target_index) 696 : PatchInfo(target_dex_file, target_index), 697 method_address(address) {} 698 HX86ComputeBaseMethodAddress* method_address; 699 }; 700 701 template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)> 702 void EmitPcRelativeLinkerPatches(const ArenaDeque<X86PcRelativePatchInfo>& infos, 703 ArenaVector<linker::LinkerPatch>* linker_patches); 704 705 Register GetInvokeExtraParameter(HInvoke* invoke, Register temp); 706 Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp); 707 708 // Labels for each block that will be compiled. 709 Label* block_labels_; // Indexed by block id. 710 Label frame_entry_label_; 711 LocationsBuilderX86 location_builder_; 712 InstructionCodeGeneratorX86 instruction_visitor_; 713 ParallelMoveResolverX86 move_resolver_; 714 X86Assembler assembler_; 715 716 // PC-relative method patch info for kBootImageLinkTimePcRelative. 717 ArenaDeque<X86PcRelativePatchInfo> boot_image_method_patches_; 718 // PC-relative method patch info for kBssEntry. 719 ArenaDeque<X86PcRelativePatchInfo> method_bss_entry_patches_; 720 // PC-relative type patch info for kBootImageLinkTimePcRelative. 721 ArenaDeque<X86PcRelativePatchInfo> boot_image_type_patches_; 722 // PC-relative type patch info for kBssEntry. 723 ArenaDeque<X86PcRelativePatchInfo> type_bss_entry_patches_; 724 // PC-relative public type patch info for kBssEntryPublic. 725 ArenaDeque<X86PcRelativePatchInfo> public_type_bss_entry_patches_; 726 // PC-relative package type patch info for kBssEntryPackage. 727 ArenaDeque<X86PcRelativePatchInfo> package_type_bss_entry_patches_; 728 // PC-relative String patch info for kBootImageLinkTimePcRelative. 729 ArenaDeque<X86PcRelativePatchInfo> boot_image_string_patches_; 730 // PC-relative String patch info for kBssEntry. 731 ArenaDeque<X86PcRelativePatchInfo> string_bss_entry_patches_; 732 // PC-relative method patch info for kBootImageLinkTimePcRelative+kCallCriticalNative. 733 ArenaDeque<X86PcRelativePatchInfo> boot_image_jni_entrypoint_patches_; 734 // PC-relative patch info for IntrinsicObjects for the boot image, 735 // and for method/type/string patches for kBootImageRelRo otherwise. 736 ArenaDeque<X86PcRelativePatchInfo> boot_image_other_patches_; 737 738 // Patches for string root accesses in JIT compiled code. 739 ArenaDeque<PatchInfo<Label>> jit_string_patches_; 740 // Patches for class root accesses in JIT compiled code. 741 ArenaDeque<PatchInfo<Label>> jit_class_patches_; 742 743 // Offset to the start of the constant area in the assembled code. 744 // Used for fixups to the constant area. 745 int32_t constant_area_start_; 746 747 // Fixups for jump tables that need to be patched after the constant table is generated. 748 ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_; 749 750 // Maps a HX86ComputeBaseMethodAddress instruction id, to its offset in the 751 // compiled code. 752 ArenaSafeMap<uint32_t, int32_t> method_address_offset_; 753 754 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86); 755 }; 756 757 } // namespace x86 758 } // namespace art 759 760 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_ 761