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_MIPS_H_
18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_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/mips/assembler_mips.h"
26 
27 namespace art {
28 namespace mips {
29 
30 // InvokeDexCallingConvention registers
31 
32 static constexpr Register kParameterCoreRegisters[] =
33     { A1, A2, A3 };
34 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
35 
36 static constexpr FRegister kParameterFpuRegisters[] =
37     { F12, F14 };
38 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
39 
40 
41 // InvokeRuntimeCallingConvention registers
42 
43 static constexpr Register kRuntimeParameterCoreRegisters[] =
44     { A0, A1, A2, A3 };
45 static constexpr size_t kRuntimeParameterCoreRegistersLength =
46     arraysize(kRuntimeParameterCoreRegisters);
47 
48 static constexpr FRegister kRuntimeParameterFpuRegisters[] =
49     { F12, F14};
50 static constexpr size_t kRuntimeParameterFpuRegistersLength =
51     arraysize(kRuntimeParameterFpuRegisters);
52 
53 
54 static constexpr Register kCoreCalleeSaves[] =
55     { S0, S1, S2, S3, S4, S5, S6, S7, FP, RA };
56 static constexpr FRegister kFpuCalleeSaves[] =
57     { F20, F22, F24, F26, F28, F30 };
58 
59 
60 class CodeGeneratorMIPS;
61 
62 class InvokeDexCallingConvention : public CallingConvention<Register, FRegister> {
63  public:
InvokeDexCallingConvention()64   InvokeDexCallingConvention()
65       : CallingConvention(kParameterCoreRegisters,
66                           kParameterCoreRegistersLength,
67                           kParameterFpuRegisters,
68                           kParameterFpuRegistersLength,
69                           kMipsPointerSize) {}
70 
71  private:
72   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
73 };
74 
75 class InvokeDexCallingConventionVisitorMIPS : public InvokeDexCallingConventionVisitor {
76  public:
InvokeDexCallingConventionVisitorMIPS()77   InvokeDexCallingConventionVisitorMIPS() {}
~InvokeDexCallingConventionVisitorMIPS()78   virtual ~InvokeDexCallingConventionVisitorMIPS() {}
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(InvokeDexCallingConventionVisitorMIPS);
88 };
89 
90 class InvokeRuntimeCallingConvention : public CallingConvention<Register, FRegister> {
91  public:
InvokeRuntimeCallingConvention()92   InvokeRuntimeCallingConvention()
93       : CallingConvention(kRuntimeParameterCoreRegisters,
94                           kRuntimeParameterCoreRegistersLength,
95                           kRuntimeParameterFpuRegisters,
96                           kRuntimeParameterFpuRegistersLength,
97                           kMipsPointerSize) {}
98 
99   Location GetReturnLocation(Primitive::Type return_type);
100 
101  private:
102   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
103 };
104 
105 class FieldAccessCallingConventionMIPS : public FieldAccessCallingConvention {
106  public:
FieldAccessCallingConventionMIPS()107   FieldAccessCallingConventionMIPS() {}
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)115   Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
116     return Primitive::Is64BitType(type)
117         ? Location::RegisterPairLocation(V0, V1)
118         : Location::RegisterLocation(V0);
119   }
GetSetValueLocation(Primitive::Type type,bool is_instance)120   Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
121     return Primitive::Is64BitType(type)
122         ? Location::RegisterPairLocation(A2, A3)
123         : (is_instance ? Location::RegisterLocation(A2) : 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(FieldAccessCallingConventionMIPS);
131 };
132 
133 class ParallelMoveResolverMIPS : public ParallelMoveResolverWithSwap {
134  public:
ParallelMoveResolverMIPS(ArenaAllocator * allocator,CodeGeneratorMIPS * codegen)135   ParallelMoveResolverMIPS(ArenaAllocator* allocator, CodeGeneratorMIPS* 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   MipsAssembler* GetAssembler() const;
146 
147  private:
148   CodeGeneratorMIPS* const codegen_;
149 
150   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS);
151 };
152 
153 class SlowPathCodeMIPS : public SlowPathCode {
154  public:
SlowPathCodeMIPS(HInstruction * instruction)155   explicit SlowPathCodeMIPS(HInstruction* instruction)
156       : SlowPathCode(instruction), entry_label_(), exit_label_() {}
157 
GetEntryLabel()158   MipsLabel* GetEntryLabel() { return &entry_label_; }
GetExitLabel()159   MipsLabel* GetExitLabel() { return &exit_label_; }
160 
161  private:
162   MipsLabel entry_label_;
163   MipsLabel exit_label_;
164 
165   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS);
166 };
167 
168 class LocationsBuilderMIPS : public HGraphVisitor {
169  public:
LocationsBuilderMIPS(HGraph * graph,CodeGeneratorMIPS * codegen)170   LocationsBuilderMIPS(HGraph* graph, CodeGeneratorMIPS* 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_MIPS(DECLARE_VISIT_INSTRUCTION)177   FOR_EACH_CONCRETE_INSTRUCTION_MIPS(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   InvokeDexCallingConventionVisitorMIPS parameter_visitor_;
195 
196   CodeGeneratorMIPS* const codegen_;
197 
198   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS);
199 };
200 
201 class InstructionCodeGeneratorMIPS : public InstructionCodeGenerator {
202  public:
203   InstructionCodeGeneratorMIPS(HGraph* graph, CodeGeneratorMIPS* 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_MIPS(DECLARE_VISIT_INSTRUCTION)209   FOR_EACH_CONCRETE_INSTRUCTION_MIPS(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   MipsAssembler* GetAssembler() const { return assembler_; }
219 
220  private:
221   void GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register 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, const FieldInfo& field_info, uint32_t dex_pc);
228   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
229   void GenerateIntCompare(IfCondition cond, LocationSummary* locations);
230   void GenerateIntCompareAndBranch(IfCondition cond,
231                                    LocationSummary* locations,
232                                    MipsLabel* label);
233   void GenerateLongCompareAndBranch(IfCondition cond,
234                                     LocationSummary* locations,
235                                     MipsLabel* label);
236   void GenerateFpCompareAndBranch(IfCondition cond,
237                                   bool gt_bias,
238                                   Primitive::Type type,
239                                   LocationSummary* locations,
240                                   MipsLabel* label);
241   void GenerateTestAndBranch(HInstruction* instruction,
242                              size_t condition_input_index,
243                              MipsLabel* true_target,
244                              MipsLabel* false_target);
245   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
246   void DivRemByPowerOfTwo(HBinaryOperation* instruction);
247   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
248   void GenerateDivRemIntegral(HBinaryOperation* instruction);
249   void HandleGoto(HInstruction* got, HBasicBlock* successor);
250 
251   MipsAssembler* const assembler_;
252   CodeGeneratorMIPS* const codegen_;
253 
254   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS);
255 };
256 
257 class CodeGeneratorMIPS : public CodeGenerator {
258  public:
259   CodeGeneratorMIPS(HGraph* graph,
260                     const MipsInstructionSetFeatures& isa_features,
261                     const CompilerOptions& compiler_options,
262                     OptimizingCompilerStats* stats = nullptr);
~CodeGeneratorMIPS()263   virtual ~CodeGeneratorMIPS() {}
264 
265   void GenerateFrameEntry() OVERRIDE;
266   void GenerateFrameExit() OVERRIDE;
267 
268   void Bind(HBasicBlock* block) OVERRIDE;
269 
270   void Move32(Location destination, Location source);
271   void Move64(Location destination, Location source);
272   void MoveConstant(Location location, HConstant* c);
273 
GetWordSize()274   size_t GetWordSize() const OVERRIDE { return kMipsWordSize; }
275 
GetFloatingPointSpillSlotSize()276   size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMipsDoublewordSize; }
277 
GetAddressOf(HBasicBlock * block)278   uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
279     return assembler_.GetLabelLocation(GetLabelOf(block));
280   }
281 
GetLocationBuilder()282   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
GetInstructionVisitor()283   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
GetAssembler()284   MipsAssembler* GetAssembler() OVERRIDE { return &assembler_; }
GetAssembler()285   const MipsAssembler& GetAssembler() const OVERRIDE { return assembler_; }
286 
287   void MarkGCCard(Register object, Register value);
288 
289   // Register allocation.
290 
291   void SetupBlockedRegisters() const OVERRIDE;
292 
293   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
294   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
295   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
296   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
297 
298   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
299   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
300 
301   // Blocks all register pairs made out of blocked core registers.
302   void UpdateBlockedPairRegisters() const;
303 
GetInstructionSet()304   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; }
305 
GetInstructionSetFeatures()306   const MipsInstructionSetFeatures& GetInstructionSetFeatures() const {
307     return isa_features_;
308   }
309 
GetLabelOf(HBasicBlock * block)310   MipsLabel* GetLabelOf(HBasicBlock* block) const {
311     return CommonGetLabelOf<MipsLabel>(block_labels_, block);
312   }
313 
Initialize()314   void Initialize() OVERRIDE {
315     block_labels_ = CommonInitializeLabels<MipsLabel>();
316   }
317 
318   void Finalize(CodeAllocator* allocator) OVERRIDE;
319 
320   // Code generation helpers.
321 
322   void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
323 
324   void MoveConstant(Location destination, int32_t value);
325 
326   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
327 
328   // Generate code to invoke a runtime entry point.
329   void InvokeRuntime(QuickEntrypointEnum entrypoint,
330                      HInstruction* instruction,
331                      uint32_t dex_pc,
332                      SlowPathCode* slow_path) OVERRIDE;
333 
334   void InvokeRuntime(int32_t offset,
335                      HInstruction* instruction,
336                      uint32_t dex_pc,
337                      SlowPathCode* slow_path,
338                      bool is_direct_entrypoint);
339 
GetMoveResolver()340   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
341 
NeedsTwoRegisters(Primitive::Type type)342   bool NeedsTwoRegisters(Primitive::Type type) const {
343     return type == Primitive::kPrimLong;
344   }
345 
346   // Check if the desired_string_load_kind is supported. If it is, return it,
347   // otherwise return a fall-back kind that should be used instead.
348   HLoadString::LoadKind GetSupportedLoadStringKind(
349       HLoadString::LoadKind desired_string_load_kind) OVERRIDE;
350 
351   // Check if the desired_dispatch_info is supported. If it is, return it,
352   // otherwise return a fall-back info that should be used instead.
353   HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
354       const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
355       MethodReference target_method) OVERRIDE;
356 
357   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
358   void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
359 
MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,Primitive::Type type ATTRIBUTE_UNUSED)360   void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
361                               Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
362     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
363   }
364 
365   void GenerateNop();
366   void GenerateImplicitNullCheck(HNullCheck* instruction);
367   void GenerateExplicitNullCheck(HNullCheck* instruction);
368 
369  private:
370   // Labels for each block that will be compiled.
371   MipsLabel* block_labels_;
372   MipsLabel frame_entry_label_;
373   LocationsBuilderMIPS location_builder_;
374   InstructionCodeGeneratorMIPS instruction_visitor_;
375   ParallelMoveResolverMIPS move_resolver_;
376   MipsAssembler assembler_;
377   const MipsInstructionSetFeatures& isa_features_;
378 
379   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS);
380 };
381 
382 }  // namespace mips
383 }  // namespace art
384 
385 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_
386