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/compiler_enums.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 };  // TODO: review
56 static constexpr FpuRegister kFpuCalleeSaves[] =
57     { F24, F25, F26, F27, F28, F29, F30, F31 };
58 
59 
60 class CodeGeneratorMIPS64;
61 
62 class InvokeDexCallingConvention : public CallingConvention<GpuRegister, FpuRegister> {
63  public:
InvokeDexCallingConvention()64   InvokeDexCallingConvention()
65       : CallingConvention(kParameterCoreRegisters,
66                           kParameterCoreRegistersLength,
67                           kParameterFpuRegisters,
68                           kParameterFpuRegistersLength,
69                           kMips64PointerSize) {}
70 
71  private:
72   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
73 };
74 
75 class InvokeDexCallingConventionVisitorMIPS64 : public InvokeDexCallingConventionVisitor {
76  public:
InvokeDexCallingConventionVisitorMIPS64()77   InvokeDexCallingConventionVisitorMIPS64() {}
~InvokeDexCallingConventionVisitorMIPS64()78   virtual ~InvokeDexCallingConventionVisitorMIPS64() {}
79 
80   Location GetNextLocation(Primitive::Type type) OVERRIDE;
81   Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
82   Location GetMethodLocation() const OVERRIDE;
83 
84  private:
85   InvokeDexCallingConvention calling_convention;
86 
87   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS64);
88 };
89 
90 class InvokeRuntimeCallingConvention : public CallingConvention<GpuRegister, FpuRegister> {
91  public:
InvokeRuntimeCallingConvention()92   InvokeRuntimeCallingConvention()
93       : CallingConvention(kRuntimeParameterCoreRegisters,
94                           kRuntimeParameterCoreRegistersLength,
95                           kRuntimeParameterFpuRegisters,
96                           kRuntimeParameterFpuRegistersLength,
97                           kMips64PointerSize) {}
98 
99   Location GetReturnLocation(Primitive::Type return_type);
100 
101  private:
102   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
103 };
104 
105 class FieldAccessCallingConventionMIPS64 : public FieldAccessCallingConvention {
106  public:
FieldAccessCallingConventionMIPS64()107   FieldAccessCallingConventionMIPS64() {}
108 
GetObjectLocation()109   Location GetObjectLocation() const OVERRIDE {
110     return Location::RegisterLocation(A1);
111   }
GetFieldIndexLocation()112   Location GetFieldIndexLocation() const OVERRIDE {
113     return Location::RegisterLocation(A0);
114   }
GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED)115   Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
116     return Location::RegisterLocation(V0);
117   }
GetSetValueLocation(Primitive::Type type,bool is_instance)118   Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
119     return Primitive::Is64BitType(type)
120         ? Location::RegisterLocation(A2)
121         : (is_instance
122             ? Location::RegisterLocation(A2)
123             : Location::RegisterLocation(A1));
124   }
GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED)125   Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
126     return Location::FpuRegisterLocation(F0);
127   }
128 
129  private:
130   DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionMIPS64);
131 };
132 
133 class ParallelMoveResolverMIPS64 : public ParallelMoveResolverWithSwap {
134  public:
ParallelMoveResolverMIPS64(ArenaAllocator * allocator,CodeGeneratorMIPS64 * codegen)135   ParallelMoveResolverMIPS64(ArenaAllocator* allocator, CodeGeneratorMIPS64* codegen)
136       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
137 
138   void EmitMove(size_t index) OVERRIDE;
139   void EmitSwap(size_t index) OVERRIDE;
140   void SpillScratch(int reg) OVERRIDE;
141   void RestoreScratch(int reg) OVERRIDE;
142 
143   void Exchange(int index1, int index2, bool double_slot);
144 
145   Mips64Assembler* GetAssembler() const;
146 
147  private:
148   CodeGeneratorMIPS64* const codegen_;
149 
150   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS64);
151 };
152 
153 class SlowPathCodeMIPS64 : public SlowPathCode {
154  public:
SlowPathCodeMIPS64(HInstruction * instruction)155   explicit SlowPathCodeMIPS64(HInstruction* instruction)
156       : SlowPathCode(instruction), entry_label_(), exit_label_() {}
157 
GetEntryLabel()158   Mips64Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()159   Mips64Label* GetExitLabel() { return &exit_label_; }
160 
161  private:
162   Mips64Label entry_label_;
163   Mips64Label exit_label_;
164 
165   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS64);
166 };
167 
168 class LocationsBuilderMIPS64 : public HGraphVisitor {
169  public:
LocationsBuilderMIPS64(HGraph * graph,CodeGeneratorMIPS64 * codegen)170   LocationsBuilderMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen)
171       : HGraphVisitor(graph), codegen_(codegen) {}
172 
173 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
174   void Visit##name(H##name* instr) OVERRIDE;
175 
176   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)177   FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)
178 
179 #undef DECLARE_VISIT_INSTRUCTION
180 
181   void VisitInstruction(HInstruction* instruction) OVERRIDE {
182     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
183                << " (id " << instruction->GetId() << ")";
184   }
185 
186  private:
187   void HandleInvoke(HInvoke* invoke);
188   void HandleBinaryOp(HBinaryOperation* operation);
189   void HandleCondition(HCondition* instruction);
190   void HandleShift(HBinaryOperation* operation);
191   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
192   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
193 
194   InvokeDexCallingConventionVisitorMIPS64 parameter_visitor_;
195 
196   CodeGeneratorMIPS64* const codegen_;
197 
198   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS64);
199 };
200 
201 class InstructionCodeGeneratorMIPS64 : public InstructionCodeGenerator {
202  public:
203   InstructionCodeGeneratorMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen);
204 
205 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
206   void Visit##name(H##name* instr) OVERRIDE;
207 
208   FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)209   FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(DECLARE_VISIT_INSTRUCTION)
210 
211 #undef DECLARE_VISIT_INSTRUCTION
212 
213   void VisitInstruction(HInstruction* instruction) OVERRIDE {
214     LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
215                << " (id " << instruction->GetId() << ")";
216   }
217 
GetAssembler()218   Mips64Assembler* GetAssembler() const { return assembler_; }
219 
220  private:
221   void GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path, GpuRegister class_reg);
222   void GenerateMemoryBarrier(MemBarrierKind kind);
223   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
224   void HandleBinaryOp(HBinaryOperation* operation);
225   void HandleCondition(HCondition* instruction);
226   void HandleShift(HBinaryOperation* operation);
227   void HandleFieldSet(HInstruction* instruction,
228                       const FieldInfo& field_info,
229                       bool value_can_be_null);
230   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
231   void GenerateTestAndBranch(HInstruction* instruction,
232                              size_t condition_input_index,
233                              Mips64Label* true_target,
234                              Mips64Label* false_target);
235   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
236   void DivRemByPowerOfTwo(HBinaryOperation* instruction);
237   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
238   void GenerateDivRemIntegral(HBinaryOperation* instruction);
239   void GenerateIntLongCompare(IfCondition cond, bool is64bit, LocationSummary* locations);
240   void GenerateIntLongCompareAndBranch(IfCondition cond,
241                                        bool is64bit,
242                                        LocationSummary* locations,
243                                        Mips64Label* label);
244   void GenerateFpCompareAndBranch(IfCondition cond,
245                                   bool gt_bias,
246                                   Primitive::Type type,
247                                   LocationSummary* locations,
248                                   Mips64Label* label);
249   void HandleGoto(HInstruction* got, HBasicBlock* successor);
250 
251   Mips64Assembler* const assembler_;
252   CodeGeneratorMIPS64* const codegen_;
253 
254   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS64);
255 };
256 
257 class CodeGeneratorMIPS64 : public CodeGenerator {
258  public:
259   CodeGeneratorMIPS64(HGraph* graph,
260                       const Mips64InstructionSetFeatures& isa_features,
261                       const CompilerOptions& compiler_options,
262                       OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorMIPS64()263   virtual ~CodeGeneratorMIPS64() {}
264 
265   void GenerateFrameEntry() OVERRIDE;
266   void GenerateFrameExit() OVERRIDE;
267 
268   void Bind(HBasicBlock* block) OVERRIDE;
269 
GetWordSize()270   size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; }
271 
GetFloatingPointSpillSlotSize()272   size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64DoublewordSize; }
273 
GetAddressOf(HBasicBlock * block)274   uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
275     return assembler_.GetLabelLocation(GetLabelOf(block));
276   }
277 
GetLocationBuilder()278   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
GetInstructionVisitor()279   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
GetAssembler()280   Mips64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
GetAssembler()281   const Mips64Assembler& GetAssembler() const OVERRIDE { return assembler_; }
282 
283   void MarkGCCard(GpuRegister object, GpuRegister value, bool value_can_be_null);
284 
285   // Register allocation.
286 
287   void SetupBlockedRegisters() const OVERRIDE;
288 
289   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
290   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
291   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
292   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
293 
294   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
295   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
296 
GetInstructionSet()297   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips64; }
298 
GetInstructionSetFeatures()299   const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const {
300     return isa_features_;
301   }
302 
GetLabelOf(HBasicBlock * block)303   Mips64Label* GetLabelOf(HBasicBlock* block) const {
304     return CommonGetLabelOf<Mips64Label>(block_labels_, block);
305   }
306 
Initialize()307   void Initialize() OVERRIDE {
308     block_labels_ = CommonInitializeLabels<Mips64Label>();
309   }
310 
311   void Finalize(CodeAllocator* allocator) OVERRIDE;
312 
313   // Code generation helpers.
314   void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
315 
316   void MoveConstant(Location destination, int32_t value) OVERRIDE;
317 
318   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
319 
320 
321   void SwapLocations(Location loc1, Location loc2, Primitive::Type type);
322 
323   // Generate code to invoke a runtime entry point.
324   void InvokeRuntime(QuickEntrypointEnum entrypoint,
325                      HInstruction* instruction,
326                      uint32_t dex_pc,
327                      SlowPathCode* slow_path) OVERRIDE;
328 
329   void InvokeRuntime(int32_t offset,
330                      HInstruction* instruction,
331                      uint32_t dex_pc,
332                      SlowPathCode* slow_path);
333 
GetMoveResolver()334   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
335 
NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED)336   bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const { return false; }
337 
338   // Check if the desired_string_load_kind is supported. If it is, return it,
339   // otherwise return a fall-back kind that should be used instead.
340   HLoadString::LoadKind GetSupportedLoadStringKind(
341       HLoadString::LoadKind desired_string_load_kind) OVERRIDE;
342 
343   // Check if the desired_dispatch_info is supported. If it is, return it,
344   // otherwise return a fall-back info that should be used instead.
345   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
346       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
347       MethodReference target_method) OVERRIDE;
348 
349   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE;
350   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
351 
MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,Primitive::Type type ATTRIBUTE_UNUSED)352   void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
353                               Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
354     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS64";
355   }
356 
357   void GenerateNop();
358   void GenerateImplicitNullCheck(HNullCheck* instruction);
359   void GenerateExplicitNullCheck(HNullCheck* instruction);
360 
361  private:
362   // Labels for each block that will be compiled.
363   Mips64Label* block_labels_;  // Indexed by block id.
364   Mips64Label frame_entry_label_;
365   LocationsBuilderMIPS64 location_builder_;
366   InstructionCodeGeneratorMIPS64 instruction_visitor_;
367   ParallelMoveResolverMIPS64 move_resolver_;
368   Mips64Assembler assembler_;
369   const Mips64InstructionSetFeatures& isa_features_;
370 
371   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS64);
372 };
373 
374 }  // namespace mips64
375 }  // namespace art
376 
377 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS64_H_
378