blob: 7c491afca9c26d3c4059f563c9ec616c5b45ba59 [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
Vladimir Markoe2727152019-10-10 10:46:42 +010020#include "base/macros.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020021#include "code_generator.h"
David Sehr9e734c72018-01-04 17:56:19 -080022#include "dex/dex_file_types.h"
David Sehr312f3b22018-03-19 08:39:26 -070023#include "dex/string_reference.h"
24#include "dex/type_reference.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020025#include "driver/compiler_options.h"
26#include "nodes.h"
27#include "parallel_move_resolver.h"
28#include "utils/mips/assembler_mips.h"
29
Vladimir Markoe2727152019-10-10 10:46:42 +010030namespace art HIDDEN {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020031namespace mips {
32
33// InvokeDexCallingConvention registers
34
35static constexpr Register kParameterCoreRegisters[] =
Alexey Frunze1b8464d2016-11-12 17:22:05 -080036 { A1, A2, A3, T0, T1 };
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020037static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters);
38
39static constexpr FRegister kParameterFpuRegisters[] =
Alexey Frunze1b8464d2016-11-12 17:22:05 -080040 { F8, F10, F12, F14, F16, F18 };
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020041static constexpr size_t kParameterFpuRegistersLength = arraysize(kParameterFpuRegisters);
42
43
44// InvokeRuntimeCallingConvention registers
45
46static constexpr Register kRuntimeParameterCoreRegisters[] =
47 { A0, A1, A2, A3 };
48static constexpr size_t kRuntimeParameterCoreRegistersLength =
49 arraysize(kRuntimeParameterCoreRegisters);
50
51static constexpr FRegister kRuntimeParameterFpuRegisters[] =
Alexey Frunze1b8464d2016-11-12 17:22:05 -080052 { F12, F14 };
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020053static constexpr size_t kRuntimeParameterFpuRegistersLength =
54 arraysize(kRuntimeParameterFpuRegisters);
55
56
57static constexpr Register kCoreCalleeSaves[] =
58 { S0, S1, S2, S3, S4, S5, S6, S7, FP, RA };
59static constexpr FRegister kFpuCalleeSaves[] =
60 { F20, F22, F24, F26, F28, F30 };
61
62
63class CodeGeneratorMIPS;
64
Lena Djokicca8c2952017-05-29 11:31:46 +020065VectorRegister VectorRegisterFrom(Location location);
66
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020067class InvokeDexCallingConvention : public CallingConvention<Register, FRegister> {
68 public:
69 InvokeDexCallingConvention()
70 : CallingConvention(kParameterCoreRegisters,
71 kParameterCoreRegistersLength,
72 kParameterFpuRegisters,
73 kParameterFpuRegistersLength,
74 kMipsPointerSize) {}
75
76 private:
77 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention);
78};
79
80class InvokeDexCallingConventionVisitorMIPS : public InvokeDexCallingConventionVisitor {
81 public:
82 InvokeDexCallingConventionVisitorMIPS() {}
83 virtual ~InvokeDexCallingConventionVisitorMIPS() {}
84
Roland Levillainbbc6e7e2018-08-24 16:58:47 +010085 Location GetNextLocation(DataType::Type type) override;
86 Location GetReturnLocation(DataType::Type type) const override;
87 Location GetMethodLocation() const override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020088
89 private:
90 InvokeDexCallingConvention calling_convention;
91
92 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorMIPS);
93};
94
95class InvokeRuntimeCallingConvention : public CallingConvention<Register, FRegister> {
96 public:
97 InvokeRuntimeCallingConvention()
98 : CallingConvention(kRuntimeParameterCoreRegisters,
99 kRuntimeParameterCoreRegistersLength,
100 kRuntimeParameterFpuRegisters,
101 kRuntimeParameterFpuRegistersLength,
102 kMipsPointerSize) {}
103
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100104 Location GetReturnLocation(DataType::Type return_type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200105
106 private:
107 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
108};
109
110class FieldAccessCallingConventionMIPS : public FieldAccessCallingConvention {
111 public:
112 FieldAccessCallingConventionMIPS() {}
113
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100114 Location GetObjectLocation() const override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200115 return Location::RegisterLocation(A1);
116 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100117 Location GetFieldIndexLocation() const override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200118 return Location::RegisterLocation(A0);
119 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100120 Location GetReturnLocation(DataType::Type type) const override {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100121 return DataType::Is64BitType(type)
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200122 ? Location::RegisterPairLocation(V0, V1)
123 : Location::RegisterLocation(V0);
124 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100125 Location GetSetValueLocation(DataType::Type type, bool is_instance) const override {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100126 return DataType::Is64BitType(type)
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200127 ? Location::RegisterPairLocation(A2, A3)
128 : (is_instance ? Location::RegisterLocation(A2) : Location::RegisterLocation(A1));
129 }
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100130 Location GetFpuLocation(DataType::Type type ATTRIBUTE_UNUSED) const override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200131 return Location::FpuRegisterLocation(F0);
132 }
133
134 private:
135 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionMIPS);
136};
137
138class ParallelMoveResolverMIPS : public ParallelMoveResolverWithSwap {
139 public:
140 ParallelMoveResolverMIPS(ArenaAllocator* allocator, CodeGeneratorMIPS* codegen)
141 : ParallelMoveResolverWithSwap(allocator), codegen_(codegen) {}
142
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100143 void EmitMove(size_t index) override;
144 void EmitSwap(size_t index) override;
145 void SpillScratch(int reg) override;
146 void RestoreScratch(int reg) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200147
148 void Exchange(int index1, int index2, bool double_slot);
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +0100149 void ExchangeQuadSlots(int index1, int index2);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200150
151 MipsAssembler* GetAssembler() const;
152
153 private:
154 CodeGeneratorMIPS* const codegen_;
155
156 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverMIPS);
157};
158
159class SlowPathCodeMIPS : public SlowPathCode {
160 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000161 explicit SlowPathCodeMIPS(HInstruction* instruction)
162 : SlowPathCode(instruction), entry_label_(), exit_label_() {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200163
164 MipsLabel* GetEntryLabel() { return &entry_label_; }
165 MipsLabel* GetExitLabel() { return &exit_label_; }
166
167 private:
168 MipsLabel entry_label_;
169 MipsLabel exit_label_;
170
171 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeMIPS);
172};
173
174class LocationsBuilderMIPS : public HGraphVisitor {
175 public:
176 LocationsBuilderMIPS(HGraph* graph, CodeGeneratorMIPS* codegen)
177 : HGraphVisitor(graph), codegen_(codegen) {}
178
179#define DECLARE_VISIT_INSTRUCTION(name, super) \
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100180 void Visit##name(H##name* instr) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200181
182 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
183 FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)
184
185#undef DECLARE_VISIT_INSTRUCTION
186
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100187 void VisitInstruction(HInstruction* instruction) override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200188 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
189 << " (id " << instruction->GetId() << ")";
190 }
191
192 private:
193 void HandleInvoke(HInvoke* invoke);
194 void HandleBinaryOp(HBinaryOperation* operation);
Vladimir Marko5f7b58e2015-11-23 19:49:34 +0000195 void HandleCondition(HCondition* instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200196 void HandleShift(HBinaryOperation* operation);
197 void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info);
198 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info);
Alexey Frunzef58b2482016-09-02 22:14:06 -0700199 Location RegisterOrZeroConstant(HInstruction* instruction);
200 Location FpuRegisterOrConstantForStore(HInstruction* instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200201
202 InvokeDexCallingConventionVisitorMIPS parameter_visitor_;
203
204 CodeGeneratorMIPS* const codegen_;
205
206 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderMIPS);
207};
208
Aart Bik42249c32016-01-07 15:33:50 -0800209class InstructionCodeGeneratorMIPS : public InstructionCodeGenerator {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200210 public:
211 InstructionCodeGeneratorMIPS(HGraph* graph, CodeGeneratorMIPS* codegen);
212
213#define DECLARE_VISIT_INSTRUCTION(name, super) \
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100214 void Visit##name(H##name* instr) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200215
216 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION)
217 FOR_EACH_CONCRETE_INSTRUCTION_MIPS(DECLARE_VISIT_INSTRUCTION)
218
219#undef DECLARE_VISIT_INSTRUCTION
220
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100221 void VisitInstruction(HInstruction* instruction) override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200222 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName()
223 << " (id " << instruction->GetId() << ")";
224 }
225
226 MipsAssembler* GetAssembler() const { return assembler_; }
227
Alexey Frunze96b66822016-09-10 02:32:44 -0700228 // Compare-and-jump packed switch generates approx. 3 + 2.5 * N 32-bit
229 // instructions for N cases.
230 // Table-based packed switch generates approx. 11 32-bit instructions
231 // and N 32-bit data words for N cases.
232 // At N = 6 they come out as 18 and 17 32-bit words respectively.
233 // We switch to the table-based method starting with 7 cases.
234 static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6;
235
Chris Larsen5633ce72017-04-10 15:47:40 -0700236 void GenerateMemoryBarrier(MemBarrierKind kind);
237
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200238 private:
239 void GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register class_reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200240 void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor);
Vladimir Marko175e7862018-03-27 09:03:13 +0000241 void GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check, Register temp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200242 void HandleBinaryOp(HBinaryOperation* operation);
Vladimir Marko5f7b58e2015-11-23 19:49:34 +0000243 void HandleCondition(HCondition* instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200244 void HandleShift(HBinaryOperation* operation);
Goran Jakovljevice114da22016-12-26 14:21:43 +0100245 void HandleFieldSet(HInstruction* instruction,
246 const FieldInfo& field_info,
247 uint32_t dex_pc,
248 bool value_can_be_null);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200249 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc);
Alexey Frunze15958152017-02-09 19:08:30 -0800250
Aart Bik351df3e2018-03-07 11:54:57 -0800251 void GenerateMinMaxInt(LocationSummary* locations, bool is_min, bool isR6, DataType::Type type);
Aart Bik1f8d51b2018-02-15 10:42:37 -0800252 void GenerateMinMaxFP(LocationSummary* locations, bool is_min, bool isR6, DataType::Type type);
Aart Bik351df3e2018-03-07 11:54:57 -0800253 void GenerateMinMax(HBinaryOperation*, bool is_min);
Aart Bik3dad3412018-02-28 12:01:46 -0800254 void GenerateAbsFP(LocationSummary* locations, DataType::Type type, bool isR2OrNewer, bool isR6);
255
Alexey Frunze15958152017-02-09 19:08:30 -0800256 // Generate a heap reference load using one register `out`:
257 //
258 // out <- *(out + offset)
259 //
260 // while honoring heap poisoning and/or read barriers (if any).
261 //
262 // Location `maybe_temp` is used when generating a read barrier and
263 // shall be a register in that case; it may be an invalid location
264 // otherwise.
265 void GenerateReferenceLoadOneRegister(HInstruction* instruction,
266 Location out,
267 uint32_t offset,
268 Location maybe_temp,
269 ReadBarrierOption read_barrier_option);
270 // Generate a heap reference load using two different registers
271 // `out` and `obj`:
272 //
273 // out <- *(obj + offset)
274 //
275 // while honoring heap poisoning and/or read barriers (if any).
276 //
277 // Location `maybe_temp` is used when generating a Baker's (fast
278 // path) read barrier and shall be a register in that case; it may
279 // be an invalid location otherwise.
280 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
281 Location out,
282 Location obj,
283 uint32_t offset,
284 Location maybe_temp,
285 ReadBarrierOption read_barrier_option);
286
Alexey Frunze06a46c42016-07-19 15:00:40 -0700287 // Generate a GC root reference load:
288 //
289 // root <- *(obj + offset)
290 //
291 // while honoring read barriers (if any).
292 void GenerateGcRootFieldLoad(HInstruction* instruction,
293 Location root,
294 Register obj,
Alexey Frunze15958152017-02-09 19:08:30 -0800295 uint32_t offset,
Alexey Frunze4147fcc2017-06-17 19:57:27 -0700296 ReadBarrierOption read_barrier_option,
297 MipsLabel* label_low = nullptr);
Alexey Frunze15958152017-02-09 19:08:30 -0800298
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800299 void GenerateIntCompare(IfCondition cond, LocationSummary* locations);
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700300 // When the function returns `false` it means that the condition holds if `dst` is non-zero
301 // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero
302 // `dst` are exchanged.
303 bool MaterializeIntCompare(IfCondition cond,
304 LocationSummary* input_locations,
305 Register dst);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800306 void GenerateIntCompareAndBranch(IfCondition cond,
307 LocationSummary* locations,
308 MipsLabel* label);
Tijana Jakovljevic6d482aa2017-02-03 13:24:08 +0100309 void GenerateLongCompare(IfCondition cond, LocationSummary* locations);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800310 void GenerateLongCompareAndBranch(IfCondition cond,
311 LocationSummary* locations,
312 MipsLabel* label);
Alexey Frunze2ddb7172016-09-06 17:04:55 -0700313 void GenerateFpCompare(IfCondition cond,
314 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100315 DataType::Type type,
Alexey Frunze2ddb7172016-09-06 17:04:55 -0700316 LocationSummary* locations);
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700317 // When the function returns `false` it means that the condition holds if the condition
318 // code flag `cc` is non-zero and doesn't hold if `cc` is zero. If it returns `true`,
319 // the roles of zero and non-zero values of the `cc` flag are exchanged.
320 bool MaterializeFpCompareR2(IfCondition cond,
321 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100322 DataType::Type type,
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700323 LocationSummary* input_locations,
324 int cc);
325 // When the function returns `false` it means that the condition holds if `dst` is non-zero
326 // and doesn't hold if `dst` is zero. If it returns `true`, the roles of zero and non-zero
327 // `dst` are exchanged.
328 bool MaterializeFpCompareR6(IfCondition cond,
329 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100330 DataType::Type type,
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700331 LocationSummary* input_locations,
332 FRegister dst);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800333 void GenerateFpCompareAndBranch(IfCondition cond,
334 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100335 DataType::Type type,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -0800336 LocationSummary* locations,
337 MipsLabel* label);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200338 void GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +0000339 size_t condition_input_index,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200340 MipsLabel* true_target,
David Brazdil0debae72015-11-12 18:37:00 +0000341 MipsLabel* false_target);
Alexey Frunze7e99e052015-11-24 19:28:01 -0800342 void DivRemOneOrMinusOne(HBinaryOperation* instruction);
343 void DivRemByPowerOfTwo(HBinaryOperation* instruction);
344 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
345 void GenerateDivRemIntegral(HBinaryOperation* instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200346 void HandleGoto(HInstruction* got, HBasicBlock* successor);
Alexey Frunze96b66822016-09-10 02:32:44 -0700347 void GenPackedSwitchWithCompares(Register value_reg,
348 int32_t lower_bound,
349 uint32_t num_entries,
350 HBasicBlock* switch_block,
351 HBasicBlock* default_block);
352 void GenTableBasedPackedSwitch(Register value_reg,
353 Register constant_area,
354 int32_t lower_bound,
355 uint32_t num_entries,
356 HBasicBlock* switch_block,
357 HBasicBlock* default_block);
Lena Djokic51765b02017-06-22 13:49:59 +0200358
359 int32_t VecAddress(LocationSummary* locations,
360 size_t size,
361 /* out */ Register* adjusted_base);
Alexey Frunze674b9ee2016-09-20 14:54:15 -0700362 void GenConditionalMoveR2(HSelect* select);
363 void GenConditionalMoveR6(HSelect* select);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200364
365 MipsAssembler* const assembler_;
366 CodeGeneratorMIPS* const codegen_;
367
368 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorMIPS);
369};
370
371class CodeGeneratorMIPS : public CodeGenerator {
372 public:
373 CodeGeneratorMIPS(HGraph* graph,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200374 const CompilerOptions& compiler_options,
375 OptimizingCompilerStats* stats = nullptr);
376 virtual ~CodeGeneratorMIPS() {}
377
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100378 void ComputeSpillMask() override;
379 bool HasAllocatedCalleeSaveRegisters() const override;
380 void GenerateFrameEntry() override;
381 void GenerateFrameExit() override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200382
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100383 void Bind(HBasicBlock* block) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200384
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200385 void MoveConstant(Location location, HConstant* c);
386
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100387 size_t GetWordSize() const override { return kMipsWordSize; }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200388
Artem Serov6a0b6572019-07-26 20:38:37 +0100389 size_t GetSlowPathFPWidth() const override {
Lena Djokicca8c2952017-05-29 11:31:46 +0200390 return GetGraph()->HasSIMD()
391 ? 2 * kMipsDoublewordSize // 16 bytes for each spill.
392 : 1 * kMipsDoublewordSize; // 8 bytes for each spill.
393 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200394
Artem Serov6a0b6572019-07-26 20:38:37 +0100395 size_t GetCalleePreservedFPWidth() const override {
396 return 1 * kMipsDoublewordSize;
397 }
398
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100399 uintptr_t GetAddressOf(HBasicBlock* block) override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200400 return assembler_.GetLabelLocation(GetLabelOf(block));
401 }
402
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100403 HGraphVisitor* GetLocationBuilder() override { return &location_builder_; }
404 HGraphVisitor* GetInstructionVisitor() override { return &instruction_visitor_; }
405 MipsAssembler* GetAssembler() override { return &assembler_; }
406 const MipsAssembler& GetAssembler() const override { return assembler_; }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200407
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700408 // Emit linker patches.
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100409 void EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) override;
410 void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) override;
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700411
Alexey Frunze15958152017-02-09 19:08:30 -0800412 // Fast path implementation of ReadBarrier::Barrier for a heap
413 // reference field load when Baker's read barriers are used.
414 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
415 Location ref,
416 Register obj,
417 uint32_t offset,
418 Location temp,
419 bool needs_null_check);
420 // Fast path implementation of ReadBarrier::Barrier for a heap
421 // reference array load when Baker's read barriers are used.
422 void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
423 Location ref,
424 Register obj,
425 uint32_t data_offset,
426 Location index,
427 Location temp,
428 bool needs_null_check);
429
430 // Factored implementation, used by GenerateFieldLoadWithBakerReadBarrier,
431 // GenerateArrayLoadWithBakerReadBarrier and some intrinsics.
432 //
433 // Load the object reference located at the address
434 // `obj + offset + (index << scale_factor)`, held by object `obj`, into
435 // `ref`, and mark it if needed.
436 //
437 // If `always_update_field` is true, the value of the reference is
438 // atomically updated in the holder (`obj`).
439 void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
440 Location ref,
441 Register obj,
442 uint32_t offset,
443 Location index,
444 ScaleFactor scale_factor,
445 Location temp,
446 bool needs_null_check,
447 bool always_update_field = false);
448
449 // Generate a read barrier for a heap reference within `instruction`
450 // using a slow path.
451 //
452 // A read barrier for an object reference read from the heap is
453 // implemented as a call to the artReadBarrierSlow runtime entry
454 // point, which is passed the values in locations `ref`, `obj`, and
455 // `offset`:
456 //
457 // mirror::Object* artReadBarrierSlow(mirror::Object* ref,
458 // mirror::Object* obj,
459 // uint32_t offset);
460 //
461 // The `out` location contains the value returned by
462 // artReadBarrierSlow.
463 //
464 // When `index` is provided (i.e. for array accesses), the offset
465 // value passed to artReadBarrierSlow is adjusted to take `index`
466 // into account.
467 void GenerateReadBarrierSlow(HInstruction* instruction,
468 Location out,
469 Location ref,
470 Location obj,
471 uint32_t offset,
472 Location index = Location::NoLocation());
473
474 // If read barriers are enabled, generate a read barrier for a heap
475 // reference using a slow path. If heap poisoning is enabled, also
476 // unpoison the reference in `out`.
477 void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
478 Location out,
479 Location ref,
480 Location obj,
481 uint32_t offset,
482 Location index = Location::NoLocation());
483
484 // Generate a read barrier for a GC root within `instruction` using
485 // a slow path.
486 //
487 // A read barrier for an object reference GC root is implemented as
488 // a call to the artReadBarrierForRootSlow runtime entry point,
489 // which is passed the value in location `root`:
490 //
491 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root);
492 //
493 // The `out` location contains the value returned by
494 // artReadBarrierForRootSlow.
495 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
496
Goran Jakovljevice114da22016-12-26 14:21:43 +0100497 void MarkGCCard(Register object, Register value, bool value_can_be_null);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200498
499 // Register allocation.
500
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100501 void SetupBlockedRegisters() const override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200502
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100503 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) override;
504 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) override;
505 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
506 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) override;
Alexey Frunze06a46c42016-07-19 15:00:40 -0700507 void ClobberRA() {
508 clobbered_ra_ = true;
509 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200510
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100511 void DumpCoreRegister(std::ostream& stream, int reg) const override;
512 void DumpFloatingPointRegister(std::ostream& stream, int reg) const override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200513
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100514 InstructionSet GetInstructionSet() const override { return InstructionSet::kMips; }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200515
Vladimir Markoa0431112018-06-25 09:32:54 +0100516 const MipsInstructionSetFeatures& GetInstructionSetFeatures() const;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200517
518 MipsLabel* GetLabelOf(HBasicBlock* block) const {
519 return CommonGetLabelOf<MipsLabel>(block_labels_, block);
520 }
521
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100522 void Initialize() override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200523 block_labels_ = CommonInitializeLabels<MipsLabel>();
524 }
525
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100526 void Finalize(CodeAllocator* allocator) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200527
528 // Code generation helpers.
529
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100530 void MoveLocation(Location dst, Location src, DataType::Type dst_type) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200531
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100532 void MoveConstant(Location destination, int32_t value) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200533
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100534 void AddLocationAsTemp(Location location, LocationSummary* locations) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200535
536 // Generate code to invoke a runtime entry point.
537 void InvokeRuntime(QuickEntrypointEnum entrypoint,
538 HInstruction* instruction,
539 uint32_t dex_pc,
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100540 SlowPathCode* slow_path = nullptr) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200541
Alexey Frunze15958152017-02-09 19:08:30 -0800542 // Generate code to invoke a runtime entry point, but do not record
543 // PC-related information in a stack map.
544 void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
545 HInstruction* instruction,
546 SlowPathCode* slow_path,
547 bool direct);
548
549 void GenerateInvokeRuntime(int32_t entry_point_offset, bool direct);
550
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100551 ParallelMoveResolver* GetMoveResolver() override { return &move_resolver_; }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200552
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100553 bool NeedsTwoRegisters(DataType::Type type) const override {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100554 return type == DataType::Type::kInt64;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200555 }
556
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000557 // Check if the desired_string_load_kind is supported. If it is, return it,
558 // otherwise return a fall-back kind that should be used instead.
559 HLoadString::LoadKind GetSupportedLoadStringKind(
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100560 HLoadString::LoadKind desired_string_load_kind) override;
Vladimir Markocac5a7e2016-02-22 10:39:50 +0000561
Vladimir Markodbb7f5b2016-03-30 13:23:58 +0100562 // Check if the desired_class_load_kind is supported. If it is, return it,
563 // otherwise return a fall-back kind that should be used instead.
564 HLoadClass::LoadKind GetSupportedLoadClassKind(
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100565 HLoadClass::LoadKind desired_class_load_kind) override;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +0100566
Vladimir Markodc151b22015-10-15 18:02:30 +0100567 // Check if the desired_dispatch_info is supported. If it is, return it,
568 // otherwise return a fall-back info that should be used instead.
569 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
570 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffraybdb2ecc2018-09-18 14:33:55 +0100571 ArtMethod* method) override;
Vladimir Markodc151b22015-10-15 18:02:30 +0100572
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100573 void GenerateStaticOrDirectCall(
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100574 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100575 void GenerateVirtualCall(
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100576 HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) override;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200577
578 void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED,
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100579 DataType::Type type ATTRIBUTE_UNUSED) override {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200580 UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
581 }
582
Roland Levillainbbc6e7e2018-08-24 16:58:47 +0100583 void GenerateNop() override;
584 void GenerateImplicitNullCheck(HNullCheck* instruction) override;
585 void GenerateExplicitNullCheck(HNullCheck* instruction) override;
David Srbeckyc7098ff2016-02-09 14:30:11 +0000586
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000587 // The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types,
588 // whether through .data.bimg.rel.ro, .bss, or directly in the boot image.
589 //
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700590 // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
591 // two patches/infos. There can be more than two patches/infos if the instruction supplying
592 // the high half is shared with e.g. a slow path, while the low half is supplied by separate
593 // instructions, e.g.:
594 // lui r1, high // patch
595 // addu r1, r1, rbase
596 // lw r2, low(r1) // patch
597 // beqz r2, slow_path
598 // back:
599 // ...
600 // slow_path:
601 // ...
602 // sw r2, low(r1) // patch
603 // b back
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000604 struct PcRelativePatchInfo : PatchInfo<MipsLabel> {
605 PcRelativePatchInfo(const DexFile* dex_file,
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700606 uint32_t off_or_idx,
607 const PcRelativePatchInfo* info_high)
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000608 : PatchInfo<MipsLabel>(dex_file, off_or_idx),
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700609 pc_rel_label(),
610 patch_info_high(info_high) { }
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700611
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700612 // Label for the instruction corresponding to PC+0. Not bound or used in low half patches.
613 // Not bound in high half patches on R2 when using HMipsComputeBaseMethodAddress.
614 // Bound in high half patches on R2 when using the NAL instruction instead of
615 // HMipsComputeBaseMethodAddress.
616 // Bound in high half patches on R6.
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700617 MipsLabel pc_rel_label;
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700618 // Pointer to the info for the high half patch or nullptr if this is the high half patch info.
619 const PcRelativePatchInfo* patch_info_high;
620
621 private:
622 PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete;
623 DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700624 };
625
Vladimir Marko6fd16062018-06-26 11:02:04 +0100626 PcRelativePatchInfo* NewBootImageIntrinsicPatch(uint32_t intrinsic_data,
627 const PcRelativePatchInfo* info_high = nullptr);
Vladimir Markob066d432018-01-03 13:14:37 +0000628 PcRelativePatchInfo* NewBootImageRelRoPatch(uint32_t boot_image_offset,
629 const PcRelativePatchInfo* info_high = nullptr);
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000630 PcRelativePatchInfo* NewBootImageMethodPatch(MethodReference target_method,
631 const PcRelativePatchInfo* info_high = nullptr);
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700632 PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
633 const PcRelativePatchInfo* info_high = nullptr);
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000634 PcRelativePatchInfo* NewBootImageTypePatch(const DexFile& dex_file,
635 dex::TypeIndex type_index,
636 const PcRelativePatchInfo* info_high = nullptr);
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700637 PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
638 dex::TypeIndex type_index,
639 const PcRelativePatchInfo* info_high = nullptr);
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000640 PcRelativePatchInfo* NewBootImageStringPatch(const DexFile& dex_file,
641 dex::StringIndex string_index,
642 const PcRelativePatchInfo* info_high = nullptr);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100643 PcRelativePatchInfo* NewStringBssEntryPatch(const DexFile& dex_file,
644 dex::StringIndex string_index,
645 const PcRelativePatchInfo* info_high = nullptr);
Alexey Frunze06a46c42016-07-19 15:00:40 -0700646 Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700647
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700648 void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
649 Register out,
Alexey Frunzea663d9d2017-07-31 18:43:18 -0700650 Register base);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000651
Vladimir Marko6fd16062018-06-26 11:02:04 +0100652 void LoadBootImageAddress(Register reg, uint32_t boot_image_reference);
653 void AllocateInstanceForIntrinsic(HInvokeStaticOrDirect* invoke, uint32_t boot_image_offset);
Vladimir Markoeebb8212018-06-05 14:57:24 +0100654
Alexey Frunze627c1a02017-01-30 19:28:14 -0800655 // The JitPatchInfo is used for JIT string and class loads.
656 struct JitPatchInfo {
657 JitPatchInfo(const DexFile& dex_file, uint64_t idx)
658 : target_dex_file(dex_file), index(idx) { }
659 JitPatchInfo(JitPatchInfo&& other) = default;
660
661 const DexFile& target_dex_file;
662 // String/type index.
663 uint64_t index;
664 // Label for the instruction loading the most significant half of the address.
Alexey Frunze627c1a02017-01-30 19:28:14 -0800665 MipsLabel high_label;
Alexey Frunze4147fcc2017-06-17 19:57:27 -0700666 // Label for the instruction supplying the least significant half of the address.
667 MipsLabel low_label;
Alexey Frunze627c1a02017-01-30 19:28:14 -0800668 };
669
670 void PatchJitRootUse(uint8_t* code,
671 const uint8_t* roots_data,
672 const JitPatchInfo& info,
673 uint64_t index_in_table) const;
674 JitPatchInfo* NewJitRootStringPatch(const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +0100675 dex::StringIndex string_index,
Alexey Frunze627c1a02017-01-30 19:28:14 -0800676 Handle<mirror::String> handle);
677 JitPatchInfo* NewJitRootClassPatch(const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +0100678 dex::TypeIndex type_index,
Alexey Frunze627c1a02017-01-30 19:28:14 -0800679 Handle<mirror::Class> handle);
680
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200681 private:
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700682 Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
683
Alexey Frunze06a46c42016-07-19 15:00:40 -0700684 using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>;
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700685
Alexey Frunze06a46c42016-07-19 15:00:40 -0700686 Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000687 PcRelativePatchInfo* NewPcRelativePatch(const DexFile* dex_file,
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700688 uint32_t offset_or_index,
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700689 const PcRelativePatchInfo* info_high,
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700690 ArenaDeque<PcRelativePatchInfo>* patches);
691
Vladimir Markod8dbc8d2017-09-20 13:37:47 +0100692 template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
Vladimir Markoaad75c62016-10-03 08:46:48 +0000693 void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
Vladimir Markod8dbc8d2017-09-20 13:37:47 +0100694 ArenaVector<linker::LinkerPatch>* linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000695
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200696 // Labels for each block that will be compiled.
697 MipsLabel* block_labels_;
698 MipsLabel frame_entry_label_;
699 LocationsBuilderMIPS location_builder_;
700 InstructionCodeGeneratorMIPS instruction_visitor_;
701 ParallelMoveResolverMIPS move_resolver_;
702 MipsAssembler assembler_;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200703
Alexey Frunze06a46c42016-07-19 15:00:40 -0700704 // Deduplication map for 32-bit literals, used for non-patchable boot image addresses.
705 Uint32ToLiteralMap uint32_literals_;
Vladimir Marko2d06e022019-07-08 15:45:19 +0100706 // PC-relative method patch info for kBootImageLinkTimePcRelative.
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000707 ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_;
Vladimir Marko0eb882b2017-05-15 13:39:18 +0100708 // PC-relative method patch info for kBssEntry.
709 ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_;
Vladimir Marko1998cd02017-01-13 13:02:58 +0000710 // PC-relative type patch info for kBootImageLinkTimePcRelative.
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000711 ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_;
Vladimir Marko1998cd02017-01-13 13:02:58 +0000712 // PC-relative type patch info for kBssEntry.
713 ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_;
Vladimir Markoe47f60c2018-02-21 13:43:28 +0000714 // PC-relative String patch info for kBootImageLinkTimePcRelative.
Vladimir Marko59eb30f2018-02-20 11:52:34 +0000715 ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_;
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +0100716 // PC-relative String patch info for kBssEntry.
717 ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_;
Vladimir Marko2d06e022019-07-08 15:45:19 +0100718 // PC-relative patch info for IntrinsicObjects for the boot image,
719 // and for method/type/string patches for kBootImageRelRo otherwise.
720 ArenaDeque<PcRelativePatchInfo> boot_image_other_patches_;
Vladimir Marko65979462017-05-19 17:25:12 +0100721
Alexey Frunze627c1a02017-01-30 19:28:14 -0800722 // Patches for string root accesses in JIT compiled code.
723 ArenaDeque<JitPatchInfo> jit_string_patches_;
724 // Patches for class root accesses in JIT compiled code.
725 ArenaDeque<JitPatchInfo> jit_class_patches_;
Alexey Frunze06a46c42016-07-19 15:00:40 -0700726
727 // PC-relative loads on R2 clobber RA, which may need to be preserved explicitly in leaf methods.
728 // This is a flag set by pc_relative_fixups_mips and dex_cache_array_fixups_mips optimizations.
729 bool clobbered_ra_;
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700730
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200731 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorMIPS);
732};
733
734} // namespace mips
735} // namespace art
736
737#endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_MIPS_H_