• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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