blob: bf3392259465019a720f25b31f2e92ef9adc86e1 [file] [log] [blame]
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001/*
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"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020021#include "driver/compiler_options.h"
22#include "nodes.h"
23#include "parallel_move_resolver.h"
24#include "utils/mips/assembler_mips.h"
25
26namespace art {
27namespace mips {
28
29// InvokeDexCallingConvention registers
30
31static constexpr Register kParameterCoreRegisters[] =
32 { A1, A2, A3 };
33static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
34
35static constexpr FRegister kParameterFpuRegisters[] =
36 { F12, F14 };
37static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
38
39
40// InvokeRuntimeCallingConvention registers
41
42static constexpr Register kRuntimeParameterCoreRegisters[] =
43 { A0, A1, A2, A3 };
44static constexpr size_t kRuntimeParameterCoreRegistersLength =
45 arraysize(kRuntimeParameterCoreRegisters);
46
47static constexpr FRegister kRuntimeParameterFpuRegisters[] =
48 { F12, F14};
49static constexpr size_t kRuntimeParameterFpuRegistersLength =
50 arraysize(kRuntimeParameterFpuRegisters);
51
52
53static constexpr Register kCoreCalleeSaves[] =
54 { S0, S1, S2, S3, S4, S5, S6, S7, FP, RA };
55static constexpr FRegister kFpuCalleeSaves[] =
56 { F20, F22, F24, F26, F28, F30 };
57
58
59class CodeGeneratorMIPS;
60
61class InvokeDexCallingConvention : public CallingConvention<Register, FRegister> {
62 public:
63 InvokeDexCallingConvention()
64 : CallingConvention(kParameterCoreRegisters,
65 kParameterCoreRegistersLength,
66 kParameterFpuRegisters,
67 kParameterFpuRegistersLength,
68 kMipsPointerSize) {}
69
70 private:
71 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
72};
73
74class InvokeDexCallingConventionVisitorMIPS : public InvokeDexCallingConventionVisitor {
75 public:
76 InvokeDexCallingConventionVisitorMIPS() {}
77 virtual ~InvokeDexCallingConventionVisitorMIPS() {}
78
79 Location GetNextLocation(Primitive::Type type) OVERRIDE;
80 Location GetReturnLocation(Primitive::Type type) const OVERRIDE;
81 Location GetMethodLocation() const OVERRIDE;
82
83 private:
84 InvokeDexCallingConvention calling_convention;
85
86 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS);
87};
88
89class InvokeRuntimeCallingConvention : public CallingConvention<Register, FRegister> {
90 public:
91 InvokeRuntimeCallingConvention()
92 : CallingConvention(kRuntimeParameterCoreRegisters,
93 kRuntimeParameterCoreRegistersLength,
94 kRuntimeParameterFpuRegisters,
95 kRuntimeParameterFpuRegistersLength,
96 kMipsPointerSize) {}
97
98 Location GetReturnLocation(Primitive::Type return_type);
99
100 private:
101 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
102};
103
104class FieldAccessCallingConventionMIPS : public FieldAccessCallingConvention {
105 public:
106 FieldAccessCallingConventionMIPS() {}
107
108 Location GetObjectLocation() const OVERRIDE {
109 return Location::RegisterLocation(A1);
110 }
111 Location GetFieldIndexLocation() const OVERRIDE {
112 return Location::RegisterLocation(A0);
113 }
114 Location GetReturnLocation(Primitive::Type type) const OVERRIDE {
115 return Primitive::Is64BitType(type)
116 ? Location::RegisterPairLocation(V0, V1)
117 : Location::RegisterLocation(V0);
118 }
119 Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE {
120 return Primitive::Is64BitType(type)
121 ? Location::RegisterPairLocation(A2, A3)
122 : (is_instance ? Location::RegisterLocation(A2) : Location::RegisterLocation(A1));
123 }
124 Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE {
125 return Location::FpuRegisterLocation(F0);
126 }
127
128 private:
129 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionMIPS);
130};
131
132class ParallelMoveResolverMIPS : public ParallelMoveResolverWithSwap {
133 public:
134 ParallelMoveResolverMIPS(ArenaAllocator* allocator, CodeGeneratorMIPS* codegen)
135 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
136
137 void EmitMove(size_t index) OVERRIDE;
138 void EmitSwap(size_t index) OVERRIDE;
139 void SpillScratch(int reg) OVERRIDE;
140 void RestoreScratch(int reg) OVERRIDE;
141
142 void Exchange(int index1, int index2, bool double_slot);
143
144 MipsAssembler* GetAssembler() const;
145
146 private:
147 CodeGeneratorMIPS* const codegen_;
148
149 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS);
150};
151
152class SlowPathCodeMIPS : public SlowPathCode {
153 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000154 explicit SlowPathCodeMIPS(HInstruction* instruction)
155 : SlowPathCode(instruction), entry_label_(), exit_label_() {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200156
157 MipsLabel* GetEntryLabel() { return &entry_label_; }
158 MipsLabel* GetExitLabel() { return &exit_label_; }
159
160 private:
161 MipsLabel entry_label_;
162 MipsLabel exit_label_;
163
164 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS);
165};
166
167class LocationsBuilderMIPS : public HGraphVisitor {
168 public:
169 LocationsBuilderMIPS(HGraph* graph, CodeGeneratorMIPS* codegen)
170 : HGraphVisitor(graph), codegen_(codegen) {}
171
172#define DECLARE_VISIT_INSTRUCTION(name, super) \
173 void Visit##name(H##name* instr) OVERRIDE;
174
175 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
176 FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)
177
178#undef DECLARE_VISIT_INSTRUCTION
179
180 void VisitInstruction(HInstruction* instruction) OVERRIDE {
181 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
182 << " (id " << instruction->GetId() << ")";
183 }
184
185 private:
186 void HandleInvoke(HInvoke* invoke);
187 void HandleBinaryOp(HBinaryOperation* operation);
Vladimir Marko5f7b58e2015-11-23 19:49:34 +0000188 void HandleCondition(HCondition* instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200189 void HandleShift(HBinaryOperation* operation);
190 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
191 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
192
193 InvokeDexCallingConventionVisitorMIPS parameter_visitor_;
194
195 CodeGeneratorMIPS* const codegen_;
196
197 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS);
198};
199
Aart Bik42249c32016-01-07 15:33:50 -0800200class InstructionCodeGeneratorMIPS : public InstructionCodeGenerator {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200201 public:
202 InstructionCodeGeneratorMIPS(HGraph* graph, CodeGeneratorMIPS* codegen);
203
204#define DECLARE_VISIT_INSTRUCTION(name, super) \
205 void Visit##name(H##name* instr) OVERRIDE;
206
207 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
208 FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)
209
210#undef DECLARE_VISIT_INSTRUCTION
211
212 void VisitInstruction(HInstruction* instruction) OVERRIDE {
213 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
214 << " (id " << instruction->GetId() << ")";
215 }
216
217 MipsAssembler* GetAssembler() const { return assembler_; }
218
219 private:
220 void GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register class_reg);
221 void GenerateMemoryBarrier(MemBarrierKind kind);
222 void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
223 void HandleBinaryOp(HBinaryOperation* operation);
Vladimir Marko5f7b58e2015-11-23 19:49:34 +0000224 void HandleCondition(HCondition* instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200225 void HandleShift(HBinaryOperation* operation);
226 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
227 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800228 void GenerateIntCompare(IfCondition cond, LocationSummary* locations);
229 void GenerateIntCompareAndBranch(IfCondition cond,
230 LocationSummary* locations,
231 MipsLabel* label);
232 void GenerateLongCompareAndBranch(IfCondition cond,
233 LocationSummary* locations,
234 MipsLabel* label);
235 void GenerateFpCompareAndBranch(IfCondition cond,
236 bool gt_bias,
237 Primitive::Type type,
238 LocationSummary* locations,
239 MipsLabel* label);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200240 void GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +0000241 size_t condition_input_index,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200242 MipsLabel* true_target,
David Brazdil0debae72015-11-12 18:37:00 +0000243 MipsLabel* false_target);
Alexey Frunze7e99e052015-11-24 19:28:01 -0800244 void DivRemOneOrMinusOne(HBinaryOperation* instruction);
245 void DivRemByPowerOfTwo(HBinaryOperation* instruction);
246 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
247 void GenerateDivRemIntegral(HBinaryOperation* instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200248 void HandleGoto(HInstruction* got, HBasicBlock* successor);
249
250 MipsAssembler* const assembler_;
251 CodeGeneratorMIPS* const codegen_;
252
253 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS);
254};
255
256class CodeGeneratorMIPS : public CodeGenerator {
257 public:
258 CodeGeneratorMIPS(HGraph* graph,
259 const MipsInstructionSetFeatures& isa_features,
260 const CompilerOptions& compiler_options,
261 OptimizingCompilerStats* stats = nullptr);
262 virtual ~CodeGeneratorMIPS() {}
263
Alexey Frunze73296a72016-06-03 22:51:46 -0700264 void ComputeSpillMask() OVERRIDE;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200265 void GenerateFrameEntry() OVERRIDE;
266 void GenerateFrameExit() OVERRIDE;
267
268 void Bind(HBasicBlock* block) OVERRIDE;
269
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200270 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
Alexandre Ramesc01a6642016-04-15 11:54:06 +0100278 uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200279 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
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700287 // Emit linker patches.
288 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
289
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200290 void MarkGCCard(Register object, Register value);
291
292 // Register allocation.
293
David Brazdil58282f42016-01-14 12:45:10 +0000294 void SetupBlockedRegisters() const OVERRIDE;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200295
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200296 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
297 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
298 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
299 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
300
301 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
302 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
303
304 // Blocks all register pairs made out of blocked core registers.
305 void UpdateBlockedPairRegisters() const;
306
307 InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; }
308
309 const MipsInstructionSetFeatures& GetInstructionSetFeatures() const {
310 return isa_features_;
311 }
312
313 MipsLabel* GetLabelOf(HBasicBlock* block) const {
314 return CommonGetLabelOf<MipsLabel>(block_labels_, block);
315 }
316
317 void Initialize() OVERRIDE {
318 block_labels_ = CommonInitializeLabels<MipsLabel>();
319 }
320
321 void Finalize(CodeAllocator* allocator) OVERRIDE;
322
323 // Code generation helpers.
324
325 void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
326
327 void MoveConstant(Location destination, int32_t value);
328
329 void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
330
331 // Generate code to invoke a runtime entry point.
332 void InvokeRuntime(QuickEntrypointEnum entrypoint,
333 HInstruction* instruction,
334 uint32_t dex_pc,
335 SlowPathCode* slow_path) OVERRIDE;
336
337 void InvokeRuntime(int32_t offset,
338 HInstruction* instruction,
339 uint32_t dex_pc,
340 SlowPathCode* slow_path,
341 bool is_direct_entrypoint);
342
343 ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
344
345 bool NeedsTwoRegisters(Primitive::Type type) const {
346 return type == Primitive::kPrimLong;
347 }
348
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000349 // Check if the desired_string_load_kind is supported. If it is, return it,
350 // otherwise return a fall-back kind that should be used instead.
351 HLoadString::LoadKind GetSupportedLoadStringKind(
352 HLoadString::LoadKind desired_string_load_kind) OVERRIDE;
353
Vladimir Markodbb7f5b2016-03-30 13:23:58 +0100354 // Check if the desired_class_load_kind is supported. If it is, return it,
355 // otherwise return a fall-back kind that should be used instead.
356 HLoadClass::LoadKind GetSupportedLoadClassKind(
357 HLoadClass::LoadKind desired_class_load_kind) OVERRIDE;
358
Vladimir Markodc151b22015-10-15 18:02:30 +0100359 // Check if the desired_dispatch_info is supported. If it is, return it,
360 // otherwise return a fall-back info that should be used instead.
361 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
362 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
363 MethodReference target_method) OVERRIDE;
364
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200365 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
Chris Larsen3acee732015-11-18 13:31:08 -0800366 void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200367
368 void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
369 Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE {
370 UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
371 }
372
David Srbeckyc7098ff2016-02-09 14:30:11 +0000373 void GenerateNop();
Calin Juravle2ae48182016-03-16 14:05:09 +0000374 void GenerateImplicitNullCheck(HNullCheck* instruction);
375 void GenerateExplicitNullCheck(HNullCheck* instruction);
David Srbeckyc7098ff2016-02-09 14:30:11 +0000376
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700377 // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
378 // and boot image strings. The only difference is the interpretation of the offset_or_index.
379 struct PcRelativePatchInfo {
380 PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
381 : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
382 PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
383
384 const DexFile& target_dex_file;
385 // Either the dex cache array element offset or the string index.
386 uint32_t offset_or_index;
387 // Label for the instruction loading the most significant half of the offset that's added to PC
388 // to form the base address (the least significant half is loaded with the instruction that
389 // follows).
390 MipsLabel high_label;
391 // Label for the instruction corresponding to PC+0.
392 MipsLabel pc_rel_label;
393 };
394
395 PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
396 uint32_t element_offset);
397
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200398 private:
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700399 Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
400
401 using MethodToLiteralMap = ArenaSafeMap<MethodReference, Literal*, MethodReferenceComparator>;
402
403 Literal* DeduplicateMethodLiteral(MethodReference target_method, MethodToLiteralMap* map);
404 Literal* DeduplicateMethodAddressLiteral(MethodReference target_method);
405 Literal* DeduplicateMethodCodeLiteral(MethodReference target_method);
406 PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
407 uint32_t offset_or_index,
408 ArenaDeque<PcRelativePatchInfo>* patches);
409
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200410 // Labels for each block that will be compiled.
411 MipsLabel* block_labels_;
412 MipsLabel frame_entry_label_;
413 LocationsBuilderMIPS location_builder_;
414 InstructionCodeGeneratorMIPS instruction_visitor_;
415 ParallelMoveResolverMIPS move_resolver_;
416 MipsAssembler assembler_;
417 const MipsInstructionSetFeatures& isa_features_;
418
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700419 // Method patch info, map MethodReference to a literal for method address and method code.
420 MethodToLiteralMap method_patches_;
421 MethodToLiteralMap call_patches_;
422 // PC-relative patch info for each HMipsDexCacheArraysBase.
423 ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
424
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200425 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS);
426};
427
428} // namespace mips
429} // namespace art
430
431#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_