1 /*
2  * Copyright (C) 2015 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_MIPS64_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS64_H_
19 
20 #include "code_generator.h"
21 #include "dex/type_reference.h"
22 #include "driver/compiler_options.h"
23 #include "nodes.h"
24 #include "parallel_move_resolver.h"
25 #include "utils/mips64/assembler_mips64.h"
26 
27 namespace art {
28 namespace mips64 {
29 
30 // InvokeDexCallingConvention registers
31 
32 static constexpr GpuRegister kParameterCoreRegisters[] =
33     { A1, A2, A3, A4, A5, A6, A7 };
34 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
35 
36 static constexpr FpuRegister kParameterFpuRegisters[] =
37     { F13, F14, F15, F16, F17, F18, F19 };
38 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
39 
40 
41 // InvokeRuntimeCallingConvention registers
42 
43 static constexpr GpuRegister kRuntimeParameterCoreRegisters[] =
44     { A0, A1, A2, A3, A4, A5, A6, A7 };
45 static constexpr size_t kRuntimeParameterCoreRegistersLength =
46     arraysize(kRuntimeParameterCoreRegisters);
47 
48 static constexpr FpuRegister kRuntimeParameterFpuRegisters[] =
49     { F12, F13, F14, F15, F16, F17, F18, F19 };
50 static constexpr size_t kRuntimeParameterFpuRegistersLength =
51     arraysize(kRuntimeParameterFpuRegisters);
52 
53 
54 static constexpr GpuRegister kCoreCalleeSaves[] =
55     { S0, S1, S2, S3, S4, S5, S6, S7, GP, S8, RA };
56 static constexpr FpuRegister kFpuCalleeSaves[] =
57     { F24, F25, F26, F27, F28, F29, F30, F31 };
58 
59 
60 class CodeGeneratorMIPS64;
61 
62 VectorRegister VectorRegisterFrom(Location location);
63 
64 class InvokeDexCallingConvention : public CallingConvention<GpuRegister, FpuRegister> {
65  public:
InvokeDexCallingConvention()66   InvokeDexCallingConvention()
67       : CallingConvention(kParameterCoreRegisters,
68                           kParameterCoreRegistersLength,
69                           kParameterFpuRegisters,
70                           kParameterFpuRegistersLength,
71                           kMips64PointerSize) {}
72 
73  private:
74   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
75 };
76 
77 class InvokeDexCallingConventionVisitorMIPS64 : public InvokeDexCallingConventionVisitor {
78  public:
InvokeDexCallingConventionVisitorMIPS64()79   InvokeDexCallingConventionVisitorMIPS64() {}
~InvokeDexCallingConventionVisitorMIPS64()80   virtual ~InvokeDexCallingConventionVisitorMIPS64() {}
81 
82   Location GetNextLocation(DataType::Type type) OVERRIDE;
83   Location GetReturnLocation(DataType::Type type) const OVERRIDE;
84   Location GetMethodLocation() const OVERRIDE;
85 
86  private:
87   InvokeDexCallingConvention calling_convention;
88 
89   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS64);
90 };
91 
92 class InvokeRuntimeCallingConvention : public CallingConvention<GpuRegister, FpuRegister> {
93  public:
InvokeRuntimeCallingConvention()94   InvokeRuntimeCallingConvention()
95       : CallingConvention(kRuntimeParameterCoreRegisters,
96                           kRuntimeParameterCoreRegistersLength,
97                           kRuntimeParameterFpuRegisters,
98                           kRuntimeParameterFpuRegistersLength,
99                           kMips64PointerSize) {}
100 
101   Location GetReturnLocation(DataType::Type return_type);
102 
103  private:
104   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
105 };
106 
107 class FieldAccessCallingConventionMIPS64 : public FieldAccessCallingConvention {
108  public:
FieldAccessCallingConventionMIPS64()109   FieldAccessCallingConventionMIPS64() {}
110 
GetObjectLocation()111   Location GetObjectLocation() const OVERRIDE {
112     return Location::RegisterLocation(A1);
113   }
GetFieldIndexLocation()114   Location GetFieldIndexLocation() const OVERRIDE {
115     return Location::RegisterLocation(A0);
116   }
GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED)117   Location GetReturnLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
118     return Location::RegisterLocation(V0);
119   }
GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED,bool is_instance)120   Location GetSetValueLocation(DataType::Type type ATTRIBUTE_UNUSED,
121                                bool is_instance) const OVERRIDE {
122     return is_instance
123         ? Location::RegisterLocation(A2)
124         : Location::RegisterLocation(A1);
125   }
GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED)126   Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
127     return Location::FpuRegisterLocation(F0);
128   }
129 
130  private:
131   DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionMIPS64);
132 };
133 
134 class ParallelMoveResolverMIPS64 : public ParallelMoveResolverWithSwap {
135  public:
ParallelMoveResolverMIPS64(ArenaAllocator * allocator,CodeGeneratorMIPS64 * codegen)136   ParallelMoveResolverMIPS64(ArenaAllocator* allocator, CodeGeneratorMIPS64* codegen)
137       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
138 
139   void EmitMove(size_t index) OVERRIDE;
140   void EmitSwap(size_t index) OVERRIDE;
141   void SpillScratch(int reg) OVERRIDE;
142   void RestoreScratch(int reg) OVERRIDE;
143 
144   void Exchange(int index1, int index2, bool double_slot);
145   void ExchangeQuadSlots(int index1, int index2);
146 
147   Mips64Assembler* GetAssembler() const;
148 
149  private:
150   CodeGeneratorMIPS64* const codegen_;
151 
152   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS64);
153 };
154 
155 class SlowPathCodeMIPS64 : public SlowPathCode {
156  public:
SlowPathCodeMIPS64(HInstruction * instruction)157   explicit SlowPathCodeMIPS64(HInstruction* instruction)
158       : SlowPathCode(instruction), entry_label_(), exit_label_() {}
159 
GetEntryLabel()160   Mips64Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()161   Mips64Label* GetExitLabel() { return &exit_label_; }
162 
163  private:
164   Mips64Label entry_label_;
165   Mips64Label exit_label_;
166 
167   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS64);
168 };
169 
170 class LocationsBuilderMIPS64 : public HGraphVisitor {
171  public:
LocationsBuilderMIPS64(HGraph * graph,CodeGeneratorMIPS64 * codegen)172   LocationsBuilderMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen)
173       : HGraphVisitor(graph), codegen_(codegen) {}
174 
175 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
176   void Visit##name(H##name* instr) OVERRIDE;
177 
178   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)179   FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)
180 
181 #undef DECLARE_VISIT_INSTRUCTION
182 
183   void VisitInstruction(HInstruction* instruction) OVERRIDE {
184     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
185                << " (id " << instruction->GetId() << ")";
186   }
187 
188  private:
189   void HandleInvoke(HInvoke* invoke);
190   void HandleBinaryOp(HBinaryOperation* operation);
191   void HandleCondition(HCondition* instruction);
192   void HandleShift(HBinaryOperation* operation);
193   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
194   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
195   Location RegisterOrZeroConstant(HInstruction* instruction);
196   Location FpuRegisterOrConstantForStore(HInstruction* instruction);
197 
198   InvokeDexCallingConventionVisitorMIPS64 parameter_visitor_;
199 
200   CodeGeneratorMIPS64* const codegen_;
201 
202   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS64);
203 };
204 
205 class InstructionCodeGeneratorMIPS64 : public InstructionCodeGenerator {
206  public:
207   InstructionCodeGeneratorMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen);
208 
209 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
210   void Visit##name(H##name* instr) OVERRIDE;
211 
212   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)213   FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)
214 
215 #undef DECLARE_VISIT_INSTRUCTION
216 
217   void VisitInstruction(HInstruction* instruction) OVERRIDE {
218     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
219                << " (id " << instruction->GetId() << ")";
220   }
221 
GetAssembler()222   Mips64Assembler* GetAssembler() const { return assembler_; }
223 
224   // Compare-and-jump packed switch generates approx. 3 + 2.5 * N 32-bit
225   // instructions for N cases.
226   // Table-based packed switch generates approx. 11 32-bit instructions
227   // and N 32-bit data words for N cases.
228   // At N = 6 they come out as 18 and 17 32-bit words respectively.
229   // We switch to the table-based method starting with 7 cases.
230   static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6;
231 
232   void GenerateMemoryBarrier(MemBarrierKind kind);
233 
234  private:
235   void GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path, GpuRegister class_reg);
236   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
237   void HandleBinaryOp(HBinaryOperation* operation);
238   void HandleCondition(HCondition* instruction);
239   void HandleShift(HBinaryOperation* operation);
240   void HandleFieldSet(HInstruction* instruction,
241                       const FieldInfo& field_info,
242                       bool value_can_be_null);
243   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
244 
245   // Generate a heap reference load using one register `out`:
246   //
247   //   out <- *(out + offset)
248   //
249   // while honoring heap poisoning and/or read barriers (if any).
250   //
251   // Location `maybe_temp` is used when generating a read barrier and
252   // shall be a register in that case; it may be an invalid location
253   // otherwise.
254   void GenerateReferenceLoadOneRegister(HInstruction* instruction,
255                                         Location out,
256                                         uint32_t offset,
257                                         Location maybe_temp,
258                                         ReadBarrierOption read_barrier_option);
259   // Generate a heap reference load using two different registers
260   // `out` and `obj`:
261   //
262   //   out <- *(obj + offset)
263   //
264   // while honoring heap poisoning and/or read barriers (if any).
265   //
266   // Location `maybe_temp` is used when generating a Baker's (fast
267   // path) read barrier and shall be a register in that case; it may
268   // be an invalid location otherwise.
269   void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
270                                          Location out,
271                                          Location obj,
272                                          uint32_t offset,
273                                          Location maybe_temp,
274                                          ReadBarrierOption read_barrier_option);
275 
276   // Generate a GC root reference load:
277   //
278   //   root <- *(obj + offset)
279   //
280   // while honoring read barriers (if any).
281   void GenerateGcRootFieldLoad(HInstruction* instruction,
282                                Location root,
283                                GpuRegister obj,
284                                uint32_t offset,
285                                ReadBarrierOption read_barrier_option,
286                                Mips64Label* label_low = nullptr);
287 
288   void GenerateTestAndBranch(HInstruction* instruction,
289                              size_t condition_input_index,
290                              Mips64Label* true_target,
291                              Mips64Label* false_target);
292   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
293   void DivRemByPowerOfTwo(HBinaryOperation* instruction);
294   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
295   void GenerateDivRemIntegral(HBinaryOperation* instruction);
296   void GenerateIntLongCompare(IfCondition cond, bool is64bit, LocationSummary* locations);
297   // When the function returns `false` it means that the condition holds if `dst` is non-zero
298   // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero
299   // `dst` are exchanged.
300   bool MaterializeIntLongCompare(IfCondition cond,
301                                  bool is64bit,
302                                  LocationSummary* input_locations,
303                                  GpuRegister dst);
304   void GenerateIntLongCompareAndBranch(IfCondition cond,
305                                        bool is64bit,
306                                        LocationSummary* locations,
307                                        Mips64Label* label);
308   void GenerateFpCompare(IfCondition cond,
309                          bool gt_bias,
310                          DataType::Type type,
311                          LocationSummary* locations);
312   // When the function returns `false` it means that the condition holds if `dst` is non-zero
313   // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero
314   // `dst` are exchanged.
315   bool MaterializeFpCompare(IfCondition cond,
316                             bool gt_bias,
317                             DataType::Type type,
318                             LocationSummary* input_locations,
319                             FpuRegister dst);
320   void GenerateFpCompareAndBranch(IfCondition cond,
321                                   bool gt_bias,
322                                   DataType::Type type,
323                                   LocationSummary* locations,
324                                   Mips64Label* label);
325   void HandleGoto(HInstruction* got, HBasicBlock* successor);
326   void GenPackedSwitchWithCompares(GpuRegister value_reg,
327                                    int32_t lower_bound,
328                                    uint32_t num_entries,
329                                    HBasicBlock* switch_block,
330                                    HBasicBlock* default_block);
331   void GenTableBasedPackedSwitch(GpuRegister value_reg,
332                                  int32_t lower_bound,
333                                  uint32_t num_entries,
334                                  HBasicBlock* switch_block,
335                                  HBasicBlock* default_block);
336   int32_t VecAddress(LocationSummary* locations,
337                      size_t size,
338                      /* out */ GpuRegister* adjusted_base);
339   void GenConditionalMove(HSelect* select);
340 
341   Mips64Assembler* const assembler_;
342   CodeGeneratorMIPS64* const codegen_;
343 
344   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS64);
345 };
346 
347 class CodeGeneratorMIPS64 : public CodeGenerator {
348  public:
349   CodeGeneratorMIPS64(HGraph* graph,
350                       const Mips64InstructionSetFeatures& isa_features,
351                       const CompilerOptions& compiler_options,
352                       OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorMIPS64()353   virtual ~CodeGeneratorMIPS64() {}
354 
355   void GenerateFrameEntry() OVERRIDE;
356   void GenerateFrameExit() OVERRIDE;
357 
358   void Bind(HBasicBlock* block) OVERRIDE;
359 
GetWordSize()360   size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; }
361 
GetFloatingPointSpillSlotSize()362   size_t GetFloatingPointSpillSlotSize() const OVERRIDE {
363     return GetGraph()->HasSIMD()
364         ? 2 * kMips64DoublewordSize   // 16 bytes for each spill.
365         : 1 * kMips64DoublewordSize;  //  8 bytes for each spill.
366   }
367 
GetAddressOf(HBasicBlock * block)368   uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
369     return assembler_.GetLabelLocation(GetLabelOf(block));
370   }
371 
GetLocationBuilder()372   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
GetInstructionVisitor()373   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
GetAssembler()374   Mips64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
GetAssembler()375   const Mips64Assembler& GetAssembler() const OVERRIDE { return assembler_; }
376 
377   // Emit linker patches.
378   void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) OVERRIDE;
379   void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
380 
381   // Fast path implementation of ReadBarrier::Barrier for a heap
382   // reference field load when Baker's read barriers are used.
383   void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
384                                              Location ref,
385                                              GpuRegister obj,
386                                              uint32_t offset,
387                                              Location temp,
388                                              bool needs_null_check);
389   // Fast path implementation of ReadBarrier::Barrier for a heap
390   // reference array load when Baker's read barriers are used.
391   void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
392                                              Location ref,
393                                              GpuRegister obj,
394                                              uint32_t data_offset,
395                                              Location index,
396                                              Location temp,
397                                              bool needs_null_check);
398 
399   // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier,
400   // GenerateArrayLoadWithBakerReadBarrier and some intrinsics.
401   //
402   // Load the object reference located at the address
403   // `obj + offset + (index << scale_factor)`, held by object `obj`, into
404   // `ref`, and mark it if needed.
405   //
406   // If `always_update_field` is true, the value of the reference is
407   // atomically updated in the holder (`obj`).
408   void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
409                                                  Location ref,
410                                                  GpuRegister obj,
411                                                  uint32_t offset,
412                                                  Location index,
413                                                  ScaleFactor scale_factor,
414                                                  Location temp,
415                                                  bool needs_null_check,
416                                                  bool always_update_field = false);
417 
418   // Generate a read barrier for a heap reference within `instruction`
419   // using a slow path.
420   //
421   // A read barrier for an object reference read from the heap is
422   // implemented as a call to the artReadBarrierSlow runtime entry
423   // point, which is passed the values in locations `ref`, `obj`, and
424   // `offset`:
425   //
426   //   mirror::Object* artReadBarrierSlow(mirror::Object* ref,
427   //                                      mirror::Object* obj,
428   //                                      uint32_t offset);
429   //
430   // The `out` location contains the value returned by
431   // artReadBarrierSlow.
432   //
433   // When `index` is provided (i.e. for array accesses), the offset
434   // value passed to artReadBarrierSlow is adjusted to take `index`
435   // into account.
436   void GenerateReadBarrierSlow(HInstruction* instruction,
437                                Location out,
438                                Location ref,
439                                Location obj,
440                                uint32_t offset,
441                                Location index = Location::NoLocation());
442 
443   // If read barriers are enabled, generate a read barrier for a heap
444   // reference using a slow path. If heap poisoning is enabled, also
445   // unpoison the reference in `out`.
446   void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
447                                     Location out,
448                                     Location ref,
449                                     Location obj,
450                                     uint32_t offset,
451                                     Location index = Location::NoLocation());
452 
453   // Generate a read barrier for a GC root within `instruction` using
454   // a slow path.
455   //
456   // A read barrier for an object reference GC root is implemented as
457   // a call to the artReadBarrierForRootSlow runtime entry point,
458   // which is passed the value in location `root`:
459   //
460   //   mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
461   //
462   // The `out` location contains the value returned by
463   // artReadBarrierForRootSlow.
464   void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
465 
466   void MarkGCCard(GpuRegister object, GpuRegister value, bool value_can_be_null);
467 
468   // Register allocation.
469 
470   void SetupBlockedRegisters() const OVERRIDE;
471 
472   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
473   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
474   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
475   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
476 
477   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
478   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
479 
GetInstructionSet()480   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips64; }
481 
GetInstructionSetFeatures()482   const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const {
483     return isa_features_;
484   }
485 
GetLabelOf(HBasicBlock * block)486   Mips64Label* GetLabelOf(HBasicBlock* block) const {
487     return CommonGetLabelOf<Mips64Label>(block_labels_, block);
488   }
489 
Initialize()490   void Initialize() OVERRIDE {
491     block_labels_ = CommonInitializeLabels<Mips64Label>();
492   }
493 
494   // We prefer aligned loads and stores (less code), so spill and restore registers in slow paths
495   // at aligned locations.
GetPreferredSlotsAlignment()496   uint32_t GetPreferredSlotsAlignment() const OVERRIDE { return kMips64DoublewordSize; }
497 
498   void Finalize(CodeAllocator* allocator) OVERRIDE;
499 
500   // Code generation helpers.
501   void MoveLocation(Location dst, Location src, DataType::Type dst_type) OVERRIDE;
502 
503   void MoveConstant(Location destination, int32_t value) OVERRIDE;
504 
505   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
506 
507 
508   void SwapLocations(Location loc1, Location loc2, DataType::Type type);
509 
510   // Generate code to invoke a runtime entry point.
511   void InvokeRuntime(QuickEntrypointEnum entrypoint,
512                      HInstruction* instruction,
513                      uint32_t dex_pc,
514                      SlowPathCode* slow_path = nullptr) OVERRIDE;
515 
516   // Generate code to invoke a runtime entry point, but do not record
517   // PC-related information in a stack map.
518   void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
519                                            HInstruction* instruction,
520                                            SlowPathCode* slow_path);
521 
522   void GenerateInvokeRuntime(int32_t entry_point_offset);
523 
GetMoveResolver()524   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
525 
NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED)526   bool NeedsTwoRegisters(DataType::Type type ATTRIBUTE_UNUSED) const OVERRIDE { return false; }
527 
528   // Check if the desired_string_load_kind is supported. If it is, return it,
529   // otherwise return a fall-back kind that should be used instead.
530   HLoadString::LoadKind GetSupportedLoadStringKind(
531       HLoadString::LoadKind desired_string_load_kind) OVERRIDE;
532 
533   // Check if the desired_class_load_kind is supported. If it is, return it,
534   // otherwise return a fall-back kind that should be used instead.
535   HLoadClass::LoadKind GetSupportedLoadClassKind(
536       HLoadClass::LoadKind desired_class_load_kind) OVERRIDE;
537 
538   // Check if the desired_dispatch_info is supported. If it is, return it,
539   // otherwise return a fall-back info that should be used instead.
540   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
541       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
542       HInvokeStaticOrDirect* invoke) OVERRIDE;
543 
544   void GenerateStaticOrDirectCall(
545       HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
546   void GenerateVirtualCall(
547       HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE;
548 
MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,DataType::Type type ATTRIBUTE_UNUSED)549   void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
550                               DataType::Type type ATTRIBUTE_UNUSED) OVERRIDE {
551     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS64";
552   }
553 
554   void GenerateNop() OVERRIDE;
555   void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
556   void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
557 
558   // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
559   // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
560   //
561   // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
562   // two patches/infos. There can be more than two patches/infos if the instruction supplying
563   // the high half is shared with e.g. a slow path, while the low half is supplied by separate
564   // instructions, e.g.:
565   //     auipc r1, high       // patch
566   //     lwu   r2, low(r1)    // patch
567   //     beqzc r2, slow_path
568   //   back:
569   //     ...
570   //   slow_path:
571   //     ...
572   //     sw    r2, low(r1)    // patch
573   //     bc    back
574   struct PcRelativePatchInfo : PatchInfo<Mips64Label> {
PcRelativePatchInfoPcRelativePatchInfo575     PcRelativePatchInfo(const DexFile* dex_file,
576                         uint32_t off_or_idx,
577                         const PcRelativePatchInfo* info_high)
578         : PatchInfo<Mips64Label>(dex_file, off_or_idx),
579           patch_info_high(info_high) { }
580 
581     // Pointer to the info for the high half patch or nullptr if this is the high half patch info.
582     const PcRelativePatchInfo* patch_info_high;
583 
584    private:
585     PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete;
586     DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
587   };
588 
589   PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method,
590                                                const PcRelativePatchInfo* info_high = nullptr);
591   PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
592                                               const PcRelativePatchInfo* info_high = nullptr);
593   PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file,
594                                              dex::TypeIndex type_index,
595                                              const PcRelativePatchInfo* info_high = nullptr);
596   PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
597                                             dex::TypeIndex type_index,
598                                             const PcRelativePatchInfo* info_high = nullptr);
599   PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file,
600                                                dex::StringIndex string_index,
601                                                const PcRelativePatchInfo* info_high = nullptr);
602   PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file,
603                                               dex::StringIndex string_index,
604                                               const PcRelativePatchInfo* info_high = nullptr);
605   Literal* DeduplicateBootImageAddressLiteral(uint64_t address);
606 
607   void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
608                                             GpuRegister out,
609                                             PcRelativePatchInfo* info_low = nullptr);
610 
611   void PatchJitRootUse(uint8_t* code,
612                        const uint8_t* roots_data,
613                        const Literal* literal,
614                        uint64_t index_in_table) const;
615   Literal* DeduplicateJitStringLiteral(const DexFile& dex_file,
616                                        dex::StringIndex string_index,
617                                        Handle<mirror::String> handle);
618   Literal* DeduplicateJitClassLiteral(const DexFile& dex_file,
619                                       dex::TypeIndex type_index,
620                                       Handle<mirror::Class> handle);
621 
622  private:
623   using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>;
624   using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, Literal*>;
625   using StringToLiteralMap = ArenaSafeMap<StringReference,
626                                           Literal*,
627                                           StringReferenceValueComparator>;
628   using TypeToLiteralMap = ArenaSafeMap<TypeReference,
629                                         Literal*,
630                                         TypeReferenceValueComparator>;
631 
632   Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
633   Literal* DeduplicateUint64Literal(uint64_t value);
634 
635   PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file,
636                                           uint32_t offset_or_index,
637                                           const PcRelativePatchInfo* info_high,
638                                           ArenaDeque<PcRelativePatchInfo>* patches);
639 
640   template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
641   void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
642                                    ArenaVector<linker::LinkerPatch>* linker_patches);
643 
644   // Labels for each block that will be compiled.
645   Mips64Label* block_labels_;  // Indexed by block id.
646   Mips64Label frame_entry_label_;
647   LocationsBuilderMIPS64 location_builder_;
648   InstructionCodeGeneratorMIPS64 instruction_visitor_;
649   ParallelMoveResolverMIPS64 move_resolver_;
650   Mips64Assembler assembler_;
651   const Mips64InstructionSetFeatures& isa_features_;
652 
653   // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
654   Uint32ToLiteralMap uint32_literals_;
655   // Deduplication map for 64-bit literals, used for non-patchable method address or method code
656   // address.
657   Uint64ToLiteralMap uint64_literals_;
658   // PC-relative method patch info for kBootImageLinkTimePcRelative.
659   ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
660   // PC-relative method patch info for kBssEntry.
661   ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
662   // PC-relative type patch info for kBootImageLinkTimePcRelative.
663   ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
664   // PC-relative type patch info for kBssEntry.
665   ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
666   // PC-relative String patch info; type depends on configuration (intern table or boot image PIC).
667   ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
668   // PC-relative type patch info for kBssEntry.
669   ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
670 
671   // Patches for string root accesses in JIT compiled code.
672   StringToLiteralMap jit_string_patches_;
673   // Patches for class root accesses in JIT compiled code.
674   TypeToLiteralMap jit_class_patches_;
675 
676   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS64);
677 };
678 
679 }  // namespace mips64
680 }  // namespace art
681 
682 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS64_H_
683