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
27namespace art {
28namespace mips {
29
30// InvokeDexCallingConvention registers
31
32static constexpr Register kParameterCoreRegisters[] =
33    { A1, A2, A3 };
34static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
35
36static constexpr FRegister kParameterFpuRegisters[] =
37    { F12, F14 };
38static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
39
40
41// InvokeRuntimeCallingConvention registers
42
43static constexpr Register kRuntimeParameterCoreRegisters[] =
44    { A0, A1, A2, A3 };
45static constexpr size_t kRuntimeParameterCoreRegistersLength =
46    arraysize(kRuntimeParameterCoreRegisters);
47
48static constexpr FRegister kRuntimeParameterFpuRegisters[] =
49    { F12, F14};
50static constexpr size_t kRuntimeParameterFpuRegistersLength =
51    arraysize(kRuntimeParameterFpuRegisters);
52
53
54static constexpr Register kCoreCalleeSaves[] =
55    { S0, S1, S2, S3, S4, S5, S6, S7, FP, RA };
56static constexpr FRegister kFpuCalleeSaves[] =
57    { F20, F22, F24, F26, F28, F30 };
58
59
60class CodeGeneratorMIPS;
61
62class InvokeDexCallingConvention : public CallingConvention<Register, FRegister> {
63 public:
64  InvokeDexCallingConvention()
65      : CallingConvention(kParameterCoreRegisters,
66                          kParameterCoreRegistersLength,
67                          kParameterFpuRegisters,
68                          kParameterFpuRegistersLength,
69                          kMipsPointerSize) {}
70
71 private:
72  DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
73};
74
75class InvokeDexCallingConventionVisitorMIPS : public InvokeDexCallingConventionVisitor {
76 public:
77  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
90class InvokeRuntimeCallingConvention : public CallingConvention<Register, FRegister> {
91 public:
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
105class FieldAccessCallingConventionMIPS : public FieldAccessCallingConvention {
106 public:
107  FieldAccessCallingConventionMIPS() {}
108
109  Location GetObjectLocation() const OVERRIDE {
110    return Location::RegisterLocation(A1);
111  }
112  Location GetFieldIndexLocation() const OVERRIDE {
113    return Location::RegisterLocation(A0);
114  }
115  Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
116    return Primitive::Is64BitType(type)
117        ? Location::RegisterPairLocation(V0, V1)
118        : Location::RegisterLocation(V0);
119  }
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  }
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
133class ParallelMoveResolverMIPS : public ParallelMoveResolverWithSwap {
134 public:
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
153class SlowPathCodeMIPS : public SlowPathCode {
154 public:
155  explicit SlowPathCodeMIPS(HInstruction* instruction)
156      : SlowPathCode(instruction), entry_label_(), exit_label_() {}
157
158  MipsLabel* GetEntryLabel() { return &entry_label_; }
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
168class LocationsBuilderMIPS : public HGraphVisitor {
169 public:
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)
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
201class 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)
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
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
257class CodeGeneratorMIPS : public CodeGenerator {
258 public:
259  CodeGeneratorMIPS(HGraph* graph,
260                    const MipsInstructionSetFeatures& isa_features,
261                    const CompilerOptions& compiler_options,
262                    OptimizingCompilerStats* stats = nullptr);
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
274  size_t GetWordSize() const OVERRIDE { return kMipsWordSize; }
275
276  size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMipsDoublewordSize; }
277
278  uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
279    return assembler_.GetLabelLocation(GetLabelOf(block));
280  }
281
282  HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; }
283  HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; }
284  MipsAssembler* GetAssembler() OVERRIDE { return &assembler_; }
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
304  InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; }
305
306  const MipsInstructionSetFeatures& GetInstructionSetFeatures() const {
307    return isa_features_;
308  }
309
310  MipsLabel* GetLabelOf(HBasicBlock* block) const {
311    return CommonGetLabelOf<MipsLabel>(block_labels_, block);
312  }
313
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
340  ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
341
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
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