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 // Use a local definition to prevent copying mistakes.
31 static constexpr size_t kMips64WordSize = kMips64PointerSize;
32 
33 
34 // InvokeDexCallingConvention registers
35 
36 static constexpr GpuRegister kParameterCoreRegisters[] =
37     { A1, A2, A3, A4, A5, A6, A7 };
38 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
39 
40 static constexpr FpuRegister kParameterFpuRegisters[] =
41     { F13, F14, F15, F16, F17, F18, F19 };
42 static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
43 
44 
45 // InvokeRuntimeCallingConvention registers
46 
47 static constexpr GpuRegister kRuntimeParameterCoreRegisters[] =
48     { A0, A1, A2, A3, A4, A5, A6, A7 };
49 static constexpr size_t kRuntimeParameterCoreRegistersLength =
50     arraysize(kRuntimeParameterCoreRegisters);
51 
52 static constexpr FpuRegister kRuntimeParameterFpuRegisters[] =
53     { F12, F13, F14, F15, F16, F17, F18, F19 };
54 static constexpr size_t kRuntimeParameterFpuRegistersLength =
55     arraysize(kRuntimeParameterFpuRegisters);
56 
57 
58 static constexpr GpuRegister kCoreCalleeSaves[] =
59     { S0, S1, S2, S3, S4, S5, S6, S7, GP, S8, RA };  // TODO: review
60 static constexpr FpuRegister kFpuCalleeSaves[] =
61     { F24, F25, F26, F27, F28, F29, F30, F31 };
62 
63 
64 class CodeGeneratorMIPS64;
65 
66 class InvokeDexCallingConvention : public CallingConvention<GpuRegister, FpuRegister> {
67  public:
InvokeDexCallingConvention()68   InvokeDexCallingConvention()
69       : CallingConvention(kParameterCoreRegisters,
70                           kParameterCoreRegistersLength,
71                           kParameterFpuRegisters,
72                           kParameterFpuRegistersLength,
73                           kMips64PointerSize) {}
74 
75  private:
76   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
77 };
78 
79 class InvokeDexCallingConventionVisitorMIPS64 : public InvokeDexCallingConventionVisitor {
80  public:
InvokeDexCallingConventionVisitorMIPS64()81   InvokeDexCallingConventionVisitorMIPS64() {}
~InvokeDexCallingConventionVisitorMIPS64()82   virtual ~InvokeDexCallingConventionVisitorMIPS64() {}
83 
84   Location GetNextLocation(Primitive::Type type) OVERRIDE;
85   Location GetReturnLocation(Primitive::Type type) const;
86 
87  private:
88   InvokeDexCallingConvention calling_convention;
89 
90   DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS64);
91 };
92 
93 class InvokeRuntimeCallingConvention : public CallingConvention<GpuRegister, FpuRegister> {
94  public:
InvokeRuntimeCallingConvention()95   InvokeRuntimeCallingConvention()
96       : CallingConvention(kRuntimeParameterCoreRegisters,
97                           kRuntimeParameterCoreRegistersLength,
98                           kRuntimeParameterFpuRegisters,
99                           kRuntimeParameterFpuRegistersLength,
100                           kMips64PointerSize) {}
101 
102   Location GetReturnLocation(Primitive::Type return_type);
103 
104  private:
105   DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
106 };
107 
108 class ParallelMoveResolverMIPS64 : public ParallelMoveResolverWithSwap {
109  public:
ParallelMoveResolverMIPS64(ArenaAllocator * allocator,CodeGeneratorMIPS64 * codegen)110   ParallelMoveResolverMIPS64(ArenaAllocator* allocator, CodeGeneratorMIPS64* codegen)
111       : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
112 
113   void EmitMove(size_t index) OVERRIDE;
114   void EmitSwap(size_t index) OVERRIDE;
115   void SpillScratch(int reg) OVERRIDE;
116   void RestoreScratch(int reg) OVERRIDE;
117 
118   void Exchange(int index1, int index2, bool double_slot);
119 
120   Mips64Assembler* GetAssembler() const;
121 
122  private:
123   CodeGeneratorMIPS64* const codegen_;
124 
125   DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS64);
126 };
127 
128 class SlowPathCodeMIPS64 : public SlowPathCode {
129  public:
SlowPathCodeMIPS64()130   SlowPathCodeMIPS64() : entry_label_(), exit_label_() {}
131 
GetEntryLabel()132   Label* GetEntryLabel() { return &entry_label_; }
GetExitLabel()133   Label* GetExitLabel() { return &exit_label_; }
134 
135  private:
136   Label entry_label_;
137   Label exit_label_;
138 
139   DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS64);
140 };
141 
142 class LocationsBuilderMIPS64 : public HGraphVisitor {
143  public:
LocationsBuilderMIPS64(HGraph * graph,CodeGeneratorMIPS64 * codegen)144   LocationsBuilderMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen)
145       : HGraphVisitor(graph), codegen_(codegen) {}
146 
147 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
148   void Visit##name(H##name* instr);
149 
150   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
151 
152 #undef DECLARE_VISIT_INSTRUCTION
153 
154  private:
155   void HandleInvoke(HInvoke* invoke);
156   void HandleBinaryOp(HBinaryOperation* operation);
157   void HandleShift(HBinaryOperation* operation);
158   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
159   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
160 
161   InvokeDexCallingConventionVisitorMIPS64 parameter_visitor_;
162 
163   CodeGeneratorMIPS64* const codegen_;
164 
165   DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS64);
166 };
167 
168 class InstructionCodeGeneratorMIPS64 : public HGraphVisitor {
169  public:
170   InstructionCodeGeneratorMIPS64(HGraph* graph, CodeGeneratorMIPS64* codegen);
171 
172 #define DECLARE_VISIT_INSTRUCTION(name, super)     \
173   void Visit##name(H##name* instr);
174 
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)175   FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
176 
177 #undef DECLARE_VISIT_INSTRUCTION
178 
179   Mips64Assembler* GetAssembler() const { return assembler_; }
180 
181  private:
182   // Generate code for the given suspend check. If not null, `successor`
183   // is the block to branch to if the suspend check is not needed, and after
184   // the suspend call.
185   void GenerateClassInitializationCheck(SlowPathCodeMIPS64* slow_path, GpuRegister class_reg);
186   void GenerateMemoryBarrier(MemBarrierKind kind);
187   void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
188   void HandleBinaryOp(HBinaryOperation* operation);
189   void HandleShift(HBinaryOperation* operation);
190   void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
191   void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
192   void GenerateImplicitNullCheck(HNullCheck* instruction);
193   void GenerateExplicitNullCheck(HNullCheck* instruction);
194   void GenerateTestAndBranch(HInstruction* instruction,
195                              Label* true_target,
196                              Label* false_target,
197                              Label* always_true_target);
198 
199   Mips64Assembler* const assembler_;
200   CodeGeneratorMIPS64* const codegen_;
201 
202   DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS64);
203 };
204 
205 class CodeGeneratorMIPS64 : public CodeGenerator {
206  public:
207   CodeGeneratorMIPS64(HGraph* graph,
208                       const Mips64InstructionSetFeatures& isa_features,
209                       const CompilerOptions& compiler_options);
~CodeGeneratorMIPS64()210   virtual ~CodeGeneratorMIPS64() {}
211 
212   void GenerateFrameEntry() OVERRIDE;
213   void GenerateFrameExit() OVERRIDE;
214 
215   void Bind(HBasicBlock* block) OVERRIDE;
216 
217   void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
218 
GetWordSize()219   size_t GetWordSize() const OVERRIDE { return kMips64WordSize; }
220 
GetFloatingPointSpillSlotSize()221   size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64WordSize; }
222 
GetAddressOf(HBasicBlock * block)223   uintptr_t GetAddressOf(HBasicBlock* block) const OVERRIDE {
224     return GetLabelOf(block)->Position();
225   }
226 
GetLocationBuilder()227   HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
GetInstructionVisitor()228   HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
GetAssembler()229   Mips64Assembler* GetAssembler() OVERRIDE { return &assembler_; }
230 
231   void MarkGCCard(GpuRegister object, GpuRegister value);
232 
233   // Register allocation.
234 
235   void SetupBlockedRegisters(bool is_baseline) const OVERRIDE;
236   // AllocateFreeRegister() is only used when allocating registers locally
237   // during CompileBaseline().
238   Location AllocateFreeRegister(Primitive::Type type) const OVERRIDE;
239 
240   Location GetStackLocation(HLoadLocal* load) const OVERRIDE;
241 
242   size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
243   size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
244   size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
245   size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
246 
247   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
248   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
249 
GetInstructionSet()250   InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips64; }
251 
GetInstructionSetFeatures()252   const Mips64InstructionSetFeatures& GetInstructionSetFeatures() const {
253     return isa_features_;
254   }
255 
GetLabelOf(HBasicBlock * block)256   Label* GetLabelOf(HBasicBlock* block) const {
257     return CommonGetLabelOf<Label>(block_labels_.GetRawStorage(), block);
258   }
259 
Initialize()260   void Initialize() OVERRIDE {
261     block_labels_.SetSize(GetGraph()->GetBlocks().Size());
262   }
263 
264   void Finalize(CodeAllocator* allocator) OVERRIDE;
265 
266   // Code generation helpers.
267 
268   void MoveLocation(Location destination, Location source, Primitive::Type type);
269 
270   void SwapLocations(Location loc1, Location loc2, Primitive::Type type);
271 
272   void LoadCurrentMethod(GpuRegister current_method);
273 
274   // Generate code to invoke a runtime entry point.
275   void InvokeRuntime(int32_t offset,
276                      HInstruction* instruction,
277                      uint32_t dex_pc,
278                      SlowPathCode* slow_path);
279 
GetMoveResolver()280   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
281 
NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED)282   bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const { return false; }
283 
284   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, GpuRegister temp);
285 
286  private:
287   // Labels for each block that will be compiled.
288   GrowableArray<Label> block_labels_;
289   Label frame_entry_label_;
290   LocationsBuilderMIPS64 location_builder_;
291   InstructionCodeGeneratorMIPS64 instruction_visitor_;
292   ParallelMoveResolverMIPS64 move_resolver_;
293   Mips64Assembler assembler_;
294   const Mips64InstructionSetFeatures& isa_features_;
295 
296   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS64);
297 };
298 
299 }  // namespace mips64
300 }  // namespace art
301 
302 #endif  // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS64_H_
303