blob: 5c0ca85c7803b5ac559be4d47990e6259dbe895a [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#include "code_generator_mips.h"
18
19#include "arch/mips/entrypoints_direct_mips.h"
20#include "arch/mips/instruction_set_features_mips.h"
21#include "art_method.h"
Chris Larsen701566a2015-10-27 15:29:13 -070022#include "code_generator_utils.h"
Vladimir Marko3a21e382016-09-02 12:38:38 +010023#include "compiled_method.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020024#include "entrypoints/quick/quick_entrypoints.h"
25#include "entrypoints/quick/quick_entrypoints_enum.h"
26#include "gc/accounting/card_table.h"
27#include "intrinsics.h"
Chris Larsen701566a2015-10-27 15:29:13 -070028#include "intrinsics_mips.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020029#include "mirror/array-inl.h"
30#include "mirror/class-inl.h"
31#include "offsets.h"
32#include "thread.h"
33#include "utils/assembler.h"
34#include "utils/mips/assembler_mips.h"
35#include "utils/stack_checks.h"
36
37namespace art {
38namespace mips {
39
40static constexpr int kCurrentMethodStackOffset = 0;
41static constexpr Register kMethodRegisterArgument = A0;
42
Alexey Frunzee3fb2452016-05-10 16:08:05 -070043// We'll maximize the range of a single load instruction for dex cache array accesses
44// by aligning offset -32768 with the offset of the first used element.
45static constexpr uint32_t kDexCacheArrayLwOffset = 0x8000;
46
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020047Location MipsReturnLocation(Primitive::Type return_type) {
48 switch (return_type) {
49 case Primitive::kPrimBoolean:
50 case Primitive::kPrimByte:
51 case Primitive::kPrimChar:
52 case Primitive::kPrimShort:
53 case Primitive::kPrimInt:
54 case Primitive::kPrimNot:
55 return Location::RegisterLocation(V0);
56
57 case Primitive::kPrimLong:
58 return Location::RegisterPairLocation(V0, V1);
59
60 case Primitive::kPrimFloat:
61 case Primitive::kPrimDouble:
62 return Location::FpuRegisterLocation(F0);
63
64 case Primitive::kPrimVoid:
65 return Location();
66 }
67 UNREACHABLE();
68}
69
70Location InvokeDexCallingConventionVisitorMIPS::GetReturnLocation(Primitive::Type type) const {
71 return MipsReturnLocation(type);
72}
73
74Location InvokeDexCallingConventionVisitorMIPS::GetMethodLocation() const {
75 return Location::RegisterLocation(kMethodRegisterArgument);
76}
77
78Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(Primitive::Type type) {
79 Location next_location;
80
81 switch (type) {
82 case Primitive::kPrimBoolean:
83 case Primitive::kPrimByte:
84 case Primitive::kPrimChar:
85 case Primitive::kPrimShort:
86 case Primitive::kPrimInt:
87 case Primitive::kPrimNot: {
88 uint32_t gp_index = gp_index_++;
89 if (gp_index < calling_convention.GetNumberOfRegisters()) {
90 next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index));
91 } else {
92 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
93 next_location = Location::StackSlot(stack_offset);
94 }
95 break;
96 }
97
98 case Primitive::kPrimLong: {
99 uint32_t gp_index = gp_index_;
100 gp_index_ += 2;
101 if (gp_index + 1 < calling_convention.GetNumberOfRegisters()) {
102 if (calling_convention.GetRegisterAt(gp_index) == A1) {
103 gp_index_++; // Skip A1, and use A2_A3 instead.
104 gp_index++;
105 }
106 Register low_even = calling_convention.GetRegisterAt(gp_index);
107 Register high_odd = calling_convention.GetRegisterAt(gp_index + 1);
108 DCHECK_EQ(low_even + 1, high_odd);
109 next_location = Location::RegisterPairLocation(low_even, high_odd);
110 } else {
111 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
112 next_location = Location::DoubleStackSlot(stack_offset);
113 }
114 break;
115 }
116
117 // Note: both float and double types are stored in even FPU registers. On 32 bit FPU, double
118 // will take up the even/odd pair, while floats are stored in even regs only.
119 // On 64 bit FPU, both double and float are stored in even registers only.
120 case Primitive::kPrimFloat:
121 case Primitive::kPrimDouble: {
122 uint32_t float_index = float_index_++;
123 if (float_index < calling_convention.GetNumberOfFpuRegisters()) {
124 next_location = Location::FpuRegisterLocation(
125 calling_convention.GetFpuRegisterAt(float_index));
126 } else {
127 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
128 next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
129 : Location::StackSlot(stack_offset);
130 }
131 break;
132 }
133
134 case Primitive::kPrimVoid:
135 LOG(FATAL) << "Unexpected parameter type " << type;
136 break;
137 }
138
139 // Space on the stack is reserved for all arguments.
140 stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
141
142 return next_location;
143}
144
145Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) {
146 return MipsReturnLocation(type);
147}
148
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100149// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
150#define __ down_cast<CodeGeneratorMIPS*>(codegen)->GetAssembler()-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -0700151#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200152
153class BoundsCheckSlowPathMIPS : public SlowPathCodeMIPS {
154 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000155 explicit BoundsCheckSlowPathMIPS(HBoundsCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200156
157 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
158 LocationSummary* locations = instruction_->GetLocations();
159 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
160 __ Bind(GetEntryLabel());
161 if (instruction_->CanThrowIntoCatchBlock()) {
162 // Live registers will be restored in the catch block if caught.
163 SaveLiveRegisters(codegen, instruction_->GetLocations());
164 }
165 // We're moving two locations to locations that could overlap, so we need a parallel
166 // move resolver.
167 InvokeRuntimeCallingConvention calling_convention;
168 codegen->EmitParallelMoves(locations->InAt(0),
169 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
170 Primitive::kPrimInt,
171 locations->InAt(1),
172 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
173 Primitive::kPrimInt);
Serban Constantinescufca16662016-07-14 09:21:59 +0100174 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
175 ? kQuickThrowStringBounds
176 : kQuickThrowArrayBounds;
177 mips_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100178 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200179 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
180 }
181
182 bool IsFatal() const OVERRIDE { return true; }
183
184 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS"; }
185
186 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200187 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathMIPS);
188};
189
190class DivZeroCheckSlowPathMIPS : public SlowPathCodeMIPS {
191 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000192 explicit DivZeroCheckSlowPathMIPS(HDivZeroCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200193
194 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
195 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
196 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100197 mips_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200198 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
199 }
200
201 bool IsFatal() const OVERRIDE { return true; }
202
203 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS"; }
204
205 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200206 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS);
207};
208
209class LoadClassSlowPathMIPS : public SlowPathCodeMIPS {
210 public:
211 LoadClassSlowPathMIPS(HLoadClass* cls,
212 HInstruction* at,
213 uint32_t dex_pc,
214 bool do_clinit)
David Srbecky9cd6d372016-02-09 15:24:47 +0000215 : SlowPathCodeMIPS(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200216 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
217 }
218
219 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
220 LocationSummary* locations = at_->GetLocations();
221 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
222
223 __ Bind(GetEntryLabel());
224 SaveLiveRegisters(codegen, locations);
225
226 InvokeRuntimeCallingConvention calling_convention;
227 __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
228
Serban Constantinescufca16662016-07-14 09:21:59 +0100229 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
230 : kQuickInitializeType;
231 mips_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200232 if (do_clinit_) {
233 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
234 } else {
235 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
236 }
237
238 // Move the class to the desired location.
239 Location out = locations->Out();
240 if (out.IsValid()) {
241 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
242 Primitive::Type type = at_->GetType();
243 mips_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
244 }
245
246 RestoreLiveRegisters(codegen, locations);
247 __ B(GetExitLabel());
248 }
249
250 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathMIPS"; }
251
252 private:
253 // The class this slow path will load.
254 HLoadClass* const cls_;
255
256 // The instruction where this slow path is happening.
257 // (Might be the load class or an initialization check).
258 HInstruction* const at_;
259
260 // The dex PC of `at_`.
261 const uint32_t dex_pc_;
262
263 // Whether to initialize the class.
264 const bool do_clinit_;
265
266 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS);
267};
268
269class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
270 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000271 explicit LoadStringSlowPathMIPS(HLoadString* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200272
273 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
274 LocationSummary* locations = instruction_->GetLocations();
275 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
276 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
277
278 __ Bind(GetEntryLabel());
279 SaveLiveRegisters(codegen, locations);
280
281 InvokeRuntimeCallingConvention calling_convention;
David Srbecky9cd6d372016-02-09 15:24:47 +0000282 const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
283 __ LoadConst32(calling_convention.GetRegisterAt(0), string_index);
Serban Constantinescufca16662016-07-14 09:21:59 +0100284 mips_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200285 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
286 Primitive::Type type = instruction_->GetType();
287 mips_codegen->MoveLocation(locations->Out(),
288 calling_convention.GetReturnLocation(type),
289 type);
290
291 RestoreLiveRegisters(codegen, locations);
292 __ B(GetExitLabel());
293 }
294
295 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
296
297 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200298 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
299};
300
301class NullCheckSlowPathMIPS : public SlowPathCodeMIPS {
302 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000303 explicit NullCheckSlowPathMIPS(HNullCheck* instr) : SlowPathCodeMIPS(instr) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200304
305 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
306 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
307 __ Bind(GetEntryLabel());
308 if (instruction_->CanThrowIntoCatchBlock()) {
309 // Live registers will be restored in the catch block if caught.
310 SaveLiveRegisters(codegen, instruction_->GetLocations());
311 }
Serban Constantinescufca16662016-07-14 09:21:59 +0100312 mips_codegen->InvokeRuntime(kQuickThrowNullPointer,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200313 instruction_,
314 instruction_->GetDexPc(),
Serban Constantinescufca16662016-07-14 09:21:59 +0100315 this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200316 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
317 }
318
319 bool IsFatal() const OVERRIDE { return true; }
320
321 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS"; }
322
323 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200324 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathMIPS);
325};
326
327class SuspendCheckSlowPathMIPS : public SlowPathCodeMIPS {
328 public:
329 SuspendCheckSlowPathMIPS(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000330 : SlowPathCodeMIPS(instruction), successor_(successor) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200331
332 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
333 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
334 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100335 mips_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200336 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200337 if (successor_ == nullptr) {
338 __ B(GetReturnLabel());
339 } else {
340 __ B(mips_codegen->GetLabelOf(successor_));
341 }
342 }
343
344 MipsLabel* GetReturnLabel() {
345 DCHECK(successor_ == nullptr);
346 return &return_label_;
347 }
348
349 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS"; }
350
351 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200352 // If not null, the block to branch to after the suspend check.
353 HBasicBlock* const successor_;
354
355 // If `successor_` is null, the label to branch to after the suspend check.
356 MipsLabel return_label_;
357
358 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathMIPS);
359};
360
361class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS {
362 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000363 explicit TypeCheckSlowPathMIPS(HInstruction* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200364
365 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
366 LocationSummary* locations = instruction_->GetLocations();
367 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0) : locations->Out();
368 uint32_t dex_pc = instruction_->GetDexPc();
369 DCHECK(instruction_->IsCheckCast()
370 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
371 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
372
373 __ Bind(GetEntryLabel());
374 SaveLiveRegisters(codegen, locations);
375
376 // We're moving two locations to locations that could overlap, so we need a parallel
377 // move resolver.
378 InvokeRuntimeCallingConvention calling_convention;
379 codegen->EmitParallelMoves(locations->InAt(1),
380 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
381 Primitive::kPrimNot,
382 object_class,
383 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
384 Primitive::kPrimNot);
385
386 if (instruction_->IsInstanceOf()) {
Serban Constantinescufca16662016-07-14 09:21:59 +0100387 mips_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
Roland Levillain888d0672015-11-23 18:53:50 +0000388 CheckEntrypointTypes<
Andreas Gampe67409972016-07-19 22:34:53 -0700389 kQuickInstanceofNonTrivial, size_t, const mirror::Class*, const mirror::Class*>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200390 Primitive::Type ret_type = instruction_->GetType();
391 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
392 mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200393 } else {
394 DCHECK(instruction_->IsCheckCast());
Serban Constantinescufca16662016-07-14 09:21:59 +0100395 mips_codegen->InvokeRuntime(kQuickCheckCast, instruction_, dex_pc, this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200396 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
397 }
398
399 RestoreLiveRegisters(codegen, locations);
400 __ B(GetExitLabel());
401 }
402
403 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS"; }
404
405 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200406 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathMIPS);
407};
408
409class DeoptimizationSlowPathMIPS : public SlowPathCodeMIPS {
410 public:
Aart Bik42249c32016-01-07 15:33:50 -0800411 explicit DeoptimizationSlowPathMIPS(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000412 : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200413
414 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800415 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200416 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100417 mips_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000418 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200419 }
420
421 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS"; }
422
423 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200424 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS);
425};
426
427CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph,
428 const MipsInstructionSetFeatures& isa_features,
429 const CompilerOptions& compiler_options,
430 OptimizingCompilerStats* stats)
431 : CodeGenerator(graph,
432 kNumberOfCoreRegisters,
433 kNumberOfFRegisters,
434 kNumberOfRegisterPairs,
435 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
436 arraysize(kCoreCalleeSaves)),
437 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
438 arraysize(kFpuCalleeSaves)),
439 compiler_options,
440 stats),
441 block_labels_(nullptr),
442 location_builder_(graph, this),
443 instruction_visitor_(graph, this),
444 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +0100445 assembler_(graph->GetArena(), &isa_features),
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700446 isa_features_(isa_features),
Alexey Frunze06a46c42016-07-19 15:00:40 -0700447 uint32_literals_(std::less<uint32_t>(),
448 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700449 method_patches_(MethodReferenceComparator(),
450 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
451 call_patches_(MethodReferenceComparator(),
452 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Alexey Frunze06a46c42016-07-19 15:00:40 -0700453 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
454 boot_image_string_patches_(StringReferenceValueComparator(),
455 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
456 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
457 boot_image_type_patches_(TypeReferenceValueComparator(),
458 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
459 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
460 boot_image_address_patches_(std::less<uint32_t>(),
461 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
462 clobbered_ra_(false) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200463 // Save RA (containing the return address) to mimic Quick.
464 AddAllocatedRegister(Location::RegisterLocation(RA));
465}
466
467#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100468// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
469#define __ down_cast<MipsAssembler*>(GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -0700470#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200471
472void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) {
473 // Ensure that we fix up branches.
474 __ FinalizeCode();
475
476 // Adjust native pc offsets in stack maps.
477 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
478 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
479 uint32_t new_position = __ GetAdjustedPosition(old_position);
480 DCHECK_GE(new_position, old_position);
481 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
482 }
483
484 // Adjust pc offsets for the disassembly information.
485 if (disasm_info_ != nullptr) {
486 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
487 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
488 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
489 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
490 it.second.start = __ GetAdjustedPosition(it.second.start);
491 it.second.end = __ GetAdjustedPosition(it.second.end);
492 }
493 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
494 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
495 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
496 }
497 }
498
499 CodeGenerator::Finalize(allocator);
500}
501
502MipsAssembler* ParallelMoveResolverMIPS::GetAssembler() const {
503 return codegen_->GetAssembler();
504}
505
506void ParallelMoveResolverMIPS::EmitMove(size_t index) {
507 DCHECK_LT(index, moves_.size());
508 MoveOperands* move = moves_[index];
509 codegen_->MoveLocation(move->GetDestination(), move->GetSource(), move->GetType());
510}
511
512void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
513 DCHECK_LT(index, moves_.size());
514 MoveOperands* move = moves_[index];
515 Primitive::Type type = move->GetType();
516 Location loc1 = move->GetDestination();
517 Location loc2 = move->GetSource();
518
519 DCHECK(!loc1.IsConstant());
520 DCHECK(!loc2.IsConstant());
521
522 if (loc1.Equals(loc2)) {
523 return;
524 }
525
526 if (loc1.IsRegister() && loc2.IsRegister()) {
527 // Swap 2 GPRs.
528 Register r1 = loc1.AsRegister<Register>();
529 Register r2 = loc2.AsRegister<Register>();
530 __ Move(TMP, r2);
531 __ Move(r2, r1);
532 __ Move(r1, TMP);
533 } else if (loc1.IsFpuRegister() && loc2.IsFpuRegister()) {
534 FRegister f1 = loc1.AsFpuRegister<FRegister>();
535 FRegister f2 = loc2.AsFpuRegister<FRegister>();
536 if (type == Primitive::kPrimFloat) {
537 __ MovS(FTMP, f2);
538 __ MovS(f2, f1);
539 __ MovS(f1, FTMP);
540 } else {
541 DCHECK_EQ(type, Primitive::kPrimDouble);
542 __ MovD(FTMP, f2);
543 __ MovD(f2, f1);
544 __ MovD(f1, FTMP);
545 }
546 } else if ((loc1.IsRegister() && loc2.IsFpuRegister()) ||
547 (loc1.IsFpuRegister() && loc2.IsRegister())) {
548 // Swap FPR and GPR.
549 DCHECK_EQ(type, Primitive::kPrimFloat); // Can only swap a float.
550 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
551 : loc2.AsFpuRegister<FRegister>();
552 Register r2 = loc1.IsRegister() ? loc1.AsRegister<Register>()
553 : loc2.AsRegister<Register>();
554 __ Move(TMP, r2);
555 __ Mfc1(r2, f1);
556 __ Mtc1(TMP, f1);
557 } else if (loc1.IsRegisterPair() && loc2.IsRegisterPair()) {
558 // Swap 2 GPR register pairs.
559 Register r1 = loc1.AsRegisterPairLow<Register>();
560 Register r2 = loc2.AsRegisterPairLow<Register>();
561 __ Move(TMP, r2);
562 __ Move(r2, r1);
563 __ Move(r1, TMP);
564 r1 = loc1.AsRegisterPairHigh<Register>();
565 r2 = loc2.AsRegisterPairHigh<Register>();
566 __ Move(TMP, r2);
567 __ Move(r2, r1);
568 __ Move(r1, TMP);
569 } else if ((loc1.IsRegisterPair() && loc2.IsFpuRegister()) ||
570 (loc1.IsFpuRegister() && loc2.IsRegisterPair())) {
571 // Swap FPR and GPR register pair.
572 DCHECK_EQ(type, Primitive::kPrimDouble);
573 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
574 : loc2.AsFpuRegister<FRegister>();
575 Register r2_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
576 : loc2.AsRegisterPairLow<Register>();
577 Register r2_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
578 : loc2.AsRegisterPairHigh<Register>();
579 // Use 2 temporary registers because we can't first swap the low 32 bits of an FPR and
580 // then swap the high 32 bits of the same FPR. mtc1 makes the high 32 bits of an FPR
581 // unpredictable and the following mfch1 will fail.
582 __ Mfc1(TMP, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800583 __ MoveFromFpuHigh(AT, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200584 __ Mtc1(r2_l, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800585 __ MoveToFpuHigh(r2_h, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200586 __ Move(r2_l, TMP);
587 __ Move(r2_h, AT);
588 } else if (loc1.IsStackSlot() && loc2.IsStackSlot()) {
589 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ false);
590 } else if (loc1.IsDoubleStackSlot() && loc2.IsDoubleStackSlot()) {
591 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ true);
David Brazdilcc0f3112016-01-28 17:14:52 +0000592 } else if ((loc1.IsRegister() && loc2.IsStackSlot()) ||
593 (loc1.IsStackSlot() && loc2.IsRegister())) {
594 Register reg = loc1.IsRegister() ? loc1.AsRegister<Register>()
595 : loc2.AsRegister<Register>();
596 intptr_t offset = loc1.IsStackSlot() ? loc1.GetStackIndex()
597 : loc2.GetStackIndex();
598 __ Move(TMP, reg);
599 __ LoadFromOffset(kLoadWord, reg, SP, offset);
600 __ StoreToOffset(kStoreWord, TMP, SP, offset);
601 } else if ((loc1.IsRegisterPair() && loc2.IsDoubleStackSlot()) ||
602 (loc1.IsDoubleStackSlot() && loc2.IsRegisterPair())) {
603 Register reg_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
604 : loc2.AsRegisterPairLow<Register>();
605 Register reg_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
606 : loc2.AsRegisterPairHigh<Register>();
607 intptr_t offset_l = loc1.IsDoubleStackSlot() ? loc1.GetStackIndex()
608 : loc2.GetStackIndex();
609 intptr_t offset_h = loc1.IsDoubleStackSlot() ? loc1.GetHighStackIndex(kMipsWordSize)
610 : loc2.GetHighStackIndex(kMipsWordSize);
611 __ Move(TMP, reg_l);
David Brazdilcc0f3112016-01-28 17:14:52 +0000612 __ LoadFromOffset(kLoadWord, reg_l, SP, offset_l);
David Brazdilcc0f3112016-01-28 17:14:52 +0000613 __ StoreToOffset(kStoreWord, TMP, SP, offset_l);
David Brazdil04d3e872016-01-29 09:50:09 +0000614 __ Move(TMP, reg_h);
615 __ LoadFromOffset(kLoadWord, reg_h, SP, offset_h);
616 __ StoreToOffset(kStoreWord, TMP, SP, offset_h);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200617 } else {
618 LOG(FATAL) << "Swap between " << loc1 << " and " << loc2 << " is unsupported";
619 }
620}
621
622void ParallelMoveResolverMIPS::RestoreScratch(int reg) {
623 __ Pop(static_cast<Register>(reg));
624}
625
626void ParallelMoveResolverMIPS::SpillScratch(int reg) {
627 __ Push(static_cast<Register>(reg));
628}
629
630void ParallelMoveResolverMIPS::Exchange(int index1, int index2, bool double_slot) {
631 // Allocate a scratch register other than TMP, if available.
632 // Else, spill V0 (arbitrary choice) and use it as a scratch register (it will be
633 // automatically unspilled when the scratch scope object is destroyed).
634 ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters());
635 // If V0 spills onto the stack, SP-relative offsets need to be adjusted.
636 int stack_offset = ensure_scratch.IsSpilled() ? kMipsWordSize : 0;
637 for (int i = 0; i <= (double_slot ? 1 : 0); i++, stack_offset += kMipsWordSize) {
638 __ LoadFromOffset(kLoadWord,
639 Register(ensure_scratch.GetRegister()),
640 SP,
641 index1 + stack_offset);
642 __ LoadFromOffset(kLoadWord,
643 TMP,
644 SP,
645 index2 + stack_offset);
646 __ StoreToOffset(kStoreWord,
647 Register(ensure_scratch.GetRegister()),
648 SP,
649 index2 + stack_offset);
650 __ StoreToOffset(kStoreWord, TMP, SP, index1 + stack_offset);
651 }
652}
653
Alexey Frunze73296a72016-06-03 22:51:46 -0700654void CodeGeneratorMIPS::ComputeSpillMask() {
655 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
656 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
657 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
658 // If there're FPU callee-saved registers and there's an odd number of GPR callee-saved
659 // registers, include the ZERO register to force alignment of FPU callee-saved registers
660 // within the stack frame.
661 if ((fpu_spill_mask_ != 0) && (POPCOUNT(core_spill_mask_) % 2 != 0)) {
662 core_spill_mask_ |= (1 << ZERO);
663 }
Alexey Frunze58320ce2016-08-30 21:40:46 -0700664}
665
666bool CodeGeneratorMIPS::HasAllocatedCalleeSaveRegisters() const {
Alexey Frunze06a46c42016-07-19 15:00:40 -0700667 // If RA is clobbered by PC-relative operations on R2 and it's the only spilled register
Alexey Frunze58320ce2016-08-30 21:40:46 -0700668 // (this can happen in leaf methods), force CodeGenerator::InitializeCodeGeneration()
669 // into the path that creates a stack frame so that RA can be explicitly saved and restored.
670 // RA can't otherwise be saved/restored when it's the only spilled register.
Alexey Frunze06a46c42016-07-19 15:00:40 -0700671 // TODO: Can this be improved? It causes creation of a stack frame (while RA might be
672 // saved in an unused temporary register) and saving of RA and the current method pointer
673 // in the frame.
Alexey Frunze58320ce2016-08-30 21:40:46 -0700674 return CodeGenerator::HasAllocatedCalleeSaveRegisters() || clobbered_ra_;
Alexey Frunze73296a72016-06-03 22:51:46 -0700675}
676
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200677static dwarf::Reg DWARFReg(Register reg) {
678 return dwarf::Reg::MipsCore(static_cast<int>(reg));
679}
680
681// TODO: mapping of floating-point registers to DWARF.
682
683void CodeGeneratorMIPS::GenerateFrameEntry() {
684 __ Bind(&frame_entry_label_);
685
686 bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kMips) || !IsLeafMethod();
687
688 if (do_overflow_check) {
689 __ LoadFromOffset(kLoadWord,
690 ZERO,
691 SP,
692 -static_cast<int32_t>(GetStackOverflowReservedBytes(kMips)));
693 RecordPcInfo(nullptr, 0);
694 }
695
696 if (HasEmptyFrame()) {
Alexey Frunze58320ce2016-08-30 21:40:46 -0700697 CHECK_EQ(fpu_spill_mask_, 0u);
698 CHECK_EQ(core_spill_mask_, 1u << RA);
699 CHECK(!clobbered_ra_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200700 return;
701 }
702
703 // Make sure the frame size isn't unreasonably large.
704 if (GetFrameSize() > GetStackOverflowReservedBytes(kMips)) {
705 LOG(FATAL) << "Stack frame larger than " << GetStackOverflowReservedBytes(kMips) << " bytes";
706 }
707
708 // Spill callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200709
Alexey Frunze73296a72016-06-03 22:51:46 -0700710 uint32_t ofs = GetFrameSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200711 __ IncreaseFrameSize(ofs);
712
Alexey Frunze73296a72016-06-03 22:51:46 -0700713 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
714 Register reg = static_cast<Register>(MostSignificantBit(mask));
715 mask ^= 1u << reg;
716 ofs -= kMipsWordSize;
717 // The ZERO register is only included for alignment.
718 if (reg != ZERO) {
719 __ StoreToOffset(kStoreWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200720 __ cfi().RelOffset(DWARFReg(reg), ofs);
721 }
722 }
723
Alexey Frunze73296a72016-06-03 22:51:46 -0700724 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
725 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
726 mask ^= 1u << reg;
727 ofs -= kMipsDoublewordSize;
728 __ StoreDToOffset(reg, SP, ofs);
729 // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200730 }
731
Alexey Frunze73296a72016-06-03 22:51:46 -0700732 // Store the current method pointer.
Alexey Frunze58320ce2016-08-30 21:40:46 -0700733 // TODO: can we not do this if RequiresCurrentMethod() returns false?
Alexey Frunze73296a72016-06-03 22:51:46 -0700734 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, kCurrentMethodStackOffset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200735}
736
737void CodeGeneratorMIPS::GenerateFrameExit() {
738 __ cfi().RememberState();
739
740 if (!HasEmptyFrame()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200741 // Restore callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200742
Alexey Frunze73296a72016-06-03 22:51:46 -0700743 // For better instruction scheduling restore RA before other registers.
744 uint32_t ofs = GetFrameSize();
745 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
746 Register reg = static_cast<Register>(MostSignificantBit(mask));
747 mask ^= 1u << reg;
748 ofs -= kMipsWordSize;
749 // The ZERO register is only included for alignment.
750 if (reg != ZERO) {
751 __ LoadFromOffset(kLoadWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200752 __ cfi().Restore(DWARFReg(reg));
753 }
754 }
755
Alexey Frunze73296a72016-06-03 22:51:46 -0700756 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
757 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
758 mask ^= 1u << reg;
759 ofs -= kMipsDoublewordSize;
760 __ LoadDFromOffset(reg, SP, ofs);
761 // TODO: __ cfi().Restore(DWARFReg(reg));
762 }
763
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700764 size_t frame_size = GetFrameSize();
765 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
766 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
767 bool reordering = __ SetReorder(false);
768 if (exchange) {
769 __ Jr(RA);
770 __ DecreaseFrameSize(frame_size); // Single instruction in delay slot.
771 } else {
772 __ DecreaseFrameSize(frame_size);
773 __ Jr(RA);
774 __ Nop(); // In delay slot.
775 }
776 __ SetReorder(reordering);
777 } else {
778 __ Jr(RA);
779 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200780 }
781
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200782 __ cfi().RestoreState();
783 __ cfi().DefCFAOffset(GetFrameSize());
784}
785
786void CodeGeneratorMIPS::Bind(HBasicBlock* block) {
787 __ Bind(GetLabelOf(block));
788}
789
790void CodeGeneratorMIPS::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
791 if (src.Equals(dst)) {
792 return;
793 }
794
795 if (src.IsConstant()) {
796 MoveConstant(dst, src.GetConstant());
797 } else {
798 if (Primitive::Is64BitType(dst_type)) {
799 Move64(dst, src);
800 } else {
801 Move32(dst, src);
802 }
803 }
804}
805
806void CodeGeneratorMIPS::Move32(Location destination, Location source) {
807 if (source.Equals(destination)) {
808 return;
809 }
810
811 if (destination.IsRegister()) {
812 if (source.IsRegister()) {
813 __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
814 } else if (source.IsFpuRegister()) {
815 __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
816 } else {
817 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
818 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
819 }
820 } else if (destination.IsFpuRegister()) {
821 if (source.IsRegister()) {
822 __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
823 } else if (source.IsFpuRegister()) {
824 __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
825 } else {
826 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
827 __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
828 }
829 } else {
830 DCHECK(destination.IsStackSlot()) << destination;
831 if (source.IsRegister()) {
832 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
833 } else if (source.IsFpuRegister()) {
834 __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, destination.GetStackIndex());
835 } else {
836 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
837 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
838 __ StoreToOffset(kStoreWord, TMP, SP, destination.GetStackIndex());
839 }
840 }
841}
842
843void CodeGeneratorMIPS::Move64(Location destination, Location source) {
844 if (source.Equals(destination)) {
845 return;
846 }
847
848 if (destination.IsRegisterPair()) {
849 if (source.IsRegisterPair()) {
850 __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
851 __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
852 } else if (source.IsFpuRegister()) {
853 Register dst_high = destination.AsRegisterPairHigh<Register>();
854 Register dst_low = destination.AsRegisterPairLow<Register>();
855 FRegister src = source.AsFpuRegister<FRegister>();
856 __ Mfc1(dst_low, src);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800857 __ MoveFromFpuHigh(dst_high, src);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200858 } else {
859 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
860 int32_t off = source.GetStackIndex();
861 Register r = destination.AsRegisterPairLow<Register>();
862 __ LoadFromOffset(kLoadDoubleword, r, SP, off);
863 }
864 } else if (destination.IsFpuRegister()) {
865 if (source.IsRegisterPair()) {
866 FRegister dst = destination.AsFpuRegister<FRegister>();
867 Register src_high = source.AsRegisterPairHigh<Register>();
868 Register src_low = source.AsRegisterPairLow<Register>();
869 __ Mtc1(src_low, dst);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800870 __ MoveToFpuHigh(src_high, dst);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200871 } else if (source.IsFpuRegister()) {
872 __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
873 } else {
874 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
875 __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
876 }
877 } else {
878 DCHECK(destination.IsDoubleStackSlot()) << destination;
879 int32_t off = destination.GetStackIndex();
880 if (source.IsRegisterPair()) {
881 __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, off);
882 } else if (source.IsFpuRegister()) {
883 __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, off);
884 } else {
885 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
886 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
887 __ StoreToOffset(kStoreWord, TMP, SP, off);
888 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
889 __ StoreToOffset(kStoreWord, TMP, SP, off + 4);
890 }
891 }
892}
893
894void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) {
895 if (c->IsIntConstant() || c->IsNullConstant()) {
896 // Move 32 bit constant.
897 int32_t value = GetInt32ValueOf(c);
898 if (destination.IsRegister()) {
899 Register dst = destination.AsRegister<Register>();
900 __ LoadConst32(dst, value);
901 } else {
902 DCHECK(destination.IsStackSlot())
903 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700904 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200905 }
906 } else if (c->IsLongConstant()) {
907 // Move 64 bit constant.
908 int64_t value = GetInt64ValueOf(c);
909 if (destination.IsRegisterPair()) {
910 Register r_h = destination.AsRegisterPairHigh<Register>();
911 Register r_l = destination.AsRegisterPairLow<Register>();
912 __ LoadConst64(r_h, r_l, value);
913 } else {
914 DCHECK(destination.IsDoubleStackSlot())
915 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700916 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200917 }
918 } else if (c->IsFloatConstant()) {
919 // Move 32 bit float constant.
920 int32_t value = GetInt32ValueOf(c);
921 if (destination.IsFpuRegister()) {
922 __ LoadSConst32(destination.AsFpuRegister<FRegister>(), value, TMP);
923 } else {
924 DCHECK(destination.IsStackSlot())
925 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700926 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200927 }
928 } else {
929 // Move 64 bit double constant.
930 DCHECK(c->IsDoubleConstant()) << c->DebugName();
931 int64_t value = GetInt64ValueOf(c);
932 if (destination.IsFpuRegister()) {
933 FRegister fd = destination.AsFpuRegister<FRegister>();
934 __ LoadDConst64(fd, value, TMP);
935 } else {
936 DCHECK(destination.IsDoubleStackSlot())
937 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700938 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200939 }
940 }
941}
942
943void CodeGeneratorMIPS::MoveConstant(Location destination, int32_t value) {
944 DCHECK(destination.IsRegister());
945 Register dst = destination.AsRegister<Register>();
946 __ LoadConst32(dst, value);
947}
948
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200949void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
950 if (location.IsRegister()) {
951 locations->AddTemp(location);
Alexey Frunzec9e94f32015-10-26 16:11:39 -0700952 } else if (location.IsRegisterPair()) {
953 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
954 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200955 } else {
956 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
957 }
958}
959
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700960void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
961 DCHECK(linker_patches->empty());
962 size_t size =
963 method_patches_.size() +
964 call_patches_.size() +
Alexey Frunze06a46c42016-07-19 15:00:40 -0700965 pc_relative_dex_cache_patches_.size() +
966 pc_relative_string_patches_.size() +
967 pc_relative_type_patches_.size() +
968 boot_image_string_patches_.size() +
969 boot_image_type_patches_.size() +
970 boot_image_address_patches_.size();
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700971 linker_patches->reserve(size);
972 for (const auto& entry : method_patches_) {
973 const MethodReference& target_method = entry.first;
974 Literal* literal = entry.second;
975 DCHECK(literal->GetLabel()->IsBound());
976 uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
977 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
978 target_method.dex_file,
979 target_method.dex_method_index));
980 }
981 for (const auto& entry : call_patches_) {
982 const MethodReference& target_method = entry.first;
983 Literal* literal = entry.second;
984 DCHECK(literal->GetLabel()->IsBound());
985 uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
986 linker_patches->push_back(LinkerPatch::CodePatch(literal_offset,
987 target_method.dex_file,
988 target_method.dex_method_index));
989 }
990 for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
991 const DexFile& dex_file = info.target_dex_file;
992 size_t base_element_offset = info.offset_or_index;
993 DCHECK(info.high_label.IsBound());
994 uint32_t high_offset = __ GetLabelLocation(&info.high_label);
995 DCHECK(info.pc_rel_label.IsBound());
996 uint32_t pc_rel_offset = __ GetLabelLocation(&info.pc_rel_label);
997 linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(high_offset,
998 &dex_file,
999 pc_rel_offset,
1000 base_element_offset));
1001 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07001002 for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
1003 const DexFile& dex_file = info.target_dex_file;
1004 size_t string_index = info.offset_or_index;
1005 DCHECK(info.high_label.IsBound());
1006 uint32_t high_offset = __ GetLabelLocation(&info.high_label);
1007 // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
1008 // the assembler's base label used for PC-relative literals.
1009 uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
1010 ? __ GetLabelLocation(&info.pc_rel_label)
1011 : __ GetPcRelBaseLabelLocation();
1012 linker_patches->push_back(LinkerPatch::RelativeStringPatch(high_offset,
1013 &dex_file,
1014 pc_rel_offset,
1015 string_index));
1016 }
1017 for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
1018 const DexFile& dex_file = info.target_dex_file;
1019 size_t type_index = info.offset_or_index;
1020 DCHECK(info.high_label.IsBound());
1021 uint32_t high_offset = __ GetLabelLocation(&info.high_label);
1022 // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
1023 // the assembler's base label used for PC-relative literals.
1024 uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
1025 ? __ GetLabelLocation(&info.pc_rel_label)
1026 : __ GetPcRelBaseLabelLocation();
1027 linker_patches->push_back(LinkerPatch::RelativeTypePatch(high_offset,
1028 &dex_file,
1029 pc_rel_offset,
1030 type_index));
1031 }
1032 for (const auto& entry : boot_image_string_patches_) {
1033 const StringReference& target_string = entry.first;
1034 Literal* literal = entry.second;
1035 DCHECK(literal->GetLabel()->IsBound());
1036 uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1037 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
1038 target_string.dex_file,
1039 target_string.string_index));
1040 }
1041 for (const auto& entry : boot_image_type_patches_) {
1042 const TypeReference& target_type = entry.first;
1043 Literal* literal = entry.second;
1044 DCHECK(literal->GetLabel()->IsBound());
1045 uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1046 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
1047 target_type.dex_file,
1048 target_type.type_index));
1049 }
1050 for (const auto& entry : boot_image_address_patches_) {
1051 DCHECK(GetCompilerOptions().GetIncludePatchInformation());
1052 Literal* literal = entry.second;
1053 DCHECK(literal->GetLabel()->IsBound());
1054 uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1055 linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
1056 }
1057}
1058
1059CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPatch(
1060 const DexFile& dex_file, uint32_t string_index) {
1061 return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_);
1062}
1063
1064CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
1065 const DexFile& dex_file, uint32_t type_index) {
1066 return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001067}
1068
1069CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch(
1070 const DexFile& dex_file, uint32_t element_offset) {
1071 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
1072}
1073
1074CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
1075 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
1076 patches->emplace_back(dex_file, offset_or_index);
1077 return &patches->back();
1078}
1079
Alexey Frunze06a46c42016-07-19 15:00:40 -07001080Literal* CodeGeneratorMIPS::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
1081 return map->GetOrCreate(
1082 value,
1083 [this, value]() { return __ NewLiteral<uint32_t>(value); });
1084}
1085
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001086Literal* CodeGeneratorMIPS::DeduplicateMethodLiteral(MethodReference target_method,
1087 MethodToLiteralMap* map) {
1088 return map->GetOrCreate(
1089 target_method,
1090 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1091}
1092
1093Literal* CodeGeneratorMIPS::DeduplicateMethodAddressLiteral(MethodReference target_method) {
1094 return DeduplicateMethodLiteral(target_method, &method_patches_);
1095}
1096
1097Literal* CodeGeneratorMIPS::DeduplicateMethodCodeLiteral(MethodReference target_method) {
1098 return DeduplicateMethodLiteral(target_method, &call_patches_);
1099}
1100
Alexey Frunze06a46c42016-07-19 15:00:40 -07001101Literal* CodeGeneratorMIPS::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
1102 uint32_t string_index) {
1103 return boot_image_string_patches_.GetOrCreate(
1104 StringReference(&dex_file, string_index),
1105 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1106}
1107
1108Literal* CodeGeneratorMIPS::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
1109 uint32_t type_index) {
1110 return boot_image_type_patches_.GetOrCreate(
1111 TypeReference(&dex_file, type_index),
1112 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1113}
1114
1115Literal* CodeGeneratorMIPS::DeduplicateBootImageAddressLiteral(uint32_t address) {
1116 bool needs_patch = GetCompilerOptions().GetIncludePatchInformation();
1117 Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_;
1118 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
1119}
1120
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001121void CodeGeneratorMIPS::MarkGCCard(Register object, Register value) {
1122 MipsLabel done;
1123 Register card = AT;
1124 Register temp = TMP;
1125 __ Beqz(value, &done);
1126 __ LoadFromOffset(kLoadWord,
1127 card,
1128 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07001129 Thread::CardTableOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001130 __ Srl(temp, object, gc::accounting::CardTable::kCardShift);
1131 __ Addu(temp, card, temp);
1132 __ Sb(card, temp, 0);
1133 __ Bind(&done);
1134}
1135
David Brazdil58282f42016-01-14 12:45:10 +00001136void CodeGeneratorMIPS::SetupBlockedRegisters() const {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001137 // Don't allocate the dalvik style register pair passing.
1138 blocked_register_pairs_[A1_A2] = true;
1139
1140 // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated.
1141 blocked_core_registers_[ZERO] = true;
1142 blocked_core_registers_[K0] = true;
1143 blocked_core_registers_[K1] = true;
1144 blocked_core_registers_[GP] = true;
1145 blocked_core_registers_[SP] = true;
1146 blocked_core_registers_[RA] = true;
1147
1148 // AT and TMP(T8) are used as temporary/scratch registers
1149 // (similar to how AT is used by MIPS assemblers).
1150 blocked_core_registers_[AT] = true;
1151 blocked_core_registers_[TMP] = true;
1152 blocked_fpu_registers_[FTMP] = true;
1153
1154 // Reserve suspend and thread registers.
1155 blocked_core_registers_[S0] = true;
1156 blocked_core_registers_[TR] = true;
1157
1158 // Reserve T9 for function calls
1159 blocked_core_registers_[T9] = true;
1160
1161 // Reserve odd-numbered FPU registers.
1162 for (size_t i = 1; i < kNumberOfFRegisters; i += 2) {
1163 blocked_fpu_registers_[i] = true;
1164 }
1165
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02001166 if (GetGraph()->IsDebuggable()) {
1167 // Stubs do not save callee-save floating point registers. If the graph
1168 // is debuggable, we need to deal with these registers differently. For
1169 // now, just block them.
1170 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1171 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
1172 }
1173 }
1174
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001175 UpdateBlockedPairRegisters();
1176}
1177
1178void CodeGeneratorMIPS::UpdateBlockedPairRegisters() const {
1179 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
1180 MipsManagedRegister current =
1181 MipsManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
1182 if (blocked_core_registers_[current.AsRegisterPairLow()]
1183 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
1184 blocked_register_pairs_[i] = true;
1185 }
1186 }
1187}
1188
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001189size_t CodeGeneratorMIPS::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1190 __ StoreToOffset(kStoreWord, Register(reg_id), SP, stack_index);
1191 return kMipsWordSize;
1192}
1193
1194size_t CodeGeneratorMIPS::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1195 __ LoadFromOffset(kLoadWord, Register(reg_id), SP, stack_index);
1196 return kMipsWordSize;
1197}
1198
1199size_t CodeGeneratorMIPS::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1200 __ StoreDToOffset(FRegister(reg_id), SP, stack_index);
1201 return kMipsDoublewordSize;
1202}
1203
1204size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1205 __ LoadDFromOffset(FRegister(reg_id), SP, stack_index);
1206 return kMipsDoublewordSize;
1207}
1208
1209void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001210 stream << Register(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001211}
1212
1213void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001214 stream << FRegister(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001215}
1216
Serban Constantinescufca16662016-07-14 09:21:59 +01001217constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16;
1218
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001219void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
1220 HInstruction* instruction,
1221 uint32_t dex_pc,
1222 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001223 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001224 bool reordering = __ SetReorder(false);
Serban Constantinescufca16662016-07-14 09:21:59 +01001225 __ LoadFromOffset(kLoadWord, T9, TR, GetThreadOffset<kMipsPointerSize>(entrypoint).Int32Value());
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001226 __ Jalr(T9);
Serban Constantinescufca16662016-07-14 09:21:59 +01001227 if (IsDirectEntrypoint(entrypoint)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001228 // Reserve argument space on stack (for $a0-$a3) for
1229 // entrypoints that directly reference native implementations.
1230 // Called function may use this space to store $a0-$a3 regs.
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001231 __ IncreaseFrameSize(kMipsDirectEntrypointRuntimeOffset); // Single instruction in delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001232 __ DecreaseFrameSize(kMipsDirectEntrypointRuntimeOffset);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001233 } else {
1234 __ Nop(); // In delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001235 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001236 __ SetReorder(reordering);
Serban Constantinescufca16662016-07-14 09:21:59 +01001237 if (EntrypointRequiresStackMap(entrypoint)) {
1238 RecordPcInfo(instruction, dex_pc, slow_path);
1239 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001240}
1241
1242void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
1243 Register class_reg) {
1244 __ LoadFromOffset(kLoadWord, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
1245 __ LoadConst32(AT, mirror::Class::kStatusInitialized);
1246 __ Blt(TMP, AT, slow_path->GetEntryLabel());
1247 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1248 __ Sync(0);
1249 __ Bind(slow_path->GetExitLabel());
1250}
1251
1252void InstructionCodeGeneratorMIPS::GenerateMemoryBarrier(MemBarrierKind kind ATTRIBUTE_UNUSED) {
1253 __ Sync(0); // Only stype 0 is supported.
1254}
1255
1256void InstructionCodeGeneratorMIPS::GenerateSuspendCheck(HSuspendCheck* instruction,
1257 HBasicBlock* successor) {
1258 SuspendCheckSlowPathMIPS* slow_path =
1259 new (GetGraph()->GetArena()) SuspendCheckSlowPathMIPS(instruction, successor);
1260 codegen_->AddSlowPath(slow_path);
1261
1262 __ LoadFromOffset(kLoadUnsignedHalfword,
1263 TMP,
1264 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07001265 Thread::ThreadFlagsOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001266 if (successor == nullptr) {
1267 __ Bnez(TMP, slow_path->GetEntryLabel());
1268 __ Bind(slow_path->GetReturnLabel());
1269 } else {
1270 __ Beqz(TMP, codegen_->GetLabelOf(successor));
1271 __ B(slow_path->GetEntryLabel());
1272 // slow_path will return to GetLabelOf(successor).
1273 }
1274}
1275
1276InstructionCodeGeneratorMIPS::InstructionCodeGeneratorMIPS(HGraph* graph,
1277 CodeGeneratorMIPS* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001278 : InstructionCodeGenerator(graph, codegen),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001279 assembler_(codegen->GetAssembler()),
1280 codegen_(codegen) {}
1281
1282void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1283 DCHECK_EQ(instruction->InputCount(), 2U);
1284 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1285 Primitive::Type type = instruction->GetResultType();
1286 switch (type) {
1287 case Primitive::kPrimInt: {
1288 locations->SetInAt(0, Location::RequiresRegister());
1289 HInstruction* right = instruction->InputAt(1);
1290 bool can_use_imm = false;
1291 if (right->IsConstant()) {
1292 int32_t imm = CodeGenerator::GetInt32ValueOf(right->AsConstant());
1293 if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
1294 can_use_imm = IsUint<16>(imm);
1295 } else if (instruction->IsAdd()) {
1296 can_use_imm = IsInt<16>(imm);
1297 } else {
1298 DCHECK(instruction->IsSub());
1299 can_use_imm = IsInt<16>(-imm);
1300 }
1301 }
1302 if (can_use_imm)
1303 locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
1304 else
1305 locations->SetInAt(1, Location::RequiresRegister());
1306 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1307 break;
1308 }
1309
1310 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001311 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001312 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1313 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001314 break;
1315 }
1316
1317 case Primitive::kPrimFloat:
1318 case Primitive::kPrimDouble:
1319 DCHECK(instruction->IsAdd() || instruction->IsSub());
1320 locations->SetInAt(0, Location::RequiresFpuRegister());
1321 locations->SetInAt(1, Location::RequiresFpuRegister());
1322 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1323 break;
1324
1325 default:
1326 LOG(FATAL) << "Unexpected " << instruction->DebugName() << " type " << type;
1327 }
1328}
1329
1330void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1331 Primitive::Type type = instruction->GetType();
1332 LocationSummary* locations = instruction->GetLocations();
1333
1334 switch (type) {
1335 case Primitive::kPrimInt: {
1336 Register dst = locations->Out().AsRegister<Register>();
1337 Register lhs = locations->InAt(0).AsRegister<Register>();
1338 Location rhs_location = locations->InAt(1);
1339
1340 Register rhs_reg = ZERO;
1341 int32_t rhs_imm = 0;
1342 bool use_imm = rhs_location.IsConstant();
1343 if (use_imm) {
1344 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
1345 } else {
1346 rhs_reg = rhs_location.AsRegister<Register>();
1347 }
1348
1349 if (instruction->IsAnd()) {
1350 if (use_imm)
1351 __ Andi(dst, lhs, rhs_imm);
1352 else
1353 __ And(dst, lhs, rhs_reg);
1354 } else if (instruction->IsOr()) {
1355 if (use_imm)
1356 __ Ori(dst, lhs, rhs_imm);
1357 else
1358 __ Or(dst, lhs, rhs_reg);
1359 } else if (instruction->IsXor()) {
1360 if (use_imm)
1361 __ Xori(dst, lhs, rhs_imm);
1362 else
1363 __ Xor(dst, lhs, rhs_reg);
1364 } else if (instruction->IsAdd()) {
1365 if (use_imm)
1366 __ Addiu(dst, lhs, rhs_imm);
1367 else
1368 __ Addu(dst, lhs, rhs_reg);
1369 } else {
1370 DCHECK(instruction->IsSub());
1371 if (use_imm)
1372 __ Addiu(dst, lhs, -rhs_imm);
1373 else
1374 __ Subu(dst, lhs, rhs_reg);
1375 }
1376 break;
1377 }
1378
1379 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001380 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
1381 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
1382 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
1383 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001384 Location rhs_location = locations->InAt(1);
1385 bool use_imm = rhs_location.IsConstant();
1386 if (!use_imm) {
1387 Register rhs_high = rhs_location.AsRegisterPairHigh<Register>();
1388 Register rhs_low = rhs_location.AsRegisterPairLow<Register>();
1389 if (instruction->IsAnd()) {
1390 __ And(dst_low, lhs_low, rhs_low);
1391 __ And(dst_high, lhs_high, rhs_high);
1392 } else if (instruction->IsOr()) {
1393 __ Or(dst_low, lhs_low, rhs_low);
1394 __ Or(dst_high, lhs_high, rhs_high);
1395 } else if (instruction->IsXor()) {
1396 __ Xor(dst_low, lhs_low, rhs_low);
1397 __ Xor(dst_high, lhs_high, rhs_high);
1398 } else if (instruction->IsAdd()) {
1399 if (lhs_low == rhs_low) {
1400 // Special case for lhs = rhs and the sum potentially overwriting both lhs and rhs.
1401 __ Slt(TMP, lhs_low, ZERO);
1402 __ Addu(dst_low, lhs_low, rhs_low);
1403 } else {
1404 __ Addu(dst_low, lhs_low, rhs_low);
1405 // If the sum overwrites rhs, lhs remains unchanged, otherwise rhs remains unchanged.
1406 __ Sltu(TMP, dst_low, (dst_low == rhs_low) ? lhs_low : rhs_low);
1407 }
1408 __ Addu(dst_high, lhs_high, rhs_high);
1409 __ Addu(dst_high, dst_high, TMP);
1410 } else {
1411 DCHECK(instruction->IsSub());
1412 __ Sltu(TMP, lhs_low, rhs_low);
1413 __ Subu(dst_low, lhs_low, rhs_low);
1414 __ Subu(dst_high, lhs_high, rhs_high);
1415 __ Subu(dst_high, dst_high, TMP);
1416 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001417 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001418 int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
1419 if (instruction->IsOr()) {
1420 uint32_t low = Low32Bits(value);
1421 uint32_t high = High32Bits(value);
1422 if (IsUint<16>(low)) {
1423 if (dst_low != lhs_low || low != 0) {
1424 __ Ori(dst_low, lhs_low, low);
1425 }
1426 } else {
1427 __ LoadConst32(TMP, low);
1428 __ Or(dst_low, lhs_low, TMP);
1429 }
1430 if (IsUint<16>(high)) {
1431 if (dst_high != lhs_high || high != 0) {
1432 __ Ori(dst_high, lhs_high, high);
1433 }
1434 } else {
1435 if (high != low) {
1436 __ LoadConst32(TMP, high);
1437 }
1438 __ Or(dst_high, lhs_high, TMP);
1439 }
1440 } else if (instruction->IsXor()) {
1441 uint32_t low = Low32Bits(value);
1442 uint32_t high = High32Bits(value);
1443 if (IsUint<16>(low)) {
1444 if (dst_low != lhs_low || low != 0) {
1445 __ Xori(dst_low, lhs_low, low);
1446 }
1447 } else {
1448 __ LoadConst32(TMP, low);
1449 __ Xor(dst_low, lhs_low, TMP);
1450 }
1451 if (IsUint<16>(high)) {
1452 if (dst_high != lhs_high || high != 0) {
1453 __ Xori(dst_high, lhs_high, high);
1454 }
1455 } else {
1456 if (high != low) {
1457 __ LoadConst32(TMP, high);
1458 }
1459 __ Xor(dst_high, lhs_high, TMP);
1460 }
1461 } else if (instruction->IsAnd()) {
1462 uint32_t low = Low32Bits(value);
1463 uint32_t high = High32Bits(value);
1464 if (IsUint<16>(low)) {
1465 __ Andi(dst_low, lhs_low, low);
1466 } else if (low != 0xFFFFFFFF) {
1467 __ LoadConst32(TMP, low);
1468 __ And(dst_low, lhs_low, TMP);
1469 } else if (dst_low != lhs_low) {
1470 __ Move(dst_low, lhs_low);
1471 }
1472 if (IsUint<16>(high)) {
1473 __ Andi(dst_high, lhs_high, high);
1474 } else if (high != 0xFFFFFFFF) {
1475 if (high != low) {
1476 __ LoadConst32(TMP, high);
1477 }
1478 __ And(dst_high, lhs_high, TMP);
1479 } else if (dst_high != lhs_high) {
1480 __ Move(dst_high, lhs_high);
1481 }
1482 } else {
1483 if (instruction->IsSub()) {
1484 value = -value;
1485 } else {
1486 DCHECK(instruction->IsAdd());
1487 }
1488 int32_t low = Low32Bits(value);
1489 int32_t high = High32Bits(value);
1490 if (IsInt<16>(low)) {
1491 if (dst_low != lhs_low || low != 0) {
1492 __ Addiu(dst_low, lhs_low, low);
1493 }
1494 if (low != 0) {
1495 __ Sltiu(AT, dst_low, low);
1496 }
1497 } else {
1498 __ LoadConst32(TMP, low);
1499 __ Addu(dst_low, lhs_low, TMP);
1500 __ Sltu(AT, dst_low, TMP);
1501 }
1502 if (IsInt<16>(high)) {
1503 if (dst_high != lhs_high || high != 0) {
1504 __ Addiu(dst_high, lhs_high, high);
1505 }
1506 } else {
1507 if (high != low) {
1508 __ LoadConst32(TMP, high);
1509 }
1510 __ Addu(dst_high, lhs_high, TMP);
1511 }
1512 if (low != 0) {
1513 __ Addu(dst_high, dst_high, AT);
1514 }
1515 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001516 }
1517 break;
1518 }
1519
1520 case Primitive::kPrimFloat:
1521 case Primitive::kPrimDouble: {
1522 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
1523 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
1524 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
1525 if (instruction->IsAdd()) {
1526 if (type == Primitive::kPrimFloat) {
1527 __ AddS(dst, lhs, rhs);
1528 } else {
1529 __ AddD(dst, lhs, rhs);
1530 }
1531 } else {
1532 DCHECK(instruction->IsSub());
1533 if (type == Primitive::kPrimFloat) {
1534 __ SubS(dst, lhs, rhs);
1535 } else {
1536 __ SubD(dst, lhs, rhs);
1537 }
1538 }
1539 break;
1540 }
1541
1542 default:
1543 LOG(FATAL) << "Unexpected binary operation type " << type;
1544 }
1545}
1546
1547void LocationsBuilderMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001548 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001549
1550 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1551 Primitive::Type type = instr->GetResultType();
1552 switch (type) {
1553 case Primitive::kPrimInt:
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001554 locations->SetInAt(0, Location::RequiresRegister());
1555 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1556 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1557 break;
1558 case Primitive::kPrimLong:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001559 locations->SetInAt(0, Location::RequiresRegister());
1560 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1561 locations->SetOut(Location::RequiresRegister());
1562 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001563 default:
1564 LOG(FATAL) << "Unexpected shift type " << type;
1565 }
1566}
1567
1568static constexpr size_t kMipsBitsPerWord = kMipsWordSize * kBitsPerByte;
1569
1570void InstructionCodeGeneratorMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001571 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001572 LocationSummary* locations = instr->GetLocations();
1573 Primitive::Type type = instr->GetType();
1574
1575 Location rhs_location = locations->InAt(1);
1576 bool use_imm = rhs_location.IsConstant();
1577 Register rhs_reg = use_imm ? ZERO : rhs_location.AsRegister<Register>();
1578 int64_t rhs_imm = use_imm ? CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()) : 0;
Roland Levillain5b5b9312016-03-22 14:57:31 +00001579 const uint32_t shift_mask =
1580 (type == Primitive::kPrimInt) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001581 const uint32_t shift_value = rhs_imm & shift_mask;
Alexey Frunze92d90602015-12-18 18:16:36 -08001582 // Are the INS (Insert Bit Field) and ROTR instructions supported?
1583 bool has_ins_rotr = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001584
1585 switch (type) {
1586 case Primitive::kPrimInt: {
1587 Register dst = locations->Out().AsRegister<Register>();
1588 Register lhs = locations->InAt(0).AsRegister<Register>();
1589 if (use_imm) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001590 if (shift_value == 0) {
1591 if (dst != lhs) {
1592 __ Move(dst, lhs);
1593 }
1594 } else if (instr->IsShl()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001595 __ Sll(dst, lhs, shift_value);
1596 } else if (instr->IsShr()) {
1597 __ Sra(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001598 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001599 __ Srl(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001600 } else {
1601 if (has_ins_rotr) {
1602 __ Rotr(dst, lhs, shift_value);
1603 } else {
1604 __ Sll(TMP, lhs, (kMipsBitsPerWord - shift_value) & shift_mask);
1605 __ Srl(dst, lhs, shift_value);
1606 __ Or(dst, dst, TMP);
1607 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001608 }
1609 } else {
1610 if (instr->IsShl()) {
1611 __ Sllv(dst, lhs, rhs_reg);
1612 } else if (instr->IsShr()) {
1613 __ Srav(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08001614 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001615 __ Srlv(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08001616 } else {
1617 if (has_ins_rotr) {
1618 __ Rotrv(dst, lhs, rhs_reg);
1619 } else {
1620 __ Subu(TMP, ZERO, rhs_reg);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001621 // 32-bit shift instructions use the 5 least significant bits of the shift count, so
1622 // shifting by `-rhs_reg` is equivalent to shifting by `(32 - rhs_reg) & 31`. The case
1623 // when `rhs_reg & 31 == 0` is OK even though we don't shift `lhs` left all the way out
1624 // by 32, because the result in this case is computed as `(lhs >> 0) | (lhs << 0)`,
1625 // IOW, the OR'd values are equal.
Alexey Frunze92d90602015-12-18 18:16:36 -08001626 __ Sllv(TMP, lhs, TMP);
1627 __ Srlv(dst, lhs, rhs_reg);
1628 __ Or(dst, dst, TMP);
1629 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001630 }
1631 }
1632 break;
1633 }
1634
1635 case Primitive::kPrimLong: {
1636 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
1637 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
1638 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
1639 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
1640 if (use_imm) {
1641 if (shift_value == 0) {
1642 codegen_->Move64(locations->Out(), locations->InAt(0));
1643 } else if (shift_value < kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001644 if (has_ins_rotr) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001645 if (instr->IsShl()) {
1646 __ Srl(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
1647 __ Ins(dst_high, lhs_high, shift_value, kMipsBitsPerWord - shift_value);
1648 __ Sll(dst_low, lhs_low, shift_value);
1649 } else if (instr->IsShr()) {
1650 __ Srl(dst_low, lhs_low, shift_value);
1651 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1652 __ Sra(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001653 } else if (instr->IsUShr()) {
1654 __ Srl(dst_low, lhs_low, shift_value);
1655 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1656 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001657 } else {
1658 __ Srl(dst_low, lhs_low, shift_value);
1659 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1660 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001661 __ Ins(dst_high, lhs_low, kMipsBitsPerWord - shift_value, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001662 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001663 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001664 if (instr->IsShl()) {
1665 __ Sll(dst_low, lhs_low, shift_value);
1666 __ Srl(TMP, lhs_low, kMipsBitsPerWord - shift_value);
1667 __ Sll(dst_high, lhs_high, shift_value);
1668 __ Or(dst_high, dst_high, TMP);
1669 } else if (instr->IsShr()) {
1670 __ Sra(dst_high, lhs_high, shift_value);
1671 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
1672 __ Srl(dst_low, lhs_low, shift_value);
1673 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08001674 } else if (instr->IsUShr()) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001675 __ Srl(dst_high, lhs_high, shift_value);
1676 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
1677 __ Srl(dst_low, lhs_low, shift_value);
1678 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08001679 } else {
1680 __ Srl(TMP, lhs_low, shift_value);
1681 __ Sll(dst_low, lhs_high, kMipsBitsPerWord - shift_value);
1682 __ Or(dst_low, dst_low, TMP);
1683 __ Srl(TMP, lhs_high, shift_value);
1684 __ Sll(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
1685 __ Or(dst_high, dst_high, TMP);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001686 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001687 }
1688 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001689 const uint32_t shift_value_high = shift_value - kMipsBitsPerWord;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001690 if (instr->IsShl()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001691 __ Sll(dst_high, lhs_low, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001692 __ Move(dst_low, ZERO);
1693 } else if (instr->IsShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001694 __ Sra(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001695 __ Sra(dst_high, dst_low, kMipsBitsPerWord - 1);
Alexey Frunze92d90602015-12-18 18:16:36 -08001696 } else if (instr->IsUShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001697 __ Srl(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001698 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08001699 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001700 if (shift_value == kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001701 // 64-bit rotation by 32 is just a swap.
1702 __ Move(dst_low, lhs_high);
1703 __ Move(dst_high, lhs_low);
1704 } else {
1705 if (has_ins_rotr) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001706 __ Srl(dst_low, lhs_high, shift_value_high);
1707 __ Ins(dst_low, lhs_low, kMipsBitsPerWord - shift_value_high, shift_value_high);
1708 __ Srl(dst_high, lhs_low, shift_value_high);
1709 __ Ins(dst_high, lhs_high, kMipsBitsPerWord - shift_value_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001710 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001711 __ Sll(TMP, lhs_low, kMipsBitsPerWord - shift_value_high);
1712 __ Srl(dst_low, lhs_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001713 __ Or(dst_low, dst_low, TMP);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001714 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value_high);
1715 __ Srl(dst_high, lhs_low, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001716 __ Or(dst_high, dst_high, TMP);
1717 }
1718 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001719 }
1720 }
1721 } else {
1722 MipsLabel done;
1723 if (instr->IsShl()) {
1724 __ Sllv(dst_low, lhs_low, rhs_reg);
1725 __ Nor(AT, ZERO, rhs_reg);
1726 __ Srl(TMP, lhs_low, 1);
1727 __ Srlv(TMP, TMP, AT);
1728 __ Sllv(dst_high, lhs_high, rhs_reg);
1729 __ Or(dst_high, dst_high, TMP);
1730 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1731 __ Beqz(TMP, &done);
1732 __ Move(dst_high, dst_low);
1733 __ Move(dst_low, ZERO);
1734 } else if (instr->IsShr()) {
1735 __ Srav(dst_high, lhs_high, rhs_reg);
1736 __ Nor(AT, ZERO, rhs_reg);
1737 __ Sll(TMP, lhs_high, 1);
1738 __ Sllv(TMP, TMP, AT);
1739 __ Srlv(dst_low, lhs_low, rhs_reg);
1740 __ Or(dst_low, dst_low, TMP);
1741 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1742 __ Beqz(TMP, &done);
1743 __ Move(dst_low, dst_high);
1744 __ Sra(dst_high, dst_high, 31);
Alexey Frunze92d90602015-12-18 18:16:36 -08001745 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001746 __ Srlv(dst_high, lhs_high, rhs_reg);
1747 __ Nor(AT, ZERO, rhs_reg);
1748 __ Sll(TMP, lhs_high, 1);
1749 __ Sllv(TMP, TMP, AT);
1750 __ Srlv(dst_low, lhs_low, rhs_reg);
1751 __ Or(dst_low, dst_low, TMP);
1752 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1753 __ Beqz(TMP, &done);
1754 __ Move(dst_low, dst_high);
1755 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08001756 } else {
1757 __ Nor(AT, ZERO, rhs_reg);
1758 __ Srlv(TMP, lhs_low, rhs_reg);
1759 __ Sll(dst_low, lhs_high, 1);
1760 __ Sllv(dst_low, dst_low, AT);
1761 __ Or(dst_low, dst_low, TMP);
1762 __ Srlv(TMP, lhs_high, rhs_reg);
1763 __ Sll(dst_high, lhs_low, 1);
1764 __ Sllv(dst_high, dst_high, AT);
1765 __ Or(dst_high, dst_high, TMP);
1766 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1767 __ Beqz(TMP, &done);
1768 __ Move(TMP, dst_high);
1769 __ Move(dst_high, dst_low);
1770 __ Move(dst_low, TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001771 }
1772 __ Bind(&done);
1773 }
1774 break;
1775 }
1776
1777 default:
1778 LOG(FATAL) << "Unexpected shift operation type " << type;
1779 }
1780}
1781
1782void LocationsBuilderMIPS::VisitAdd(HAdd* instruction) {
1783 HandleBinaryOp(instruction);
1784}
1785
1786void InstructionCodeGeneratorMIPS::VisitAdd(HAdd* instruction) {
1787 HandleBinaryOp(instruction);
1788}
1789
1790void LocationsBuilderMIPS::VisitAnd(HAnd* instruction) {
1791 HandleBinaryOp(instruction);
1792}
1793
1794void InstructionCodeGeneratorMIPS::VisitAnd(HAnd* instruction) {
1795 HandleBinaryOp(instruction);
1796}
1797
1798void LocationsBuilderMIPS::VisitArrayGet(HArrayGet* instruction) {
1799 LocationSummary* locations =
1800 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1801 locations->SetInAt(0, Location::RequiresRegister());
1802 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1803 if (Primitive::IsFloatingPointType(instruction->GetType())) {
1804 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1805 } else {
1806 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1807 }
1808}
1809
Alexey Frunze2923db72016-08-20 01:55:47 -07001810auto InstructionCodeGeneratorMIPS::GetImplicitNullChecker(HInstruction* instruction) {
1811 auto null_checker = [this, instruction]() {
1812 this->codegen_->MaybeRecordImplicitNullCheck(instruction);
1813 };
1814 return null_checker;
1815}
1816
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001817void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
1818 LocationSummary* locations = instruction->GetLocations();
1819 Register obj = locations->InAt(0).AsRegister<Register>();
1820 Location index = locations->InAt(1);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01001821 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Alexey Frunze2923db72016-08-20 01:55:47 -07001822 auto null_checker = GetImplicitNullChecker(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001823
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01001824 Primitive::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001825 switch (type) {
1826 case Primitive::kPrimBoolean: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001827 Register out = locations->Out().AsRegister<Register>();
1828 if (index.IsConstant()) {
1829 size_t offset =
1830 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001831 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001832 } else {
1833 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07001834 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001835 }
1836 break;
1837 }
1838
1839 case Primitive::kPrimByte: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001840 Register out = locations->Out().AsRegister<Register>();
1841 if (index.IsConstant()) {
1842 size_t offset =
1843 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001844 __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001845 } else {
1846 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07001847 __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001848 }
1849 break;
1850 }
1851
1852 case Primitive::kPrimShort: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001853 Register out = locations->Out().AsRegister<Register>();
1854 if (index.IsConstant()) {
1855 size_t offset =
1856 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001857 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001858 } else {
1859 __ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
1860 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07001861 __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001862 }
1863 break;
1864 }
1865
1866 case Primitive::kPrimChar: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001867 Register out = locations->Out().AsRegister<Register>();
1868 if (index.IsConstant()) {
1869 size_t offset =
1870 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001871 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001872 } else {
1873 __ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
1874 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07001875 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001876 }
1877 break;
1878 }
1879
1880 case Primitive::kPrimInt:
1881 case Primitive::kPrimNot: {
1882 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001883 Register out = locations->Out().AsRegister<Register>();
1884 if (index.IsConstant()) {
1885 size_t offset =
1886 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001887 __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001888 } else {
1889 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
1890 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07001891 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001892 }
1893 break;
1894 }
1895
1896 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001897 Register out = locations->Out().AsRegisterPairLow<Register>();
1898 if (index.IsConstant()) {
1899 size_t offset =
1900 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001901 __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001902 } else {
1903 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
1904 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07001905 __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001906 }
1907 break;
1908 }
1909
1910 case Primitive::kPrimFloat: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001911 FRegister out = locations->Out().AsFpuRegister<FRegister>();
1912 if (index.IsConstant()) {
1913 size_t offset =
1914 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001915 __ LoadSFromOffset(out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001916 } else {
1917 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
1918 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07001919 __ LoadSFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001920 }
1921 break;
1922 }
1923
1924 case Primitive::kPrimDouble: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001925 FRegister out = locations->Out().AsFpuRegister<FRegister>();
1926 if (index.IsConstant()) {
1927 size_t offset =
1928 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001929 __ LoadDFromOffset(out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001930 } else {
1931 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
1932 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07001933 __ LoadDFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001934 }
1935 break;
1936 }
1937
1938 case Primitive::kPrimVoid:
1939 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1940 UNREACHABLE();
1941 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001942}
1943
1944void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
1945 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1946 locations->SetInAt(0, Location::RequiresRegister());
1947 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1948}
1949
1950void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) {
1951 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01001952 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001953 Register obj = locations->InAt(0).AsRegister<Register>();
1954 Register out = locations->Out().AsRegister<Register>();
1955 __ LoadFromOffset(kLoadWord, out, obj, offset);
1956 codegen_->MaybeRecordImplicitNullCheck(instruction);
1957}
1958
Alexey Frunzef58b2482016-09-02 22:14:06 -07001959Location LocationsBuilderMIPS::RegisterOrZeroConstant(HInstruction* instruction) {
1960 return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern())
1961 ? Location::ConstantLocation(instruction->AsConstant())
1962 : Location::RequiresRegister();
1963}
1964
1965Location LocationsBuilderMIPS::FpuRegisterOrConstantForStore(HInstruction* instruction) {
1966 // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register.
1967 // We can store a non-zero float or double constant without first loading it into the FPU,
1968 // but we should only prefer this if the constant has a single use.
1969 if (instruction->IsConstant() &&
1970 (instruction->AsConstant()->IsZeroBitPattern() ||
1971 instruction->GetUses().HasExactlyOneElement())) {
1972 return Location::ConstantLocation(instruction->AsConstant());
1973 // Otherwise fall through and require an FPU register for the constant.
1974 }
1975 return Location::RequiresFpuRegister();
1976}
1977
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001978void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) {
Pavle Batuta934808f2015-11-03 13:23:54 +01001979 bool needs_runtime_call = instruction->NeedsTypeCheck();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001980 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1981 instruction,
Serban Constantinescu54ff4822016-07-07 18:03:19 +01001982 needs_runtime_call ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Pavle Batuta934808f2015-11-03 13:23:54 +01001983 if (needs_runtime_call) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001984 InvokeRuntimeCallingConvention calling_convention;
1985 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1986 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1987 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1988 } else {
1989 locations->SetInAt(0, Location::RequiresRegister());
1990 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1991 if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07001992 locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001993 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07001994 locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001995 }
1996 }
1997}
1998
1999void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
2000 LocationSummary* locations = instruction->GetLocations();
2001 Register obj = locations->InAt(0).AsRegister<Register>();
2002 Location index = locations->InAt(1);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002003 Location value_location = locations->InAt(2);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002004 Primitive::Type value_type = instruction->GetComponentType();
2005 bool needs_runtime_call = locations->WillCall();
2006 bool needs_write_barrier =
2007 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Alexey Frunze2923db72016-08-20 01:55:47 -07002008 auto null_checker = GetImplicitNullChecker(instruction);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002009 Register base_reg = index.IsConstant() ? obj : TMP;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002010
2011 switch (value_type) {
2012 case Primitive::kPrimBoolean:
2013 case Primitive::kPrimByte: {
2014 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002015 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002016 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002017 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002018 __ Addu(base_reg, obj, index.AsRegister<Register>());
2019 }
2020 if (value_location.IsConstant()) {
2021 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2022 __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker);
2023 } else {
2024 Register value = value_location.AsRegister<Register>();
2025 __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002026 }
2027 break;
2028 }
2029
2030 case Primitive::kPrimShort:
2031 case Primitive::kPrimChar: {
2032 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002033 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002034 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002035 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002036 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_2);
2037 __ Addu(base_reg, obj, base_reg);
2038 }
2039 if (value_location.IsConstant()) {
2040 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2041 __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker);
2042 } else {
2043 Register value = value_location.AsRegister<Register>();
2044 __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002045 }
2046 break;
2047 }
2048
2049 case Primitive::kPrimInt:
2050 case Primitive::kPrimNot: {
2051 if (!needs_runtime_call) {
2052 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002053 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002054 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002055 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002056 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
2057 __ Addu(base_reg, obj, base_reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002058 }
Alexey Frunzef58b2482016-09-02 22:14:06 -07002059 if (value_location.IsConstant()) {
2060 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2061 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2062 DCHECK(!needs_write_barrier);
2063 } else {
2064 Register value = value_location.AsRegister<Register>();
2065 __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2066 if (needs_write_barrier) {
2067 DCHECK_EQ(value_type, Primitive::kPrimNot);
2068 codegen_->MarkGCCard(obj, value);
2069 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002070 }
2071 } else {
2072 DCHECK_EQ(value_type, Primitive::kPrimNot);
Serban Constantinescufca16662016-07-14 09:21:59 +01002073 codegen_->InvokeRuntime(kQuickAputObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002074 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
2075 }
2076 break;
2077 }
2078
2079 case Primitive::kPrimLong: {
2080 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002081 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002082 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002083 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002084 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_8);
2085 __ Addu(base_reg, obj, base_reg);
2086 }
2087 if (value_location.IsConstant()) {
2088 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2089 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2090 } else {
2091 Register value = value_location.AsRegisterPairLow<Register>();
2092 __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002093 }
2094 break;
2095 }
2096
2097 case Primitive::kPrimFloat: {
2098 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002099 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002100 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002101 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002102 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
2103 __ Addu(base_reg, obj, base_reg);
2104 }
2105 if (value_location.IsConstant()) {
2106 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2107 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2108 } else {
2109 FRegister value = value_location.AsFpuRegister<FRegister>();
2110 __ StoreSToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002111 }
2112 break;
2113 }
2114
2115 case Primitive::kPrimDouble: {
2116 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002117 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002118 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002119 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002120 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_8);
2121 __ Addu(base_reg, obj, base_reg);
2122 }
2123 if (value_location.IsConstant()) {
2124 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2125 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2126 } else {
2127 FRegister value = value_location.AsFpuRegister<FRegister>();
2128 __ StoreDToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002129 }
2130 break;
2131 }
2132
2133 case Primitive::kPrimVoid:
2134 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2135 UNREACHABLE();
2136 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002137}
2138
2139void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01002140 RegisterSet caller_saves = RegisterSet::Empty();
2141 InvokeRuntimeCallingConvention calling_convention;
2142 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2143 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2144 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002145 locations->SetInAt(0, Location::RequiresRegister());
2146 locations->SetInAt(1, Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002147}
2148
2149void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
2150 LocationSummary* locations = instruction->GetLocations();
2151 BoundsCheckSlowPathMIPS* slow_path =
2152 new (GetGraph()->GetArena()) BoundsCheckSlowPathMIPS(instruction);
2153 codegen_->AddSlowPath(slow_path);
2154
2155 Register index = locations->InAt(0).AsRegister<Register>();
2156 Register length = locations->InAt(1).AsRegister<Register>();
2157
2158 // length is limited by the maximum positive signed 32-bit integer.
2159 // Unsigned comparison of length and index checks for index < 0
2160 // and for length <= index simultaneously.
2161 __ Bgeu(index, length, slow_path->GetEntryLabel());
2162}
2163
2164void LocationsBuilderMIPS::VisitCheckCast(HCheckCast* instruction) {
2165 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2166 instruction,
2167 LocationSummary::kCallOnSlowPath);
2168 locations->SetInAt(0, Location::RequiresRegister());
2169 locations->SetInAt(1, Location::RequiresRegister());
2170 // Note that TypeCheckSlowPathMIPS uses this register too.
2171 locations->AddTemp(Location::RequiresRegister());
2172}
2173
2174void InstructionCodeGeneratorMIPS::VisitCheckCast(HCheckCast* instruction) {
2175 LocationSummary* locations = instruction->GetLocations();
2176 Register obj = locations->InAt(0).AsRegister<Register>();
2177 Register cls = locations->InAt(1).AsRegister<Register>();
2178 Register obj_cls = locations->GetTemp(0).AsRegister<Register>();
2179
2180 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction);
2181 codegen_->AddSlowPath(slow_path);
2182
2183 // TODO: avoid this check if we know obj is not null.
2184 __ Beqz(obj, slow_path->GetExitLabel());
2185 // Compare the class of `obj` with `cls`.
2186 __ LoadFromOffset(kLoadWord, obj_cls, obj, mirror::Object::ClassOffset().Int32Value());
2187 __ Bne(obj_cls, cls, slow_path->GetEntryLabel());
2188 __ Bind(slow_path->GetExitLabel());
2189}
2190
2191void LocationsBuilderMIPS::VisitClinitCheck(HClinitCheck* check) {
2192 LocationSummary* locations =
2193 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2194 locations->SetInAt(0, Location::RequiresRegister());
2195 if (check->HasUses()) {
2196 locations->SetOut(Location::SameAsFirstInput());
2197 }
2198}
2199
2200void InstructionCodeGeneratorMIPS::VisitClinitCheck(HClinitCheck* check) {
2201 // We assume the class is not null.
2202 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
2203 check->GetLoadClass(),
2204 check,
2205 check->GetDexPc(),
2206 true);
2207 codegen_->AddSlowPath(slow_path);
2208 GenerateClassInitializationCheck(slow_path,
2209 check->GetLocations()->InAt(0).AsRegister<Register>());
2210}
2211
2212void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
2213 Primitive::Type in_type = compare->InputAt(0)->GetType();
2214
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002215 LocationSummary* locations =
2216 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002217
2218 switch (in_type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002219 case Primitive::kPrimBoolean:
2220 case Primitive::kPrimByte:
2221 case Primitive::kPrimShort:
2222 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002223 case Primitive::kPrimInt:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002224 case Primitive::kPrimLong:
2225 locations->SetInAt(0, Location::RequiresRegister());
2226 locations->SetInAt(1, Location::RequiresRegister());
2227 // Output overlaps because it is written before doing the low comparison.
2228 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2229 break;
2230
2231 case Primitive::kPrimFloat:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002232 case Primitive::kPrimDouble:
2233 locations->SetInAt(0, Location::RequiresFpuRegister());
2234 locations->SetInAt(1, Location::RequiresFpuRegister());
2235 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002236 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002237
2238 default:
2239 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
2240 }
2241}
2242
2243void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
2244 LocationSummary* locations = instruction->GetLocations();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002245 Register res = locations->Out().AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002246 Primitive::Type in_type = instruction->InputAt(0)->GetType();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002247 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002248
2249 // 0 if: left == right
2250 // 1 if: left > right
2251 // -1 if: left < right
2252 switch (in_type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002253 case Primitive::kPrimBoolean:
2254 case Primitive::kPrimByte:
2255 case Primitive::kPrimShort:
2256 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002257 case Primitive::kPrimInt: {
2258 Register lhs = locations->InAt(0).AsRegister<Register>();
2259 Register rhs = locations->InAt(1).AsRegister<Register>();
2260 __ Slt(TMP, lhs, rhs);
2261 __ Slt(res, rhs, lhs);
2262 __ Subu(res, res, TMP);
2263 break;
2264 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002265 case Primitive::kPrimLong: {
2266 MipsLabel done;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002267 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2268 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2269 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
2270 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
2271 // TODO: more efficient (direct) comparison with a constant.
2272 __ Slt(TMP, lhs_high, rhs_high);
2273 __ Slt(AT, rhs_high, lhs_high); // Inverted: is actually gt.
2274 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
2275 __ Bnez(res, &done); // If we compared ==, check if lower bits are also equal.
2276 __ Sltu(TMP, lhs_low, rhs_low);
2277 __ Sltu(AT, rhs_low, lhs_low); // Inverted: is actually gt.
2278 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
2279 __ Bind(&done);
2280 break;
2281 }
2282
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002283 case Primitive::kPrimFloat: {
Roland Levillain32ca3752016-02-17 16:49:37 +00002284 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002285 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2286 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2287 MipsLabel done;
2288 if (isR6) {
2289 __ CmpEqS(FTMP, lhs, rhs);
2290 __ LoadConst32(res, 0);
2291 __ Bc1nez(FTMP, &done);
2292 if (gt_bias) {
2293 __ CmpLtS(FTMP, lhs, rhs);
2294 __ LoadConst32(res, -1);
2295 __ Bc1nez(FTMP, &done);
2296 __ LoadConst32(res, 1);
2297 } else {
2298 __ CmpLtS(FTMP, rhs, lhs);
2299 __ LoadConst32(res, 1);
2300 __ Bc1nez(FTMP, &done);
2301 __ LoadConst32(res, -1);
2302 }
2303 } else {
2304 if (gt_bias) {
2305 __ ColtS(0, lhs, rhs);
2306 __ LoadConst32(res, -1);
2307 __ Bc1t(0, &done);
2308 __ CeqS(0, lhs, rhs);
2309 __ LoadConst32(res, 1);
2310 __ Movt(res, ZERO, 0);
2311 } else {
2312 __ ColtS(0, rhs, lhs);
2313 __ LoadConst32(res, 1);
2314 __ Bc1t(0, &done);
2315 __ CeqS(0, lhs, rhs);
2316 __ LoadConst32(res, -1);
2317 __ Movt(res, ZERO, 0);
2318 }
2319 }
2320 __ Bind(&done);
2321 break;
2322 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002323 case Primitive::kPrimDouble: {
Roland Levillain32ca3752016-02-17 16:49:37 +00002324 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002325 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2326 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2327 MipsLabel done;
2328 if (isR6) {
2329 __ CmpEqD(FTMP, lhs, rhs);
2330 __ LoadConst32(res, 0);
2331 __ Bc1nez(FTMP, &done);
2332 if (gt_bias) {
2333 __ CmpLtD(FTMP, lhs, rhs);
2334 __ LoadConst32(res, -1);
2335 __ Bc1nez(FTMP, &done);
2336 __ LoadConst32(res, 1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002337 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002338 __ CmpLtD(FTMP, rhs, lhs);
2339 __ LoadConst32(res, 1);
2340 __ Bc1nez(FTMP, &done);
2341 __ LoadConst32(res, -1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002342 }
2343 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002344 if (gt_bias) {
2345 __ ColtD(0, lhs, rhs);
2346 __ LoadConst32(res, -1);
2347 __ Bc1t(0, &done);
2348 __ CeqD(0, lhs, rhs);
2349 __ LoadConst32(res, 1);
2350 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002351 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002352 __ ColtD(0, rhs, lhs);
2353 __ LoadConst32(res, 1);
2354 __ Bc1t(0, &done);
2355 __ CeqD(0, lhs, rhs);
2356 __ LoadConst32(res, -1);
2357 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002358 }
2359 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002360 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002361 break;
2362 }
2363
2364 default:
2365 LOG(FATAL) << "Unimplemented compare type " << in_type;
2366 }
2367}
2368
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002369void LocationsBuilderMIPS::HandleCondition(HCondition* instruction) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002370 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002371 switch (instruction->InputAt(0)->GetType()) {
2372 default:
2373 case Primitive::kPrimLong:
2374 locations->SetInAt(0, Location::RequiresRegister());
2375 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2376 break;
2377
2378 case Primitive::kPrimFloat:
2379 case Primitive::kPrimDouble:
2380 locations->SetInAt(0, Location::RequiresFpuRegister());
2381 locations->SetInAt(1, Location::RequiresFpuRegister());
2382 break;
2383 }
David Brazdilb3e773e2016-01-26 11:28:37 +00002384 if (!instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002385 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2386 }
2387}
2388
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002389void InstructionCodeGeneratorMIPS::HandleCondition(HCondition* instruction) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002390 if (instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002391 return;
2392 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002393
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002394 Primitive::Type type = instruction->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002395 LocationSummary* locations = instruction->GetLocations();
2396 Register dst = locations->Out().AsRegister<Register>();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002397 MipsLabel true_label;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002398
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002399 switch (type) {
2400 default:
2401 // Integer case.
2402 GenerateIntCompare(instruction->GetCondition(), locations);
2403 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002404
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002405 case Primitive::kPrimLong:
2406 // TODO: don't use branches.
2407 GenerateLongCompareAndBranch(instruction->GetCondition(), locations, &true_label);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002408 break;
2409
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002410 case Primitive::kPrimFloat:
2411 case Primitive::kPrimDouble:
Alexey Frunze2ddb7172016-09-06 17:04:55 -07002412 GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
2413 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002414 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002415
2416 // Convert the branches into the result.
2417 MipsLabel done;
2418
2419 // False case: result = 0.
2420 __ LoadConst32(dst, 0);
2421 __ B(&done);
2422
2423 // True case: result = 1.
2424 __ Bind(&true_label);
2425 __ LoadConst32(dst, 1);
2426 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002427}
2428
Alexey Frunze7e99e052015-11-24 19:28:01 -08002429void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2430 DCHECK(instruction->IsDiv() || instruction->IsRem());
2431 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2432
2433 LocationSummary* locations = instruction->GetLocations();
2434 Location second = locations->InAt(1);
2435 DCHECK(second.IsConstant());
2436
2437 Register out = locations->Out().AsRegister<Register>();
2438 Register dividend = locations->InAt(0).AsRegister<Register>();
2439 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2440 DCHECK(imm == 1 || imm == -1);
2441
2442 if (instruction->IsRem()) {
2443 __ Move(out, ZERO);
2444 } else {
2445 if (imm == -1) {
2446 __ Subu(out, ZERO, dividend);
2447 } else if (out != dividend) {
2448 __ Move(out, dividend);
2449 }
2450 }
2451}
2452
2453void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2454 DCHECK(instruction->IsDiv() || instruction->IsRem());
2455 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2456
2457 LocationSummary* locations = instruction->GetLocations();
2458 Location second = locations->InAt(1);
2459 DCHECK(second.IsConstant());
2460
2461 Register out = locations->Out().AsRegister<Register>();
2462 Register dividend = locations->InAt(0).AsRegister<Register>();
2463 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002464 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Alexey Frunze7e99e052015-11-24 19:28:01 -08002465 int ctz_imm = CTZ(abs_imm);
2466
2467 if (instruction->IsDiv()) {
2468 if (ctz_imm == 1) {
2469 // Fast path for division by +/-2, which is very common.
2470 __ Srl(TMP, dividend, 31);
2471 } else {
2472 __ Sra(TMP, dividend, 31);
2473 __ Srl(TMP, TMP, 32 - ctz_imm);
2474 }
2475 __ Addu(out, dividend, TMP);
2476 __ Sra(out, out, ctz_imm);
2477 if (imm < 0) {
2478 __ Subu(out, ZERO, out);
2479 }
2480 } else {
2481 if (ctz_imm == 1) {
2482 // Fast path for modulo +/-2, which is very common.
2483 __ Sra(TMP, dividend, 31);
2484 __ Subu(out, dividend, TMP);
2485 __ Andi(out, out, 1);
2486 __ Addu(out, out, TMP);
2487 } else {
2488 __ Sra(TMP, dividend, 31);
2489 __ Srl(TMP, TMP, 32 - ctz_imm);
2490 __ Addu(out, dividend, TMP);
2491 if (IsUint<16>(abs_imm - 1)) {
2492 __ Andi(out, out, abs_imm - 1);
2493 } else {
2494 __ Sll(out, out, 32 - ctz_imm);
2495 __ Srl(out, out, 32 - ctz_imm);
2496 }
2497 __ Subu(out, out, TMP);
2498 }
2499 }
2500}
2501
2502void InstructionCodeGeneratorMIPS::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2503 DCHECK(instruction->IsDiv() || instruction->IsRem());
2504 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2505
2506 LocationSummary* locations = instruction->GetLocations();
2507 Location second = locations->InAt(1);
2508 DCHECK(second.IsConstant());
2509
2510 Register out = locations->Out().AsRegister<Register>();
2511 Register dividend = locations->InAt(0).AsRegister<Register>();
2512 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2513
2514 int64_t magic;
2515 int shift;
2516 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2517
2518 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
2519
2520 __ LoadConst32(TMP, magic);
2521 if (isR6) {
2522 __ MuhR6(TMP, dividend, TMP);
2523 } else {
2524 __ MultR2(dividend, TMP);
2525 __ Mfhi(TMP);
2526 }
2527 if (imm > 0 && magic < 0) {
2528 __ Addu(TMP, TMP, dividend);
2529 } else if (imm < 0 && magic > 0) {
2530 __ Subu(TMP, TMP, dividend);
2531 }
2532
2533 if (shift != 0) {
2534 __ Sra(TMP, TMP, shift);
2535 }
2536
2537 if (instruction->IsDiv()) {
2538 __ Sra(out, TMP, 31);
2539 __ Subu(out, TMP, out);
2540 } else {
2541 __ Sra(AT, TMP, 31);
2542 __ Subu(AT, TMP, AT);
2543 __ LoadConst32(TMP, imm);
2544 if (isR6) {
2545 __ MulR6(TMP, AT, TMP);
2546 } else {
2547 __ MulR2(TMP, AT, TMP);
2548 }
2549 __ Subu(out, dividend, TMP);
2550 }
2551}
2552
2553void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2554 DCHECK(instruction->IsDiv() || instruction->IsRem());
2555 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2556
2557 LocationSummary* locations = instruction->GetLocations();
2558 Register out = locations->Out().AsRegister<Register>();
2559 Location second = locations->InAt(1);
2560
2561 if (second.IsConstant()) {
2562 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2563 if (imm == 0) {
2564 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2565 } else if (imm == 1 || imm == -1) {
2566 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002567 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08002568 DivRemByPowerOfTwo(instruction);
2569 } else {
2570 DCHECK(imm <= -2 || imm >= 2);
2571 GenerateDivRemWithAnyConstant(instruction);
2572 }
2573 } else {
2574 Register dividend = locations->InAt(0).AsRegister<Register>();
2575 Register divisor = second.AsRegister<Register>();
2576 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
2577 if (instruction->IsDiv()) {
2578 if (isR6) {
2579 __ DivR6(out, dividend, divisor);
2580 } else {
2581 __ DivR2(out, dividend, divisor);
2582 }
2583 } else {
2584 if (isR6) {
2585 __ ModR6(out, dividend, divisor);
2586 } else {
2587 __ ModR2(out, dividend, divisor);
2588 }
2589 }
2590 }
2591}
2592
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002593void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
2594 Primitive::Type type = div->GetResultType();
2595 LocationSummary::CallKind call_kind = (type == Primitive::kPrimLong)
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002596 ? LocationSummary::kCallOnMainOnly
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002597 : LocationSummary::kNoCall;
2598
2599 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2600
2601 switch (type) {
2602 case Primitive::kPrimInt:
2603 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08002604 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002605 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2606 break;
2607
2608 case Primitive::kPrimLong: {
2609 InvokeRuntimeCallingConvention calling_convention;
2610 locations->SetInAt(0, Location::RegisterPairLocation(
2611 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2612 locations->SetInAt(1, Location::RegisterPairLocation(
2613 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2614 locations->SetOut(calling_convention.GetReturnLocation(type));
2615 break;
2616 }
2617
2618 case Primitive::kPrimFloat:
2619 case Primitive::kPrimDouble:
2620 locations->SetInAt(0, Location::RequiresFpuRegister());
2621 locations->SetInAt(1, Location::RequiresFpuRegister());
2622 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2623 break;
2624
2625 default:
2626 LOG(FATAL) << "Unexpected div type " << type;
2627 }
2628}
2629
2630void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) {
2631 Primitive::Type type = instruction->GetType();
2632 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002633
2634 switch (type) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08002635 case Primitive::kPrimInt:
2636 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002637 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002638 case Primitive::kPrimLong: {
Serban Constantinescufca16662016-07-14 09:21:59 +01002639 codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002640 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
2641 break;
2642 }
2643 case Primitive::kPrimFloat:
2644 case Primitive::kPrimDouble: {
2645 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
2646 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2647 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2648 if (type == Primitive::kPrimFloat) {
2649 __ DivS(dst, lhs, rhs);
2650 } else {
2651 __ DivD(dst, lhs, rhs);
2652 }
2653 break;
2654 }
2655 default:
2656 LOG(FATAL) << "Unexpected div type " << type;
2657 }
2658}
2659
2660void LocationsBuilderMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01002661 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002662 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002663}
2664
2665void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2666 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathMIPS(instruction);
2667 codegen_->AddSlowPath(slow_path);
2668 Location value = instruction->GetLocations()->InAt(0);
2669 Primitive::Type type = instruction->GetType();
2670
2671 switch (type) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00002672 case Primitive::kPrimBoolean:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002673 case Primitive::kPrimByte:
2674 case Primitive::kPrimChar:
2675 case Primitive::kPrimShort:
2676 case Primitive::kPrimInt: {
2677 if (value.IsConstant()) {
2678 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2679 __ B(slow_path->GetEntryLabel());
2680 } else {
2681 // A division by a non-null constant is valid. We don't need to perform
2682 // any check, so simply fall through.
2683 }
2684 } else {
2685 DCHECK(value.IsRegister()) << value;
2686 __ Beqz(value.AsRegister<Register>(), slow_path->GetEntryLabel());
2687 }
2688 break;
2689 }
2690 case Primitive::kPrimLong: {
2691 if (value.IsConstant()) {
2692 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2693 __ B(slow_path->GetEntryLabel());
2694 } else {
2695 // A division by a non-null constant is valid. We don't need to perform
2696 // any check, so simply fall through.
2697 }
2698 } else {
2699 DCHECK(value.IsRegisterPair()) << value;
2700 __ Or(TMP, value.AsRegisterPairHigh<Register>(), value.AsRegisterPairLow<Register>());
2701 __ Beqz(TMP, slow_path->GetEntryLabel());
2702 }
2703 break;
2704 }
2705 default:
2706 LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
2707 }
2708}
2709
2710void LocationsBuilderMIPS::VisitDoubleConstant(HDoubleConstant* constant) {
2711 LocationSummary* locations =
2712 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2713 locations->SetOut(Location::ConstantLocation(constant));
2714}
2715
2716void InstructionCodeGeneratorMIPS::VisitDoubleConstant(HDoubleConstant* cst ATTRIBUTE_UNUSED) {
2717 // Will be generated at use site.
2718}
2719
2720void LocationsBuilderMIPS::VisitExit(HExit* exit) {
2721 exit->SetLocations(nullptr);
2722}
2723
2724void InstructionCodeGeneratorMIPS::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
2725}
2726
2727void LocationsBuilderMIPS::VisitFloatConstant(HFloatConstant* constant) {
2728 LocationSummary* locations =
2729 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2730 locations->SetOut(Location::ConstantLocation(constant));
2731}
2732
2733void InstructionCodeGeneratorMIPS::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
2734 // Will be generated at use site.
2735}
2736
2737void LocationsBuilderMIPS::VisitGoto(HGoto* got) {
2738 got->SetLocations(nullptr);
2739}
2740
2741void InstructionCodeGeneratorMIPS::HandleGoto(HInstruction* got, HBasicBlock* successor) {
2742 DCHECK(!successor->IsExitBlock());
2743 HBasicBlock* block = got->GetBlock();
2744 HInstruction* previous = got->GetPrevious();
2745 HLoopInformation* info = block->GetLoopInformation();
2746
2747 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
2748 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2749 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2750 return;
2751 }
2752 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2753 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2754 }
2755 if (!codegen_->GoesToNextBlock(block, successor)) {
2756 __ B(codegen_->GetLabelOf(successor));
2757 }
2758}
2759
2760void InstructionCodeGeneratorMIPS::VisitGoto(HGoto* got) {
2761 HandleGoto(got, got->GetSuccessor());
2762}
2763
2764void LocationsBuilderMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
2765 try_boundary->SetLocations(nullptr);
2766}
2767
2768void InstructionCodeGeneratorMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
2769 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2770 if (!successor->IsExitBlock()) {
2771 HandleGoto(try_boundary, successor);
2772 }
2773}
2774
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002775void InstructionCodeGeneratorMIPS::GenerateIntCompare(IfCondition cond,
2776 LocationSummary* locations) {
2777 Register dst = locations->Out().AsRegister<Register>();
2778 Register lhs = locations->InAt(0).AsRegister<Register>();
2779 Location rhs_location = locations->InAt(1);
2780 Register rhs_reg = ZERO;
2781 int64_t rhs_imm = 0;
2782 bool use_imm = rhs_location.IsConstant();
2783 if (use_imm) {
2784 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
2785 } else {
2786 rhs_reg = rhs_location.AsRegister<Register>();
2787 }
2788
2789 switch (cond) {
2790 case kCondEQ:
2791 case kCondNE:
2792 if (use_imm && IsUint<16>(rhs_imm)) {
2793 __ Xori(dst, lhs, rhs_imm);
2794 } else {
2795 if (use_imm) {
2796 rhs_reg = TMP;
2797 __ LoadConst32(rhs_reg, rhs_imm);
2798 }
2799 __ Xor(dst, lhs, rhs_reg);
2800 }
2801 if (cond == kCondEQ) {
2802 __ Sltiu(dst, dst, 1);
2803 } else {
2804 __ Sltu(dst, ZERO, dst);
2805 }
2806 break;
2807
2808 case kCondLT:
2809 case kCondGE:
2810 if (use_imm && IsInt<16>(rhs_imm)) {
2811 __ Slti(dst, lhs, rhs_imm);
2812 } else {
2813 if (use_imm) {
2814 rhs_reg = TMP;
2815 __ LoadConst32(rhs_reg, rhs_imm);
2816 }
2817 __ Slt(dst, lhs, rhs_reg);
2818 }
2819 if (cond == kCondGE) {
2820 // Simulate lhs >= rhs via !(lhs < rhs) since there's
2821 // only the slt instruction but no sge.
2822 __ Xori(dst, dst, 1);
2823 }
2824 break;
2825
2826 case kCondLE:
2827 case kCondGT:
2828 if (use_imm && IsInt<16>(rhs_imm + 1)) {
2829 // Simulate lhs <= rhs via lhs < rhs + 1.
2830 __ Slti(dst, lhs, rhs_imm + 1);
2831 if (cond == kCondGT) {
2832 // Simulate lhs > rhs via !(lhs <= rhs) since there's
2833 // only the slti instruction but no sgti.
2834 __ Xori(dst, dst, 1);
2835 }
2836 } else {
2837 if (use_imm) {
2838 rhs_reg = TMP;
2839 __ LoadConst32(rhs_reg, rhs_imm);
2840 }
2841 __ Slt(dst, rhs_reg, lhs);
2842 if (cond == kCondLE) {
2843 // Simulate lhs <= rhs via !(rhs < lhs) since there's
2844 // only the slt instruction but no sle.
2845 __ Xori(dst, dst, 1);
2846 }
2847 }
2848 break;
2849
2850 case kCondB:
2851 case kCondAE:
2852 if (use_imm && IsInt<16>(rhs_imm)) {
2853 // Sltiu sign-extends its 16-bit immediate operand before
2854 // the comparison and thus lets us compare directly with
2855 // unsigned values in the ranges [0, 0x7fff] and
2856 // [0xffff8000, 0xffffffff].
2857 __ Sltiu(dst, lhs, rhs_imm);
2858 } else {
2859 if (use_imm) {
2860 rhs_reg = TMP;
2861 __ LoadConst32(rhs_reg, rhs_imm);
2862 }
2863 __ Sltu(dst, lhs, rhs_reg);
2864 }
2865 if (cond == kCondAE) {
2866 // Simulate lhs >= rhs via !(lhs < rhs) since there's
2867 // only the sltu instruction but no sgeu.
2868 __ Xori(dst, dst, 1);
2869 }
2870 break;
2871
2872 case kCondBE:
2873 case kCondA:
2874 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
2875 // Simulate lhs <= rhs via lhs < rhs + 1.
2876 // Note that this only works if rhs + 1 does not overflow
2877 // to 0, hence the check above.
2878 // Sltiu sign-extends its 16-bit immediate operand before
2879 // the comparison and thus lets us compare directly with
2880 // unsigned values in the ranges [0, 0x7fff] and
2881 // [0xffff8000, 0xffffffff].
2882 __ Sltiu(dst, lhs, rhs_imm + 1);
2883 if (cond == kCondA) {
2884 // Simulate lhs > rhs via !(lhs <= rhs) since there's
2885 // only the sltiu instruction but no sgtiu.
2886 __ Xori(dst, dst, 1);
2887 }
2888 } else {
2889 if (use_imm) {
2890 rhs_reg = TMP;
2891 __ LoadConst32(rhs_reg, rhs_imm);
2892 }
2893 __ Sltu(dst, rhs_reg, lhs);
2894 if (cond == kCondBE) {
2895 // Simulate lhs <= rhs via !(rhs < lhs) since there's
2896 // only the sltu instruction but no sleu.
2897 __ Xori(dst, dst, 1);
2898 }
2899 }
2900 break;
2901 }
2902}
2903
2904void InstructionCodeGeneratorMIPS::GenerateIntCompareAndBranch(IfCondition cond,
2905 LocationSummary* locations,
2906 MipsLabel* label) {
2907 Register lhs = locations->InAt(0).AsRegister<Register>();
2908 Location rhs_location = locations->InAt(1);
2909 Register rhs_reg = ZERO;
2910 int32_t rhs_imm = 0;
2911 bool use_imm = rhs_location.IsConstant();
2912 if (use_imm) {
2913 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
2914 } else {
2915 rhs_reg = rhs_location.AsRegister<Register>();
2916 }
2917
2918 if (use_imm && rhs_imm == 0) {
2919 switch (cond) {
2920 case kCondEQ:
2921 case kCondBE: // <= 0 if zero
2922 __ Beqz(lhs, label);
2923 break;
2924 case kCondNE:
2925 case kCondA: // > 0 if non-zero
2926 __ Bnez(lhs, label);
2927 break;
2928 case kCondLT:
2929 __ Bltz(lhs, label);
2930 break;
2931 case kCondGE:
2932 __ Bgez(lhs, label);
2933 break;
2934 case kCondLE:
2935 __ Blez(lhs, label);
2936 break;
2937 case kCondGT:
2938 __ Bgtz(lhs, label);
2939 break;
2940 case kCondB: // always false
2941 break;
2942 case kCondAE: // always true
2943 __ B(label);
2944 break;
2945 }
2946 } else {
2947 if (use_imm) {
2948 // TODO: more efficient comparison with 16-bit constants without loading them into TMP.
2949 rhs_reg = TMP;
2950 __ LoadConst32(rhs_reg, rhs_imm);
2951 }
2952 switch (cond) {
2953 case kCondEQ:
2954 __ Beq(lhs, rhs_reg, label);
2955 break;
2956 case kCondNE:
2957 __ Bne(lhs, rhs_reg, label);
2958 break;
2959 case kCondLT:
2960 __ Blt(lhs, rhs_reg, label);
2961 break;
2962 case kCondGE:
2963 __ Bge(lhs, rhs_reg, label);
2964 break;
2965 case kCondLE:
2966 __ Bge(rhs_reg, lhs, label);
2967 break;
2968 case kCondGT:
2969 __ Blt(rhs_reg, lhs, label);
2970 break;
2971 case kCondB:
2972 __ Bltu(lhs, rhs_reg, label);
2973 break;
2974 case kCondAE:
2975 __ Bgeu(lhs, rhs_reg, label);
2976 break;
2977 case kCondBE:
2978 __ Bgeu(rhs_reg, lhs, label);
2979 break;
2980 case kCondA:
2981 __ Bltu(rhs_reg, lhs, label);
2982 break;
2983 }
2984 }
2985}
2986
2987void InstructionCodeGeneratorMIPS::GenerateLongCompareAndBranch(IfCondition cond,
2988 LocationSummary* locations,
2989 MipsLabel* label) {
2990 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2991 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2992 Location rhs_location = locations->InAt(1);
2993 Register rhs_high = ZERO;
2994 Register rhs_low = ZERO;
2995 int64_t imm = 0;
2996 uint32_t imm_high = 0;
2997 uint32_t imm_low = 0;
2998 bool use_imm = rhs_location.IsConstant();
2999 if (use_imm) {
3000 imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
3001 imm_high = High32Bits(imm);
3002 imm_low = Low32Bits(imm);
3003 } else {
3004 rhs_high = rhs_location.AsRegisterPairHigh<Register>();
3005 rhs_low = rhs_location.AsRegisterPairLow<Register>();
3006 }
3007
3008 if (use_imm && imm == 0) {
3009 switch (cond) {
3010 case kCondEQ:
3011 case kCondBE: // <= 0 if zero
3012 __ Or(TMP, lhs_high, lhs_low);
3013 __ Beqz(TMP, label);
3014 break;
3015 case kCondNE:
3016 case kCondA: // > 0 if non-zero
3017 __ Or(TMP, lhs_high, lhs_low);
3018 __ Bnez(TMP, label);
3019 break;
3020 case kCondLT:
3021 __ Bltz(lhs_high, label);
3022 break;
3023 case kCondGE:
3024 __ Bgez(lhs_high, label);
3025 break;
3026 case kCondLE:
3027 __ Or(TMP, lhs_high, lhs_low);
3028 __ Sra(AT, lhs_high, 31);
3029 __ Bgeu(AT, TMP, label);
3030 break;
3031 case kCondGT:
3032 __ Or(TMP, lhs_high, lhs_low);
3033 __ Sra(AT, lhs_high, 31);
3034 __ Bltu(AT, TMP, label);
3035 break;
3036 case kCondB: // always false
3037 break;
3038 case kCondAE: // always true
3039 __ B(label);
3040 break;
3041 }
3042 } else if (use_imm) {
3043 // TODO: more efficient comparison with constants without loading them into TMP/AT.
3044 switch (cond) {
3045 case kCondEQ:
3046 __ LoadConst32(TMP, imm_high);
3047 __ Xor(TMP, TMP, lhs_high);
3048 __ LoadConst32(AT, imm_low);
3049 __ Xor(AT, AT, lhs_low);
3050 __ Or(TMP, TMP, AT);
3051 __ Beqz(TMP, label);
3052 break;
3053 case kCondNE:
3054 __ LoadConst32(TMP, imm_high);
3055 __ Xor(TMP, TMP, lhs_high);
3056 __ LoadConst32(AT, imm_low);
3057 __ Xor(AT, AT, lhs_low);
3058 __ Or(TMP, TMP, AT);
3059 __ Bnez(TMP, label);
3060 break;
3061 case kCondLT:
3062 __ LoadConst32(TMP, imm_high);
3063 __ Blt(lhs_high, TMP, label);
3064 __ Slt(TMP, TMP, lhs_high);
3065 __ LoadConst32(AT, imm_low);
3066 __ Sltu(AT, lhs_low, AT);
3067 __ Blt(TMP, AT, label);
3068 break;
3069 case kCondGE:
3070 __ LoadConst32(TMP, imm_high);
3071 __ Blt(TMP, lhs_high, label);
3072 __ Slt(TMP, lhs_high, TMP);
3073 __ LoadConst32(AT, imm_low);
3074 __ Sltu(AT, lhs_low, AT);
3075 __ Or(TMP, TMP, AT);
3076 __ Beqz(TMP, label);
3077 break;
3078 case kCondLE:
3079 __ LoadConst32(TMP, imm_high);
3080 __ Blt(lhs_high, TMP, label);
3081 __ Slt(TMP, TMP, lhs_high);
3082 __ LoadConst32(AT, imm_low);
3083 __ Sltu(AT, AT, lhs_low);
3084 __ Or(TMP, TMP, AT);
3085 __ Beqz(TMP, label);
3086 break;
3087 case kCondGT:
3088 __ LoadConst32(TMP, imm_high);
3089 __ Blt(TMP, lhs_high, label);
3090 __ Slt(TMP, lhs_high, TMP);
3091 __ LoadConst32(AT, imm_low);
3092 __ Sltu(AT, AT, lhs_low);
3093 __ Blt(TMP, AT, label);
3094 break;
3095 case kCondB:
3096 __ LoadConst32(TMP, imm_high);
3097 __ Bltu(lhs_high, TMP, label);
3098 __ Sltu(TMP, TMP, lhs_high);
3099 __ LoadConst32(AT, imm_low);
3100 __ Sltu(AT, lhs_low, AT);
3101 __ Blt(TMP, AT, label);
3102 break;
3103 case kCondAE:
3104 __ LoadConst32(TMP, imm_high);
3105 __ Bltu(TMP, lhs_high, label);
3106 __ Sltu(TMP, lhs_high, TMP);
3107 __ LoadConst32(AT, imm_low);
3108 __ Sltu(AT, lhs_low, AT);
3109 __ Or(TMP, TMP, AT);
3110 __ Beqz(TMP, label);
3111 break;
3112 case kCondBE:
3113 __ LoadConst32(TMP, imm_high);
3114 __ Bltu(lhs_high, TMP, label);
3115 __ Sltu(TMP, TMP, lhs_high);
3116 __ LoadConst32(AT, imm_low);
3117 __ Sltu(AT, AT, lhs_low);
3118 __ Or(TMP, TMP, AT);
3119 __ Beqz(TMP, label);
3120 break;
3121 case kCondA:
3122 __ LoadConst32(TMP, imm_high);
3123 __ Bltu(TMP, lhs_high, label);
3124 __ Sltu(TMP, lhs_high, TMP);
3125 __ LoadConst32(AT, imm_low);
3126 __ Sltu(AT, AT, lhs_low);
3127 __ Blt(TMP, AT, label);
3128 break;
3129 }
3130 } else {
3131 switch (cond) {
3132 case kCondEQ:
3133 __ Xor(TMP, lhs_high, rhs_high);
3134 __ Xor(AT, lhs_low, rhs_low);
3135 __ Or(TMP, TMP, AT);
3136 __ Beqz(TMP, label);
3137 break;
3138 case kCondNE:
3139 __ Xor(TMP, lhs_high, rhs_high);
3140 __ Xor(AT, lhs_low, rhs_low);
3141 __ Or(TMP, TMP, AT);
3142 __ Bnez(TMP, label);
3143 break;
3144 case kCondLT:
3145 __ Blt(lhs_high, rhs_high, label);
3146 __ Slt(TMP, rhs_high, lhs_high);
3147 __ Sltu(AT, lhs_low, rhs_low);
3148 __ Blt(TMP, AT, label);
3149 break;
3150 case kCondGE:
3151 __ Blt(rhs_high, lhs_high, label);
3152 __ Slt(TMP, lhs_high, rhs_high);
3153 __ Sltu(AT, lhs_low, rhs_low);
3154 __ Or(TMP, TMP, AT);
3155 __ Beqz(TMP, label);
3156 break;
3157 case kCondLE:
3158 __ Blt(lhs_high, rhs_high, label);
3159 __ Slt(TMP, rhs_high, lhs_high);
3160 __ Sltu(AT, rhs_low, lhs_low);
3161 __ Or(TMP, TMP, AT);
3162 __ Beqz(TMP, label);
3163 break;
3164 case kCondGT:
3165 __ Blt(rhs_high, lhs_high, label);
3166 __ Slt(TMP, lhs_high, rhs_high);
3167 __ Sltu(AT, rhs_low, lhs_low);
3168 __ Blt(TMP, AT, label);
3169 break;
3170 case kCondB:
3171 __ Bltu(lhs_high, rhs_high, label);
3172 __ Sltu(TMP, rhs_high, lhs_high);
3173 __ Sltu(AT, lhs_low, rhs_low);
3174 __ Blt(TMP, AT, label);
3175 break;
3176 case kCondAE:
3177 __ Bltu(rhs_high, lhs_high, label);
3178 __ Sltu(TMP, lhs_high, rhs_high);
3179 __ Sltu(AT, lhs_low, rhs_low);
3180 __ Or(TMP, TMP, AT);
3181 __ Beqz(TMP, label);
3182 break;
3183 case kCondBE:
3184 __ Bltu(lhs_high, rhs_high, label);
3185 __ Sltu(TMP, rhs_high, lhs_high);
3186 __ Sltu(AT, rhs_low, lhs_low);
3187 __ Or(TMP, TMP, AT);
3188 __ Beqz(TMP, label);
3189 break;
3190 case kCondA:
3191 __ Bltu(rhs_high, lhs_high, label);
3192 __ Sltu(TMP, lhs_high, rhs_high);
3193 __ Sltu(AT, rhs_low, lhs_low);
3194 __ Blt(TMP, AT, label);
3195 break;
3196 }
3197 }
3198}
3199
Alexey Frunze2ddb7172016-09-06 17:04:55 -07003200void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
3201 bool gt_bias,
3202 Primitive::Type type,
3203 LocationSummary* locations) {
3204 Register dst = locations->Out().AsRegister<Register>();
3205 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3206 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3207 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3208 if (type == Primitive::kPrimFloat) {
3209 if (isR6) {
3210 switch (cond) {
3211 case kCondEQ:
3212 __ CmpEqS(FTMP, lhs, rhs);
3213 __ Mfc1(dst, FTMP);
3214 __ Andi(dst, dst, 1);
3215 break;
3216 case kCondNE:
3217 __ CmpEqS(FTMP, lhs, rhs);
3218 __ Mfc1(dst, FTMP);
3219 __ Addiu(dst, dst, 1);
3220 break;
3221 case kCondLT:
3222 if (gt_bias) {
3223 __ CmpLtS(FTMP, lhs, rhs);
3224 } else {
3225 __ CmpUltS(FTMP, lhs, rhs);
3226 }
3227 __ Mfc1(dst, FTMP);
3228 __ Andi(dst, dst, 1);
3229 break;
3230 case kCondLE:
3231 if (gt_bias) {
3232 __ CmpLeS(FTMP, lhs, rhs);
3233 } else {
3234 __ CmpUleS(FTMP, lhs, rhs);
3235 }
3236 __ Mfc1(dst, FTMP);
3237 __ Andi(dst, dst, 1);
3238 break;
3239 case kCondGT:
3240 if (gt_bias) {
3241 __ CmpUltS(FTMP, rhs, lhs);
3242 } else {
3243 __ CmpLtS(FTMP, rhs, lhs);
3244 }
3245 __ Mfc1(dst, FTMP);
3246 __ Andi(dst, dst, 1);
3247 break;
3248 case kCondGE:
3249 if (gt_bias) {
3250 __ CmpUleS(FTMP, rhs, lhs);
3251 } else {
3252 __ CmpLeS(FTMP, rhs, lhs);
3253 }
3254 __ Mfc1(dst, FTMP);
3255 __ Andi(dst, dst, 1);
3256 break;
3257 default:
3258 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3259 UNREACHABLE();
3260 }
3261 } else {
3262 switch (cond) {
3263 case kCondEQ:
3264 __ CeqS(0, lhs, rhs);
3265 __ LoadConst32(dst, 1);
3266 __ Movf(dst, ZERO, 0);
3267 break;
3268 case kCondNE:
3269 __ CeqS(0, lhs, rhs);
3270 __ LoadConst32(dst, 1);
3271 __ Movt(dst, ZERO, 0);
3272 break;
3273 case kCondLT:
3274 if (gt_bias) {
3275 __ ColtS(0, lhs, rhs);
3276 } else {
3277 __ CultS(0, lhs, rhs);
3278 }
3279 __ LoadConst32(dst, 1);
3280 __ Movf(dst, ZERO, 0);
3281 break;
3282 case kCondLE:
3283 if (gt_bias) {
3284 __ ColeS(0, lhs, rhs);
3285 } else {
3286 __ CuleS(0, lhs, rhs);
3287 }
3288 __ LoadConst32(dst, 1);
3289 __ Movf(dst, ZERO, 0);
3290 break;
3291 case kCondGT:
3292 if (gt_bias) {
3293 __ CultS(0, rhs, lhs);
3294 } else {
3295 __ ColtS(0, rhs, lhs);
3296 }
3297 __ LoadConst32(dst, 1);
3298 __ Movf(dst, ZERO, 0);
3299 break;
3300 case kCondGE:
3301 if (gt_bias) {
3302 __ CuleS(0, rhs, lhs);
3303 } else {
3304 __ ColeS(0, rhs, lhs);
3305 }
3306 __ LoadConst32(dst, 1);
3307 __ Movf(dst, ZERO, 0);
3308 break;
3309 default:
3310 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3311 UNREACHABLE();
3312 }
3313 }
3314 } else {
3315 DCHECK_EQ(type, Primitive::kPrimDouble);
3316 if (isR6) {
3317 switch (cond) {
3318 case kCondEQ:
3319 __ CmpEqD(FTMP, lhs, rhs);
3320 __ Mfc1(dst, FTMP);
3321 __ Andi(dst, dst, 1);
3322 break;
3323 case kCondNE:
3324 __ CmpEqD(FTMP, lhs, rhs);
3325 __ Mfc1(dst, FTMP);
3326 __ Addiu(dst, dst, 1);
3327 break;
3328 case kCondLT:
3329 if (gt_bias) {
3330 __ CmpLtD(FTMP, lhs, rhs);
3331 } else {
3332 __ CmpUltD(FTMP, lhs, rhs);
3333 }
3334 __ Mfc1(dst, FTMP);
3335 __ Andi(dst, dst, 1);
3336 break;
3337 case kCondLE:
3338 if (gt_bias) {
3339 __ CmpLeD(FTMP, lhs, rhs);
3340 } else {
3341 __ CmpUleD(FTMP, lhs, rhs);
3342 }
3343 __ Mfc1(dst, FTMP);
3344 __ Andi(dst, dst, 1);
3345 break;
3346 case kCondGT:
3347 if (gt_bias) {
3348 __ CmpUltD(FTMP, rhs, lhs);
3349 } else {
3350 __ CmpLtD(FTMP, rhs, lhs);
3351 }
3352 __ Mfc1(dst, FTMP);
3353 __ Andi(dst, dst, 1);
3354 break;
3355 case kCondGE:
3356 if (gt_bias) {
3357 __ CmpUleD(FTMP, rhs, lhs);
3358 } else {
3359 __ CmpLeD(FTMP, rhs, lhs);
3360 }
3361 __ Mfc1(dst, FTMP);
3362 __ Andi(dst, dst, 1);
3363 break;
3364 default:
3365 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3366 UNREACHABLE();
3367 }
3368 } else {
3369 switch (cond) {
3370 case kCondEQ:
3371 __ CeqD(0, lhs, rhs);
3372 __ LoadConst32(dst, 1);
3373 __ Movf(dst, ZERO, 0);
3374 break;
3375 case kCondNE:
3376 __ CeqD(0, lhs, rhs);
3377 __ LoadConst32(dst, 1);
3378 __ Movt(dst, ZERO, 0);
3379 break;
3380 case kCondLT:
3381 if (gt_bias) {
3382 __ ColtD(0, lhs, rhs);
3383 } else {
3384 __ CultD(0, lhs, rhs);
3385 }
3386 __ LoadConst32(dst, 1);
3387 __ Movf(dst, ZERO, 0);
3388 break;
3389 case kCondLE:
3390 if (gt_bias) {
3391 __ ColeD(0, lhs, rhs);
3392 } else {
3393 __ CuleD(0, lhs, rhs);
3394 }
3395 __ LoadConst32(dst, 1);
3396 __ Movf(dst, ZERO, 0);
3397 break;
3398 case kCondGT:
3399 if (gt_bias) {
3400 __ CultD(0, rhs, lhs);
3401 } else {
3402 __ ColtD(0, rhs, lhs);
3403 }
3404 __ LoadConst32(dst, 1);
3405 __ Movf(dst, ZERO, 0);
3406 break;
3407 case kCondGE:
3408 if (gt_bias) {
3409 __ CuleD(0, rhs, lhs);
3410 } else {
3411 __ ColeD(0, rhs, lhs);
3412 }
3413 __ LoadConst32(dst, 1);
3414 __ Movf(dst, ZERO, 0);
3415 break;
3416 default:
3417 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3418 UNREACHABLE();
3419 }
3420 }
3421 }
3422}
3423
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003424void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
3425 bool gt_bias,
3426 Primitive::Type type,
3427 LocationSummary* locations,
3428 MipsLabel* label) {
3429 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3430 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3431 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3432 if (type == Primitive::kPrimFloat) {
3433 if (isR6) {
3434 switch (cond) {
3435 case kCondEQ:
3436 __ CmpEqS(FTMP, lhs, rhs);
3437 __ Bc1nez(FTMP, label);
3438 break;
3439 case kCondNE:
3440 __ CmpEqS(FTMP, lhs, rhs);
3441 __ Bc1eqz(FTMP, label);
3442 break;
3443 case kCondLT:
3444 if (gt_bias) {
3445 __ CmpLtS(FTMP, lhs, rhs);
3446 } else {
3447 __ CmpUltS(FTMP, lhs, rhs);
3448 }
3449 __ Bc1nez(FTMP, label);
3450 break;
3451 case kCondLE:
3452 if (gt_bias) {
3453 __ CmpLeS(FTMP, lhs, rhs);
3454 } else {
3455 __ CmpUleS(FTMP, lhs, rhs);
3456 }
3457 __ Bc1nez(FTMP, label);
3458 break;
3459 case kCondGT:
3460 if (gt_bias) {
3461 __ CmpUltS(FTMP, rhs, lhs);
3462 } else {
3463 __ CmpLtS(FTMP, rhs, lhs);
3464 }
3465 __ Bc1nez(FTMP, label);
3466 break;
3467 case kCondGE:
3468 if (gt_bias) {
3469 __ CmpUleS(FTMP, rhs, lhs);
3470 } else {
3471 __ CmpLeS(FTMP, rhs, lhs);
3472 }
3473 __ Bc1nez(FTMP, label);
3474 break;
3475 default:
3476 LOG(FATAL) << "Unexpected non-floating-point condition";
3477 }
3478 } else {
3479 switch (cond) {
3480 case kCondEQ:
3481 __ CeqS(0, lhs, rhs);
3482 __ Bc1t(0, label);
3483 break;
3484 case kCondNE:
3485 __ CeqS(0, lhs, rhs);
3486 __ Bc1f(0, label);
3487 break;
3488 case kCondLT:
3489 if (gt_bias) {
3490 __ ColtS(0, lhs, rhs);
3491 } else {
3492 __ CultS(0, lhs, rhs);
3493 }
3494 __ Bc1t(0, label);
3495 break;
3496 case kCondLE:
3497 if (gt_bias) {
3498 __ ColeS(0, lhs, rhs);
3499 } else {
3500 __ CuleS(0, lhs, rhs);
3501 }
3502 __ Bc1t(0, label);
3503 break;
3504 case kCondGT:
3505 if (gt_bias) {
3506 __ CultS(0, rhs, lhs);
3507 } else {
3508 __ ColtS(0, rhs, lhs);
3509 }
3510 __ Bc1t(0, label);
3511 break;
3512 case kCondGE:
3513 if (gt_bias) {
3514 __ CuleS(0, rhs, lhs);
3515 } else {
3516 __ ColeS(0, rhs, lhs);
3517 }
3518 __ Bc1t(0, label);
3519 break;
3520 default:
3521 LOG(FATAL) << "Unexpected non-floating-point condition";
3522 }
3523 }
3524 } else {
3525 DCHECK_EQ(type, Primitive::kPrimDouble);
3526 if (isR6) {
3527 switch (cond) {
3528 case kCondEQ:
3529 __ CmpEqD(FTMP, lhs, rhs);
3530 __ Bc1nez(FTMP, label);
3531 break;
3532 case kCondNE:
3533 __ CmpEqD(FTMP, lhs, rhs);
3534 __ Bc1eqz(FTMP, label);
3535 break;
3536 case kCondLT:
3537 if (gt_bias) {
3538 __ CmpLtD(FTMP, lhs, rhs);
3539 } else {
3540 __ CmpUltD(FTMP, lhs, rhs);
3541 }
3542 __ Bc1nez(FTMP, label);
3543 break;
3544 case kCondLE:
3545 if (gt_bias) {
3546 __ CmpLeD(FTMP, lhs, rhs);
3547 } else {
3548 __ CmpUleD(FTMP, lhs, rhs);
3549 }
3550 __ Bc1nez(FTMP, label);
3551 break;
3552 case kCondGT:
3553 if (gt_bias) {
3554 __ CmpUltD(FTMP, rhs, lhs);
3555 } else {
3556 __ CmpLtD(FTMP, rhs, lhs);
3557 }
3558 __ Bc1nez(FTMP, label);
3559 break;
3560 case kCondGE:
3561 if (gt_bias) {
3562 __ CmpUleD(FTMP, rhs, lhs);
3563 } else {
3564 __ CmpLeD(FTMP, rhs, lhs);
3565 }
3566 __ Bc1nez(FTMP, label);
3567 break;
3568 default:
3569 LOG(FATAL) << "Unexpected non-floating-point condition";
3570 }
3571 } else {
3572 switch (cond) {
3573 case kCondEQ:
3574 __ CeqD(0, lhs, rhs);
3575 __ Bc1t(0, label);
3576 break;
3577 case kCondNE:
3578 __ CeqD(0, lhs, rhs);
3579 __ Bc1f(0, label);
3580 break;
3581 case kCondLT:
3582 if (gt_bias) {
3583 __ ColtD(0, lhs, rhs);
3584 } else {
3585 __ CultD(0, lhs, rhs);
3586 }
3587 __ Bc1t(0, label);
3588 break;
3589 case kCondLE:
3590 if (gt_bias) {
3591 __ ColeD(0, lhs, rhs);
3592 } else {
3593 __ CuleD(0, lhs, rhs);
3594 }
3595 __ Bc1t(0, label);
3596 break;
3597 case kCondGT:
3598 if (gt_bias) {
3599 __ CultD(0, rhs, lhs);
3600 } else {
3601 __ ColtD(0, rhs, lhs);
3602 }
3603 __ Bc1t(0, label);
3604 break;
3605 case kCondGE:
3606 if (gt_bias) {
3607 __ CuleD(0, rhs, lhs);
3608 } else {
3609 __ ColeD(0, rhs, lhs);
3610 }
3611 __ Bc1t(0, label);
3612 break;
3613 default:
3614 LOG(FATAL) << "Unexpected non-floating-point condition";
3615 }
3616 }
3617 }
3618}
3619
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003620void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00003621 size_t condition_input_index,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003622 MipsLabel* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00003623 MipsLabel* false_target) {
3624 HInstruction* cond = instruction->InputAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003625
David Brazdil0debae72015-11-12 18:37:00 +00003626 if (true_target == nullptr && false_target == nullptr) {
3627 // Nothing to do. The code always falls through.
3628 return;
3629 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00003630 // Constant condition, statically compared against "true" (integer value 1).
3631 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00003632 if (true_target != nullptr) {
3633 __ B(true_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003634 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003635 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00003636 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00003637 if (false_target != nullptr) {
3638 __ B(false_target);
3639 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003640 }
David Brazdil0debae72015-11-12 18:37:00 +00003641 return;
3642 }
3643
3644 // The following code generates these patterns:
3645 // (1) true_target == nullptr && false_target != nullptr
3646 // - opposite condition true => branch to false_target
3647 // (2) true_target != nullptr && false_target == nullptr
3648 // - condition true => branch to true_target
3649 // (3) true_target != nullptr && false_target != nullptr
3650 // - condition true => branch to true_target
3651 // - branch to false_target
3652 if (IsBooleanValueOrMaterializedCondition(cond)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003653 // The condition instruction has been materialized, compare the output to 0.
David Brazdil0debae72015-11-12 18:37:00 +00003654 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003655 DCHECK(cond_val.IsRegister());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003656 if (true_target == nullptr) {
David Brazdil0debae72015-11-12 18:37:00 +00003657 __ Beqz(cond_val.AsRegister<Register>(), false_target);
3658 } else {
3659 __ Bnez(cond_val.AsRegister<Register>(), true_target);
3660 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003661 } else {
3662 // The condition instruction has not been materialized, use its inputs as
3663 // the comparison and its condition as the branch condition.
David Brazdil0debae72015-11-12 18:37:00 +00003664 HCondition* condition = cond->AsCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003665 Primitive::Type type = condition->InputAt(0)->GetType();
3666 LocationSummary* locations = cond->GetLocations();
3667 IfCondition if_cond = condition->GetCondition();
3668 MipsLabel* branch_target = true_target;
David Brazdil0debae72015-11-12 18:37:00 +00003669
David Brazdil0debae72015-11-12 18:37:00 +00003670 if (true_target == nullptr) {
3671 if_cond = condition->GetOppositeCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003672 branch_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00003673 }
3674
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003675 switch (type) {
3676 default:
3677 GenerateIntCompareAndBranch(if_cond, locations, branch_target);
3678 break;
3679 case Primitive::kPrimLong:
3680 GenerateLongCompareAndBranch(if_cond, locations, branch_target);
3681 break;
3682 case Primitive::kPrimFloat:
3683 case Primitive::kPrimDouble:
3684 GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
3685 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003686 }
3687 }
David Brazdil0debae72015-11-12 18:37:00 +00003688
3689 // If neither branch falls through (case 3), the conditional branch to `true_target`
3690 // was already emitted (case 2) and we need to emit a jump to `false_target`.
3691 if (true_target != nullptr && false_target != nullptr) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003692 __ B(false_target);
3693 }
3694}
3695
3696void LocationsBuilderMIPS::VisitIf(HIf* if_instr) {
3697 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
David Brazdil0debae72015-11-12 18:37:00 +00003698 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003699 locations->SetInAt(0, Location::RequiresRegister());
3700 }
3701}
3702
3703void InstructionCodeGeneratorMIPS::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00003704 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
3705 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
3706 MipsLabel* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
3707 nullptr : codegen_->GetLabelOf(true_successor);
3708 MipsLabel* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
3709 nullptr : codegen_->GetLabelOf(false_successor);
3710 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003711}
3712
3713void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
3714 LocationSummary* locations = new (GetGraph()->GetArena())
3715 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01003716 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
David Brazdil0debae72015-11-12 18:37:00 +00003717 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003718 locations->SetInAt(0, Location::RequiresRegister());
3719 }
3720}
3721
3722void InstructionCodeGeneratorMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08003723 SlowPathCodeMIPS* slow_path =
3724 deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathMIPS>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00003725 GenerateTestAndBranch(deoptimize,
3726 /* condition_input_index */ 0,
3727 slow_path->GetEntryLabel(),
3728 /* false_target */ nullptr);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003729}
3730
David Brazdil74eb1b22015-12-14 11:44:01 +00003731void LocationsBuilderMIPS::VisitSelect(HSelect* select) {
3732 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
3733 if (Primitive::IsFloatingPointType(select->GetType())) {
3734 locations->SetInAt(0, Location::RequiresFpuRegister());
3735 locations->SetInAt(1, Location::RequiresFpuRegister());
3736 } else {
3737 locations->SetInAt(0, Location::RequiresRegister());
3738 locations->SetInAt(1, Location::RequiresRegister());
3739 }
3740 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
3741 locations->SetInAt(2, Location::RequiresRegister());
3742 }
3743 locations->SetOut(Location::SameAsFirstInput());
3744}
3745
3746void InstructionCodeGeneratorMIPS::VisitSelect(HSelect* select) {
3747 LocationSummary* locations = select->GetLocations();
3748 MipsLabel false_target;
3749 GenerateTestAndBranch(select,
3750 /* condition_input_index */ 2,
3751 /* true_target */ nullptr,
3752 &false_target);
3753 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
3754 __ Bind(&false_target);
3755}
3756
David Srbecky0cf44932015-12-09 14:09:59 +00003757void LocationsBuilderMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
3758 new (GetGraph()->GetArena()) LocationSummary(info);
3759}
3760
David Srbeckyd28f4a02016-03-14 17:14:24 +00003761void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo*) {
3762 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00003763}
3764
3765void CodeGeneratorMIPS::GenerateNop() {
3766 __ Nop();
David Srbecky0cf44932015-12-09 14:09:59 +00003767}
3768
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003769void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3770 Primitive::Type field_type = field_info.GetFieldType();
3771 bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
3772 bool generate_volatile = field_info.IsVolatile() && is_wide;
3773 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003774 instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003775
3776 locations->SetInAt(0, Location::RequiresRegister());
3777 if (generate_volatile) {
3778 InvokeRuntimeCallingConvention calling_convention;
3779 // need A0 to hold base + offset
3780 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3781 if (field_type == Primitive::kPrimLong) {
3782 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimLong));
3783 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003784 // Use Location::Any() to prevent situations when running out of available fp registers.
3785 locations->SetOut(Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003786 // Need some temp core regs since FP results are returned in core registers
3787 Location reg = calling_convention.GetReturnLocation(Primitive::kPrimLong);
3788 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairLow<Register>()));
3789 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairHigh<Register>()));
3790 }
3791 } else {
3792 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3793 locations->SetOut(Location::RequiresFpuRegister());
3794 } else {
3795 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3796 }
3797 }
3798}
3799
3800void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
3801 const FieldInfo& field_info,
3802 uint32_t dex_pc) {
3803 Primitive::Type type = field_info.GetFieldType();
3804 LocationSummary* locations = instruction->GetLocations();
3805 Register obj = locations->InAt(0).AsRegister<Register>();
3806 LoadOperandType load_type = kLoadUnsignedByte;
3807 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003808 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Alexey Frunze2923db72016-08-20 01:55:47 -07003809 auto null_checker = GetImplicitNullChecker(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003810
3811 switch (type) {
3812 case Primitive::kPrimBoolean:
3813 load_type = kLoadUnsignedByte;
3814 break;
3815 case Primitive::kPrimByte:
3816 load_type = kLoadSignedByte;
3817 break;
3818 case Primitive::kPrimShort:
3819 load_type = kLoadSignedHalfword;
3820 break;
3821 case Primitive::kPrimChar:
3822 load_type = kLoadUnsignedHalfword;
3823 break;
3824 case Primitive::kPrimInt:
3825 case Primitive::kPrimFloat:
3826 case Primitive::kPrimNot:
3827 load_type = kLoadWord;
3828 break;
3829 case Primitive::kPrimLong:
3830 case Primitive::kPrimDouble:
3831 load_type = kLoadDoubleword;
3832 break;
3833 case Primitive::kPrimVoid:
3834 LOG(FATAL) << "Unreachable type " << type;
3835 UNREACHABLE();
3836 }
3837
3838 if (is_volatile && load_type == kLoadDoubleword) {
3839 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003840 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003841 // Do implicit Null check
3842 __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
3843 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Serban Constantinescufca16662016-07-14 09:21:59 +01003844 codegen_->InvokeRuntime(kQuickA64Load, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003845 CheckEntrypointTypes<kQuickA64Load, int64_t, volatile const int64_t*>();
3846 if (type == Primitive::kPrimDouble) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003847 // FP results are returned in core registers. Need to move them.
3848 Location out = locations->Out();
3849 if (out.IsFpuRegister()) {
3850 __ Mtc1(locations->GetTemp(1).AsRegister<Register>(), out.AsFpuRegister<FRegister>());
3851 __ MoveToFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
3852 out.AsFpuRegister<FRegister>());
3853 } else {
3854 DCHECK(out.IsDoubleStackSlot());
3855 __ StoreToOffset(kStoreWord,
3856 locations->GetTemp(1).AsRegister<Register>(),
3857 SP,
3858 out.GetStackIndex());
3859 __ StoreToOffset(kStoreWord,
3860 locations->GetTemp(2).AsRegister<Register>(),
3861 SP,
3862 out.GetStackIndex() + 4);
3863 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003864 }
3865 } else {
3866 if (!Primitive::IsFloatingPointType(type)) {
3867 Register dst;
3868 if (type == Primitive::kPrimLong) {
3869 DCHECK(locations->Out().IsRegisterPair());
3870 dst = locations->Out().AsRegisterPairLow<Register>();
3871 } else {
3872 DCHECK(locations->Out().IsRegister());
3873 dst = locations->Out().AsRegister<Register>();
3874 }
Alexey Frunze2923db72016-08-20 01:55:47 -07003875 __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003876 } else {
3877 DCHECK(locations->Out().IsFpuRegister());
3878 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
3879 if (type == Primitive::kPrimFloat) {
Alexey Frunze2923db72016-08-20 01:55:47 -07003880 __ LoadSFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003881 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07003882 __ LoadDFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003883 }
3884 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003885 }
3886
3887 if (is_volatile) {
3888 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3889 }
3890}
3891
3892void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3893 Primitive::Type field_type = field_info.GetFieldType();
3894 bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
3895 bool generate_volatile = field_info.IsVolatile() && is_wide;
3896 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003897 instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003898
3899 locations->SetInAt(0, Location::RequiresRegister());
3900 if (generate_volatile) {
3901 InvokeRuntimeCallingConvention calling_convention;
3902 // need A0 to hold base + offset
3903 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3904 if (field_type == Primitive::kPrimLong) {
3905 locations->SetInAt(1, Location::RegisterPairLocation(
3906 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3907 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003908 // Use Location::Any() to prevent situations when running out of available fp registers.
3909 locations->SetInAt(1, Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003910 // Pass FP parameters in core registers.
3911 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
3912 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
3913 }
3914 } else {
3915 if (Primitive::IsFloatingPointType(field_type)) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003916 locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003917 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003918 locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003919 }
3920 }
3921}
3922
3923void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction,
3924 const FieldInfo& field_info,
3925 uint32_t dex_pc) {
3926 Primitive::Type type = field_info.GetFieldType();
3927 LocationSummary* locations = instruction->GetLocations();
3928 Register obj = locations->InAt(0).AsRegister<Register>();
Alexey Frunzef58b2482016-09-02 22:14:06 -07003929 Location value_location = locations->InAt(1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003930 StoreOperandType store_type = kStoreByte;
3931 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003932 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Alexey Frunze2923db72016-08-20 01:55:47 -07003933 auto null_checker = GetImplicitNullChecker(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003934
3935 switch (type) {
3936 case Primitive::kPrimBoolean:
3937 case Primitive::kPrimByte:
3938 store_type = kStoreByte;
3939 break;
3940 case Primitive::kPrimShort:
3941 case Primitive::kPrimChar:
3942 store_type = kStoreHalfword;
3943 break;
3944 case Primitive::kPrimInt:
3945 case Primitive::kPrimFloat:
3946 case Primitive::kPrimNot:
3947 store_type = kStoreWord;
3948 break;
3949 case Primitive::kPrimLong:
3950 case Primitive::kPrimDouble:
3951 store_type = kStoreDoubleword;
3952 break;
3953 case Primitive::kPrimVoid:
3954 LOG(FATAL) << "Unreachable type " << type;
3955 UNREACHABLE();
3956 }
3957
3958 if (is_volatile) {
3959 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3960 }
3961
3962 if (is_volatile && store_type == kStoreDoubleword) {
3963 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003964 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003965 // Do implicit Null check.
3966 __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
3967 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3968 if (type == Primitive::kPrimDouble) {
3969 // Pass FP parameters in core registers.
Alexey Frunzef58b2482016-09-02 22:14:06 -07003970 if (value_location.IsFpuRegister()) {
3971 __ Mfc1(locations->GetTemp(1).AsRegister<Register>(),
3972 value_location.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003973 __ MoveFromFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
Alexey Frunzef58b2482016-09-02 22:14:06 -07003974 value_location.AsFpuRegister<FRegister>());
3975 } else if (value_location.IsDoubleStackSlot()) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003976 __ LoadFromOffset(kLoadWord,
3977 locations->GetTemp(1).AsRegister<Register>(),
3978 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07003979 value_location.GetStackIndex());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003980 __ LoadFromOffset(kLoadWord,
3981 locations->GetTemp(2).AsRegister<Register>(),
3982 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07003983 value_location.GetStackIndex() + 4);
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003984 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003985 DCHECK(value_location.IsConstant());
3986 DCHECK(value_location.GetConstant()->IsDoubleConstant());
3987 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02003988 __ LoadConst64(locations->GetTemp(2).AsRegister<Register>(),
3989 locations->GetTemp(1).AsRegister<Register>(),
3990 value);
3991 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003992 }
Serban Constantinescufca16662016-07-14 09:21:59 +01003993 codegen_->InvokeRuntime(kQuickA64Store, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003994 CheckEntrypointTypes<kQuickA64Store, void, volatile int64_t *, int64_t>();
3995 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003996 if (value_location.IsConstant()) {
3997 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
3998 __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
3999 } else if (!Primitive::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004000 Register src;
4001 if (type == Primitive::kPrimLong) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07004002 src = value_location.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004003 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07004004 src = value_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004005 }
Alexey Frunze2923db72016-08-20 01:55:47 -07004006 __ StoreToOffset(store_type, src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004007 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07004008 FRegister src = value_location.AsFpuRegister<FRegister>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004009 if (type == Primitive::kPrimFloat) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004010 __ StoreSToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004011 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07004012 __ StoreDToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004013 }
4014 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004015 }
4016
4017 // TODO: memory barriers?
4018 if (CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1))) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07004019 Register src = value_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004020 codegen_->MarkGCCard(obj, src);
4021 }
4022
4023 if (is_volatile) {
4024 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4025 }
4026}
4027
4028void LocationsBuilderMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4029 HandleFieldGet(instruction, instruction->GetFieldInfo());
4030}
4031
4032void InstructionCodeGeneratorMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4033 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
4034}
4035
4036void LocationsBuilderMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4037 HandleFieldSet(instruction, instruction->GetFieldInfo());
4038}
4039
4040void InstructionCodeGeneratorMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4041 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
4042}
4043
Alexey Frunze06a46c42016-07-19 15:00:40 -07004044void InstructionCodeGeneratorMIPS::GenerateGcRootFieldLoad(
4045 HInstruction* instruction ATTRIBUTE_UNUSED,
4046 Location root,
4047 Register obj,
4048 uint32_t offset) {
4049 Register root_reg = root.AsRegister<Register>();
4050 if (kEmitCompilerReadBarrier) {
4051 UNIMPLEMENTED(FATAL) << "for read barrier";
4052 } else {
4053 // Plain GC root load with no read barrier.
4054 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
4055 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
4056 // Note that GC roots are not affected by heap poisoning, thus we
4057 // do not have to unpoison `root_reg` here.
4058 }
4059}
4060
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004061void LocationsBuilderMIPS::VisitInstanceOf(HInstanceOf* instruction) {
4062 LocationSummary::CallKind call_kind =
4063 instruction->IsExactCheck() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
4064 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4065 locations->SetInAt(0, Location::RequiresRegister());
4066 locations->SetInAt(1, Location::RequiresRegister());
4067 // The output does overlap inputs.
4068 // Note that TypeCheckSlowPathMIPS uses this register too.
4069 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
4070}
4071
4072void InstructionCodeGeneratorMIPS::VisitInstanceOf(HInstanceOf* instruction) {
4073 LocationSummary* locations = instruction->GetLocations();
4074 Register obj = locations->InAt(0).AsRegister<Register>();
4075 Register cls = locations->InAt(1).AsRegister<Register>();
4076 Register out = locations->Out().AsRegister<Register>();
4077
4078 MipsLabel done;
4079
4080 // Return 0 if `obj` is null.
4081 // TODO: Avoid this check if we know `obj` is not null.
4082 __ Move(out, ZERO);
4083 __ Beqz(obj, &done);
4084
4085 // Compare the class of `obj` with `cls`.
4086 __ LoadFromOffset(kLoadWord, out, obj, mirror::Object::ClassOffset().Int32Value());
4087 if (instruction->IsExactCheck()) {
4088 // Classes must be equal for the instanceof to succeed.
4089 __ Xor(out, out, cls);
4090 __ Sltiu(out, out, 1);
4091 } else {
4092 // If the classes are not equal, we go into a slow path.
4093 DCHECK(locations->OnlyCallsOnSlowPath());
4094 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction);
4095 codegen_->AddSlowPath(slow_path);
4096 __ Bne(out, cls, slow_path->GetEntryLabel());
4097 __ LoadConst32(out, 1);
4098 __ Bind(slow_path->GetExitLabel());
4099 }
4100
4101 __ Bind(&done);
4102}
4103
4104void LocationsBuilderMIPS::VisitIntConstant(HIntConstant* constant) {
4105 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
4106 locations->SetOut(Location::ConstantLocation(constant));
4107}
4108
4109void InstructionCodeGeneratorMIPS::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
4110 // Will be generated at use site.
4111}
4112
4113void LocationsBuilderMIPS::VisitNullConstant(HNullConstant* constant) {
4114 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
4115 locations->SetOut(Location::ConstantLocation(constant));
4116}
4117
4118void InstructionCodeGeneratorMIPS::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
4119 // Will be generated at use site.
4120}
4121
4122void LocationsBuilderMIPS::HandleInvoke(HInvoke* invoke) {
4123 InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
4124 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
4125}
4126
4127void LocationsBuilderMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
4128 HandleInvoke(invoke);
4129 // The register T0 is required to be used for the hidden argument in
4130 // art_quick_imt_conflict_trampoline, so add the hidden argument.
4131 invoke->GetLocations()->AddTemp(Location::RegisterLocation(T0));
4132}
4133
4134void InstructionCodeGeneratorMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
4135 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
4136 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004137 Location receiver = invoke->GetLocations()->InAt(0);
4138 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07004139 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004140
4141 // Set the hidden argument.
4142 __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
4143 invoke->GetDexMethodIndex());
4144
4145 // temp = object->GetClass();
4146 if (receiver.IsStackSlot()) {
4147 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
4148 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
4149 } else {
4150 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
4151 }
4152 codegen_->MaybeRecordImplicitNullCheck(invoke);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00004153 __ LoadFromOffset(kLoadWord, temp, temp,
4154 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
4155 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00004156 invoke->GetImtIndex(), kMipsPointerSize));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004157 // temp = temp->GetImtEntryAt(method_offset);
4158 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
4159 // T9 = temp->GetEntryPoint();
4160 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
4161 // T9();
4162 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004163 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004164 DCHECK(!codegen_->IsLeafMethod());
4165 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
4166}
4167
4168void LocationsBuilderMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Chris Larsen701566a2015-10-27 15:29:13 -07004169 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
4170 if (intrinsic.TryDispatch(invoke)) {
4171 return;
4172 }
4173
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004174 HandleInvoke(invoke);
4175}
4176
4177void LocationsBuilderMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00004178 // Explicit clinit checks triggered by static invokes must have been pruned by
4179 // art::PrepareForRegisterAllocation.
4180 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004181
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004182 HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
4183 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
4184 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4185
4186 // kDirectAddressWithFixup and kCallDirectWithFixup need no extra input on R6 because
4187 // R6 has PC-relative addressing.
4188 bool has_extra_input = !isR6 &&
4189 ((method_load_kind == HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup) ||
4190 (code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup));
4191
4192 if (invoke->HasPcRelativeDexCache()) {
4193 // kDexCachePcRelative is mutually exclusive with
4194 // kDirectAddressWithFixup/kCallDirectWithFixup.
4195 CHECK(!has_extra_input);
4196 has_extra_input = true;
4197 }
4198
Chris Larsen701566a2015-10-27 15:29:13 -07004199 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
4200 if (intrinsic.TryDispatch(invoke)) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004201 if (invoke->GetLocations()->CanCall() && has_extra_input) {
4202 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
4203 }
Chris Larsen701566a2015-10-27 15:29:13 -07004204 return;
4205 }
4206
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004207 HandleInvoke(invoke);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004208
4209 // Add the extra input register if either the dex cache array base register
4210 // or the PC-relative base register for accessing literals is needed.
4211 if (has_extra_input) {
4212 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
4213 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004214}
4215
Chris Larsen701566a2015-10-27 15:29:13 -07004216static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004217 if (invoke->GetLocations()->Intrinsified()) {
Chris Larsen701566a2015-10-27 15:29:13 -07004218 IntrinsicCodeGeneratorMIPS intrinsic(codegen);
4219 intrinsic.Dispatch(invoke);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004220 return true;
4221 }
4222 return false;
4223}
4224
Vladimir Markocac5a7e2016-02-22 10:39:50 +00004225HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
Alexey Frunze06a46c42016-07-19 15:00:40 -07004226 HLoadString::LoadKind desired_string_load_kind) {
4227 if (kEmitCompilerReadBarrier) {
4228 UNIMPLEMENTED(FATAL) << "for read barrier";
4229 }
4230 // We disable PC-relative load when there is an irreducible loop, as the optimization
4231 // is incompatible with it.
4232 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
4233 bool fallback_load = has_irreducible_loops;
4234 switch (desired_string_load_kind) {
4235 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
4236 DCHECK(!GetCompilerOptions().GetCompilePic());
4237 break;
4238 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
4239 DCHECK(GetCompilerOptions().GetCompilePic());
4240 break;
4241 case HLoadString::LoadKind::kBootImageAddress:
4242 break;
4243 case HLoadString::LoadKind::kDexCacheAddress:
4244 DCHECK(Runtime::Current()->UseJitCompilation());
4245 fallback_load = false;
4246 break;
4247 case HLoadString::LoadKind::kDexCachePcRelative:
4248 DCHECK(!Runtime::Current()->UseJitCompilation());
4249 // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods
4250 // with irreducible loops.
4251 break;
4252 case HLoadString::LoadKind::kDexCacheViaMethod:
4253 fallback_load = false;
4254 break;
4255 }
4256 if (fallback_load) {
4257 desired_string_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
4258 }
4259 return desired_string_load_kind;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00004260}
4261
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01004262HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind(
4263 HLoadClass::LoadKind desired_class_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07004264 if (kEmitCompilerReadBarrier) {
4265 UNIMPLEMENTED(FATAL) << "for read barrier";
4266 }
4267 // We disable pc-relative load when there is an irreducible loop, as the optimization
4268 // is incompatible with it.
4269 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
4270 bool fallback_load = has_irreducible_loops;
4271 switch (desired_class_load_kind) {
4272 case HLoadClass::LoadKind::kReferrersClass:
4273 fallback_load = false;
4274 break;
4275 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
4276 DCHECK(!GetCompilerOptions().GetCompilePic());
4277 break;
4278 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
4279 DCHECK(GetCompilerOptions().GetCompilePic());
4280 break;
4281 case HLoadClass::LoadKind::kBootImageAddress:
4282 break;
4283 case HLoadClass::LoadKind::kDexCacheAddress:
4284 DCHECK(Runtime::Current()->UseJitCompilation());
4285 fallback_load = false;
4286 break;
4287 case HLoadClass::LoadKind::kDexCachePcRelative:
4288 DCHECK(!Runtime::Current()->UseJitCompilation());
4289 // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods
4290 // with irreducible loops.
4291 break;
4292 case HLoadClass::LoadKind::kDexCacheViaMethod:
4293 fallback_load = false;
4294 break;
4295 }
4296 if (fallback_load) {
4297 desired_class_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
4298 }
4299 return desired_class_load_kind;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01004300}
4301
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004302Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
4303 Register temp) {
4304 CHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
4305 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
4306 if (!invoke->GetLocations()->Intrinsified()) {
4307 return location.AsRegister<Register>();
4308 }
4309 // For intrinsics we allow any location, so it may be on the stack.
4310 if (!location.IsRegister()) {
4311 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
4312 return temp;
4313 }
4314 // For register locations, check if the register was saved. If so, get it from the stack.
4315 // Note: There is a chance that the register was saved but not overwritten, so we could
4316 // save one load. However, since this is just an intrinsic slow path we prefer this
4317 // simple and more robust approach rather that trying to determine if that's the case.
4318 SlowPathCode* slow_path = GetCurrentSlowPath();
4319 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
4320 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
4321 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
4322 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
4323 return temp;
4324 }
4325 return location.AsRegister<Register>();
4326}
4327
Vladimir Markodc151b22015-10-15 18:02:30 +01004328HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
4329 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +01004330 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004331 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
4332 // We disable PC-relative load when there is an irreducible loop, as the optimization
4333 // is incompatible with it.
4334 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
4335 bool fallback_load = true;
4336 bool fallback_call = true;
4337 switch (dispatch_info.method_load_kind) {
Vladimir Markodc151b22015-10-15 18:02:30 +01004338 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
4339 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004340 fallback_load = has_irreducible_loops;
4341 break;
Vladimir Markodc151b22015-10-15 18:02:30 +01004342 default:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004343 fallback_load = false;
Vladimir Markodc151b22015-10-15 18:02:30 +01004344 break;
4345 }
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004346 switch (dispatch_info.code_ptr_location) {
Vladimir Markodc151b22015-10-15 18:02:30 +01004347 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004348 fallback_call = has_irreducible_loops;
4349 break;
Vladimir Markodc151b22015-10-15 18:02:30 +01004350 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004351 // TODO: Implement this type.
4352 break;
Vladimir Markodc151b22015-10-15 18:02:30 +01004353 default:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004354 fallback_call = false;
4355 break;
Vladimir Markodc151b22015-10-15 18:02:30 +01004356 }
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004357 if (fallback_load) {
4358 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
4359 dispatch_info.method_load_data = 0;
4360 }
4361 if (fallback_call) {
4362 dispatch_info.code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
4363 dispatch_info.direct_code_ptr = 0;
4364 }
4365 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01004366}
4367
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004368void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
4369 // All registers are assumed to be correctly set up per the calling convention.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004370 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004371 HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
4372 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
4373 bool isR6 = isa_features_.IsR6();
4374 // kDirectAddressWithFixup and kCallDirectWithFixup have no extra input on R6 because
4375 // R6 has PC-relative addressing.
4376 bool has_extra_input = invoke->HasPcRelativeDexCache() ||
4377 (!isR6 &&
4378 ((method_load_kind == HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup) ||
4379 (code_ptr_location == HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup)));
4380 Register base_reg = has_extra_input
4381 ? GetInvokeStaticOrDirectExtraParameter(invoke, temp.AsRegister<Register>())
4382 : ZERO;
4383
4384 // For better instruction scheduling we load the direct code pointer before the method pointer.
4385 switch (code_ptr_location) {
4386 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
4387 // T9 = invoke->GetDirectCodePtr();
4388 __ LoadConst32(T9, invoke->GetDirectCodePtr());
4389 break;
4390 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4391 // T9 = code address from literal pool with link-time patch.
4392 __ LoadLiteral(T9, base_reg, DeduplicateMethodCodeLiteral(invoke->GetTargetMethod()));
4393 break;
4394 default:
4395 break;
4396 }
4397
4398 switch (method_load_kind) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01004399 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004400 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01004401 uint32_t offset =
4402 GetThreadOffset<kMipsPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004403 __ LoadFromOffset(kLoadWord,
4404 temp.AsRegister<Register>(),
4405 TR,
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01004406 offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004407 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01004408 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004409 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00004410 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004411 break;
4412 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
4413 __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
4414 break;
4415 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004416 __ LoadLiteral(temp.AsRegister<Register>(),
4417 base_reg,
4418 DeduplicateMethodAddressLiteral(invoke->GetTargetMethod()));
4419 break;
4420 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
4421 HMipsDexCacheArraysBase* base =
4422 invoke->InputAt(invoke->GetSpecialInputIndex())->AsMipsDexCacheArraysBase();
4423 int32_t offset =
4424 invoke->GetDexCacheArrayOffset() - base->GetElementOffset() - kDexCacheArrayLwOffset;
4425 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
4426 break;
4427 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004428 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00004429 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004430 Register reg = temp.AsRegister<Register>();
4431 Register method_reg;
4432 if (current_method.IsRegister()) {
4433 method_reg = current_method.AsRegister<Register>();
4434 } else {
4435 // TODO: use the appropriate DCHECK() here if possible.
4436 // DCHECK(invoke->GetLocations()->Intrinsified());
4437 DCHECK(!current_method.IsValid());
4438 method_reg = reg;
4439 __ Lw(reg, SP, kCurrentMethodStackOffset);
4440 }
4441
4442 // temp = temp->dex_cache_resolved_methods_;
4443 __ LoadFromOffset(kLoadWord,
4444 reg,
4445 method_reg,
4446 ArtMethod::DexCacheResolvedMethodsOffset(kMipsPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01004447 // temp = temp[index_in_cache];
4448 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
4449 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004450 __ LoadFromOffset(kLoadWord,
4451 reg,
4452 reg,
4453 CodeGenerator::GetCachePointerOffset(index_in_cache));
4454 break;
4455 }
4456 }
4457
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004458 switch (code_ptr_location) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004459 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004460 __ Bal(&frame_entry_label_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004461 break;
4462 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004463 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
4464 // T9 prepared above for better instruction scheduling.
4465 // T9()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004466 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004467 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004468 break;
Vladimir Markodc151b22015-10-15 18:02:30 +01004469 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07004470 // TODO: Implement this type.
Vladimir Markodc151b22015-10-15 18:02:30 +01004471 // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch().
4472 LOG(FATAL) << "Unsupported";
4473 UNREACHABLE();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004474 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
4475 // T9 = callee_method->entry_point_from_quick_compiled_code_;
Goran Jakovljevic1a878372015-10-26 14:28:52 +01004476 __ LoadFromOffset(kLoadWord,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004477 T9,
4478 callee_method.AsRegister<Register>(),
4479 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07004480 kMipsPointerSize).Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004481 // T9()
4482 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004483 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004484 break;
4485 }
4486 DCHECK(!IsLeafMethod());
4487}
4488
4489void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00004490 // Explicit clinit checks triggered by static invokes must have been pruned by
4491 // art::PrepareForRegisterAllocation.
4492 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004493
4494 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
4495 return;
4496 }
4497
4498 LocationSummary* locations = invoke->GetLocations();
4499 codegen_->GenerateStaticOrDirectCall(invoke,
4500 locations->HasTemps()
4501 ? locations->GetTemp(0)
4502 : Location::NoLocation());
4503 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
4504}
4505
Chris Larsen3acee732015-11-18 13:31:08 -08004506void CodeGeneratorMIPS::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004507 LocationSummary* locations = invoke->GetLocations();
4508 Location receiver = locations->InAt(0);
Chris Larsen3acee732015-11-18 13:31:08 -08004509 Register temp = temp_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004510 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
4511 invoke->GetVTableIndex(), kMipsPointerSize).SizeValue();
4512 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07004513 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004514
4515 // temp = object->GetClass();
Chris Larsen3acee732015-11-18 13:31:08 -08004516 DCHECK(receiver.IsRegister());
4517 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
4518 MaybeRecordImplicitNullCheck(invoke);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004519 // temp = temp->GetMethodAt(method_offset);
4520 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
4521 // T9 = temp->GetEntryPoint();
4522 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
4523 // T9();
4524 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004525 __ NopIfNoReordering();
Chris Larsen3acee732015-11-18 13:31:08 -08004526}
4527
4528void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
4529 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
4530 return;
4531 }
4532
4533 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004534 DCHECK(!codegen_->IsLeafMethod());
4535 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
4536}
4537
4538void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07004539 if (cls->NeedsAccessCheck()) {
4540 InvokeRuntimeCallingConvention calling_convention;
4541 CodeGenerator::CreateLoadClassLocationSummary(
4542 cls,
4543 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
4544 Location::RegisterLocation(V0),
4545 /* code_generator_supports_read_barrier */ false); // TODO: revisit this bool.
4546 return;
4547 }
4548
4549 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
4550 ? LocationSummary::kCallOnSlowPath
4551 : LocationSummary::kNoCall;
4552 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
4553 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
4554 switch (load_kind) {
4555 // We need an extra register for PC-relative literals on R2.
4556 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
4557 case HLoadClass::LoadKind::kBootImageAddress:
4558 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
4559 if (codegen_->GetInstructionSetFeatures().IsR6()) {
4560 break;
4561 }
4562 FALLTHROUGH_INTENDED;
4563 // We need an extra register for PC-relative dex cache accesses.
4564 case HLoadClass::LoadKind::kDexCachePcRelative:
4565 case HLoadClass::LoadKind::kReferrersClass:
4566 case HLoadClass::LoadKind::kDexCacheViaMethod:
4567 locations->SetInAt(0, Location::RequiresRegister());
4568 break;
4569 default:
4570 break;
4571 }
4572 locations->SetOut(Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004573}
4574
4575void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
4576 LocationSummary* locations = cls->GetLocations();
Pavle Batutae87a7182015-10-28 13:10:42 +01004577 if (cls->NeedsAccessCheck()) {
4578 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
Serban Constantinescufca16662016-07-14 09:21:59 +01004579 codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00004580 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Pavle Batutae87a7182015-10-28 13:10:42 +01004581 return;
4582 }
4583
Alexey Frunze06a46c42016-07-19 15:00:40 -07004584 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
4585 Location out_loc = locations->Out();
4586 Register out = out_loc.AsRegister<Register>();
4587 Register base_or_current_method_reg;
4588 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4589 switch (load_kind) {
4590 // We need an extra register for PC-relative literals on R2.
4591 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
4592 case HLoadClass::LoadKind::kBootImageAddress:
4593 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
4594 base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
4595 break;
4596 // We need an extra register for PC-relative dex cache accesses.
4597 case HLoadClass::LoadKind::kDexCachePcRelative:
4598 case HLoadClass::LoadKind::kReferrersClass:
4599 case HLoadClass::LoadKind::kDexCacheViaMethod:
4600 base_or_current_method_reg = locations->InAt(0).AsRegister<Register>();
4601 break;
4602 default:
4603 base_or_current_method_reg = ZERO;
4604 break;
4605 }
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00004606
Alexey Frunze06a46c42016-07-19 15:00:40 -07004607 bool generate_null_check = false;
4608 switch (load_kind) {
4609 case HLoadClass::LoadKind::kReferrersClass: {
4610 DCHECK(!cls->CanCallRuntime());
4611 DCHECK(!cls->MustGenerateClinitCheck());
4612 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
4613 GenerateGcRootFieldLoad(cls,
4614 out_loc,
4615 base_or_current_method_reg,
4616 ArtMethod::DeclaringClassOffset().Int32Value());
4617 break;
4618 }
4619 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
4620 DCHECK(!kEmitCompilerReadBarrier);
4621 __ LoadLiteral(out,
4622 base_or_current_method_reg,
4623 codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
4624 cls->GetTypeIndex()));
4625 break;
4626 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
4627 DCHECK(!kEmitCompilerReadBarrier);
4628 CodeGeneratorMIPS::PcRelativePatchInfo* info =
4629 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004630 bool reordering = __ SetReorder(false);
Alexey Frunze06a46c42016-07-19 15:00:40 -07004631 if (isR6) {
4632 __ Bind(&info->high_label);
4633 __ Bind(&info->pc_rel_label);
4634 // Add a 32-bit offset to PC.
4635 __ Auipc(out, /* placeholder */ 0x1234);
4636 __ Addiu(out, out, /* placeholder */ 0x5678);
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00004637 } else {
Alexey Frunze06a46c42016-07-19 15:00:40 -07004638 __ Bind(&info->high_label);
4639 __ Lui(out, /* placeholder */ 0x1234);
4640 // We do not bind info->pc_rel_label here, we'll use the assembler's label
4641 // for PC-relative literals and the base from HMipsComputeBaseMethodAddress.
4642 __ Ori(out, out, /* placeholder */ 0x5678);
4643 // Add a 32-bit offset to PC.
4644 __ Addu(out, out, base_or_current_method_reg);
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00004645 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004646 __ SetReorder(reordering);
Alexey Frunze06a46c42016-07-19 15:00:40 -07004647 break;
4648 }
4649 case HLoadClass::LoadKind::kBootImageAddress: {
4650 DCHECK(!kEmitCompilerReadBarrier);
4651 DCHECK_NE(cls->GetAddress(), 0u);
4652 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
4653 __ LoadLiteral(out,
4654 base_or_current_method_reg,
4655 codegen_->DeduplicateBootImageAddressLiteral(address));
4656 break;
4657 }
4658 case HLoadClass::LoadKind::kDexCacheAddress: {
4659 DCHECK_NE(cls->GetAddress(), 0u);
4660 uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
4661 static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
4662 DCHECK_ALIGNED(cls->GetAddress(), 4u);
4663 int16_t offset = Low16Bits(address);
4664 uint32_t base_address = address - offset; // This accounts for offset sign extension.
4665 __ Lui(out, High16Bits(base_address));
4666 // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
4667 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
4668 generate_null_check = !cls->IsInDexCache();
4669 break;
4670 }
4671 case HLoadClass::LoadKind::kDexCachePcRelative: {
4672 HMipsDexCacheArraysBase* base = cls->InputAt(0)->AsMipsDexCacheArraysBase();
4673 int32_t offset =
4674 cls->GetDexCacheElementOffset() - base->GetElementOffset() - kDexCacheArrayLwOffset;
4675 // /* GcRoot<mirror::Class> */ out = *(dex_cache_arrays_base + offset)
4676 GenerateGcRootFieldLoad(cls, out_loc, base_or_current_method_reg, offset);
4677 generate_null_check = !cls->IsInDexCache();
4678 break;
4679 }
4680 case HLoadClass::LoadKind::kDexCacheViaMethod: {
4681 // /* GcRoot<mirror::Class>[] */ out =
4682 // current_method.ptr_sized_fields_->dex_cache_resolved_types_
4683 __ LoadFromOffset(kLoadWord,
4684 out,
4685 base_or_current_method_reg,
4686 ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
4687 // /* GcRoot<mirror::Class> */ out = out[type_index]
4688 size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
4689 GenerateGcRootFieldLoad(cls, out_loc, out, offset);
4690 generate_null_check = !cls->IsInDexCache();
4691 }
4692 }
4693
4694 if (generate_null_check || cls->MustGenerateClinitCheck()) {
4695 DCHECK(cls->CanCallRuntime());
4696 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
4697 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4698 codegen_->AddSlowPath(slow_path);
4699 if (generate_null_check) {
4700 __ Beqz(out, slow_path->GetEntryLabel());
4701 }
4702 if (cls->MustGenerateClinitCheck()) {
4703 GenerateClassInitializationCheck(slow_path, out);
4704 } else {
4705 __ Bind(slow_path->GetExitLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004706 }
4707 }
4708}
4709
4710static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07004711 return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004712}
4713
4714void LocationsBuilderMIPS::VisitLoadException(HLoadException* load) {
4715 LocationSummary* locations =
4716 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4717 locations->SetOut(Location::RequiresRegister());
4718}
4719
4720void InstructionCodeGeneratorMIPS::VisitLoadException(HLoadException* load) {
4721 Register out = load->GetLocations()->Out().AsRegister<Register>();
4722 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4723}
4724
4725void LocationsBuilderMIPS::VisitClearException(HClearException* clear) {
4726 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4727}
4728
4729void InstructionCodeGeneratorMIPS::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4730 __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
4731}
4732
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004733void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07004734 LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
Vladimir Markocac5a7e2016-02-22 10:39:50 +00004735 ? LocationSummary::kCallOnSlowPath
4736 : LocationSummary::kNoCall;
Nicolas Geoffray917d0162015-11-24 18:25:35 +00004737 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Alexey Frunze06a46c42016-07-19 15:00:40 -07004738 HLoadString::LoadKind load_kind = load->GetLoadKind();
4739 switch (load_kind) {
4740 // We need an extra register for PC-relative literals on R2.
4741 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
4742 case HLoadString::LoadKind::kBootImageAddress:
4743 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
4744 if (codegen_->GetInstructionSetFeatures().IsR6()) {
4745 break;
4746 }
4747 FALLTHROUGH_INTENDED;
4748 // We need an extra register for PC-relative dex cache accesses.
4749 case HLoadString::LoadKind::kDexCachePcRelative:
4750 case HLoadString::LoadKind::kDexCacheViaMethod:
4751 locations->SetInAt(0, Location::RequiresRegister());
4752 break;
4753 default:
4754 break;
4755 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004756 locations->SetOut(Location::RequiresRegister());
4757}
4758
4759void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07004760 HLoadString::LoadKind load_kind = load->GetLoadKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004761 LocationSummary* locations = load->GetLocations();
Alexey Frunze06a46c42016-07-19 15:00:40 -07004762 Location out_loc = locations->Out();
4763 Register out = out_loc.AsRegister<Register>();
4764 Register base_or_current_method_reg;
4765 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4766 switch (load_kind) {
4767 // We need an extra register for PC-relative literals on R2.
4768 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
4769 case HLoadString::LoadKind::kBootImageAddress:
4770 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
4771 base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
4772 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07004773 default:
4774 base_or_current_method_reg = ZERO;
4775 break;
4776 }
4777
4778 switch (load_kind) {
4779 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
4780 DCHECK(!kEmitCompilerReadBarrier);
4781 __ LoadLiteral(out,
4782 base_or_current_method_reg,
4783 codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
4784 load->GetStringIndex()));
4785 return; // No dex cache slow path.
4786 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
4787 DCHECK(!kEmitCompilerReadBarrier);
4788 CodeGeneratorMIPS::PcRelativePatchInfo* info =
4789 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004790 bool reordering = __ SetReorder(false);
Alexey Frunze06a46c42016-07-19 15:00:40 -07004791 if (isR6) {
4792 __ Bind(&info->high_label);
4793 __ Bind(&info->pc_rel_label);
4794 // Add a 32-bit offset to PC.
4795 __ Auipc(out, /* placeholder */ 0x1234);
4796 __ Addiu(out, out, /* placeholder */ 0x5678);
4797 } else {
4798 __ Bind(&info->high_label);
4799 __ Lui(out, /* placeholder */ 0x1234);
4800 // We do not bind info->pc_rel_label here, we'll use the assembler's label
4801 // for PC-relative literals and the base from HMipsComputeBaseMethodAddress.
4802 __ Ori(out, out, /* placeholder */ 0x5678);
4803 // Add a 32-bit offset to PC.
4804 __ Addu(out, out, base_or_current_method_reg);
4805 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07004806 __ SetReorder(reordering);
Alexey Frunze06a46c42016-07-19 15:00:40 -07004807 return; // No dex cache slow path.
4808 }
4809 case HLoadString::LoadKind::kBootImageAddress: {
4810 DCHECK(!kEmitCompilerReadBarrier);
4811 DCHECK_NE(load->GetAddress(), 0u);
4812 uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
4813 __ LoadLiteral(out,
4814 base_or_current_method_reg,
4815 codegen_->DeduplicateBootImageAddressLiteral(address));
4816 return; // No dex cache slow path.
4817 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07004818 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07004819 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07004820 }
Nicolas Geoffray917d0162015-11-24 18:25:35 +00004821
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07004822 // TODO: Re-add the compiler code to do string dex cache lookup again.
4823 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
4824 codegen_->AddSlowPath(slow_path);
4825 __ B(slow_path->GetEntryLabel());
4826 __ Bind(slow_path->GetExitLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004827}
4828
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004829void LocationsBuilderMIPS::VisitLongConstant(HLongConstant* constant) {
4830 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
4831 locations->SetOut(Location::ConstantLocation(constant));
4832}
4833
4834void InstructionCodeGeneratorMIPS::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
4835 // Will be generated at use site.
4836}
4837
4838void LocationsBuilderMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
4839 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004840 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004841 InvokeRuntimeCallingConvention calling_convention;
4842 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4843}
4844
4845void InstructionCodeGeneratorMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
4846 if (instruction->IsEnter()) {
Serban Constantinescufca16662016-07-14 09:21:59 +01004847 codegen_->InvokeRuntime(kQuickLockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004848 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
4849 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01004850 codegen_->InvokeRuntime(kQuickUnlockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004851 }
4852 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
4853}
4854
4855void LocationsBuilderMIPS::VisitMul(HMul* mul) {
4856 LocationSummary* locations =
4857 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
4858 switch (mul->GetResultType()) {
4859 case Primitive::kPrimInt:
4860 case Primitive::kPrimLong:
4861 locations->SetInAt(0, Location::RequiresRegister());
4862 locations->SetInAt(1, Location::RequiresRegister());
4863 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4864 break;
4865
4866 case Primitive::kPrimFloat:
4867 case Primitive::kPrimDouble:
4868 locations->SetInAt(0, Location::RequiresFpuRegister());
4869 locations->SetInAt(1, Location::RequiresFpuRegister());
4870 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4871 break;
4872
4873 default:
4874 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
4875 }
4876}
4877
4878void InstructionCodeGeneratorMIPS::VisitMul(HMul* instruction) {
4879 Primitive::Type type = instruction->GetType();
4880 LocationSummary* locations = instruction->GetLocations();
4881 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4882
4883 switch (type) {
4884 case Primitive::kPrimInt: {
4885 Register dst = locations->Out().AsRegister<Register>();
4886 Register lhs = locations->InAt(0).AsRegister<Register>();
4887 Register rhs = locations->InAt(1).AsRegister<Register>();
4888
4889 if (isR6) {
4890 __ MulR6(dst, lhs, rhs);
4891 } else {
4892 __ MulR2(dst, lhs, rhs);
4893 }
4894 break;
4895 }
4896 case Primitive::kPrimLong: {
4897 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
4898 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
4899 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4900 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
4901 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
4902 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
4903
4904 // Extra checks to protect caused by the existance of A1_A2.
4905 // The algorithm is wrong if dst_high is either lhs_lo or rhs_lo:
4906 // (e.g. lhs=a0_a1, rhs=a2_a3 and dst=a1_a2).
4907 DCHECK_NE(dst_high, lhs_low);
4908 DCHECK_NE(dst_high, rhs_low);
4909
4910 // A_B * C_D
4911 // dst_hi: [ low(A*D) + low(B*C) + hi(B*D) ]
4912 // dst_lo: [ low(B*D) ]
4913 // Note: R2 and R6 MUL produce the low 32 bit of the multiplication result.
4914
4915 if (isR6) {
4916 __ MulR6(TMP, lhs_high, rhs_low);
4917 __ MulR6(dst_high, lhs_low, rhs_high);
4918 __ Addu(dst_high, dst_high, TMP);
4919 __ MuhuR6(TMP, lhs_low, rhs_low);
4920 __ Addu(dst_high, dst_high, TMP);
4921 __ MulR6(dst_low, lhs_low, rhs_low);
4922 } else {
4923 __ MulR2(TMP, lhs_high, rhs_low);
4924 __ MulR2(dst_high, lhs_low, rhs_high);
4925 __ Addu(dst_high, dst_high, TMP);
4926 __ MultuR2(lhs_low, rhs_low);
4927 __ Mfhi(TMP);
4928 __ Addu(dst_high, dst_high, TMP);
4929 __ Mflo(dst_low);
4930 }
4931 break;
4932 }
4933 case Primitive::kPrimFloat:
4934 case Primitive::kPrimDouble: {
4935 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4936 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
4937 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
4938 if (type == Primitive::kPrimFloat) {
4939 __ MulS(dst, lhs, rhs);
4940 } else {
4941 __ MulD(dst, lhs, rhs);
4942 }
4943 break;
4944 }
4945 default:
4946 LOG(FATAL) << "Unexpected mul type " << type;
4947 }
4948}
4949
4950void LocationsBuilderMIPS::VisitNeg(HNeg* neg) {
4951 LocationSummary* locations =
4952 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
4953 switch (neg->GetResultType()) {
4954 case Primitive::kPrimInt:
4955 case Primitive::kPrimLong:
4956 locations->SetInAt(0, Location::RequiresRegister());
4957 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4958 break;
4959
4960 case Primitive::kPrimFloat:
4961 case Primitive::kPrimDouble:
4962 locations->SetInAt(0, Location::RequiresFpuRegister());
4963 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4964 break;
4965
4966 default:
4967 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
4968 }
4969}
4970
4971void InstructionCodeGeneratorMIPS::VisitNeg(HNeg* instruction) {
4972 Primitive::Type type = instruction->GetType();
4973 LocationSummary* locations = instruction->GetLocations();
4974
4975 switch (type) {
4976 case Primitive::kPrimInt: {
4977 Register dst = locations->Out().AsRegister<Register>();
4978 Register src = locations->InAt(0).AsRegister<Register>();
4979 __ Subu(dst, ZERO, src);
4980 break;
4981 }
4982 case Primitive::kPrimLong: {
4983 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
4984 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
4985 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4986 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
4987 __ Subu(dst_low, ZERO, src_low);
4988 __ Sltu(TMP, ZERO, dst_low);
4989 __ Subu(dst_high, ZERO, src_high);
4990 __ Subu(dst_high, dst_high, TMP);
4991 break;
4992 }
4993 case Primitive::kPrimFloat:
4994 case Primitive::kPrimDouble: {
4995 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4996 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
4997 if (type == Primitive::kPrimFloat) {
4998 __ NegS(dst, src);
4999 } else {
5000 __ NegD(dst, src);
5001 }
5002 break;
5003 }
5004 default:
5005 LOG(FATAL) << "Unexpected neg type " << type;
5006 }
5007}
5008
5009void LocationsBuilderMIPS::VisitNewArray(HNewArray* instruction) {
5010 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005011 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005012 InvokeRuntimeCallingConvention calling_convention;
5013 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5014 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
5015 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
5016 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5017}
5018
5019void InstructionCodeGeneratorMIPS::VisitNewArray(HNewArray* instruction) {
5020 InvokeRuntimeCallingConvention calling_convention;
5021 Register current_method_register = calling_convention.GetRegisterAt(2);
5022 __ Lw(current_method_register, SP, kCurrentMethodStackOffset);
5023 // Move an uint16_t value to a register.
5024 __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
Serban Constantinescufca16662016-07-14 09:21:59 +01005025 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005026 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
5027 void*, uint32_t, int32_t, ArtMethod*>();
5028}
5029
5030void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) {
5031 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005032 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005033 InvokeRuntimeCallingConvention calling_convention;
David Brazdil6de19382016-01-08 17:37:10 +00005034 if (instruction->IsStringAlloc()) {
5035 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
5036 } else {
5037 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5038 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5039 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005040 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
5041}
5042
5043void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) {
David Brazdil6de19382016-01-08 17:37:10 +00005044 if (instruction->IsStringAlloc()) {
5045 // String is allocated through StringFactory. Call NewEmptyString entry point.
5046 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07005047 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00005048 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
5049 __ LoadFromOffset(kLoadWord, T9, temp, code_offset.Int32Value());
5050 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005051 __ NopIfNoReordering();
David Brazdil6de19382016-01-08 17:37:10 +00005052 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
5053 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01005054 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
David Brazdil6de19382016-01-08 17:37:10 +00005055 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
5056 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005057}
5058
5059void LocationsBuilderMIPS::VisitNot(HNot* instruction) {
5060 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
5061 locations->SetInAt(0, Location::RequiresRegister());
5062 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5063}
5064
5065void InstructionCodeGeneratorMIPS::VisitNot(HNot* instruction) {
5066 Primitive::Type type = instruction->GetType();
5067 LocationSummary* locations = instruction->GetLocations();
5068
5069 switch (type) {
5070 case Primitive::kPrimInt: {
5071 Register dst = locations->Out().AsRegister<Register>();
5072 Register src = locations->InAt(0).AsRegister<Register>();
5073 __ Nor(dst, src, ZERO);
5074 break;
5075 }
5076
5077 case Primitive::kPrimLong: {
5078 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
5079 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
5080 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
5081 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
5082 __ Nor(dst_high, src_high, ZERO);
5083 __ Nor(dst_low, src_low, ZERO);
5084 break;
5085 }
5086
5087 default:
5088 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
5089 }
5090}
5091
5092void LocationsBuilderMIPS::VisitBooleanNot(HBooleanNot* instruction) {
5093 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
5094 locations->SetInAt(0, Location::RequiresRegister());
5095 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5096}
5097
5098void InstructionCodeGeneratorMIPS::VisitBooleanNot(HBooleanNot* instruction) {
5099 LocationSummary* locations = instruction->GetLocations();
5100 __ Xori(locations->Out().AsRegister<Register>(),
5101 locations->InAt(0).AsRegister<Register>(),
5102 1);
5103}
5104
5105void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01005106 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
5107 locations->SetInAt(0, Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005108}
5109
Calin Juravle2ae48182016-03-16 14:05:09 +00005110void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
5111 if (CanMoveNullCheckToUser(instruction)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005112 return;
5113 }
5114 Location obj = instruction->GetLocations()->InAt(0);
5115
5116 __ Lw(ZERO, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00005117 RecordPcInfo(instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005118}
5119
Calin Juravle2ae48182016-03-16 14:05:09 +00005120void CodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005121 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathMIPS(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00005122 AddSlowPath(slow_path);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005123
5124 Location obj = instruction->GetLocations()->InAt(0);
5125
5126 __ Beqz(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
5127}
5128
5129void InstructionCodeGeneratorMIPS::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00005130 codegen_->GenerateNullCheck(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005131}
5132
5133void LocationsBuilderMIPS::VisitOr(HOr* instruction) {
5134 HandleBinaryOp(instruction);
5135}
5136
5137void InstructionCodeGeneratorMIPS::VisitOr(HOr* instruction) {
5138 HandleBinaryOp(instruction);
5139}
5140
5141void LocationsBuilderMIPS::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
5142 LOG(FATAL) << "Unreachable";
5143}
5144
5145void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) {
5146 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
5147}
5148
5149void LocationsBuilderMIPS::VisitParameterValue(HParameterValue* instruction) {
5150 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
5151 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
5152 if (location.IsStackSlot()) {
5153 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5154 } else if (location.IsDoubleStackSlot()) {
5155 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
5156 }
5157 locations->SetOut(location);
5158}
5159
5160void InstructionCodeGeneratorMIPS::VisitParameterValue(HParameterValue* instruction
5161 ATTRIBUTE_UNUSED) {
5162 // Nothing to do, the parameter is already at its location.
5163}
5164
5165void LocationsBuilderMIPS::VisitCurrentMethod(HCurrentMethod* instruction) {
5166 LocationSummary* locations =
5167 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5168 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
5169}
5170
5171void InstructionCodeGeneratorMIPS::VisitCurrentMethod(HCurrentMethod* instruction
5172 ATTRIBUTE_UNUSED) {
5173 // Nothing to do, the method is already at its location.
5174}
5175
5176void LocationsBuilderMIPS::VisitPhi(HPhi* instruction) {
5177 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Vladimir Marko372f10e2016-05-17 16:30:10 +01005178 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005179 locations->SetInAt(i, Location::Any());
5180 }
5181 locations->SetOut(Location::Any());
5182}
5183
5184void InstructionCodeGeneratorMIPS::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
5185 LOG(FATAL) << "Unreachable";
5186}
5187
5188void LocationsBuilderMIPS::VisitRem(HRem* rem) {
5189 Primitive::Type type = rem->GetResultType();
5190 LocationSummary::CallKind call_kind =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005191 (type == Primitive::kPrimInt) ? LocationSummary::kNoCall : LocationSummary::kCallOnMainOnly;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005192 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
5193
5194 switch (type) {
5195 case Primitive::kPrimInt:
5196 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08005197 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005198 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5199 break;
5200
5201 case Primitive::kPrimLong: {
5202 InvokeRuntimeCallingConvention calling_convention;
5203 locations->SetInAt(0, Location::RegisterPairLocation(
5204 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
5205 locations->SetInAt(1, Location::RegisterPairLocation(
5206 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
5207 locations->SetOut(calling_convention.GetReturnLocation(type));
5208 break;
5209 }
5210
5211 case Primitive::kPrimFloat:
5212 case Primitive::kPrimDouble: {
5213 InvokeRuntimeCallingConvention calling_convention;
5214 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
5215 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
5216 locations->SetOut(calling_convention.GetReturnLocation(type));
5217 break;
5218 }
5219
5220 default:
5221 LOG(FATAL) << "Unexpected rem type " << type;
5222 }
5223}
5224
5225void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) {
5226 Primitive::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005227
5228 switch (type) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08005229 case Primitive::kPrimInt:
5230 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005231 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005232 case Primitive::kPrimLong: {
Serban Constantinescufca16662016-07-14 09:21:59 +01005233 codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005234 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
5235 break;
5236 }
5237 case Primitive::kPrimFloat: {
Serban Constantinescufca16662016-07-14 09:21:59 +01005238 codegen_->InvokeRuntime(kQuickFmodf, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00005239 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005240 break;
5241 }
5242 case Primitive::kPrimDouble: {
Serban Constantinescufca16662016-07-14 09:21:59 +01005243 codegen_->InvokeRuntime(kQuickFmod, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00005244 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005245 break;
5246 }
5247 default:
5248 LOG(FATAL) << "Unexpected rem type " << type;
5249 }
5250}
5251
5252void LocationsBuilderMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
5253 memory_barrier->SetLocations(nullptr);
5254}
5255
5256void InstructionCodeGeneratorMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
5257 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
5258}
5259
5260void LocationsBuilderMIPS::VisitReturn(HReturn* ret) {
5261 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
5262 Primitive::Type return_type = ret->InputAt(0)->GetType();
5263 locations->SetInAt(0, MipsReturnLocation(return_type));
5264}
5265
5266void InstructionCodeGeneratorMIPS::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
5267 codegen_->GenerateFrameExit();
5268}
5269
5270void LocationsBuilderMIPS::VisitReturnVoid(HReturnVoid* ret) {
5271 ret->SetLocations(nullptr);
5272}
5273
5274void InstructionCodeGeneratorMIPS::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
5275 codegen_->GenerateFrameExit();
5276}
5277
Alexey Frunze92d90602015-12-18 18:16:36 -08005278void LocationsBuilderMIPS::VisitRor(HRor* ror) {
5279 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00005280}
5281
Alexey Frunze92d90602015-12-18 18:16:36 -08005282void InstructionCodeGeneratorMIPS::VisitRor(HRor* ror) {
5283 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00005284}
5285
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005286void LocationsBuilderMIPS::VisitShl(HShl* shl) {
5287 HandleShift(shl);
5288}
5289
5290void InstructionCodeGeneratorMIPS::VisitShl(HShl* shl) {
5291 HandleShift(shl);
5292}
5293
5294void LocationsBuilderMIPS::VisitShr(HShr* shr) {
5295 HandleShift(shr);
5296}
5297
5298void InstructionCodeGeneratorMIPS::VisitShr(HShr* shr) {
5299 HandleShift(shr);
5300}
5301
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005302void LocationsBuilderMIPS::VisitSub(HSub* instruction) {
5303 HandleBinaryOp(instruction);
5304}
5305
5306void InstructionCodeGeneratorMIPS::VisitSub(HSub* instruction) {
5307 HandleBinaryOp(instruction);
5308}
5309
5310void LocationsBuilderMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5311 HandleFieldGet(instruction, instruction->GetFieldInfo());
5312}
5313
5314void InstructionCodeGeneratorMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
5315 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
5316}
5317
5318void LocationsBuilderMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5319 HandleFieldSet(instruction, instruction->GetFieldInfo());
5320}
5321
5322void InstructionCodeGeneratorMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
5323 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
5324}
5325
5326void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldGet(
5327 HUnresolvedInstanceFieldGet* instruction) {
5328 FieldAccessCallingConventionMIPS calling_convention;
5329 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
5330 instruction->GetFieldType(),
5331 calling_convention);
5332}
5333
5334void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldGet(
5335 HUnresolvedInstanceFieldGet* instruction) {
5336 FieldAccessCallingConventionMIPS calling_convention;
5337 codegen_->GenerateUnresolvedFieldAccess(instruction,
5338 instruction->GetFieldType(),
5339 instruction->GetFieldIndex(),
5340 instruction->GetDexPc(),
5341 calling_convention);
5342}
5343
5344void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldSet(
5345 HUnresolvedInstanceFieldSet* instruction) {
5346 FieldAccessCallingConventionMIPS calling_convention;
5347 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
5348 instruction->GetFieldType(),
5349 calling_convention);
5350}
5351
5352void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldSet(
5353 HUnresolvedInstanceFieldSet* instruction) {
5354 FieldAccessCallingConventionMIPS calling_convention;
5355 codegen_->GenerateUnresolvedFieldAccess(instruction,
5356 instruction->GetFieldType(),
5357 instruction->GetFieldIndex(),
5358 instruction->GetDexPc(),
5359 calling_convention);
5360}
5361
5362void LocationsBuilderMIPS::VisitUnresolvedStaticFieldGet(
5363 HUnresolvedStaticFieldGet* instruction) {
5364 FieldAccessCallingConventionMIPS calling_convention;
5365 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
5366 instruction->GetFieldType(),
5367 calling_convention);
5368}
5369
5370void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldGet(
5371 HUnresolvedStaticFieldGet* instruction) {
5372 FieldAccessCallingConventionMIPS calling_convention;
5373 codegen_->GenerateUnresolvedFieldAccess(instruction,
5374 instruction->GetFieldType(),
5375 instruction->GetFieldIndex(),
5376 instruction->GetDexPc(),
5377 calling_convention);
5378}
5379
5380void LocationsBuilderMIPS::VisitUnresolvedStaticFieldSet(
5381 HUnresolvedStaticFieldSet* instruction) {
5382 FieldAccessCallingConventionMIPS calling_convention;
5383 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
5384 instruction->GetFieldType(),
5385 calling_convention);
5386}
5387
5388void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldSet(
5389 HUnresolvedStaticFieldSet* instruction) {
5390 FieldAccessCallingConventionMIPS calling_convention;
5391 codegen_->GenerateUnresolvedFieldAccess(instruction,
5392 instruction->GetFieldType(),
5393 instruction->GetFieldIndex(),
5394 instruction->GetDexPc(),
5395 calling_convention);
5396}
5397
5398void LocationsBuilderMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01005399 LocationSummary* locations =
5400 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01005401 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005402}
5403
5404void InstructionCodeGeneratorMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
5405 HBasicBlock* block = instruction->GetBlock();
5406 if (block->GetLoopInformation() != nullptr) {
5407 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
5408 // The back edge will generate the suspend check.
5409 return;
5410 }
5411 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
5412 // The goto will generate the suspend check.
5413 return;
5414 }
5415 GenerateSuspendCheck(instruction, nullptr);
5416}
5417
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005418void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
5419 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005420 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005421 InvokeRuntimeCallingConvention calling_convention;
5422 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5423}
5424
5425void InstructionCodeGeneratorMIPS::VisitThrow(HThrow* instruction) {
Serban Constantinescufca16662016-07-14 09:21:59 +01005426 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005427 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
5428}
5429
5430void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
5431 Primitive::Type input_type = conversion->GetInputType();
5432 Primitive::Type result_type = conversion->GetResultType();
5433 DCHECK_NE(input_type, result_type);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005434 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005435
5436 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
5437 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
5438 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
5439 }
5440
5441 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005442 if (!isR6 &&
5443 ((Primitive::IsFloatingPointType(result_type) && input_type == Primitive::kPrimLong) ||
5444 (result_type == Primitive::kPrimLong && Primitive::IsFloatingPointType(input_type)))) {
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005445 call_kind = LocationSummary::kCallOnMainOnly;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005446 }
5447
5448 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
5449
5450 if (call_kind == LocationSummary::kNoCall) {
5451 if (Primitive::IsFloatingPointType(input_type)) {
5452 locations->SetInAt(0, Location::RequiresFpuRegister());
5453 } else {
5454 locations->SetInAt(0, Location::RequiresRegister());
5455 }
5456
5457 if (Primitive::IsFloatingPointType(result_type)) {
5458 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5459 } else {
5460 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5461 }
5462 } else {
5463 InvokeRuntimeCallingConvention calling_convention;
5464
5465 if (Primitive::IsFloatingPointType(input_type)) {
5466 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
5467 } else {
5468 DCHECK_EQ(input_type, Primitive::kPrimLong);
5469 locations->SetInAt(0, Location::RegisterPairLocation(
5470 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
5471 }
5472
5473 locations->SetOut(calling_convention.GetReturnLocation(result_type));
5474 }
5475}
5476
5477void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversion) {
5478 LocationSummary* locations = conversion->GetLocations();
5479 Primitive::Type result_type = conversion->GetResultType();
5480 Primitive::Type input_type = conversion->GetInputType();
5481 bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005482 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005483
5484 DCHECK_NE(input_type, result_type);
5485
5486 if (result_type == Primitive::kPrimLong && Primitive::IsIntegralType(input_type)) {
5487 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
5488 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
5489 Register src = locations->InAt(0).AsRegister<Register>();
5490
Alexey Frunzea871ef12016-06-27 15:20:11 -07005491 if (dst_low != src) {
5492 __ Move(dst_low, src);
5493 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005494 __ Sra(dst_high, src, 31);
5495 } else if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
5496 Register dst = locations->Out().AsRegister<Register>();
5497 Register src = (input_type == Primitive::kPrimLong)
5498 ? locations->InAt(0).AsRegisterPairLow<Register>()
5499 : locations->InAt(0).AsRegister<Register>();
5500
5501 switch (result_type) {
5502 case Primitive::kPrimChar:
5503 __ Andi(dst, src, 0xFFFF);
5504 break;
5505 case Primitive::kPrimByte:
5506 if (has_sign_extension) {
5507 __ Seb(dst, src);
5508 } else {
5509 __ Sll(dst, src, 24);
5510 __ Sra(dst, dst, 24);
5511 }
5512 break;
5513 case Primitive::kPrimShort:
5514 if (has_sign_extension) {
5515 __ Seh(dst, src);
5516 } else {
5517 __ Sll(dst, src, 16);
5518 __ Sra(dst, dst, 16);
5519 }
5520 break;
5521 case Primitive::kPrimInt:
Alexey Frunzea871ef12016-06-27 15:20:11 -07005522 if (dst != src) {
5523 __ Move(dst, src);
5524 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005525 break;
5526
5527 default:
5528 LOG(FATAL) << "Unexpected type conversion from " << input_type
5529 << " to " << result_type;
5530 }
5531 } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005532 if (input_type == Primitive::kPrimLong) {
5533 if (isR6) {
5534 // cvt.s.l/cvt.d.l requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
5535 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
5536 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
5537 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
5538 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
5539 __ Mtc1(src_low, FTMP);
5540 __ Mthc1(src_high, FTMP);
5541 if (result_type == Primitive::kPrimFloat) {
5542 __ Cvtsl(dst, FTMP);
5543 } else {
5544 __ Cvtdl(dst, FTMP);
5545 }
5546 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01005547 QuickEntrypointEnum entrypoint = (result_type == Primitive::kPrimFloat) ? kQuickL2f
5548 : kQuickL2d;
5549 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005550 if (result_type == Primitive::kPrimFloat) {
5551 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
5552 } else {
5553 CheckEntrypointTypes<kQuickL2d, double, int64_t>();
5554 }
5555 }
5556 } else {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005557 Register src = locations->InAt(0).AsRegister<Register>();
5558 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
5559 __ Mtc1(src, FTMP);
5560 if (result_type == Primitive::kPrimFloat) {
5561 __ Cvtsw(dst, FTMP);
5562 } else {
5563 __ Cvtdw(dst, FTMP);
5564 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005565 }
5566 } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
5567 CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005568 if (result_type == Primitive::kPrimLong) {
5569 if (isR6) {
5570 // trunc.l.s/trunc.l.d requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
5571 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
5572 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
5573 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
5574 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
5575 MipsLabel truncate;
5576 MipsLabel done;
5577
5578 // When NAN2008=0 (R2 and before), the truncate instruction produces the maximum positive
5579 // value when the input is either a NaN or is outside of the range of the output type
5580 // after the truncation. IOW, the three special cases (NaN, too small, too big) produce
5581 // the same result.
5582 //
5583 // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
5584 // value of the output type if the input is outside of the range after the truncation or
5585 // produces 0 when the input is a NaN. IOW, the three special cases produce three distinct
5586 // results. This matches the desired float/double-to-int/long conversion exactly.
5587 //
5588 // So, NAN2008 affects handling of negative values and NaNs by the truncate instruction.
5589 //
5590 // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
5591 // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
5592 // even though it must be NAN2008=1 on R6.
5593 //
5594 // The code takes care of the different behaviors by first comparing the input to the
5595 // minimum output value (-2**-63 for truncating to long, -2**-31 for truncating to int).
5596 // If the input is greater than or equal to the minimum, it procedes to the truncate
5597 // instruction, which will handle such an input the same way irrespective of NAN2008.
5598 // Otherwise the input is compared to itself to determine whether it is a NaN or not
5599 // in order to return either zero or the minimum value.
5600 //
5601 // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
5602 // truncate instruction for MIPS64R6.
5603 if (input_type == Primitive::kPrimFloat) {
5604 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int64_t>::min());
5605 __ LoadConst32(TMP, min_val);
5606 __ Mtc1(TMP, FTMP);
5607 __ CmpLeS(FTMP, FTMP, src);
5608 } else {
5609 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int64_t>::min());
5610 __ LoadConst32(TMP, High32Bits(min_val));
5611 __ Mtc1(ZERO, FTMP);
5612 __ Mthc1(TMP, FTMP);
5613 __ CmpLeD(FTMP, FTMP, src);
5614 }
5615
5616 __ Bc1nez(FTMP, &truncate);
5617
5618 if (input_type == Primitive::kPrimFloat) {
5619 __ CmpEqS(FTMP, src, src);
5620 } else {
5621 __ CmpEqD(FTMP, src, src);
5622 }
5623 __ Move(dst_low, ZERO);
5624 __ LoadConst32(dst_high, std::numeric_limits<int32_t>::min());
5625 __ Mfc1(TMP, FTMP);
5626 __ And(dst_high, dst_high, TMP);
5627
5628 __ B(&done);
5629
5630 __ Bind(&truncate);
5631
5632 if (input_type == Primitive::kPrimFloat) {
5633 __ TruncLS(FTMP, src);
5634 } else {
5635 __ TruncLD(FTMP, src);
5636 }
5637 __ Mfc1(dst_low, FTMP);
5638 __ Mfhc1(dst_high, FTMP);
5639
5640 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005641 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01005642 QuickEntrypointEnum entrypoint = (input_type == Primitive::kPrimFloat) ? kQuickF2l
5643 : kQuickD2l;
5644 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005645 if (input_type == Primitive::kPrimFloat) {
5646 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
5647 } else {
5648 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
5649 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005650 }
5651 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005652 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
5653 Register dst = locations->Out().AsRegister<Register>();
5654 MipsLabel truncate;
5655 MipsLabel done;
5656
5657 // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
5658 // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
5659 // even though it must be NAN2008=1 on R6.
5660 //
5661 // For details see the large comment above for the truncation of float/double to long on R6.
5662 //
5663 // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
5664 // truncate instruction for MIPS64R6.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005665 if (input_type == Primitive::kPrimFloat) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005666 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
5667 __ LoadConst32(TMP, min_val);
5668 __ Mtc1(TMP, FTMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005669 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005670 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int32_t>::min());
5671 __ LoadConst32(TMP, High32Bits(min_val));
5672 __ Mtc1(ZERO, FTMP);
Alexey Frunzea871ef12016-06-27 15:20:11 -07005673 __ MoveToFpuHigh(TMP, FTMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005674 }
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005675
5676 if (isR6) {
5677 if (input_type == Primitive::kPrimFloat) {
5678 __ CmpLeS(FTMP, FTMP, src);
5679 } else {
5680 __ CmpLeD(FTMP, FTMP, src);
5681 }
5682 __ Bc1nez(FTMP, &truncate);
5683
5684 if (input_type == Primitive::kPrimFloat) {
5685 __ CmpEqS(FTMP, src, src);
5686 } else {
5687 __ CmpEqD(FTMP, src, src);
5688 }
5689 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
5690 __ Mfc1(TMP, FTMP);
5691 __ And(dst, dst, TMP);
5692 } else {
5693 if (input_type == Primitive::kPrimFloat) {
5694 __ ColeS(0, FTMP, src);
5695 } else {
5696 __ ColeD(0, FTMP, src);
5697 }
5698 __ Bc1t(0, &truncate);
5699
5700 if (input_type == Primitive::kPrimFloat) {
5701 __ CeqS(0, src, src);
5702 } else {
5703 __ CeqD(0, src, src);
5704 }
5705 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
5706 __ Movf(dst, ZERO, 0);
5707 }
5708
5709 __ B(&done);
5710
5711 __ Bind(&truncate);
5712
5713 if (input_type == Primitive::kPrimFloat) {
5714 __ TruncWS(FTMP, src);
5715 } else {
5716 __ TruncWD(FTMP, src);
5717 }
5718 __ Mfc1(dst, FTMP);
5719
5720 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005721 }
5722 } else if (Primitive::IsFloatingPointType(result_type) &&
5723 Primitive::IsFloatingPointType(input_type)) {
5724 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
5725 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
5726 if (result_type == Primitive::kPrimFloat) {
5727 __ Cvtsd(dst, src);
5728 } else {
5729 __ Cvtds(dst, src);
5730 }
5731 } else {
5732 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
5733 << " to " << result_type;
5734 }
5735}
5736
5737void LocationsBuilderMIPS::VisitUShr(HUShr* ushr) {
5738 HandleShift(ushr);
5739}
5740
5741void InstructionCodeGeneratorMIPS::VisitUShr(HUShr* ushr) {
5742 HandleShift(ushr);
5743}
5744
5745void LocationsBuilderMIPS::VisitXor(HXor* instruction) {
5746 HandleBinaryOp(instruction);
5747}
5748
5749void InstructionCodeGeneratorMIPS::VisitXor(HXor* instruction) {
5750 HandleBinaryOp(instruction);
5751}
5752
5753void LocationsBuilderMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
5754 // Nothing to do, this should be removed during prepare for register allocator.
5755 LOG(FATAL) << "Unreachable";
5756}
5757
5758void InstructionCodeGeneratorMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
5759 // Nothing to do, this should be removed during prepare for register allocator.
5760 LOG(FATAL) << "Unreachable";
5761}
5762
5763void LocationsBuilderMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005764 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005765}
5766
5767void InstructionCodeGeneratorMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005768 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005769}
5770
5771void LocationsBuilderMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005772 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005773}
5774
5775void InstructionCodeGeneratorMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005776 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005777}
5778
5779void LocationsBuilderMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005780 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005781}
5782
5783void InstructionCodeGeneratorMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005784 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005785}
5786
5787void LocationsBuilderMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005788 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005789}
5790
5791void InstructionCodeGeneratorMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005792 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005793}
5794
5795void LocationsBuilderMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005796 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005797}
5798
5799void InstructionCodeGeneratorMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005800 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005801}
5802
5803void LocationsBuilderMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005804 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005805}
5806
5807void InstructionCodeGeneratorMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005808 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005809}
5810
5811void LocationsBuilderMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005812 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005813}
5814
5815void InstructionCodeGeneratorMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005816 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005817}
5818
5819void LocationsBuilderMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005820 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005821}
5822
5823void InstructionCodeGeneratorMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005824 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005825}
5826
5827void LocationsBuilderMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005828 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005829}
5830
5831void InstructionCodeGeneratorMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005832 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005833}
5834
5835void LocationsBuilderMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005836 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005837}
5838
5839void InstructionCodeGeneratorMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005840 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005841}
5842
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005843void LocationsBuilderMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5844 LocationSummary* locations =
5845 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5846 locations->SetInAt(0, Location::RequiresRegister());
5847}
5848
Alexey Frunze96b66822016-09-10 02:32:44 -07005849void InstructionCodeGeneratorMIPS::GenPackedSwitchWithCompares(Register value_reg,
5850 int32_t lower_bound,
5851 uint32_t num_entries,
5852 HBasicBlock* switch_block,
5853 HBasicBlock* default_block) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005854 // Create a set of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00005855 Register temp_reg = TMP;
5856 __ Addiu32(temp_reg, value_reg, -lower_bound);
5857 // Jump to default if index is negative
5858 // Note: We don't check the case that index is positive while value < lower_bound, because in
5859 // this case, index >= num_entries must be true. So that we can save one branch instruction.
5860 __ Bltz(temp_reg, codegen_->GetLabelOf(default_block));
5861
Alexey Frunze96b66822016-09-10 02:32:44 -07005862 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00005863 // Jump to successors[0] if value == lower_bound.
5864 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[0]));
5865 int32_t last_index = 0;
5866 for (; num_entries - last_index > 2; last_index += 2) {
5867 __ Addiu(temp_reg, temp_reg, -2);
5868 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
5869 __ Bltz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
5870 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
5871 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 2]));
5872 }
5873 if (num_entries - last_index == 2) {
5874 // The last missing case_value.
5875 __ Addiu(temp_reg, temp_reg, -1);
5876 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005877 }
5878
Vladimir Markof3e0ee22015-12-17 15:23:13 +00005879 // And the default for any other value.
Alexey Frunze96b66822016-09-10 02:32:44 -07005880 if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005881 __ B(codegen_->GetLabelOf(default_block));
5882 }
5883}
5884
Alexey Frunze96b66822016-09-10 02:32:44 -07005885void InstructionCodeGeneratorMIPS::GenTableBasedPackedSwitch(Register value_reg,
5886 Register constant_area,
5887 int32_t lower_bound,
5888 uint32_t num_entries,
5889 HBasicBlock* switch_block,
5890 HBasicBlock* default_block) {
5891 // Create a jump table.
5892 std::vector<MipsLabel*> labels(num_entries);
5893 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
5894 for (uint32_t i = 0; i < num_entries; i++) {
5895 labels[i] = codegen_->GetLabelOf(successors[i]);
5896 }
5897 JumpTable* table = __ CreateJumpTable(std::move(labels));
5898
5899 // Is the value in range?
5900 __ Addiu32(TMP, value_reg, -lower_bound);
5901 if (IsInt<16>(static_cast<int32_t>(num_entries))) {
5902 __ Sltiu(AT, TMP, num_entries);
5903 __ Beqz(AT, codegen_->GetLabelOf(default_block));
5904 } else {
5905 __ LoadConst32(AT, num_entries);
5906 __ Bgeu(TMP, AT, codegen_->GetLabelOf(default_block));
5907 }
5908
5909 // We are in the range of the table.
5910 // Load the target address from the jump table, indexing by the value.
5911 __ LoadLabelAddress(AT, constant_area, table->GetLabel());
5912 __ Sll(TMP, TMP, 2);
5913 __ Addu(TMP, TMP, AT);
5914 __ Lw(TMP, TMP, 0);
5915 // Compute the absolute target address by adding the table start address
5916 // (the table contains offsets to targets relative to its start).
5917 __ Addu(TMP, TMP, AT);
5918 // And jump.
5919 __ Jr(TMP);
5920 __ NopIfNoReordering();
5921}
5922
5923void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5924 int32_t lower_bound = switch_instr->GetStartValue();
5925 uint32_t num_entries = switch_instr->GetNumEntries();
5926 LocationSummary* locations = switch_instr->GetLocations();
5927 Register value_reg = locations->InAt(0).AsRegister<Register>();
5928 HBasicBlock* switch_block = switch_instr->GetBlock();
5929 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5930
5931 if (codegen_->GetInstructionSetFeatures().IsR6() &&
5932 num_entries > kPackedSwitchJumpTableThreshold) {
5933 // R6 uses PC-relative addressing to access the jump table.
5934 // R2, OTOH, requires an HMipsComputeBaseMethodAddress input to access
5935 // the jump table and it is implemented by changing HPackedSwitch to
5936 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress.
5937 // See VisitMipsPackedSwitch() for the table-based implementation on R2.
5938 GenTableBasedPackedSwitch(value_reg,
5939 ZERO,
5940 lower_bound,
5941 num_entries,
5942 switch_block,
5943 default_block);
5944 } else {
5945 GenPackedSwitchWithCompares(value_reg,
5946 lower_bound,
5947 num_entries,
5948 switch_block,
5949 default_block);
5950 }
5951}
5952
5953void LocationsBuilderMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
5954 LocationSummary* locations =
5955 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5956 locations->SetInAt(0, Location::RequiresRegister());
5957 // Constant area pointer (HMipsComputeBaseMethodAddress).
5958 locations->SetInAt(1, Location::RequiresRegister());
5959}
5960
5961void InstructionCodeGeneratorMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
5962 int32_t lower_bound = switch_instr->GetStartValue();
5963 uint32_t num_entries = switch_instr->GetNumEntries();
5964 LocationSummary* locations = switch_instr->GetLocations();
5965 Register value_reg = locations->InAt(0).AsRegister<Register>();
5966 Register constant_area = locations->InAt(1).AsRegister<Register>();
5967 HBasicBlock* switch_block = switch_instr->GetBlock();
5968 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5969
5970 // This is an R2-only path. HPackedSwitch has been changed to
5971 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress
5972 // required to address the jump table relative to PC.
5973 GenTableBasedPackedSwitch(value_reg,
5974 constant_area,
5975 lower_bound,
5976 num_entries,
5977 switch_block,
5978 default_block);
5979}
5980
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005981void LocationsBuilderMIPS::VisitMipsComputeBaseMethodAddress(
5982 HMipsComputeBaseMethodAddress* insn) {
5983 LocationSummary* locations =
5984 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5985 locations->SetOut(Location::RequiresRegister());
5986}
5987
5988void InstructionCodeGeneratorMIPS::VisitMipsComputeBaseMethodAddress(
5989 HMipsComputeBaseMethodAddress* insn) {
5990 LocationSummary* locations = insn->GetLocations();
5991 Register reg = locations->Out().AsRegister<Register>();
5992
5993 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
5994
5995 // Generate a dummy PC-relative call to obtain PC.
5996 __ Nal();
5997 // Grab the return address off RA.
5998 __ Move(reg, RA);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005999 // TODO: Can we share this code with that of VisitMipsDexCacheArraysBase()?
Alexey Frunzee3fb2452016-05-10 16:08:05 -07006000
6001 // Remember this offset (the obtained PC value) for later use with constant area.
6002 __ BindPcRelBaseLabel();
6003}
6004
6005void LocationsBuilderMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
6006 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
6007 locations->SetOut(Location::RequiresRegister());
6008}
6009
6010void InstructionCodeGeneratorMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
6011 Register reg = base->GetLocations()->Out().AsRegister<Register>();
6012 CodeGeneratorMIPS::PcRelativePatchInfo* info =
6013 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Alexey Frunze57eb0f52016-07-29 22:04:46 -07006014 bool reordering = __ SetReorder(false);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07006015 if (codegen_->GetInstructionSetFeatures().IsR6()) {
6016 __ Bind(&info->high_label);
6017 __ Bind(&info->pc_rel_label);
6018 // Add a 32-bit offset to PC.
6019 __ Auipc(reg, /* placeholder */ 0x1234);
6020 __ Addiu(reg, reg, /* placeholder */ 0x5678);
6021 } else {
6022 // Generate a dummy PC-relative call to obtain PC.
6023 __ Nal();
6024 __ Bind(&info->high_label);
6025 __ Lui(reg, /* placeholder */ 0x1234);
6026 __ Bind(&info->pc_rel_label);
6027 __ Ori(reg, reg, /* placeholder */ 0x5678);
6028 // Add a 32-bit offset to PC.
6029 __ Addu(reg, reg, RA);
Alexey Frunze06a46c42016-07-19 15:00:40 -07006030 // TODO: Can we share this code with that of VisitMipsComputeBaseMethodAddress()?
Alexey Frunzee3fb2452016-05-10 16:08:05 -07006031 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07006032 __ SetReorder(reordering);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07006033}
6034
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006035void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
6036 // The trampoline uses the same calling convention as dex calling conventions,
6037 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
6038 // the method_idx.
6039 HandleInvoke(invoke);
6040}
6041
6042void InstructionCodeGeneratorMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
6043 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
6044}
6045
Roland Levillain2aba7cd2016-02-03 12:27:20 +00006046void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet* instruction) {
6047 LocationSummary* locations =
6048 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6049 locations->SetInAt(0, Location::RequiresRegister());
6050 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006051}
6052
Roland Levillain2aba7cd2016-02-03 12:27:20 +00006053void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
6054 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00006055 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01006056 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Roland Levillain2aba7cd2016-02-03 12:27:20 +00006057 instruction->GetIndex(), kMipsPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01006058 __ LoadFromOffset(kLoadWord,
6059 locations->Out().AsRegister<Register>(),
6060 locations->InAt(0).AsRegister<Register>(),
6061 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +00006062 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01006063 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00006064 instruction->GetIndex(), kMipsPointerSize));
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00006065 __ LoadFromOffset(kLoadWord,
6066 locations->Out().AsRegister<Register>(),
6067 locations->InAt(0).AsRegister<Register>(),
6068 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01006069 __ LoadFromOffset(kLoadWord,
6070 locations->Out().AsRegister<Register>(),
6071 locations->Out().AsRegister<Register>(),
6072 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +00006073 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00006074}
6075
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006076#undef __
6077#undef QUICK_ENTRY_POINT
6078
6079} // namespace mips
6080} // namespace art