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   X86Assembler* const assembler_;
348   CodeGeneratorX86* const codegen_;
349 
350   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorX86);
351 };
352 
353 class JumpTableRIPFixup;
354 
355 class CodeGeneratorX86 : public CodeGenerator {
356  public:
357   CodeGeneratorX86(HGraph* graph,
358                    const CompilerOptions& compiler_options,
359                    OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorX86()360   virtual ~CodeGeneratorX86() {}
361 
362   void GenerateFrameEntry() override;
363   void GenerateFrameExit() override;
364   void Bind(HBasicBlock* block) override;
365   void MoveConstant(Location destination, int32_t value) override;
366   void MoveLocation(Location dst, Location src, DataType::Type dst_type) override;
367   void AddLocationAsTemp(Location location, LocationSummary* locations) override;
368 
369   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) override;
370   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) override;
371   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
372   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
373 
374   // Generate code to invoke a runtime entry point.
375   void InvokeRuntime(QuickEntrypointEnum entrypoint,
376                      HInstruction* instruction,
377                      uint32_t dex_pc,
378                      SlowPathCode* slow_path = nullptr) override;
379 
380   // Generate code to invoke a runtime entry point, but do not record
381   // PC-related information in a stack map.
382   void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
383                                            HInstruction* instruction,
384                                            SlowPathCode* slow_path);
385 
386   void GenerateInvokeRuntime(int32_t entry_point_offset);
387 
GetWordSize()388   size_t GetWordSize() const override {
389     return kX86WordSize;
390   }
391 
GetSlowPathFPWidth()392   size_t GetSlowPathFPWidth() const override {
393     return GetGraph()->HasSIMD()
394         ? GetSIMDRegisterWidth()
395         : 2 * kX86WordSize;  //  8 bytes == 2 words for each spill
396   }
397 
GetCalleePreservedFPWidth()398   size_t GetCalleePreservedFPWidth() const override {
399     return 2 * kX86WordSize;
400   }
401 
GetSIMDRegisterWidth()402   size_t GetSIMDRegisterWidth() const override {
403     return 4 * kX86WordSize;
404   }
405 
GetLocationBuilder()406   HGraphVisitor* GetLocationBuilder() override {
407     return &location_builder_;
408   }
409 
GetInstructionVisitor()410   HGraphVisitor* GetInstructionVisitor() override {
411     return &instruction_visitor_;
412   }
413 
GetAssembler()414   X86Assembler* GetAssembler() override {
415     return &assembler_;
416   }
417 
GetAssembler()418   const X86Assembler& GetAssembler() const override {
419     return assembler_;
420   }
421 
GetAddressOf(HBasicBlock * block)422   uintptr_t GetAddressOf(HBasicBlock* block) override {
423     return GetLabelOf(block)->Position();
424   }
425 
426   void SetupBlockedRegisters() const override;
427 
428   void DumpCoreRegister(std::ostream& stream, int reg) const override;
429   void DumpFloatingPointRegister(std::ostream& stream, int reg) const override;
430 
GetMoveResolver()431   ParallelMoveResolverX86* GetMoveResolver() override {
432     return &move_resolver_;
433   }
434 
GetInstructionSet()435   InstructionSet GetInstructionSet() const override {
436     return InstructionSet::kX86;
437   }
438 
439   const X86InstructionSetFeatures& GetInstructionSetFeatures() const;
440 
441   // Helper method to move a 32bits value between two locations.
442   void Move32(Location destination, Location source);
443   // Helper method to move a 64bits value between two locations.
444   void Move64(Location destination, Location source);
445   // Helper method to load a value from an address to a register.
446   void LoadFromMemoryNoBarrier(DataType::Type dst_type,
447                                Location dst,
448                                Address src,
449                                XmmRegister temp = kNoXmmRegister,
450                                bool is_atomic_load = false);
451   // Helper method to move a primitive value from a location to an address.
452   void MoveToMemory(DataType::Type src_type,
453                     Location src,
454                     Register dst_base,
455                     Register dst_index = Register::kNoRegister,
456                     ScaleFactor dst_scale = TIMES_1,
457                     int32_t dst_disp = 0);
458 
459   // Check if the desired_string_load_kind is supported. If it is, return it,
460   // otherwise return a fall-back kind that should be used instead.
461   HLoadString::LoadKind GetSupportedLoadStringKind(
462       HLoadString::LoadKind desired_string_load_kind) override;
463 
464   // Check if the desired_class_load_kind is supported. If it is, return it,
465   // otherwise return a fall-back kind that should be used instead.
466   HLoadClass::LoadKind GetSupportedLoadClassKind(
467       HLoadClass::LoadKind desired_class_load_kind) override;
468 
469   // Check if the desired_dispatch_info is supported. If it is, return it,
470   // otherwise return a fall-back info that should be used instead.
471   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
472       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
473       ArtMethod* method) override;
474 
475   void LoadMethod(MethodLoadKind load_kind, Location temp, HInvoke* invoke);
476   // Generate a call to a static or direct method.
477   void GenerateStaticOrDirectCall(
478       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
479   // Generate a call to a virtual method.
480   void GenerateVirtualCall(
481       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
482 
483   void RecordBootImageIntrinsicPatch(HX86ComputeBaseMethodAddress* method_address,
484                                      uint32_t intrinsic_data);
485   void RecordBootImageRelRoPatch(HX86ComputeBaseMethodAddress* method_address,
486                                  uint32_t boot_image_offset);
487   void RecordBootImageMethodPatch(HInvoke* invoke);
488   void RecordMethodBssEntryPatch(HInvoke* invoke);
489   void RecordBootImageTypePatch(HLoadClass* load_class);
490   Label* NewTypeBssEntryPatch(HLoadClass* load_class);
491   void RecordBootImageStringPatch(HLoadString* load_string);
492   Label* NewStringBssEntryPatch(HLoadString* load_string);
493   void RecordBootImageJniEntrypointPatch(HInvokeStaticOrDirect* invoke);
494 
495   void LoadBootImageAddress(Register reg,
496                             uint32_t boot_image_reference,
497                             HInvokeStaticOrDirect* invoke);
498   void LoadIntrinsicDeclaringClass(Register reg, HInvokeStaticOrDirect* invoke);
499 
500   Label* NewJitRootStringPatch(const DexFile& dex_file,
501                                dex::StringIndex string_index,
502                                Handle<mirror::String> handle);
503   Label* NewJitRootClassPatch(const DexFile& dex_file,
504                               dex::TypeIndex type_index,
505                               Handle<mirror::Class> handle);
506 
507   void MoveFromReturnRegister(Location trg, DataType::Type type) override;
508 
509   // Emit linker patches.
510   void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) override;
511 
512   void PatchJitRootUse(uint8_t* code,
513                        const uint8_t* roots_data,
514                        const PatchInfo<Label>& info,
515                        uint64_t index_in_table) const;
516   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) override;
517 
518   // Emit a write barrier.
519   void MarkGCCard(Register temp,
520                   Register card,
521                   Register object,
522                   Register value,
523                   bool value_can_be_null);
524 
525   void GenerateMemoryBarrier(MemBarrierKind kind);
526 
GetLabelOf(HBasicBlock * block)527   Label* GetLabelOf(HBasicBlock* block) const {
528     return CommonGetLabelOf<Label>(block_labels_, block);
529   }
530 
Initialize()531   void Initialize() override {
532     block_labels_ = CommonInitializeLabels<Label>();
533   }
534 
NeedsTwoRegisters(DataType::Type type)535   bool NeedsTwoRegisters(DataType::Type type) const override {
536     return type == DataType::Type::kInt64;
537   }
538 
ShouldSplitLongMoves()539   bool ShouldSplitLongMoves() const override { return true; }
540 
GetFrameEntryLabel()541   Label* GetFrameEntryLabel() { return &frame_entry_label_; }
542 
AddMethodAddressOffset(HX86ComputeBaseMethodAddress * method_base,int32_t offset)543   void AddMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base, int32_t offset) {
544     method_address_offset_.Put(method_base->GetId(), offset);
545   }
546 
GetMethodAddressOffset(HX86ComputeBaseMethodAddress * method_base)547   int32_t GetMethodAddressOffset(HX86ComputeBaseMethodAddress* method_base) const {
548     return method_address_offset_.Get(method_base->GetId());
549   }
550 
ConstantAreaStart()551   int32_t ConstantAreaStart() const {
552     return constant_area_start_;
553   }
554 
555   Address LiteralDoubleAddress(double v, HX86ComputeBaseMethodAddress* method_base, Register reg);
556   Address LiteralFloatAddress(float v, HX86ComputeBaseMethodAddress* method_base, Register reg);
557   Address LiteralInt32Address(int32_t v, HX86ComputeBaseMethodAddress* method_base, Register reg);
558   Address LiteralInt64Address(int64_t v, HX86ComputeBaseMethodAddress* method_base, Register reg);
559 
560   // Load a 32-bit value into a register in the most efficient manner.
561   void Load32BitValue(Register dest, int32_t value);
562 
563   // Compare a register with a 32-bit value in the most efficient manner.
564   void Compare32BitValue(Register dest, int32_t value);
565 
566   // Compare int values. Supports only register locations for `lhs`.
567   void GenerateIntCompare(Location lhs, Location rhs);
568   void GenerateIntCompare(Register lhs, Location rhs);
569 
570   // Construct address for array access.
571   static Address ArrayAddress(Register obj,
572                               Location index,
573                               ScaleFactor scale,
574                               uint32_t data_offset);
575 
576   Address LiteralCaseTable(HX86PackedSwitch* switch_instr, Register reg, Register value);
577 
578   void Finalize(CodeAllocator* allocator) override;
579 
580   // Fast path implementation of ReadBarrier::Barrier for a heap
581   // reference field load when Baker's read barriers are used.
582   void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
583                                              Location ref,
584                                              Register obj,
585                                              uint32_t offset,
586                                              bool needs_null_check);
587   // Fast path implementation of ReadBarrier::Barrier for a heap
588   // reference array load when Baker's read barriers are used.
589   void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
590                                              Location ref,
591                                              Register obj,
592                                              uint32_t data_offset,
593                                              Location index,
594                                              bool needs_null_check);
595   // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier,
596   // GenerateArrayLoadWithBakerReadBarrier and some intrinsics.
597   //
598   // Load the object reference located at address `src`, held by
599   // object `obj`, into `ref`, and mark it if needed.  The base of
600   // address `src` must be `obj`.
601   //
602   // If `always_update_field` is true, the value of the reference is
603   // atomically updated in the holder (`obj`).  This operation
604   // requires a temporary register, which must be provided as a
605   // non-null pointer (`temp`).
606   void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
607                                                  Location ref,
608                                                  Register obj,
609                                                  const Address& src,
610                                                  bool needs_null_check,
611                                                  bool always_update_field = false,
612                                                  Register* temp = nullptr);
613 
614   // Generate a read barrier for a heap reference within `instruction`
615   // using a slow path.
616   //
617   // A read barrier for an object reference read from the heap is
618   // implemented as a call to the artReadBarrierSlow runtime entry
619   // point, which is passed the values in locations `ref`, `obj`, and
620   // `offset`:
621   //
622   //   mirror::Object* artReadBarrierSlow(mirror::Object* ref,
623   //                                      mirror::Object* obj,
624   //                                      uint32_t offset);
625   //
626   // The `out` location contains the value returned by
627   // artReadBarrierSlow.
628   //
629   // When `index` is provided (i.e. for array accesses), the offset
630   // value passed to artReadBarrierSlow is adjusted to take `index`
631   // into account.
632   void GenerateReadBarrierSlow(HInstruction* instruction,
633                                Location out,
634                                Location ref,
635                                Location obj,
636                                uint32_t offset,
637                                Location index = Location::NoLocation());
638 
639   // If read barriers are enabled, generate a read barrier for a heap
640   // reference using a slow path. If heap poisoning is enabled, also
641   // unpoison the reference in `out`.
642   void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
643                                     Location out,
644                                     Location ref,
645                                     Location obj,
646                                     uint32_t offset,
647                                     Location index = Location::NoLocation());
648 
649   // Generate a read barrier for a GC root within `instruction` using
650   // a slow path.
651   //
652   // A read barrier for an object reference GC root is implemented as
653   // a call to the artReadBarrierForRootSlow runtime entry point,
654   // which is passed the value in location `root`:
655   //
656   //   mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
657   //
658   // The `out` location contains the value returned by
659   // artReadBarrierForRootSlow.
660   void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
661 
662   // Ensure that prior stores complete to memory before subsequent loads.
663   // The locked add implementation will avoid serializing device memory, but will
664   // touch (but not change) the top of the stack.
665   // The 'non_temporal' parameter should be used to ensure ordering of non-temporal stores.
666   void MemoryFence(bool non_temporal = false) {
667     if (!non_temporal) {
668       assembler_.lock()->addl(Address(ESP, 0), Immediate(0));
669     } else {
670       assembler_.mfence();
671     }
672   }
673 
674   void IncreaseFrame(size_t adjustment) override;
675   void DecreaseFrame(size_t adjustment) override;
676 
677   void GenerateNop() override;
678   void GenerateImplicitNullCheck(HNullCheck* instruction) override;
679   void GenerateExplicitNullCheck(HNullCheck* instruction) override;
680 
681   void MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass);
682   void MaybeIncrementHotness(bool is_frame_entry);
683 
684   // When we don't know the proper offset for the value, we use kPlaceholder32BitOffset.
685   // The correct value will be inserted when processing Assembler fixups.
686   static constexpr int32_t kPlaceholder32BitOffset = 256;
687 
688  private:
689   struct X86PcRelativePatchInfo : PatchInfo<Label> {
X86PcRelativePatchInfoX86PcRelativePatchInfo690     X86PcRelativePatchInfo(HX86ComputeBaseMethodAddress* address,
691                            const DexFile* target_dex_file,
692                            uint32_t target_index)
693         : PatchInfo(target_dex_file, target_index),
694           method_address(address) {}
695     HX86ComputeBaseMethodAddress* method_address;
696   };
697 
698   template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
699   void EmitPcRelativeLinkerPatches(const ArenaDeque<X86PcRelativePatchInfo>& infos,
700                                    ArenaVector<linker::LinkerPatch>* linker_patches);
701 
702   Register GetInvokeExtraParameter(HInvoke* invoke, Register temp);
703   Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
704 
705   // Labels for each block that will be compiled.
706   Label* block_labels_;  // Indexed by block id.
707   Label frame_entry_label_;
708   LocationsBuilderX86 location_builder_;
709   InstructionCodeGeneratorX86 instruction_visitor_;
710   ParallelMoveResolverX86 move_resolver_;
711   X86Assembler assembler_;
712 
713   // PC-relative method patch info for kBootImageLinkTimePcRelative.
714   ArenaDeque<X86PcRelativePatchInfo> boot_image_method_patches_;
715   // PC-relative method patch info for kBssEntry.
716   ArenaDeque<X86PcRelativePatchInfo> method_bss_entry_patches_;
717   // PC-relative type patch info for kBootImageLinkTimePcRelative.
718   ArenaDeque<X86PcRelativePatchInfo> boot_image_type_patches_;
719   // PC-relative type patch info for kBssEntry.
720   ArenaDeque<X86PcRelativePatchInfo> type_bss_entry_patches_;
721   // PC-relative public type patch info for kBssEntryPublic.
722   ArenaDeque<X86PcRelativePatchInfo> public_type_bss_entry_patches_;
723   // PC-relative package type patch info for kBssEntryPackage.
724   ArenaDeque<X86PcRelativePatchInfo> package_type_bss_entry_patches_;
725   // PC-relative String patch info for kBootImageLinkTimePcRelative.
726   ArenaDeque<X86PcRelativePatchInfo> boot_image_string_patches_;
727   // PC-relative String patch info for kBssEntry.
728   ArenaDeque<X86PcRelativePatchInfo> string_bss_entry_patches_;
729   // PC-relative method patch info for kBootImageLinkTimePcRelative+kCallCriticalNative.
730   ArenaDeque<X86PcRelativePatchInfo> boot_image_jni_entrypoint_patches_;
731   // PC-relative patch info for IntrinsicObjects for the boot image,
732   // and for method/type/string patches for kBootImageRelRo otherwise.
733   ArenaDeque<X86PcRelativePatchInfo> boot_image_other_patches_;
734 
735   // Patches for string root accesses in JIT compiled code.
736   ArenaDeque<PatchInfo<Label>> jit_string_patches_;
737   // Patches for class root accesses in JIT compiled code.
738   ArenaDeque<PatchInfo<Label>> jit_class_patches_;
739 
740   // Offset to the start of the constant area in the assembled code.
741   // Used for fixups to the constant area.
742   int32_t constant_area_start_;
743 
744   // Fixups for jump tables that need to be patched after the constant table is generated.
745   ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_;
746 
747   // Maps a HX86ComputeBaseMethodAddress instruction id, to its offset in the
748   // compiled code.
749   ArenaSafeMap<uint32_t, int32_t> method_address_offset_;
750 
751   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86);
752 };
753 
754 }  // namespace x86
755 }  // namespace art
756 
757 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_X86_H_
758