blob: 3fc7ebde6a45ceb58fbacc9682c9ef67ca6a083c [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()) {
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800102 Register reg = calling_convention.GetRegisterAt(gp_index);
103 if (reg == A1 || reg == A3) {
104 gp_index_++; // Skip A1(A3), and use A2_A3(T0_T1) instead.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200105 gp_index++;
106 }
107 Register low_even = calling_convention.GetRegisterAt(gp_index);
108 Register high_odd = calling_convention.GetRegisterAt(gp_index + 1);
109 DCHECK_EQ(low_even + 1, high_odd);
110 next_location = Location::RegisterPairLocation(low_even, high_odd);
111 } else {
112 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
113 next_location = Location::DoubleStackSlot(stack_offset);
114 }
115 break;
116 }
117
118 // Note: both float and double types are stored in even FPU registers. On 32 bit FPU, double
119 // will take up the even/odd pair, while floats are stored in even regs only.
120 // On 64 bit FPU, both double and float are stored in even registers only.
121 case Primitive::kPrimFloat:
122 case Primitive::kPrimDouble: {
123 uint32_t float_index = float_index_++;
124 if (float_index < calling_convention.GetNumberOfFpuRegisters()) {
125 next_location = Location::FpuRegisterLocation(
126 calling_convention.GetFpuRegisterAt(float_index));
127 } else {
128 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
129 next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
130 : Location::StackSlot(stack_offset);
131 }
132 break;
133 }
134
135 case Primitive::kPrimVoid:
136 LOG(FATAL) << "Unexpected parameter type " << type;
137 break;
138 }
139
140 // Space on the stack is reserved for all arguments.
141 stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
142
143 return next_location;
144}
145
146Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) {
147 return MipsReturnLocation(type);
148}
149
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100150// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
151#define __ down_cast<CodeGeneratorMIPS*>(codegen)->GetAssembler()-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -0700152#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200153
154class BoundsCheckSlowPathMIPS : public SlowPathCodeMIPS {
155 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000156 explicit BoundsCheckSlowPathMIPS(HBoundsCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200157
158 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
159 LocationSummary* locations = instruction_->GetLocations();
160 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
161 __ Bind(GetEntryLabel());
162 if (instruction_->CanThrowIntoCatchBlock()) {
163 // Live registers will be restored in the catch block if caught.
164 SaveLiveRegisters(codegen, instruction_->GetLocations());
165 }
166 // We're moving two locations to locations that could overlap, so we need a parallel
167 // move resolver.
168 InvokeRuntimeCallingConvention calling_convention;
169 codegen->EmitParallelMoves(locations->InAt(0),
170 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
171 Primitive::kPrimInt,
172 locations->InAt(1),
173 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
174 Primitive::kPrimInt);
Serban Constantinescufca16662016-07-14 09:21:59 +0100175 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
176 ? kQuickThrowStringBounds
177 : kQuickThrowArrayBounds;
178 mips_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100179 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200180 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
181 }
182
183 bool IsFatal() const OVERRIDE { return true; }
184
185 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS"; }
186
187 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200188 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathMIPS);
189};
190
191class DivZeroCheckSlowPathMIPS : public SlowPathCodeMIPS {
192 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000193 explicit DivZeroCheckSlowPathMIPS(HDivZeroCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200194
195 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
196 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
197 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100198 mips_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200199 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
200 }
201
202 bool IsFatal() const OVERRIDE { return true; }
203
204 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS"; }
205
206 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200207 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS);
208};
209
210class LoadClassSlowPathMIPS : public SlowPathCodeMIPS {
211 public:
212 LoadClassSlowPathMIPS(HLoadClass* cls,
213 HInstruction* at,
214 uint32_t dex_pc,
215 bool do_clinit)
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000216 : SlowPathCodeMIPS(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200217 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
218 }
219
220 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000221 LocationSummary* locations = instruction_->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200222 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
223
224 __ Bind(GetEntryLabel());
225 SaveLiveRegisters(codegen, locations);
226
227 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000228 dex::TypeIndex type_index = cls_->GetTypeIndex();
229 __ LoadConst32(calling_convention.GetRegisterAt(0), type_index.index_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200230
Serban Constantinescufca16662016-07-14 09:21:59 +0100231 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
232 : kQuickInitializeType;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000233 mips_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200234 if (do_clinit_) {
235 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
236 } else {
237 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
238 }
239
240 // Move the class to the desired location.
241 Location out = locations->Out();
242 if (out.IsValid()) {
243 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000244 Primitive::Type type = instruction_->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200245 mips_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
246 }
247
248 RestoreLiveRegisters(codegen, locations);
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000249 // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
250 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
251 if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
252 DCHECK(out.IsValid());
253 // TODO: Change art_quick_initialize_type/art_quick_initialize_static_storage to
254 // kSaveEverything and use a temporary for the .bss entry address in the fast path,
255 // so that we can avoid another calculation here.
256 bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
257 Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
258 DCHECK_NE(out.AsRegister<Register>(), AT);
259 CodeGeneratorMIPS::PcRelativePatchInfo* info =
Vladimir Marko1998cd02017-01-13 13:02:58 +0000260 mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
Alexey Frunze6b892cd2017-01-03 17:11:38 -0800261 bool reordering = __ SetReorder(false);
262 mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
263 __ StoreToOffset(kStoreWord, out.AsRegister<Register>(), TMP, /* placeholder */ 0x5678);
264 __ SetReorder(reordering);
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000265 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200266 __ B(GetExitLabel());
267 }
268
269 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathMIPS"; }
270
271 private:
272 // The class this slow path will load.
273 HLoadClass* const cls_;
274
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200275 // The dex PC of `at_`.
276 const uint32_t dex_pc_;
277
278 // Whether to initialize the class.
279 const bool do_clinit_;
280
281 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS);
282};
283
284class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
285 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000286 explicit LoadStringSlowPathMIPS(HLoadString* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200287
288 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
289 LocationSummary* locations = instruction_->GetLocations();
290 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
291 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
292
293 __ Bind(GetEntryLabel());
294 SaveLiveRegisters(codegen, locations);
295
296 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoaad75c62016-10-03 08:46:48 +0000297 HLoadString* load = instruction_->AsLoadString();
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000298 const dex::StringIndex string_index = load->GetStringIndex();
299 __ LoadConst32(calling_convention.GetRegisterAt(0), string_index.index_);
Serban Constantinescufca16662016-07-14 09:21:59 +0100300 mips_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200301 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
302 Primitive::Type type = instruction_->GetType();
303 mips_codegen->MoveLocation(locations->Out(),
304 calling_convention.GetReturnLocation(type),
305 type);
306
307 RestoreLiveRegisters(codegen, locations);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000308
309 // Store the resolved String to the BSS entry.
310 // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary for the
311 // .bss entry address in the fast path, so that we can avoid another calculation here.
312 bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
313 Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
314 Register out = locations->Out().AsRegister<Register>();
315 DCHECK_NE(out, AT);
316 CodeGeneratorMIPS::PcRelativePatchInfo* info =
317 mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
Alexey Frunze6b892cd2017-01-03 17:11:38 -0800318 bool reordering = __ SetReorder(false);
319 mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
320 __ StoreToOffset(kStoreWord, out, TMP, /* placeholder */ 0x5678);
321 __ SetReorder(reordering);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000322
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200323 __ B(GetExitLabel());
324 }
325
326 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
327
328 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200329 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
330};
331
332class NullCheckSlowPathMIPS : public SlowPathCodeMIPS {
333 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000334 explicit NullCheckSlowPathMIPS(HNullCheck* instr) : SlowPathCodeMIPS(instr) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200335
336 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
337 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
338 __ Bind(GetEntryLabel());
339 if (instruction_->CanThrowIntoCatchBlock()) {
340 // Live registers will be restored in the catch block if caught.
341 SaveLiveRegisters(codegen, instruction_->GetLocations());
342 }
Serban Constantinescufca16662016-07-14 09:21:59 +0100343 mips_codegen->InvokeRuntime(kQuickThrowNullPointer,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200344 instruction_,
345 instruction_->GetDexPc(),
Serban Constantinescufca16662016-07-14 09:21:59 +0100346 this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200347 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
348 }
349
350 bool IsFatal() const OVERRIDE { return true; }
351
352 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS"; }
353
354 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200355 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathMIPS);
356};
357
358class SuspendCheckSlowPathMIPS : public SlowPathCodeMIPS {
359 public:
360 SuspendCheckSlowPathMIPS(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000361 : SlowPathCodeMIPS(instruction), successor_(successor) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200362
363 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
364 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
365 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100366 mips_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200367 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200368 if (successor_ == nullptr) {
369 __ B(GetReturnLabel());
370 } else {
371 __ B(mips_codegen->GetLabelOf(successor_));
372 }
373 }
374
375 MipsLabel* GetReturnLabel() {
376 DCHECK(successor_ == nullptr);
377 return &return_label_;
378 }
379
380 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS"; }
381
382 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200383 // If not null, the block to branch to after the suspend check.
384 HBasicBlock* const successor_;
385
386 // If `successor_` is null, the label to branch to after the suspend check.
387 MipsLabel return_label_;
388
389 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathMIPS);
390};
391
392class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS {
393 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000394 explicit TypeCheckSlowPathMIPS(HInstruction* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200395
396 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
397 LocationSummary* locations = instruction_->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200398 uint32_t dex_pc = instruction_->GetDexPc();
399 DCHECK(instruction_->IsCheckCast()
400 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
401 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
402
403 __ Bind(GetEntryLabel());
404 SaveLiveRegisters(codegen, locations);
405
406 // We're moving two locations to locations that could overlap, so we need a parallel
407 // move resolver.
408 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800409 codegen->EmitParallelMoves(locations->InAt(0),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200410 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
411 Primitive::kPrimNot,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800412 locations->InAt(1),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200413 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
414 Primitive::kPrimNot);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200415 if (instruction_->IsInstanceOf()) {
Serban Constantinescufca16662016-07-14 09:21:59 +0100416 mips_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800417 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200418 Primitive::Type ret_type = instruction_->GetType();
419 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
420 mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200421 } else {
422 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800423 mips_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
424 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200425 }
426
427 RestoreLiveRegisters(codegen, locations);
428 __ B(GetExitLabel());
429 }
430
431 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS"; }
432
433 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200434 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathMIPS);
435};
436
437class DeoptimizationSlowPathMIPS : public SlowPathCodeMIPS {
438 public:
Aart Bik42249c32016-01-07 15:33:50 -0800439 explicit DeoptimizationSlowPathMIPS(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000440 : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200441
442 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800443 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200444 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100445 mips_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Roland Levillain888d0672015-11-23 18:53:50 +0000446 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200447 }
448
449 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS"; }
450
451 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200452 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS);
453};
454
455CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph,
456 const MipsInstructionSetFeatures& isa_features,
457 const CompilerOptions& compiler_options,
458 OptimizingCompilerStats* stats)
459 : CodeGenerator(graph,
460 kNumberOfCoreRegisters,
461 kNumberOfFRegisters,
462 kNumberOfRegisterPairs,
463 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
464 arraysize(kCoreCalleeSaves)),
465 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
466 arraysize(kFpuCalleeSaves)),
467 compiler_options,
468 stats),
469 block_labels_(nullptr),
470 location_builder_(graph, this),
471 instruction_visitor_(graph, this),
472 move_resolver_(graph->GetArena(), this),
Vladimir Marko93205e32016-04-13 11:59:46 +0100473 assembler_(graph->GetArena(), &isa_features),
Alexey Frunzee3fb2452016-05-10 16:08:05 -0700474 isa_features_(isa_features),
Alexey Frunze06a46c42016-07-19 15:00:40 -0700475 uint32_literals_(std::less<uint32_t>(),
476 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Alexey Frunze06a46c42016-07-19 15:00:40 -0700477 pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
478 boot_image_string_patches_(StringReferenceValueComparator(),
479 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
480 pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
481 boot_image_type_patches_(TypeReferenceValueComparator(),
482 graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
483 pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko1998cd02017-01-13 13:02:58 +0000484 type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Alexey Frunze627c1a02017-01-30 19:28:14 -0800485 jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
486 jit_class_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
Alexey Frunze06a46c42016-07-19 15:00:40 -0700487 clobbered_ra_(false) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200488 // Save RA (containing the return address) to mimic Quick.
489 AddAllocatedRegister(Location::RegisterLocation(RA));
490}
491
492#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100493// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
494#define __ down_cast<MipsAssembler*>(GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -0700495#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200496
497void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) {
498 // Ensure that we fix up branches.
499 __ FinalizeCode();
500
501 // Adjust native pc offsets in stack maps.
502 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
Mathieu Chartiera2f526f2017-01-19 14:48:48 -0800503 uint32_t old_position =
504 stack_map_stream_.GetStackMap(i).native_pc_code_offset.Uint32Value(kMips);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200505 uint32_t new_position = __ GetAdjustedPosition(old_position);
506 DCHECK_GE(new_position, old_position);
507 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
508 }
509
510 // Adjust pc offsets for the disassembly information.
511 if (disasm_info_ != nullptr) {
512 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
513 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
514 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
515 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
516 it.second.start = __ GetAdjustedPosition(it.second.start);
517 it.second.end = __ GetAdjustedPosition(it.second.end);
518 }
519 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
520 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
521 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
522 }
523 }
524
525 CodeGenerator::Finalize(allocator);
526}
527
528MipsAssembler* ParallelMoveResolverMIPS::GetAssembler() const {
529 return codegen_->GetAssembler();
530}
531
532void ParallelMoveResolverMIPS::EmitMove(size_t index) {
533 DCHECK_LT(index, moves_.size());
534 MoveOperands* move = moves_[index];
535 codegen_->MoveLocation(move->GetDestination(), move->GetSource(), move->GetType());
536}
537
538void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
539 DCHECK_LT(index, moves_.size());
540 MoveOperands* move = moves_[index];
541 Primitive::Type type = move->GetType();
542 Location loc1 = move->GetDestination();
543 Location loc2 = move->GetSource();
544
545 DCHECK(!loc1.IsConstant());
546 DCHECK(!loc2.IsConstant());
547
548 if (loc1.Equals(loc2)) {
549 return;
550 }
551
552 if (loc1.IsRegister() && loc2.IsRegister()) {
553 // Swap 2 GPRs.
554 Register r1 = loc1.AsRegister<Register>();
555 Register r2 = loc2.AsRegister<Register>();
556 __ Move(TMP, r2);
557 __ Move(r2, r1);
558 __ Move(r1, TMP);
559 } else if (loc1.IsFpuRegister() && loc2.IsFpuRegister()) {
560 FRegister f1 = loc1.AsFpuRegister<FRegister>();
561 FRegister f2 = loc2.AsFpuRegister<FRegister>();
562 if (type == Primitive::kPrimFloat) {
563 __ MovS(FTMP, f2);
564 __ MovS(f2, f1);
565 __ MovS(f1, FTMP);
566 } else {
567 DCHECK_EQ(type, Primitive::kPrimDouble);
568 __ MovD(FTMP, f2);
569 __ MovD(f2, f1);
570 __ MovD(f1, FTMP);
571 }
572 } else if ((loc1.IsRegister() && loc2.IsFpuRegister()) ||
573 (loc1.IsFpuRegister() && loc2.IsRegister())) {
574 // Swap FPR and GPR.
575 DCHECK_EQ(type, Primitive::kPrimFloat); // Can only swap a float.
576 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
577 : loc2.AsFpuRegister<FRegister>();
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +0200578 Register r2 = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200579 __ Move(TMP, r2);
580 __ Mfc1(r2, f1);
581 __ Mtc1(TMP, f1);
582 } else if (loc1.IsRegisterPair() && loc2.IsRegisterPair()) {
583 // Swap 2 GPR register pairs.
584 Register r1 = loc1.AsRegisterPairLow<Register>();
585 Register r2 = loc2.AsRegisterPairLow<Register>();
586 __ Move(TMP, r2);
587 __ Move(r2, r1);
588 __ Move(r1, TMP);
589 r1 = loc1.AsRegisterPairHigh<Register>();
590 r2 = loc2.AsRegisterPairHigh<Register>();
591 __ Move(TMP, r2);
592 __ Move(r2, r1);
593 __ Move(r1, TMP);
594 } else if ((loc1.IsRegisterPair() && loc2.IsFpuRegister()) ||
595 (loc1.IsFpuRegister() && loc2.IsRegisterPair())) {
596 // Swap FPR and GPR register pair.
597 DCHECK_EQ(type, Primitive::kPrimDouble);
598 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
599 : loc2.AsFpuRegister<FRegister>();
600 Register r2_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
601 : loc2.AsRegisterPairLow<Register>();
602 Register r2_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
603 : loc2.AsRegisterPairHigh<Register>();
604 // Use 2 temporary registers because we can't first swap the low 32 bits of an FPR and
605 // then swap the high 32 bits of the same FPR. mtc1 makes the high 32 bits of an FPR
606 // unpredictable and the following mfch1 will fail.
607 __ Mfc1(TMP, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800608 __ MoveFromFpuHigh(AT, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200609 __ Mtc1(r2_l, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800610 __ MoveToFpuHigh(r2_h, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200611 __ Move(r2_l, TMP);
612 __ Move(r2_h, AT);
613 } else if (loc1.IsStackSlot() && loc2.IsStackSlot()) {
614 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ false);
615 } else if (loc1.IsDoubleStackSlot() && loc2.IsDoubleStackSlot()) {
616 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ true);
David Brazdilcc0f3112016-01-28 17:14:52 +0000617 } else if ((loc1.IsRegister() && loc2.IsStackSlot()) ||
618 (loc1.IsStackSlot() && loc2.IsRegister())) {
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +0200619 Register reg = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
620 intptr_t offset = loc1.IsStackSlot() ? loc1.GetStackIndex() : loc2.GetStackIndex();
David Brazdilcc0f3112016-01-28 17:14:52 +0000621 __ Move(TMP, reg);
622 __ LoadFromOffset(kLoadWord, reg, SP, offset);
623 __ StoreToOffset(kStoreWord, TMP, SP, offset);
624 } else if ((loc1.IsRegisterPair() && loc2.IsDoubleStackSlot()) ||
625 (loc1.IsDoubleStackSlot() && loc2.IsRegisterPair())) {
626 Register reg_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
627 : loc2.AsRegisterPairLow<Register>();
628 Register reg_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
629 : loc2.AsRegisterPairHigh<Register>();
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +0200630 intptr_t offset_l = loc1.IsDoubleStackSlot() ? loc1.GetStackIndex() : loc2.GetStackIndex();
David Brazdilcc0f3112016-01-28 17:14:52 +0000631 intptr_t offset_h = loc1.IsDoubleStackSlot() ? loc1.GetHighStackIndex(kMipsWordSize)
632 : loc2.GetHighStackIndex(kMipsWordSize);
633 __ Move(TMP, reg_l);
David Brazdilcc0f3112016-01-28 17:14:52 +0000634 __ LoadFromOffset(kLoadWord, reg_l, SP, offset_l);
David Brazdilcc0f3112016-01-28 17:14:52 +0000635 __ StoreToOffset(kStoreWord, TMP, SP, offset_l);
David Brazdil04d3e872016-01-29 09:50:09 +0000636 __ Move(TMP, reg_h);
637 __ LoadFromOffset(kLoadWord, reg_h, SP, offset_h);
638 __ StoreToOffset(kStoreWord, TMP, SP, offset_h);
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +0200639 } else if (loc1.IsFpuRegister() || loc2.IsFpuRegister()) {
640 FRegister reg = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
641 : loc2.AsFpuRegister<FRegister>();
642 intptr_t offset = loc1.IsFpuRegister() ? loc2.GetStackIndex() : loc1.GetStackIndex();
643 if (type == Primitive::kPrimFloat) {
644 __ MovS(FTMP, reg);
645 __ LoadSFromOffset(reg, SP, offset);
646 __ StoreSToOffset(FTMP, SP, offset);
647 } else {
648 DCHECK_EQ(type, Primitive::kPrimDouble);
649 __ MovD(FTMP, reg);
650 __ LoadDFromOffset(reg, SP, offset);
651 __ StoreDToOffset(FTMP, SP, offset);
652 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200653 } else {
654 LOG(FATAL) << "Swap between " << loc1 << " and " << loc2 << " is unsupported";
655 }
656}
657
658void ParallelMoveResolverMIPS::RestoreScratch(int reg) {
659 __ Pop(static_cast<Register>(reg));
660}
661
662void ParallelMoveResolverMIPS::SpillScratch(int reg) {
663 __ Push(static_cast<Register>(reg));
664}
665
666void ParallelMoveResolverMIPS::Exchange(int index1, int index2, bool double_slot) {
667 // Allocate a scratch register other than TMP, if available.
668 // Else, spill V0 (arbitrary choice) and use it as a scratch register (it will be
669 // automatically unspilled when the scratch scope object is destroyed).
670 ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters());
671 // If V0 spills onto the stack, SP-relative offsets need to be adjusted.
672 int stack_offset = ensure_scratch.IsSpilled() ? kMipsWordSize : 0;
673 for (int i = 0; i <= (double_slot ? 1 : 0); i++, stack_offset += kMipsWordSize) {
674 __ LoadFromOffset(kLoadWord,
675 Register(ensure_scratch.GetRegister()),
676 SP,
677 index1 + stack_offset);
678 __ LoadFromOffset(kLoadWord,
679 TMP,
680 SP,
681 index2 + stack_offset);
682 __ StoreToOffset(kStoreWord,
683 Register(ensure_scratch.GetRegister()),
684 SP,
685 index2 + stack_offset);
686 __ StoreToOffset(kStoreWord, TMP, SP, index1 + stack_offset);
687 }
688}
689
Alexey Frunze73296a72016-06-03 22:51:46 -0700690void CodeGeneratorMIPS::ComputeSpillMask() {
691 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
692 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
693 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
694 // If there're FPU callee-saved registers and there's an odd number of GPR callee-saved
695 // registers, include the ZERO register to force alignment of FPU callee-saved registers
696 // within the stack frame.
697 if ((fpu_spill_mask_ != 0) && (POPCOUNT(core_spill_mask_) % 2 != 0)) {
698 core_spill_mask_ |= (1 << ZERO);
699 }
Alexey Frunze58320ce2016-08-30 21:40:46 -0700700}
701
702bool CodeGeneratorMIPS::HasAllocatedCalleeSaveRegisters() const {
Alexey Frunze06a46c42016-07-19 15:00:40 -0700703 // If RA is clobbered by PC-relative operations on R2 and it's the only spilled register
Alexey Frunze58320ce2016-08-30 21:40:46 -0700704 // (this can happen in leaf methods), force CodeGenerator::InitializeCodeGeneration()
705 // into the path that creates a stack frame so that RA can be explicitly saved and restored.
706 // RA can't otherwise be saved/restored when it's the only spilled register.
Alexey Frunze58320ce2016-08-30 21:40:46 -0700707 return CodeGenerator::HasAllocatedCalleeSaveRegisters() || clobbered_ra_;
Alexey Frunze73296a72016-06-03 22:51:46 -0700708}
709
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200710static dwarf::Reg DWARFReg(Register reg) {
711 return dwarf::Reg::MipsCore(static_cast<int>(reg));
712}
713
714// TODO: mapping of floating-point registers to DWARF.
715
716void CodeGeneratorMIPS::GenerateFrameEntry() {
717 __ Bind(&frame_entry_label_);
718
719 bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kMips) || !IsLeafMethod();
720
721 if (do_overflow_check) {
722 __ LoadFromOffset(kLoadWord,
723 ZERO,
724 SP,
725 -static_cast<int32_t>(GetStackOverflowReservedBytes(kMips)));
726 RecordPcInfo(nullptr, 0);
727 }
728
729 if (HasEmptyFrame()) {
Alexey Frunze58320ce2016-08-30 21:40:46 -0700730 CHECK_EQ(fpu_spill_mask_, 0u);
731 CHECK_EQ(core_spill_mask_, 1u << RA);
732 CHECK(!clobbered_ra_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200733 return;
734 }
735
736 // Make sure the frame size isn't unreasonably large.
737 if (GetFrameSize() > GetStackOverflowReservedBytes(kMips)) {
738 LOG(FATAL) << "Stack frame larger than " << GetStackOverflowReservedBytes(kMips) << " bytes";
739 }
740
741 // Spill callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200742
Alexey Frunze73296a72016-06-03 22:51:46 -0700743 uint32_t ofs = GetFrameSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200744 __ IncreaseFrameSize(ofs);
745
Alexey Frunze73296a72016-06-03 22:51:46 -0700746 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
747 Register reg = static_cast<Register>(MostSignificantBit(mask));
748 mask ^= 1u << reg;
749 ofs -= kMipsWordSize;
750 // The ZERO register is only included for alignment.
751 if (reg != ZERO) {
752 __ StoreToOffset(kStoreWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200753 __ cfi().RelOffset(DWARFReg(reg), ofs);
754 }
755 }
756
Alexey Frunze73296a72016-06-03 22:51:46 -0700757 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
758 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
759 mask ^= 1u << reg;
760 ofs -= kMipsDoublewordSize;
761 __ StoreDToOffset(reg, SP, ofs);
762 // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200763 }
764
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +0100765 // Save the current method if we need it. Note that we do not
766 // do this in HCurrentMethod, as the instruction might have been removed
767 // in the SSA graph.
768 if (RequiresCurrentMethod()) {
769 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, kCurrentMethodStackOffset);
770 }
Goran Jakovljevicc6418422016-12-05 16:31:55 +0100771
772 if (GetGraph()->HasShouldDeoptimizeFlag()) {
773 // Initialize should deoptimize flag to 0.
774 __ StoreToOffset(kStoreWord, ZERO, SP, GetStackOffsetOfShouldDeoptimizeFlag());
775 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200776}
777
778void CodeGeneratorMIPS::GenerateFrameExit() {
779 __ cfi().RememberState();
780
781 if (!HasEmptyFrame()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200782 // Restore callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200783
Alexey Frunze73296a72016-06-03 22:51:46 -0700784 // For better instruction scheduling restore RA before other registers.
785 uint32_t ofs = GetFrameSize();
786 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
787 Register reg = static_cast<Register>(MostSignificantBit(mask));
788 mask ^= 1u << reg;
789 ofs -= kMipsWordSize;
790 // The ZERO register is only included for alignment.
791 if (reg != ZERO) {
792 __ LoadFromOffset(kLoadWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200793 __ cfi().Restore(DWARFReg(reg));
794 }
795 }
796
Alexey Frunze73296a72016-06-03 22:51:46 -0700797 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
798 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
799 mask ^= 1u << reg;
800 ofs -= kMipsDoublewordSize;
801 __ LoadDFromOffset(reg, SP, ofs);
802 // TODO: __ cfi().Restore(DWARFReg(reg));
803 }
804
Alexey Frunze57eb0f52016-07-29 22:04:46 -0700805 size_t frame_size = GetFrameSize();
806 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
807 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
808 bool reordering = __ SetReorder(false);
809 if (exchange) {
810 __ Jr(RA);
811 __ DecreaseFrameSize(frame_size); // Single instruction in delay slot.
812 } else {
813 __ DecreaseFrameSize(frame_size);
814 __ Jr(RA);
815 __ Nop(); // In delay slot.
816 }
817 __ SetReorder(reordering);
818 } else {
819 __ Jr(RA);
820 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200821 }
822
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200823 __ cfi().RestoreState();
824 __ cfi().DefCFAOffset(GetFrameSize());
825}
826
827void CodeGeneratorMIPS::Bind(HBasicBlock* block) {
828 __ Bind(GetLabelOf(block));
829}
830
831void CodeGeneratorMIPS::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
832 if (src.Equals(dst)) {
833 return;
834 }
835
836 if (src.IsConstant()) {
837 MoveConstant(dst, src.GetConstant());
838 } else {
839 if (Primitive::Is64BitType(dst_type)) {
840 Move64(dst, src);
841 } else {
842 Move32(dst, src);
843 }
844 }
845}
846
847void CodeGeneratorMIPS::Move32(Location destination, Location source) {
848 if (source.Equals(destination)) {
849 return;
850 }
851
852 if (destination.IsRegister()) {
853 if (source.IsRegister()) {
854 __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
855 } else if (source.IsFpuRegister()) {
856 __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
857 } else {
858 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
859 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
860 }
861 } else if (destination.IsFpuRegister()) {
862 if (source.IsRegister()) {
863 __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
864 } else if (source.IsFpuRegister()) {
865 __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
866 } else {
867 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
868 __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
869 }
870 } else {
871 DCHECK(destination.IsStackSlot()) << destination;
872 if (source.IsRegister()) {
873 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
874 } else if (source.IsFpuRegister()) {
875 __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, destination.GetStackIndex());
876 } else {
877 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
878 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
879 __ StoreToOffset(kStoreWord, TMP, SP, destination.GetStackIndex());
880 }
881 }
882}
883
884void CodeGeneratorMIPS::Move64(Location destination, Location source) {
885 if (source.Equals(destination)) {
886 return;
887 }
888
889 if (destination.IsRegisterPair()) {
890 if (source.IsRegisterPair()) {
891 __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
892 __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
893 } else if (source.IsFpuRegister()) {
894 Register dst_high = destination.AsRegisterPairHigh<Register>();
895 Register dst_low = destination.AsRegisterPairLow<Register>();
896 FRegister src = source.AsFpuRegister<FRegister>();
897 __ Mfc1(dst_low, src);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800898 __ MoveFromFpuHigh(dst_high, src);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200899 } else {
900 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
901 int32_t off = source.GetStackIndex();
902 Register r = destination.AsRegisterPairLow<Register>();
903 __ LoadFromOffset(kLoadDoubleword, r, SP, off);
904 }
905 } else if (destination.IsFpuRegister()) {
906 if (source.IsRegisterPair()) {
907 FRegister dst = destination.AsFpuRegister<FRegister>();
908 Register src_high = source.AsRegisterPairHigh<Register>();
909 Register src_low = source.AsRegisterPairLow<Register>();
910 __ Mtc1(src_low, dst);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800911 __ MoveToFpuHigh(src_high, dst);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200912 } else if (source.IsFpuRegister()) {
913 __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
914 } else {
915 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
916 __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
917 }
918 } else {
919 DCHECK(destination.IsDoubleStackSlot()) << destination;
920 int32_t off = destination.GetStackIndex();
921 if (source.IsRegisterPair()) {
922 __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, off);
923 } else if (source.IsFpuRegister()) {
924 __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, off);
925 } else {
926 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
927 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
928 __ StoreToOffset(kStoreWord, TMP, SP, off);
929 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
930 __ StoreToOffset(kStoreWord, TMP, SP, off + 4);
931 }
932 }
933}
934
935void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) {
936 if (c->IsIntConstant() || c->IsNullConstant()) {
937 // Move 32 bit constant.
938 int32_t value = GetInt32ValueOf(c);
939 if (destination.IsRegister()) {
940 Register dst = destination.AsRegister<Register>();
941 __ LoadConst32(dst, value);
942 } else {
943 DCHECK(destination.IsStackSlot())
944 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700945 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200946 }
947 } else if (c->IsLongConstant()) {
948 // Move 64 bit constant.
949 int64_t value = GetInt64ValueOf(c);
950 if (destination.IsRegisterPair()) {
951 Register r_h = destination.AsRegisterPairHigh<Register>();
952 Register r_l = destination.AsRegisterPairLow<Register>();
953 __ LoadConst64(r_h, r_l, value);
954 } else {
955 DCHECK(destination.IsDoubleStackSlot())
956 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700957 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200958 }
959 } else if (c->IsFloatConstant()) {
960 // Move 32 bit float constant.
961 int32_t value = GetInt32ValueOf(c);
962 if (destination.IsFpuRegister()) {
963 __ LoadSConst32(destination.AsFpuRegister<FRegister>(), value, TMP);
964 } else {
965 DCHECK(destination.IsStackSlot())
966 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700967 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200968 }
969 } else {
970 // Move 64 bit double constant.
971 DCHECK(c->IsDoubleConstant()) << c->DebugName();
972 int64_t value = GetInt64ValueOf(c);
973 if (destination.IsFpuRegister()) {
974 FRegister fd = destination.AsFpuRegister<FRegister>();
975 __ LoadDConst64(fd, value, TMP);
976 } else {
977 DCHECK(destination.IsDoubleStackSlot())
978 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -0700979 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200980 }
981 }
982}
983
984void CodeGeneratorMIPS::MoveConstant(Location destination, int32_t value) {
985 DCHECK(destination.IsRegister());
986 Register dst = destination.AsRegister<Register>();
987 __ LoadConst32(dst, value);
988}
989
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200990void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
991 if (location.IsRegister()) {
992 locations->AddTemp(location);
Alexey Frunzec9e94f32015-10-26 16:11:39 -0700993 } else if (location.IsRegisterPair()) {
994 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
995 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200996 } else {
997 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
998 }
999}
1000
Vladimir Markoaad75c62016-10-03 08:46:48 +00001001template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
1002inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches(
1003 const ArenaDeque<PcRelativePatchInfo>& infos,
1004 ArenaVector<LinkerPatch>* linker_patches) {
1005 for (const PcRelativePatchInfo& info : infos) {
1006 const DexFile& dex_file = info.target_dex_file;
1007 size_t offset_or_index = info.offset_or_index;
1008 DCHECK(info.high_label.IsBound());
1009 uint32_t high_offset = __ GetLabelLocation(&info.high_label);
1010 // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
1011 // the assembler's base label used for PC-relative addressing.
1012 uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
1013 ? __ GetLabelLocation(&info.pc_rel_label)
1014 : __ GetPcRelBaseLabelLocation();
1015 linker_patches->push_back(Factory(high_offset, &dex_file, pc_rel_offset, offset_or_index));
1016 }
1017}
1018
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001019void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
1020 DCHECK(linker_patches->empty());
1021 size_t size =
Alexey Frunze06a46c42016-07-19 15:00:40 -07001022 pc_relative_dex_cache_patches_.size() +
1023 pc_relative_string_patches_.size() +
1024 pc_relative_type_patches_.size() +
Vladimir Marko1998cd02017-01-13 13:02:58 +00001025 type_bss_entry_patches_.size() +
Alexey Frunze06a46c42016-07-19 15:00:40 -07001026 boot_image_string_patches_.size() +
Richard Uhlerc52f3032017-03-02 13:45:45 +00001027 boot_image_type_patches_.size();
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001028 linker_patches->reserve(size);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001029 EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
1030 linker_patches);
1031 if (!GetCompilerOptions().IsBootImage()) {
Vladimir Marko1998cd02017-01-13 13:02:58 +00001032 DCHECK(pc_relative_type_patches_.empty());
Vladimir Markoaad75c62016-10-03 08:46:48 +00001033 EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
1034 linker_patches);
1035 } else {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001036 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
1037 linker_patches);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001038 EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
1039 linker_patches);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001040 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00001041 EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_,
1042 linker_patches);
Alexey Frunze06a46c42016-07-19 15:00:40 -07001043 for (const auto& entry : boot_image_string_patches_) {
1044 const StringReference& target_string = entry.first;
1045 Literal* literal = entry.second;
1046 DCHECK(literal->GetLabel()->IsBound());
1047 uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1048 linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
1049 target_string.dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001050 target_string.string_index.index_));
Alexey Frunze06a46c42016-07-19 15:00:40 -07001051 }
1052 for (const auto& entry : boot_image_type_patches_) {
1053 const TypeReference& target_type = entry.first;
1054 Literal* literal = entry.second;
1055 DCHECK(literal->GetLabel()->IsBound());
1056 uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
1057 linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
1058 target_type.dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08001059 target_type.type_index.index_));
Alexey Frunze06a46c42016-07-19 15:00:40 -07001060 }
Vladimir Marko1998cd02017-01-13 13:02:58 +00001061 DCHECK_EQ(size, linker_patches->size());
Alexey Frunze06a46c42016-07-19 15:00:40 -07001062}
1063
1064CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPatch(
Vladimir Marko6bec91c2017-01-09 15:03:12 +00001065 const DexFile& dex_file, dex::StringIndex string_index) {
1066 return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
Alexey Frunze06a46c42016-07-19 15:00:40 -07001067}
1068
1069CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
Andreas Gampea5b09a62016-11-17 15:21:22 -08001070 const DexFile& dex_file, dex::TypeIndex type_index) {
1071 return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001072}
1073
Vladimir Marko1998cd02017-01-13 13:02:58 +00001074CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewTypeBssEntryPatch(
1075 const DexFile& dex_file, dex::TypeIndex type_index) {
1076 return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
1077}
1078
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001079CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch(
1080 const DexFile& dex_file, uint32_t element_offset) {
1081 return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_);
1082}
1083
1084CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
1085 const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
1086 patches->emplace_back(dex_file, offset_or_index);
1087 return &patches->back();
1088}
1089
Alexey Frunze06a46c42016-07-19 15:00:40 -07001090Literal* CodeGeneratorMIPS::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
1091 return map->GetOrCreate(
1092 value,
1093 [this, value]() { return __ NewLiteral<uint32_t>(value); });
1094}
1095
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001096Literal* CodeGeneratorMIPS::DeduplicateMethodLiteral(MethodReference target_method,
1097 MethodToLiteralMap* map) {
1098 return map->GetOrCreate(
1099 target_method,
1100 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1101}
1102
Alexey Frunze06a46c42016-07-19 15:00:40 -07001103Literal* CodeGeneratorMIPS::DeduplicateBootImageStringLiteral(const DexFile& dex_file,
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001104 dex::StringIndex string_index) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07001105 return boot_image_string_patches_.GetOrCreate(
1106 StringReference(&dex_file, string_index),
1107 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1108}
1109
1110Literal* CodeGeneratorMIPS::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
Andreas Gampea5b09a62016-11-17 15:21:22 -08001111 dex::TypeIndex type_index) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07001112 return boot_image_type_patches_.GetOrCreate(
1113 TypeReference(&dex_file, type_index),
1114 [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
1115}
1116
1117Literal* CodeGeneratorMIPS::DeduplicateBootImageAddressLiteral(uint32_t address) {
Richard Uhlerc52f3032017-03-02 13:45:45 +00001118 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
Alexey Frunze06a46c42016-07-19 15:00:40 -07001119}
1120
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001121void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
1122 Register out,
1123 Register base) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00001124 if (GetInstructionSetFeatures().IsR6()) {
1125 DCHECK_EQ(base, ZERO);
1126 __ Bind(&info->high_label);
1127 __ Bind(&info->pc_rel_label);
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001128 // Add the high half of a 32-bit offset to PC.
Vladimir Markoaad75c62016-10-03 08:46:48 +00001129 __ Auipc(out, /* placeholder */ 0x1234);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001130 } else {
1131 // If base is ZERO, emit NAL to obtain the actual base.
1132 if (base == ZERO) {
1133 // Generate a dummy PC-relative call to obtain PC.
1134 __ Nal();
1135 }
1136 __ Bind(&info->high_label);
1137 __ Lui(out, /* placeholder */ 0x1234);
1138 // If we emitted the NAL, bind the pc_rel_label, otherwise base is a register holding
1139 // the HMipsComputeBaseMethodAddress which has its own label stored in MipsAssembler.
1140 if (base == ZERO) {
1141 __ Bind(&info->pc_rel_label);
1142 }
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001143 // Add the high half of a 32-bit offset to PC.
Vladimir Markoaad75c62016-10-03 08:46:48 +00001144 __ Addu(out, out, (base == ZERO) ? RA : base);
1145 }
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001146 // The immediately following instruction will add the sign-extended low half of the 32-bit
1147 // offset to `out` (e.g. lw, jialc, addiu).
Vladimir Markoaad75c62016-10-03 08:46:48 +00001148}
1149
Alexey Frunze627c1a02017-01-30 19:28:14 -08001150CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootStringPatch(
1151 const DexFile& dex_file,
1152 dex::StringIndex dex_index,
1153 Handle<mirror::String> handle) {
1154 jit_string_roots_.Overwrite(StringReference(&dex_file, dex_index),
1155 reinterpret_cast64<uint64_t>(handle.GetReference()));
1156 jit_string_patches_.emplace_back(dex_file, dex_index.index_);
1157 return &jit_string_patches_.back();
1158}
1159
1160CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootClassPatch(
1161 const DexFile& dex_file,
1162 dex::TypeIndex dex_index,
1163 Handle<mirror::Class> handle) {
1164 jit_class_roots_.Overwrite(TypeReference(&dex_file, dex_index),
1165 reinterpret_cast64<uint64_t>(handle.GetReference()));
1166 jit_class_patches_.emplace_back(dex_file, dex_index.index_);
1167 return &jit_class_patches_.back();
1168}
1169
1170void CodeGeneratorMIPS::PatchJitRootUse(uint8_t* code,
1171 const uint8_t* roots_data,
1172 const CodeGeneratorMIPS::JitPatchInfo& info,
1173 uint64_t index_in_table) const {
1174 uint32_t literal_offset = GetAssembler().GetLabelLocation(&info.high_label);
1175 uintptr_t address =
1176 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
1177 uint32_t addr32 = dchecked_integral_cast<uint32_t>(address);
1178 // lui reg, addr32_high
1179 DCHECK_EQ(code[literal_offset + 0], 0x34);
1180 DCHECK_EQ(code[literal_offset + 1], 0x12);
1181 DCHECK_EQ((code[literal_offset + 2] & 0xE0), 0x00);
1182 DCHECK_EQ(code[literal_offset + 3], 0x3C);
1183 // lw reg, reg, addr32_low
1184 DCHECK_EQ(code[literal_offset + 4], 0x78);
1185 DCHECK_EQ(code[literal_offset + 5], 0x56);
1186 DCHECK_EQ((code[literal_offset + 7] & 0xFC), 0x8C);
1187 addr32 += (addr32 & 0x8000) << 1; // Account for sign extension in "lw reg, reg, addr32_low".
1188 // lui reg, addr32_high
1189 code[literal_offset + 0] = static_cast<uint8_t>(addr32 >> 16);
1190 code[literal_offset + 1] = static_cast<uint8_t>(addr32 >> 24);
1191 // lw reg, reg, addr32_low
1192 code[literal_offset + 4] = static_cast<uint8_t>(addr32 >> 0);
1193 code[literal_offset + 5] = static_cast<uint8_t>(addr32 >> 8);
1194}
1195
1196void CodeGeneratorMIPS::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
1197 for (const JitPatchInfo& info : jit_string_patches_) {
1198 const auto& it = jit_string_roots_.find(StringReference(&info.target_dex_file,
1199 dex::StringIndex(info.index)));
1200 DCHECK(it != jit_string_roots_.end());
1201 PatchJitRootUse(code, roots_data, info, it->second);
1202 }
1203 for (const JitPatchInfo& info : jit_class_patches_) {
1204 const auto& it = jit_class_roots_.find(TypeReference(&info.target_dex_file,
1205 dex::TypeIndex(info.index)));
1206 DCHECK(it != jit_class_roots_.end());
1207 PatchJitRootUse(code, roots_data, info, it->second);
1208 }
1209}
1210
Goran Jakovljevice114da22016-12-26 14:21:43 +01001211void CodeGeneratorMIPS::MarkGCCard(Register object,
1212 Register value,
1213 bool value_can_be_null) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001214 MipsLabel done;
1215 Register card = AT;
1216 Register temp = TMP;
Goran Jakovljevice114da22016-12-26 14:21:43 +01001217 if (value_can_be_null) {
1218 __ Beqz(value, &done);
1219 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001220 __ LoadFromOffset(kLoadWord,
1221 card,
1222 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07001223 Thread::CardTableOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001224 __ Srl(temp, object, gc::accounting::CardTable::kCardShift);
1225 __ Addu(temp, card, temp);
1226 __ Sb(card, temp, 0);
Goran Jakovljevice114da22016-12-26 14:21:43 +01001227 if (value_can_be_null) {
1228 __ Bind(&done);
1229 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001230}
1231
David Brazdil58282f42016-01-14 12:45:10 +00001232void CodeGeneratorMIPS::SetupBlockedRegisters() const {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001233 // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated.
1234 blocked_core_registers_[ZERO] = true;
1235 blocked_core_registers_[K0] = true;
1236 blocked_core_registers_[K1] = true;
1237 blocked_core_registers_[GP] = true;
1238 blocked_core_registers_[SP] = true;
1239 blocked_core_registers_[RA] = true;
1240
1241 // AT and TMP(T8) are used as temporary/scratch registers
1242 // (similar to how AT is used by MIPS assemblers).
1243 blocked_core_registers_[AT] = true;
1244 blocked_core_registers_[TMP] = true;
1245 blocked_fpu_registers_[FTMP] = true;
1246
1247 // Reserve suspend and thread registers.
1248 blocked_core_registers_[S0] = true;
1249 blocked_core_registers_[TR] = true;
1250
1251 // Reserve T9 for function calls
1252 blocked_core_registers_[T9] = true;
1253
1254 // Reserve odd-numbered FPU registers.
1255 for (size_t i = 1; i < kNumberOfFRegisters; i += 2) {
1256 blocked_fpu_registers_[i] = true;
1257 }
1258
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02001259 if (GetGraph()->IsDebuggable()) {
1260 // Stubs do not save callee-save floating point registers. If the graph
1261 // is debuggable, we need to deal with these registers differently. For
1262 // now, just block them.
1263 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1264 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
1265 }
1266 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001267}
1268
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001269size_t CodeGeneratorMIPS::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1270 __ StoreToOffset(kStoreWord, Register(reg_id), SP, stack_index);
1271 return kMipsWordSize;
1272}
1273
1274size_t CodeGeneratorMIPS::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1275 __ LoadFromOffset(kLoadWord, Register(reg_id), SP, stack_index);
1276 return kMipsWordSize;
1277}
1278
1279size_t CodeGeneratorMIPS::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1280 __ StoreDToOffset(FRegister(reg_id), SP, stack_index);
1281 return kMipsDoublewordSize;
1282}
1283
1284size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1285 __ LoadDFromOffset(FRegister(reg_id), SP, stack_index);
1286 return kMipsDoublewordSize;
1287}
1288
1289void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001290 stream << Register(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001291}
1292
1293void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001294 stream << FRegister(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001295}
1296
Serban Constantinescufca16662016-07-14 09:21:59 +01001297constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16;
1298
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001299void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
1300 HInstruction* instruction,
1301 uint32_t dex_pc,
1302 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001303 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001304 bool reordering = __ SetReorder(false);
Serban Constantinescufca16662016-07-14 09:21:59 +01001305 __ LoadFromOffset(kLoadWord, T9, TR, GetThreadOffset<kMipsPointerSize>(entrypoint).Int32Value());
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001306 __ Jalr(T9);
Serban Constantinescufca16662016-07-14 09:21:59 +01001307 if (IsDirectEntrypoint(entrypoint)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001308 // Reserve argument space on stack (for $a0-$a3) for
1309 // entrypoints that directly reference native implementations.
1310 // Called function may use this space to store $a0-$a3 regs.
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001311 __ IncreaseFrameSize(kMipsDirectEntrypointRuntimeOffset); // Single instruction in delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001312 __ DecreaseFrameSize(kMipsDirectEntrypointRuntimeOffset);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001313 } else {
1314 __ Nop(); // In delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001315 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001316 __ SetReorder(reordering);
Serban Constantinescufca16662016-07-14 09:21:59 +01001317 if (EntrypointRequiresStackMap(entrypoint)) {
1318 RecordPcInfo(instruction, dex_pc, slow_path);
1319 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001320}
1321
1322void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
1323 Register class_reg) {
1324 __ LoadFromOffset(kLoadWord, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
1325 __ LoadConst32(AT, mirror::Class::kStatusInitialized);
1326 __ Blt(TMP, AT, slow_path->GetEntryLabel());
1327 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1328 __ Sync(0);
1329 __ Bind(slow_path->GetExitLabel());
1330}
1331
1332void InstructionCodeGeneratorMIPS::GenerateMemoryBarrier(MemBarrierKind kind ATTRIBUTE_UNUSED) {
1333 __ Sync(0); // Only stype 0 is supported.
1334}
1335
1336void InstructionCodeGeneratorMIPS::GenerateSuspendCheck(HSuspendCheck* instruction,
1337 HBasicBlock* successor) {
1338 SuspendCheckSlowPathMIPS* slow_path =
1339 new (GetGraph()->GetArena()) SuspendCheckSlowPathMIPS(instruction, successor);
1340 codegen_->AddSlowPath(slow_path);
1341
1342 __ LoadFromOffset(kLoadUnsignedHalfword,
1343 TMP,
1344 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07001345 Thread::ThreadFlagsOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001346 if (successor == nullptr) {
1347 __ Bnez(TMP, slow_path->GetEntryLabel());
1348 __ Bind(slow_path->GetReturnLabel());
1349 } else {
1350 __ Beqz(TMP, codegen_->GetLabelOf(successor));
1351 __ B(slow_path->GetEntryLabel());
1352 // slow_path will return to GetLabelOf(successor).
1353 }
1354}
1355
1356InstructionCodeGeneratorMIPS::InstructionCodeGeneratorMIPS(HGraph* graph,
1357 CodeGeneratorMIPS* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001358 : InstructionCodeGenerator(graph, codegen),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001359 assembler_(codegen->GetAssembler()),
1360 codegen_(codegen) {}
1361
1362void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1363 DCHECK_EQ(instruction->InputCount(), 2U);
1364 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1365 Primitive::Type type = instruction->GetResultType();
1366 switch (type) {
1367 case Primitive::kPrimInt: {
1368 locations->SetInAt(0, Location::RequiresRegister());
1369 HInstruction* right = instruction->InputAt(1);
1370 bool can_use_imm = false;
1371 if (right->IsConstant()) {
1372 int32_t imm = CodeGenerator::GetInt32ValueOf(right->AsConstant());
1373 if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
1374 can_use_imm = IsUint<16>(imm);
1375 } else if (instruction->IsAdd()) {
1376 can_use_imm = IsInt<16>(imm);
1377 } else {
1378 DCHECK(instruction->IsSub());
1379 can_use_imm = IsInt<16>(-imm);
1380 }
1381 }
1382 if (can_use_imm)
1383 locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
1384 else
1385 locations->SetInAt(1, Location::RequiresRegister());
1386 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1387 break;
1388 }
1389
1390 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001391 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001392 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1393 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001394 break;
1395 }
1396
1397 case Primitive::kPrimFloat:
1398 case Primitive::kPrimDouble:
1399 DCHECK(instruction->IsAdd() || instruction->IsSub());
1400 locations->SetInAt(0, Location::RequiresFpuRegister());
1401 locations->SetInAt(1, Location::RequiresFpuRegister());
1402 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1403 break;
1404
1405 default:
1406 LOG(FATAL) << "Unexpected " << instruction->DebugName() << " type " << type;
1407 }
1408}
1409
1410void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1411 Primitive::Type type = instruction->GetType();
1412 LocationSummary* locations = instruction->GetLocations();
1413
1414 switch (type) {
1415 case Primitive::kPrimInt: {
1416 Register dst = locations->Out().AsRegister<Register>();
1417 Register lhs = locations->InAt(0).AsRegister<Register>();
1418 Location rhs_location = locations->InAt(1);
1419
1420 Register rhs_reg = ZERO;
1421 int32_t rhs_imm = 0;
1422 bool use_imm = rhs_location.IsConstant();
1423 if (use_imm) {
1424 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
1425 } else {
1426 rhs_reg = rhs_location.AsRegister<Register>();
1427 }
1428
1429 if (instruction->IsAnd()) {
1430 if (use_imm)
1431 __ Andi(dst, lhs, rhs_imm);
1432 else
1433 __ And(dst, lhs, rhs_reg);
1434 } else if (instruction->IsOr()) {
1435 if (use_imm)
1436 __ Ori(dst, lhs, rhs_imm);
1437 else
1438 __ Or(dst, lhs, rhs_reg);
1439 } else if (instruction->IsXor()) {
1440 if (use_imm)
1441 __ Xori(dst, lhs, rhs_imm);
1442 else
1443 __ Xor(dst, lhs, rhs_reg);
1444 } else if (instruction->IsAdd()) {
1445 if (use_imm)
1446 __ Addiu(dst, lhs, rhs_imm);
1447 else
1448 __ Addu(dst, lhs, rhs_reg);
1449 } else {
1450 DCHECK(instruction->IsSub());
1451 if (use_imm)
1452 __ Addiu(dst, lhs, -rhs_imm);
1453 else
1454 __ Subu(dst, lhs, rhs_reg);
1455 }
1456 break;
1457 }
1458
1459 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001460 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
1461 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
1462 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
1463 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001464 Location rhs_location = locations->InAt(1);
1465 bool use_imm = rhs_location.IsConstant();
1466 if (!use_imm) {
1467 Register rhs_high = rhs_location.AsRegisterPairHigh<Register>();
1468 Register rhs_low = rhs_location.AsRegisterPairLow<Register>();
1469 if (instruction->IsAnd()) {
1470 __ And(dst_low, lhs_low, rhs_low);
1471 __ And(dst_high, lhs_high, rhs_high);
1472 } else if (instruction->IsOr()) {
1473 __ Or(dst_low, lhs_low, rhs_low);
1474 __ Or(dst_high, lhs_high, rhs_high);
1475 } else if (instruction->IsXor()) {
1476 __ Xor(dst_low, lhs_low, rhs_low);
1477 __ Xor(dst_high, lhs_high, rhs_high);
1478 } else if (instruction->IsAdd()) {
1479 if (lhs_low == rhs_low) {
1480 // Special case for lhs = rhs and the sum potentially overwriting both lhs and rhs.
1481 __ Slt(TMP, lhs_low, ZERO);
1482 __ Addu(dst_low, lhs_low, rhs_low);
1483 } else {
1484 __ Addu(dst_low, lhs_low, rhs_low);
1485 // If the sum overwrites rhs, lhs remains unchanged, otherwise rhs remains unchanged.
1486 __ Sltu(TMP, dst_low, (dst_low == rhs_low) ? lhs_low : rhs_low);
1487 }
1488 __ Addu(dst_high, lhs_high, rhs_high);
1489 __ Addu(dst_high, dst_high, TMP);
1490 } else {
1491 DCHECK(instruction->IsSub());
1492 __ Sltu(TMP, lhs_low, rhs_low);
1493 __ Subu(dst_low, lhs_low, rhs_low);
1494 __ Subu(dst_high, lhs_high, rhs_high);
1495 __ Subu(dst_high, dst_high, TMP);
1496 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001497 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001498 int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
1499 if (instruction->IsOr()) {
1500 uint32_t low = Low32Bits(value);
1501 uint32_t high = High32Bits(value);
1502 if (IsUint<16>(low)) {
1503 if (dst_low != lhs_low || low != 0) {
1504 __ Ori(dst_low, lhs_low, low);
1505 }
1506 } else {
1507 __ LoadConst32(TMP, low);
1508 __ Or(dst_low, lhs_low, TMP);
1509 }
1510 if (IsUint<16>(high)) {
1511 if (dst_high != lhs_high || high != 0) {
1512 __ Ori(dst_high, lhs_high, high);
1513 }
1514 } else {
1515 if (high != low) {
1516 __ LoadConst32(TMP, high);
1517 }
1518 __ Or(dst_high, lhs_high, TMP);
1519 }
1520 } else if (instruction->IsXor()) {
1521 uint32_t low = Low32Bits(value);
1522 uint32_t high = High32Bits(value);
1523 if (IsUint<16>(low)) {
1524 if (dst_low != lhs_low || low != 0) {
1525 __ Xori(dst_low, lhs_low, low);
1526 }
1527 } else {
1528 __ LoadConst32(TMP, low);
1529 __ Xor(dst_low, lhs_low, TMP);
1530 }
1531 if (IsUint<16>(high)) {
1532 if (dst_high != lhs_high || high != 0) {
1533 __ Xori(dst_high, lhs_high, high);
1534 }
1535 } else {
1536 if (high != low) {
1537 __ LoadConst32(TMP, high);
1538 }
1539 __ Xor(dst_high, lhs_high, TMP);
1540 }
1541 } else if (instruction->IsAnd()) {
1542 uint32_t low = Low32Bits(value);
1543 uint32_t high = High32Bits(value);
1544 if (IsUint<16>(low)) {
1545 __ Andi(dst_low, lhs_low, low);
1546 } else if (low != 0xFFFFFFFF) {
1547 __ LoadConst32(TMP, low);
1548 __ And(dst_low, lhs_low, TMP);
1549 } else if (dst_low != lhs_low) {
1550 __ Move(dst_low, lhs_low);
1551 }
1552 if (IsUint<16>(high)) {
1553 __ Andi(dst_high, lhs_high, high);
1554 } else if (high != 0xFFFFFFFF) {
1555 if (high != low) {
1556 __ LoadConst32(TMP, high);
1557 }
1558 __ And(dst_high, lhs_high, TMP);
1559 } else if (dst_high != lhs_high) {
1560 __ Move(dst_high, lhs_high);
1561 }
1562 } else {
1563 if (instruction->IsSub()) {
1564 value = -value;
1565 } else {
1566 DCHECK(instruction->IsAdd());
1567 }
1568 int32_t low = Low32Bits(value);
1569 int32_t high = High32Bits(value);
1570 if (IsInt<16>(low)) {
1571 if (dst_low != lhs_low || low != 0) {
1572 __ Addiu(dst_low, lhs_low, low);
1573 }
1574 if (low != 0) {
1575 __ Sltiu(AT, dst_low, low);
1576 }
1577 } else {
1578 __ LoadConst32(TMP, low);
1579 __ Addu(dst_low, lhs_low, TMP);
1580 __ Sltu(AT, dst_low, TMP);
1581 }
1582 if (IsInt<16>(high)) {
1583 if (dst_high != lhs_high || high != 0) {
1584 __ Addiu(dst_high, lhs_high, high);
1585 }
1586 } else {
1587 if (high != low) {
1588 __ LoadConst32(TMP, high);
1589 }
1590 __ Addu(dst_high, lhs_high, TMP);
1591 }
1592 if (low != 0) {
1593 __ Addu(dst_high, dst_high, AT);
1594 }
1595 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001596 }
1597 break;
1598 }
1599
1600 case Primitive::kPrimFloat:
1601 case Primitive::kPrimDouble: {
1602 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
1603 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
1604 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
1605 if (instruction->IsAdd()) {
1606 if (type == Primitive::kPrimFloat) {
1607 __ AddS(dst, lhs, rhs);
1608 } else {
1609 __ AddD(dst, lhs, rhs);
1610 }
1611 } else {
1612 DCHECK(instruction->IsSub());
1613 if (type == Primitive::kPrimFloat) {
1614 __ SubS(dst, lhs, rhs);
1615 } else {
1616 __ SubD(dst, lhs, rhs);
1617 }
1618 }
1619 break;
1620 }
1621
1622 default:
1623 LOG(FATAL) << "Unexpected binary operation type " << type;
1624 }
1625}
1626
1627void LocationsBuilderMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001628 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001629
1630 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1631 Primitive::Type type = instr->GetResultType();
1632 switch (type) {
1633 case Primitive::kPrimInt:
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001634 locations->SetInAt(0, Location::RequiresRegister());
1635 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1636 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1637 break;
1638 case Primitive::kPrimLong:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001639 locations->SetInAt(0, Location::RequiresRegister());
1640 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1641 locations->SetOut(Location::RequiresRegister());
1642 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001643 default:
1644 LOG(FATAL) << "Unexpected shift type " << type;
1645 }
1646}
1647
1648static constexpr size_t kMipsBitsPerWord = kMipsWordSize * kBitsPerByte;
1649
1650void InstructionCodeGeneratorMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001651 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001652 LocationSummary* locations = instr->GetLocations();
1653 Primitive::Type type = instr->GetType();
1654
1655 Location rhs_location = locations->InAt(1);
1656 bool use_imm = rhs_location.IsConstant();
1657 Register rhs_reg = use_imm ? ZERO : rhs_location.AsRegister<Register>();
1658 int64_t rhs_imm = use_imm ? CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()) : 0;
Roland Levillain5b5b9312016-03-22 14:57:31 +00001659 const uint32_t shift_mask =
1660 (type == Primitive::kPrimInt) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001661 const uint32_t shift_value = rhs_imm & shift_mask;
Alexey Frunze92d90602015-12-18 18:16:36 -08001662 // Are the INS (Insert Bit Field) and ROTR instructions supported?
1663 bool has_ins_rotr = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001664
1665 switch (type) {
1666 case Primitive::kPrimInt: {
1667 Register dst = locations->Out().AsRegister<Register>();
1668 Register lhs = locations->InAt(0).AsRegister<Register>();
1669 if (use_imm) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001670 if (shift_value == 0) {
1671 if (dst != lhs) {
1672 __ Move(dst, lhs);
1673 }
1674 } else if (instr->IsShl()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001675 __ Sll(dst, lhs, shift_value);
1676 } else if (instr->IsShr()) {
1677 __ Sra(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001678 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001679 __ Srl(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001680 } else {
1681 if (has_ins_rotr) {
1682 __ Rotr(dst, lhs, shift_value);
1683 } else {
1684 __ Sll(TMP, lhs, (kMipsBitsPerWord - shift_value) & shift_mask);
1685 __ Srl(dst, lhs, shift_value);
1686 __ Or(dst, dst, TMP);
1687 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001688 }
1689 } else {
1690 if (instr->IsShl()) {
1691 __ Sllv(dst, lhs, rhs_reg);
1692 } else if (instr->IsShr()) {
1693 __ Srav(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08001694 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001695 __ Srlv(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08001696 } else {
1697 if (has_ins_rotr) {
1698 __ Rotrv(dst, lhs, rhs_reg);
1699 } else {
1700 __ Subu(TMP, ZERO, rhs_reg);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001701 // 32-bit shift instructions use the 5 least significant bits of the shift count, so
1702 // shifting by `-rhs_reg` is equivalent to shifting by `(32 - rhs_reg) & 31`. The case
1703 // when `rhs_reg & 31 == 0` is OK even though we don't shift `lhs` left all the way out
1704 // by 32, because the result in this case is computed as `(lhs >> 0) | (lhs << 0)`,
1705 // IOW, the OR'd values are equal.
Alexey Frunze92d90602015-12-18 18:16:36 -08001706 __ Sllv(TMP, lhs, TMP);
1707 __ Srlv(dst, lhs, rhs_reg);
1708 __ Or(dst, dst, TMP);
1709 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001710 }
1711 }
1712 break;
1713 }
1714
1715 case Primitive::kPrimLong: {
1716 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
1717 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
1718 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
1719 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
1720 if (use_imm) {
1721 if (shift_value == 0) {
1722 codegen_->Move64(locations->Out(), locations->InAt(0));
1723 } else if (shift_value < kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001724 if (has_ins_rotr) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001725 if (instr->IsShl()) {
1726 __ Srl(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
1727 __ Ins(dst_high, lhs_high, shift_value, kMipsBitsPerWord - shift_value);
1728 __ Sll(dst_low, lhs_low, shift_value);
1729 } else if (instr->IsShr()) {
1730 __ Srl(dst_low, lhs_low, shift_value);
1731 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1732 __ Sra(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001733 } else if (instr->IsUShr()) {
1734 __ Srl(dst_low, lhs_low, shift_value);
1735 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1736 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001737 } else {
1738 __ Srl(dst_low, lhs_low, shift_value);
1739 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1740 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001741 __ Ins(dst_high, lhs_low, kMipsBitsPerWord - shift_value, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001742 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001743 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001744 if (instr->IsShl()) {
1745 __ Sll(dst_low, lhs_low, shift_value);
1746 __ Srl(TMP, lhs_low, kMipsBitsPerWord - shift_value);
1747 __ Sll(dst_high, lhs_high, shift_value);
1748 __ Or(dst_high, dst_high, TMP);
1749 } else if (instr->IsShr()) {
1750 __ Sra(dst_high, lhs_high, shift_value);
1751 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
1752 __ Srl(dst_low, lhs_low, shift_value);
1753 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08001754 } else if (instr->IsUShr()) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001755 __ Srl(dst_high, lhs_high, shift_value);
1756 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
1757 __ Srl(dst_low, lhs_low, shift_value);
1758 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08001759 } else {
1760 __ Srl(TMP, lhs_low, shift_value);
1761 __ Sll(dst_low, lhs_high, kMipsBitsPerWord - shift_value);
1762 __ Or(dst_low, dst_low, TMP);
1763 __ Srl(TMP, lhs_high, shift_value);
1764 __ Sll(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
1765 __ Or(dst_high, dst_high, TMP);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001766 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001767 }
1768 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001769 const uint32_t shift_value_high = shift_value - kMipsBitsPerWord;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001770 if (instr->IsShl()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001771 __ Sll(dst_high, lhs_low, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001772 __ Move(dst_low, ZERO);
1773 } else if (instr->IsShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001774 __ Sra(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001775 __ Sra(dst_high, dst_low, kMipsBitsPerWord - 1);
Alexey Frunze92d90602015-12-18 18:16:36 -08001776 } else if (instr->IsUShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001777 __ Srl(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001778 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08001779 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001780 if (shift_value == kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001781 // 64-bit rotation by 32 is just a swap.
1782 __ Move(dst_low, lhs_high);
1783 __ Move(dst_high, lhs_low);
1784 } else {
1785 if (has_ins_rotr) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001786 __ Srl(dst_low, lhs_high, shift_value_high);
1787 __ Ins(dst_low, lhs_low, kMipsBitsPerWord - shift_value_high, shift_value_high);
1788 __ Srl(dst_high, lhs_low, shift_value_high);
1789 __ Ins(dst_high, lhs_high, kMipsBitsPerWord - shift_value_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001790 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001791 __ Sll(TMP, lhs_low, kMipsBitsPerWord - shift_value_high);
1792 __ Srl(dst_low, lhs_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001793 __ Or(dst_low, dst_low, TMP);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001794 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value_high);
1795 __ Srl(dst_high, lhs_low, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001796 __ Or(dst_high, dst_high, TMP);
1797 }
1798 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001799 }
1800 }
1801 } else {
1802 MipsLabel done;
1803 if (instr->IsShl()) {
1804 __ Sllv(dst_low, lhs_low, rhs_reg);
1805 __ Nor(AT, ZERO, rhs_reg);
1806 __ Srl(TMP, lhs_low, 1);
1807 __ Srlv(TMP, TMP, AT);
1808 __ Sllv(dst_high, lhs_high, rhs_reg);
1809 __ Or(dst_high, dst_high, TMP);
1810 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1811 __ Beqz(TMP, &done);
1812 __ Move(dst_high, dst_low);
1813 __ Move(dst_low, ZERO);
1814 } else if (instr->IsShr()) {
1815 __ Srav(dst_high, lhs_high, rhs_reg);
1816 __ Nor(AT, ZERO, rhs_reg);
1817 __ Sll(TMP, lhs_high, 1);
1818 __ Sllv(TMP, TMP, AT);
1819 __ Srlv(dst_low, lhs_low, rhs_reg);
1820 __ Or(dst_low, dst_low, TMP);
1821 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1822 __ Beqz(TMP, &done);
1823 __ Move(dst_low, dst_high);
1824 __ Sra(dst_high, dst_high, 31);
Alexey Frunze92d90602015-12-18 18:16:36 -08001825 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001826 __ Srlv(dst_high, lhs_high, rhs_reg);
1827 __ Nor(AT, ZERO, rhs_reg);
1828 __ Sll(TMP, lhs_high, 1);
1829 __ Sllv(TMP, TMP, AT);
1830 __ Srlv(dst_low, lhs_low, rhs_reg);
1831 __ Or(dst_low, dst_low, TMP);
1832 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1833 __ Beqz(TMP, &done);
1834 __ Move(dst_low, dst_high);
1835 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08001836 } else {
1837 __ Nor(AT, ZERO, rhs_reg);
1838 __ Srlv(TMP, lhs_low, rhs_reg);
1839 __ Sll(dst_low, lhs_high, 1);
1840 __ Sllv(dst_low, dst_low, AT);
1841 __ Or(dst_low, dst_low, TMP);
1842 __ Srlv(TMP, lhs_high, rhs_reg);
1843 __ Sll(dst_high, lhs_low, 1);
1844 __ Sllv(dst_high, dst_high, AT);
1845 __ Or(dst_high, dst_high, TMP);
1846 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1847 __ Beqz(TMP, &done);
1848 __ Move(TMP, dst_high);
1849 __ Move(dst_high, dst_low);
1850 __ Move(dst_low, TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001851 }
1852 __ Bind(&done);
1853 }
1854 break;
1855 }
1856
1857 default:
1858 LOG(FATAL) << "Unexpected shift operation type " << type;
1859 }
1860}
1861
1862void LocationsBuilderMIPS::VisitAdd(HAdd* instruction) {
1863 HandleBinaryOp(instruction);
1864}
1865
1866void InstructionCodeGeneratorMIPS::VisitAdd(HAdd* instruction) {
1867 HandleBinaryOp(instruction);
1868}
1869
1870void LocationsBuilderMIPS::VisitAnd(HAnd* instruction) {
1871 HandleBinaryOp(instruction);
1872}
1873
1874void InstructionCodeGeneratorMIPS::VisitAnd(HAnd* instruction) {
1875 HandleBinaryOp(instruction);
1876}
1877
1878void LocationsBuilderMIPS::VisitArrayGet(HArrayGet* instruction) {
1879 LocationSummary* locations =
1880 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1881 locations->SetInAt(0, Location::RequiresRegister());
1882 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1883 if (Primitive::IsFloatingPointType(instruction->GetType())) {
1884 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1885 } else {
1886 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1887 }
1888}
1889
Alexey Frunze2923db72016-08-20 01:55:47 -07001890auto InstructionCodeGeneratorMIPS::GetImplicitNullChecker(HInstruction* instruction) {
1891 auto null_checker = [this, instruction]() {
1892 this->codegen_->MaybeRecordImplicitNullCheck(instruction);
1893 };
1894 return null_checker;
1895}
1896
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001897void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
1898 LocationSummary* locations = instruction->GetLocations();
1899 Register obj = locations->InAt(0).AsRegister<Register>();
1900 Location index = locations->InAt(1);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01001901 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Alexey Frunze2923db72016-08-20 01:55:47 -07001902 auto null_checker = GetImplicitNullChecker(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001903
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01001904 Primitive::Type type = instruction->GetType();
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001905 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
1906 instruction->IsStringCharAt();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001907 switch (type) {
1908 case Primitive::kPrimBoolean: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001909 Register out = locations->Out().AsRegister<Register>();
1910 if (index.IsConstant()) {
1911 size_t offset =
1912 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001913 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001914 } else {
1915 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07001916 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001917 }
1918 break;
1919 }
1920
1921 case Primitive::kPrimByte: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001922 Register out = locations->Out().AsRegister<Register>();
1923 if (index.IsConstant()) {
1924 size_t offset =
1925 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001926 __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001927 } else {
1928 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07001929 __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001930 }
1931 break;
1932 }
1933
1934 case Primitive::kPrimShort: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001935 Register out = locations->Out().AsRegister<Register>();
1936 if (index.IsConstant()) {
1937 size_t offset =
1938 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07001939 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001940 } else {
1941 __ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
1942 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07001943 __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001944 }
1945 break;
1946 }
1947
1948 case Primitive::kPrimChar: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001949 Register out = locations->Out().AsRegister<Register>();
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001950 if (maybe_compressed_char_at) {
1951 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
1952 __ LoadFromOffset(kLoadWord, TMP, obj, count_offset, null_checker);
1953 __ Sll(TMP, TMP, 31); // Extract compression flag into the most significant bit of TMP.
1954 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1955 "Expecting 0=compressed, 1=uncompressed");
1956 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001957 if (index.IsConstant()) {
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001958 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
1959 if (maybe_compressed_char_at) {
1960 MipsLabel uncompressed_load, done;
1961 __ Bnez(TMP, &uncompressed_load);
1962 __ LoadFromOffset(kLoadUnsignedByte,
1963 out,
1964 obj,
1965 data_offset + (const_index << TIMES_1));
1966 __ B(&done);
1967 __ Bind(&uncompressed_load);
1968 __ LoadFromOffset(kLoadUnsignedHalfword,
1969 out,
1970 obj,
1971 data_offset + (const_index << TIMES_2));
1972 __ Bind(&done);
1973 } else {
1974 __ LoadFromOffset(kLoadUnsignedHalfword,
1975 out,
1976 obj,
1977 data_offset + (const_index << TIMES_2),
1978 null_checker);
1979 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001980 } else {
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001981 Register index_reg = index.AsRegister<Register>();
1982 if (maybe_compressed_char_at) {
1983 MipsLabel uncompressed_load, done;
1984 __ Bnez(TMP, &uncompressed_load);
1985 __ Addu(TMP, obj, index_reg);
1986 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
1987 __ B(&done);
1988 __ Bind(&uncompressed_load);
1989 __ Sll(TMP, index_reg, TIMES_2);
1990 __ Addu(TMP, obj, TMP);
1991 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
1992 __ Bind(&done);
1993 } else {
1994 __ Sll(TMP, index_reg, TIMES_2);
1995 __ Addu(TMP, obj, TMP);
1996 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
1997 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001998 }
1999 break;
2000 }
2001
2002 case Primitive::kPrimInt:
2003 case Primitive::kPrimNot: {
2004 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002005 Register out = locations->Out().AsRegister<Register>();
2006 if (index.IsConstant()) {
2007 size_t offset =
2008 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002009 __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002010 } else {
2011 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
2012 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002013 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002014 }
2015 break;
2016 }
2017
2018 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002019 Register out = locations->Out().AsRegisterPairLow<Register>();
2020 if (index.IsConstant()) {
2021 size_t offset =
2022 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002023 __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002024 } else {
2025 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
2026 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002027 __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002028 }
2029 break;
2030 }
2031
2032 case Primitive::kPrimFloat: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002033 FRegister out = locations->Out().AsFpuRegister<FRegister>();
2034 if (index.IsConstant()) {
2035 size_t offset =
2036 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002037 __ LoadSFromOffset(out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002038 } else {
2039 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
2040 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002041 __ LoadSFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002042 }
2043 break;
2044 }
2045
2046 case Primitive::kPrimDouble: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002047 FRegister out = locations->Out().AsFpuRegister<FRegister>();
2048 if (index.IsConstant()) {
2049 size_t offset =
2050 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002051 __ LoadDFromOffset(out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002052 } else {
2053 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
2054 __ Addu(TMP, obj, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002055 __ LoadDFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002056 }
2057 break;
2058 }
2059
2060 case Primitive::kPrimVoid:
2061 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2062 UNREACHABLE();
2063 }
Alexey Frunzec061de12017-02-14 13:27:23 -08002064
2065 if (type == Primitive::kPrimNot) {
2066 Register out = locations->Out().AsRegister<Register>();
2067 __ MaybeUnpoisonHeapReference(out);
2068 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002069}
2070
2071void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
2072 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
2073 locations->SetInAt(0, Location::RequiresRegister());
2074 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2075}
2076
2077void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) {
2078 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01002079 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002080 Register obj = locations->InAt(0).AsRegister<Register>();
2081 Register out = locations->Out().AsRegister<Register>();
2082 __ LoadFromOffset(kLoadWord, out, obj, offset);
2083 codegen_->MaybeRecordImplicitNullCheck(instruction);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002084 // Mask out compression flag from String's array length.
2085 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
2086 __ Srl(out, out, 1u);
2087 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002088}
2089
Alexey Frunzef58b2482016-09-02 22:14:06 -07002090Location LocationsBuilderMIPS::RegisterOrZeroConstant(HInstruction* instruction) {
2091 return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern())
2092 ? Location::ConstantLocation(instruction->AsConstant())
2093 : Location::RequiresRegister();
2094}
2095
2096Location LocationsBuilderMIPS::FpuRegisterOrConstantForStore(HInstruction* instruction) {
2097 // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register.
2098 // We can store a non-zero float or double constant without first loading it into the FPU,
2099 // but we should only prefer this if the constant has a single use.
2100 if (instruction->IsConstant() &&
2101 (instruction->AsConstant()->IsZeroBitPattern() ||
2102 instruction->GetUses().HasExactlyOneElement())) {
2103 return Location::ConstantLocation(instruction->AsConstant());
2104 // Otherwise fall through and require an FPU register for the constant.
2105 }
2106 return Location::RequiresFpuRegister();
2107}
2108
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002109void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) {
Pavle Batuta934808f2015-11-03 13:23:54 +01002110 bool needs_runtime_call = instruction->NeedsTypeCheck();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002111 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2112 instruction,
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002113 needs_runtime_call ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Pavle Batuta934808f2015-11-03 13:23:54 +01002114 if (needs_runtime_call) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002115 InvokeRuntimeCallingConvention calling_convention;
2116 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2117 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2118 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2119 } else {
2120 locations->SetInAt(0, Location::RequiresRegister());
2121 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2122 if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002123 locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002124 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002125 locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002126 }
2127 }
2128}
2129
2130void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
2131 LocationSummary* locations = instruction->GetLocations();
2132 Register obj = locations->InAt(0).AsRegister<Register>();
2133 Location index = locations->InAt(1);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002134 Location value_location = locations->InAt(2);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002135 Primitive::Type value_type = instruction->GetComponentType();
2136 bool needs_runtime_call = locations->WillCall();
2137 bool needs_write_barrier =
2138 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Alexey Frunze2923db72016-08-20 01:55:47 -07002139 auto null_checker = GetImplicitNullChecker(instruction);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002140 Register base_reg = index.IsConstant() ? obj : TMP;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002141
2142 switch (value_type) {
2143 case Primitive::kPrimBoolean:
2144 case Primitive::kPrimByte: {
2145 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002146 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002147 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002148 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002149 __ Addu(base_reg, obj, index.AsRegister<Register>());
2150 }
2151 if (value_location.IsConstant()) {
2152 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2153 __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker);
2154 } else {
2155 Register value = value_location.AsRegister<Register>();
2156 __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002157 }
2158 break;
2159 }
2160
2161 case Primitive::kPrimShort:
2162 case Primitive::kPrimChar: {
2163 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002164 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002165 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002166 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002167 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_2);
2168 __ Addu(base_reg, obj, base_reg);
2169 }
2170 if (value_location.IsConstant()) {
2171 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2172 __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker);
2173 } else {
2174 Register value = value_location.AsRegister<Register>();
2175 __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002176 }
2177 break;
2178 }
2179
2180 case Primitive::kPrimInt:
2181 case Primitive::kPrimNot: {
2182 if (!needs_runtime_call) {
2183 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002184 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002185 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002186 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002187 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
2188 __ Addu(base_reg, obj, base_reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002189 }
Alexey Frunzef58b2482016-09-02 22:14:06 -07002190 if (value_location.IsConstant()) {
2191 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2192 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2193 DCHECK(!needs_write_barrier);
2194 } else {
2195 Register value = value_location.AsRegister<Register>();
Alexey Frunzec061de12017-02-14 13:27:23 -08002196 if (kPoisonHeapReferences && needs_write_barrier) {
2197 // Note that in the case where `value` is a null reference,
2198 // we do not enter this block, as a null reference does not
2199 // need poisoning.
2200 DCHECK_EQ(value_type, Primitive::kPrimNot);
2201 // Use Sw() instead of StoreToOffset() in order to be able to
2202 // hold the poisoned reference in AT and thus avoid allocating
2203 // yet another temporary register.
2204 if (index.IsConstant()) {
2205 if (!IsInt<16>(static_cast<int32_t>(data_offset))) {
2206 int16_t low = Low16Bits(data_offset);
2207 uint32_t high = data_offset - low;
2208 __ Addiu32(TMP, obj, high);
2209 base_reg = TMP;
2210 data_offset = low;
2211 }
2212 } else {
2213 DCHECK(IsInt<16>(static_cast<int32_t>(data_offset)));
2214 }
2215 __ PoisonHeapReference(AT, value);
2216 __ Sw(AT, base_reg, data_offset);
2217 null_checker();
2218 } else {
2219 __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2220 }
Alexey Frunzef58b2482016-09-02 22:14:06 -07002221 if (needs_write_barrier) {
2222 DCHECK_EQ(value_type, Primitive::kPrimNot);
Goran Jakovljevice114da22016-12-26 14:21:43 +01002223 codegen_->MarkGCCard(obj, value, instruction->GetValueCanBeNull());
Alexey Frunzef58b2482016-09-02 22:14:06 -07002224 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002225 }
2226 } else {
2227 DCHECK_EQ(value_type, Primitive::kPrimNot);
Alexey Frunzec061de12017-02-14 13:27:23 -08002228 // Note: if heap poisoning is enabled, pAputObject takes care
2229 // of poisoning the reference.
Serban Constantinescufca16662016-07-14 09:21:59 +01002230 codegen_->InvokeRuntime(kQuickAputObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002231 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
2232 }
2233 break;
2234 }
2235
2236 case Primitive::kPrimLong: {
2237 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002238 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002239 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002240 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002241 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_8);
2242 __ Addu(base_reg, obj, base_reg);
2243 }
2244 if (value_location.IsConstant()) {
2245 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2246 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2247 } else {
2248 Register value = value_location.AsRegisterPairLow<Register>();
2249 __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002250 }
2251 break;
2252 }
2253
2254 case Primitive::kPrimFloat: {
2255 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002256 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002257 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002258 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002259 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_4);
2260 __ Addu(base_reg, obj, base_reg);
2261 }
2262 if (value_location.IsConstant()) {
2263 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2264 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2265 } else {
2266 FRegister value = value_location.AsFpuRegister<FRegister>();
2267 __ StoreSToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002268 }
2269 break;
2270 }
2271
2272 case Primitive::kPrimDouble: {
2273 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002274 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002275 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002276 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002277 __ Sll(base_reg, index.AsRegister<Register>(), TIMES_8);
2278 __ Addu(base_reg, obj, base_reg);
2279 }
2280 if (value_location.IsConstant()) {
2281 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
2282 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
2283 } else {
2284 FRegister value = value_location.AsFpuRegister<FRegister>();
2285 __ StoreDToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002286 }
2287 break;
2288 }
2289
2290 case Primitive::kPrimVoid:
2291 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2292 UNREACHABLE();
2293 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002294}
2295
2296void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01002297 RegisterSet caller_saves = RegisterSet::Empty();
2298 InvokeRuntimeCallingConvention calling_convention;
2299 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2300 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2301 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002302 locations->SetInAt(0, Location::RequiresRegister());
2303 locations->SetInAt(1, Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002304}
2305
2306void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
2307 LocationSummary* locations = instruction->GetLocations();
2308 BoundsCheckSlowPathMIPS* slow_path =
2309 new (GetGraph()->GetArena()) BoundsCheckSlowPathMIPS(instruction);
2310 codegen_->AddSlowPath(slow_path);
2311
2312 Register index = locations->InAt(0).AsRegister<Register>();
2313 Register length = locations->InAt(1).AsRegister<Register>();
2314
2315 // length is limited by the maximum positive signed 32-bit integer.
2316 // Unsigned comparison of length and index checks for index < 0
2317 // and for length <= index simultaneously.
2318 __ Bgeu(index, length, slow_path->GetEntryLabel());
2319}
2320
2321void LocationsBuilderMIPS::VisitCheckCast(HCheckCast* instruction) {
2322 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2323 instruction,
2324 LocationSummary::kCallOnSlowPath);
2325 locations->SetInAt(0, Location::RequiresRegister());
2326 locations->SetInAt(1, Location::RequiresRegister());
2327 // Note that TypeCheckSlowPathMIPS uses this register too.
2328 locations->AddTemp(Location::RequiresRegister());
2329}
2330
2331void InstructionCodeGeneratorMIPS::VisitCheckCast(HCheckCast* instruction) {
2332 LocationSummary* locations = instruction->GetLocations();
2333 Register obj = locations->InAt(0).AsRegister<Register>();
2334 Register cls = locations->InAt(1).AsRegister<Register>();
2335 Register obj_cls = locations->GetTemp(0).AsRegister<Register>();
2336
2337 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction);
2338 codegen_->AddSlowPath(slow_path);
2339
2340 // TODO: avoid this check if we know obj is not null.
2341 __ Beqz(obj, slow_path->GetExitLabel());
2342 // Compare the class of `obj` with `cls`.
2343 __ LoadFromOffset(kLoadWord, obj_cls, obj, mirror::Object::ClassOffset().Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08002344 __ MaybeUnpoisonHeapReference(obj_cls);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002345 __ Bne(obj_cls, cls, slow_path->GetEntryLabel());
2346 __ Bind(slow_path->GetExitLabel());
2347}
2348
2349void LocationsBuilderMIPS::VisitClinitCheck(HClinitCheck* check) {
2350 LocationSummary* locations =
2351 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2352 locations->SetInAt(0, Location::RequiresRegister());
2353 if (check->HasUses()) {
2354 locations->SetOut(Location::SameAsFirstInput());
2355 }
2356}
2357
2358void InstructionCodeGeneratorMIPS::VisitClinitCheck(HClinitCheck* check) {
2359 // We assume the class is not null.
2360 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
2361 check->GetLoadClass(),
2362 check,
2363 check->GetDexPc(),
2364 true);
2365 codegen_->AddSlowPath(slow_path);
2366 GenerateClassInitializationCheck(slow_path,
2367 check->GetLocations()->InAt(0).AsRegister<Register>());
2368}
2369
2370void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
2371 Primitive::Type in_type = compare->InputAt(0)->GetType();
2372
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002373 LocationSummary* locations =
2374 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002375
2376 switch (in_type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002377 case Primitive::kPrimBoolean:
2378 case Primitive::kPrimByte:
2379 case Primitive::kPrimShort:
2380 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002381 case Primitive::kPrimInt:
Alexey Frunzee7697712016-09-15 21:37:49 -07002382 locations->SetInAt(0, Location::RequiresRegister());
2383 locations->SetInAt(1, Location::RequiresRegister());
2384 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2385 break;
2386
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002387 case Primitive::kPrimLong:
2388 locations->SetInAt(0, Location::RequiresRegister());
2389 locations->SetInAt(1, Location::RequiresRegister());
2390 // Output overlaps because it is written before doing the low comparison.
2391 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2392 break;
2393
2394 case Primitive::kPrimFloat:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002395 case Primitive::kPrimDouble:
2396 locations->SetInAt(0, Location::RequiresFpuRegister());
2397 locations->SetInAt(1, Location::RequiresFpuRegister());
2398 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002399 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002400
2401 default:
2402 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
2403 }
2404}
2405
2406void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
2407 LocationSummary* locations = instruction->GetLocations();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002408 Register res = locations->Out().AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002409 Primitive::Type in_type = instruction->InputAt(0)->GetType();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002410 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002411
2412 // 0 if: left == right
2413 // 1 if: left > right
2414 // -1 if: left < right
2415 switch (in_type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002416 case Primitive::kPrimBoolean:
2417 case Primitive::kPrimByte:
2418 case Primitive::kPrimShort:
2419 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002420 case Primitive::kPrimInt: {
2421 Register lhs = locations->InAt(0).AsRegister<Register>();
2422 Register rhs = locations->InAt(1).AsRegister<Register>();
2423 __ Slt(TMP, lhs, rhs);
2424 __ Slt(res, rhs, lhs);
2425 __ Subu(res, res, TMP);
2426 break;
2427 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002428 case Primitive::kPrimLong: {
2429 MipsLabel done;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002430 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2431 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2432 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
2433 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
2434 // TODO: more efficient (direct) comparison with a constant.
2435 __ Slt(TMP, lhs_high, rhs_high);
2436 __ Slt(AT, rhs_high, lhs_high); // Inverted: is actually gt.
2437 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
2438 __ Bnez(res, &done); // If we compared ==, check if lower bits are also equal.
2439 __ Sltu(TMP, lhs_low, rhs_low);
2440 __ Sltu(AT, rhs_low, lhs_low); // Inverted: is actually gt.
2441 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
2442 __ Bind(&done);
2443 break;
2444 }
2445
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002446 case Primitive::kPrimFloat: {
Roland Levillain32ca3752016-02-17 16:49:37 +00002447 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002448 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2449 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2450 MipsLabel done;
2451 if (isR6) {
2452 __ CmpEqS(FTMP, lhs, rhs);
2453 __ LoadConst32(res, 0);
2454 __ Bc1nez(FTMP, &done);
2455 if (gt_bias) {
2456 __ CmpLtS(FTMP, lhs, rhs);
2457 __ LoadConst32(res, -1);
2458 __ Bc1nez(FTMP, &done);
2459 __ LoadConst32(res, 1);
2460 } else {
2461 __ CmpLtS(FTMP, rhs, lhs);
2462 __ LoadConst32(res, 1);
2463 __ Bc1nez(FTMP, &done);
2464 __ LoadConst32(res, -1);
2465 }
2466 } else {
2467 if (gt_bias) {
2468 __ ColtS(0, lhs, rhs);
2469 __ LoadConst32(res, -1);
2470 __ Bc1t(0, &done);
2471 __ CeqS(0, lhs, rhs);
2472 __ LoadConst32(res, 1);
2473 __ Movt(res, ZERO, 0);
2474 } else {
2475 __ ColtS(0, rhs, lhs);
2476 __ LoadConst32(res, 1);
2477 __ Bc1t(0, &done);
2478 __ CeqS(0, lhs, rhs);
2479 __ LoadConst32(res, -1);
2480 __ Movt(res, ZERO, 0);
2481 }
2482 }
2483 __ Bind(&done);
2484 break;
2485 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002486 case Primitive::kPrimDouble: {
Roland Levillain32ca3752016-02-17 16:49:37 +00002487 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002488 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2489 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2490 MipsLabel done;
2491 if (isR6) {
2492 __ CmpEqD(FTMP, lhs, rhs);
2493 __ LoadConst32(res, 0);
2494 __ Bc1nez(FTMP, &done);
2495 if (gt_bias) {
2496 __ CmpLtD(FTMP, lhs, rhs);
2497 __ LoadConst32(res, -1);
2498 __ Bc1nez(FTMP, &done);
2499 __ LoadConst32(res, 1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002500 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002501 __ CmpLtD(FTMP, rhs, lhs);
2502 __ LoadConst32(res, 1);
2503 __ Bc1nez(FTMP, &done);
2504 __ LoadConst32(res, -1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002505 }
2506 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002507 if (gt_bias) {
2508 __ ColtD(0, lhs, rhs);
2509 __ LoadConst32(res, -1);
2510 __ Bc1t(0, &done);
2511 __ CeqD(0, lhs, rhs);
2512 __ LoadConst32(res, 1);
2513 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002514 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002515 __ ColtD(0, rhs, lhs);
2516 __ LoadConst32(res, 1);
2517 __ Bc1t(0, &done);
2518 __ CeqD(0, lhs, rhs);
2519 __ LoadConst32(res, -1);
2520 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002521 }
2522 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002523 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002524 break;
2525 }
2526
2527 default:
2528 LOG(FATAL) << "Unimplemented compare type " << in_type;
2529 }
2530}
2531
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002532void LocationsBuilderMIPS::HandleCondition(HCondition* instruction) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002533 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002534 switch (instruction->InputAt(0)->GetType()) {
2535 default:
2536 case Primitive::kPrimLong:
2537 locations->SetInAt(0, Location::RequiresRegister());
2538 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2539 break;
2540
2541 case Primitive::kPrimFloat:
2542 case Primitive::kPrimDouble:
2543 locations->SetInAt(0, Location::RequiresFpuRegister());
2544 locations->SetInAt(1, Location::RequiresFpuRegister());
2545 break;
2546 }
David Brazdilb3e773e2016-01-26 11:28:37 +00002547 if (!instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002548 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2549 }
2550}
2551
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002552void InstructionCodeGeneratorMIPS::HandleCondition(HCondition* instruction) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002553 if (instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002554 return;
2555 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002556
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002557 Primitive::Type type = instruction->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002558 LocationSummary* locations = instruction->GetLocations();
2559 Register dst = locations->Out().AsRegister<Register>();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002560 MipsLabel true_label;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002561
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002562 switch (type) {
2563 default:
2564 // Integer case.
2565 GenerateIntCompare(instruction->GetCondition(), locations);
2566 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002567
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002568 case Primitive::kPrimLong:
2569 // TODO: don't use branches.
2570 GenerateLongCompareAndBranch(instruction->GetCondition(), locations, &true_label);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002571 break;
2572
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002573 case Primitive::kPrimFloat:
2574 case Primitive::kPrimDouble:
Alexey Frunze2ddb7172016-09-06 17:04:55 -07002575 GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
2576 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002577 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002578
2579 // Convert the branches into the result.
2580 MipsLabel done;
2581
2582 // False case: result = 0.
2583 __ LoadConst32(dst, 0);
2584 __ B(&done);
2585
2586 // True case: result = 1.
2587 __ Bind(&true_label);
2588 __ LoadConst32(dst, 1);
2589 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002590}
2591
Alexey Frunze7e99e052015-11-24 19:28:01 -08002592void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2593 DCHECK(instruction->IsDiv() || instruction->IsRem());
2594 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2595
2596 LocationSummary* locations = instruction->GetLocations();
2597 Location second = locations->InAt(1);
2598 DCHECK(second.IsConstant());
2599
2600 Register out = locations->Out().AsRegister<Register>();
2601 Register dividend = locations->InAt(0).AsRegister<Register>();
2602 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2603 DCHECK(imm == 1 || imm == -1);
2604
2605 if (instruction->IsRem()) {
2606 __ Move(out, ZERO);
2607 } else {
2608 if (imm == -1) {
2609 __ Subu(out, ZERO, dividend);
2610 } else if (out != dividend) {
2611 __ Move(out, dividend);
2612 }
2613 }
2614}
2615
2616void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2617 DCHECK(instruction->IsDiv() || instruction->IsRem());
2618 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2619
2620 LocationSummary* locations = instruction->GetLocations();
2621 Location second = locations->InAt(1);
2622 DCHECK(second.IsConstant());
2623
2624 Register out = locations->Out().AsRegister<Register>();
2625 Register dividend = locations->InAt(0).AsRegister<Register>();
2626 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002627 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Alexey Frunze7e99e052015-11-24 19:28:01 -08002628 int ctz_imm = CTZ(abs_imm);
2629
2630 if (instruction->IsDiv()) {
2631 if (ctz_imm == 1) {
2632 // Fast path for division by +/-2, which is very common.
2633 __ Srl(TMP, dividend, 31);
2634 } else {
2635 __ Sra(TMP, dividend, 31);
2636 __ Srl(TMP, TMP, 32 - ctz_imm);
2637 }
2638 __ Addu(out, dividend, TMP);
2639 __ Sra(out, out, ctz_imm);
2640 if (imm < 0) {
2641 __ Subu(out, ZERO, out);
2642 }
2643 } else {
2644 if (ctz_imm == 1) {
2645 // Fast path for modulo +/-2, which is very common.
2646 __ Sra(TMP, dividend, 31);
2647 __ Subu(out, dividend, TMP);
2648 __ Andi(out, out, 1);
2649 __ Addu(out, out, TMP);
2650 } else {
2651 __ Sra(TMP, dividend, 31);
2652 __ Srl(TMP, TMP, 32 - ctz_imm);
2653 __ Addu(out, dividend, TMP);
2654 if (IsUint<16>(abs_imm - 1)) {
2655 __ Andi(out, out, abs_imm - 1);
2656 } else {
2657 __ Sll(out, out, 32 - ctz_imm);
2658 __ Srl(out, out, 32 - ctz_imm);
2659 }
2660 __ Subu(out, out, TMP);
2661 }
2662 }
2663}
2664
2665void InstructionCodeGeneratorMIPS::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2666 DCHECK(instruction->IsDiv() || instruction->IsRem());
2667 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2668
2669 LocationSummary* locations = instruction->GetLocations();
2670 Location second = locations->InAt(1);
2671 DCHECK(second.IsConstant());
2672
2673 Register out = locations->Out().AsRegister<Register>();
2674 Register dividend = locations->InAt(0).AsRegister<Register>();
2675 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2676
2677 int64_t magic;
2678 int shift;
2679 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2680
2681 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
2682
2683 __ LoadConst32(TMP, magic);
2684 if (isR6) {
2685 __ MuhR6(TMP, dividend, TMP);
2686 } else {
2687 __ MultR2(dividend, TMP);
2688 __ Mfhi(TMP);
2689 }
2690 if (imm > 0 && magic < 0) {
2691 __ Addu(TMP, TMP, dividend);
2692 } else if (imm < 0 && magic > 0) {
2693 __ Subu(TMP, TMP, dividend);
2694 }
2695
2696 if (shift != 0) {
2697 __ Sra(TMP, TMP, shift);
2698 }
2699
2700 if (instruction->IsDiv()) {
2701 __ Sra(out, TMP, 31);
2702 __ Subu(out, TMP, out);
2703 } else {
2704 __ Sra(AT, TMP, 31);
2705 __ Subu(AT, TMP, AT);
2706 __ LoadConst32(TMP, imm);
2707 if (isR6) {
2708 __ MulR6(TMP, AT, TMP);
2709 } else {
2710 __ MulR2(TMP, AT, TMP);
2711 }
2712 __ Subu(out, dividend, TMP);
2713 }
2714}
2715
2716void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2717 DCHECK(instruction->IsDiv() || instruction->IsRem());
2718 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2719
2720 LocationSummary* locations = instruction->GetLocations();
2721 Register out = locations->Out().AsRegister<Register>();
2722 Location second = locations->InAt(1);
2723
2724 if (second.IsConstant()) {
2725 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2726 if (imm == 0) {
2727 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2728 } else if (imm == 1 || imm == -1) {
2729 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002730 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08002731 DivRemByPowerOfTwo(instruction);
2732 } else {
2733 DCHECK(imm <= -2 || imm >= 2);
2734 GenerateDivRemWithAnyConstant(instruction);
2735 }
2736 } else {
2737 Register dividend = locations->InAt(0).AsRegister<Register>();
2738 Register divisor = second.AsRegister<Register>();
2739 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
2740 if (instruction->IsDiv()) {
2741 if (isR6) {
2742 __ DivR6(out, dividend, divisor);
2743 } else {
2744 __ DivR2(out, dividend, divisor);
2745 }
2746 } else {
2747 if (isR6) {
2748 __ ModR6(out, dividend, divisor);
2749 } else {
2750 __ ModR2(out, dividend, divisor);
2751 }
2752 }
2753 }
2754}
2755
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002756void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
2757 Primitive::Type type = div->GetResultType();
2758 LocationSummary::CallKind call_kind = (type == Primitive::kPrimLong)
Serban Constantinescu54ff4822016-07-07 18:03:19 +01002759 ? LocationSummary::kCallOnMainOnly
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002760 : LocationSummary::kNoCall;
2761
2762 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2763
2764 switch (type) {
2765 case Primitive::kPrimInt:
2766 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08002767 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002768 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2769 break;
2770
2771 case Primitive::kPrimLong: {
2772 InvokeRuntimeCallingConvention calling_convention;
2773 locations->SetInAt(0, Location::RegisterPairLocation(
2774 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2775 locations->SetInAt(1, Location::RegisterPairLocation(
2776 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2777 locations->SetOut(calling_convention.GetReturnLocation(type));
2778 break;
2779 }
2780
2781 case Primitive::kPrimFloat:
2782 case Primitive::kPrimDouble:
2783 locations->SetInAt(0, Location::RequiresFpuRegister());
2784 locations->SetInAt(1, Location::RequiresFpuRegister());
2785 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2786 break;
2787
2788 default:
2789 LOG(FATAL) << "Unexpected div type " << type;
2790 }
2791}
2792
2793void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) {
2794 Primitive::Type type = instruction->GetType();
2795 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002796
2797 switch (type) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08002798 case Primitive::kPrimInt:
2799 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002800 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002801 case Primitive::kPrimLong: {
Serban Constantinescufca16662016-07-14 09:21:59 +01002802 codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002803 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
2804 break;
2805 }
2806 case Primitive::kPrimFloat:
2807 case Primitive::kPrimDouble: {
2808 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
2809 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2810 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2811 if (type == Primitive::kPrimFloat) {
2812 __ DivS(dst, lhs, rhs);
2813 } else {
2814 __ DivD(dst, lhs, rhs);
2815 }
2816 break;
2817 }
2818 default:
2819 LOG(FATAL) << "Unexpected div type " << type;
2820 }
2821}
2822
2823void LocationsBuilderMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01002824 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002825 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002826}
2827
2828void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2829 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathMIPS(instruction);
2830 codegen_->AddSlowPath(slow_path);
2831 Location value = instruction->GetLocations()->InAt(0);
2832 Primitive::Type type = instruction->GetType();
2833
2834 switch (type) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00002835 case Primitive::kPrimBoolean:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002836 case Primitive::kPrimByte:
2837 case Primitive::kPrimChar:
2838 case Primitive::kPrimShort:
2839 case Primitive::kPrimInt: {
2840 if (value.IsConstant()) {
2841 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2842 __ B(slow_path->GetEntryLabel());
2843 } else {
2844 // A division by a non-null constant is valid. We don't need to perform
2845 // any check, so simply fall through.
2846 }
2847 } else {
2848 DCHECK(value.IsRegister()) << value;
2849 __ Beqz(value.AsRegister<Register>(), slow_path->GetEntryLabel());
2850 }
2851 break;
2852 }
2853 case Primitive::kPrimLong: {
2854 if (value.IsConstant()) {
2855 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2856 __ B(slow_path->GetEntryLabel());
2857 } else {
2858 // A division by a non-null constant is valid. We don't need to perform
2859 // any check, so simply fall through.
2860 }
2861 } else {
2862 DCHECK(value.IsRegisterPair()) << value;
2863 __ Or(TMP, value.AsRegisterPairHigh<Register>(), value.AsRegisterPairLow<Register>());
2864 __ Beqz(TMP, slow_path->GetEntryLabel());
2865 }
2866 break;
2867 }
2868 default:
2869 LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
2870 }
2871}
2872
2873void LocationsBuilderMIPS::VisitDoubleConstant(HDoubleConstant* constant) {
2874 LocationSummary* locations =
2875 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2876 locations->SetOut(Location::ConstantLocation(constant));
2877}
2878
2879void InstructionCodeGeneratorMIPS::VisitDoubleConstant(HDoubleConstant* cst ATTRIBUTE_UNUSED) {
2880 // Will be generated at use site.
2881}
2882
2883void LocationsBuilderMIPS::VisitExit(HExit* exit) {
2884 exit->SetLocations(nullptr);
2885}
2886
2887void InstructionCodeGeneratorMIPS::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
2888}
2889
2890void LocationsBuilderMIPS::VisitFloatConstant(HFloatConstant* constant) {
2891 LocationSummary* locations =
2892 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2893 locations->SetOut(Location::ConstantLocation(constant));
2894}
2895
2896void InstructionCodeGeneratorMIPS::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
2897 // Will be generated at use site.
2898}
2899
2900void LocationsBuilderMIPS::VisitGoto(HGoto* got) {
2901 got->SetLocations(nullptr);
2902}
2903
2904void InstructionCodeGeneratorMIPS::HandleGoto(HInstruction* got, HBasicBlock* successor) {
2905 DCHECK(!successor->IsExitBlock());
2906 HBasicBlock* block = got->GetBlock();
2907 HInstruction* previous = got->GetPrevious();
2908 HLoopInformation* info = block->GetLoopInformation();
2909
2910 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
2911 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2912 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2913 return;
2914 }
2915 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2916 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2917 }
2918 if (!codegen_->GoesToNextBlock(block, successor)) {
2919 __ B(codegen_->GetLabelOf(successor));
2920 }
2921}
2922
2923void InstructionCodeGeneratorMIPS::VisitGoto(HGoto* got) {
2924 HandleGoto(got, got->GetSuccessor());
2925}
2926
2927void LocationsBuilderMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
2928 try_boundary->SetLocations(nullptr);
2929}
2930
2931void InstructionCodeGeneratorMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
2932 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2933 if (!successor->IsExitBlock()) {
2934 HandleGoto(try_boundary, successor);
2935 }
2936}
2937
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002938void InstructionCodeGeneratorMIPS::GenerateIntCompare(IfCondition cond,
2939 LocationSummary* locations) {
2940 Register dst = locations->Out().AsRegister<Register>();
2941 Register lhs = locations->InAt(0).AsRegister<Register>();
2942 Location rhs_location = locations->InAt(1);
2943 Register rhs_reg = ZERO;
2944 int64_t rhs_imm = 0;
2945 bool use_imm = rhs_location.IsConstant();
2946 if (use_imm) {
2947 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
2948 } else {
2949 rhs_reg = rhs_location.AsRegister<Register>();
2950 }
2951
2952 switch (cond) {
2953 case kCondEQ:
2954 case kCondNE:
Alexey Frunzee7697712016-09-15 21:37:49 -07002955 if (use_imm && IsInt<16>(-rhs_imm)) {
2956 if (rhs_imm == 0) {
2957 if (cond == kCondEQ) {
2958 __ Sltiu(dst, lhs, 1);
2959 } else {
2960 __ Sltu(dst, ZERO, lhs);
2961 }
2962 } else {
2963 __ Addiu(dst, lhs, -rhs_imm);
2964 if (cond == kCondEQ) {
2965 __ Sltiu(dst, dst, 1);
2966 } else {
2967 __ Sltu(dst, ZERO, dst);
2968 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002969 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002970 } else {
Alexey Frunzee7697712016-09-15 21:37:49 -07002971 if (use_imm && IsUint<16>(rhs_imm)) {
2972 __ Xori(dst, lhs, rhs_imm);
2973 } else {
2974 if (use_imm) {
2975 rhs_reg = TMP;
2976 __ LoadConst32(rhs_reg, rhs_imm);
2977 }
2978 __ Xor(dst, lhs, rhs_reg);
2979 }
2980 if (cond == kCondEQ) {
2981 __ Sltiu(dst, dst, 1);
2982 } else {
2983 __ Sltu(dst, ZERO, dst);
2984 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002985 }
2986 break;
2987
2988 case kCondLT:
2989 case kCondGE:
2990 if (use_imm && IsInt<16>(rhs_imm)) {
2991 __ Slti(dst, lhs, rhs_imm);
2992 } else {
2993 if (use_imm) {
2994 rhs_reg = TMP;
2995 __ LoadConst32(rhs_reg, rhs_imm);
2996 }
2997 __ Slt(dst, lhs, rhs_reg);
2998 }
2999 if (cond == kCondGE) {
3000 // Simulate lhs >= rhs via !(lhs < rhs) since there's
3001 // only the slt instruction but no sge.
3002 __ Xori(dst, dst, 1);
3003 }
3004 break;
3005
3006 case kCondLE:
3007 case kCondGT:
3008 if (use_imm && IsInt<16>(rhs_imm + 1)) {
3009 // Simulate lhs <= rhs via lhs < rhs + 1.
3010 __ Slti(dst, lhs, rhs_imm + 1);
3011 if (cond == kCondGT) {
3012 // Simulate lhs > rhs via !(lhs <= rhs) since there's
3013 // only the slti instruction but no sgti.
3014 __ Xori(dst, dst, 1);
3015 }
3016 } else {
3017 if (use_imm) {
3018 rhs_reg = TMP;
3019 __ LoadConst32(rhs_reg, rhs_imm);
3020 }
3021 __ Slt(dst, rhs_reg, lhs);
3022 if (cond == kCondLE) {
3023 // Simulate lhs <= rhs via !(rhs < lhs) since there's
3024 // only the slt instruction but no sle.
3025 __ Xori(dst, dst, 1);
3026 }
3027 }
3028 break;
3029
3030 case kCondB:
3031 case kCondAE:
3032 if (use_imm && IsInt<16>(rhs_imm)) {
3033 // Sltiu sign-extends its 16-bit immediate operand before
3034 // the comparison and thus lets us compare directly with
3035 // unsigned values in the ranges [0, 0x7fff] and
3036 // [0xffff8000, 0xffffffff].
3037 __ Sltiu(dst, lhs, rhs_imm);
3038 } else {
3039 if (use_imm) {
3040 rhs_reg = TMP;
3041 __ LoadConst32(rhs_reg, rhs_imm);
3042 }
3043 __ Sltu(dst, lhs, rhs_reg);
3044 }
3045 if (cond == kCondAE) {
3046 // Simulate lhs >= rhs via !(lhs < rhs) since there's
3047 // only the sltu instruction but no sgeu.
3048 __ Xori(dst, dst, 1);
3049 }
3050 break;
3051
3052 case kCondBE:
3053 case kCondA:
3054 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
3055 // Simulate lhs <= rhs via lhs < rhs + 1.
3056 // Note that this only works if rhs + 1 does not overflow
3057 // to 0, hence the check above.
3058 // Sltiu sign-extends its 16-bit immediate operand before
3059 // the comparison and thus lets us compare directly with
3060 // unsigned values in the ranges [0, 0x7fff] and
3061 // [0xffff8000, 0xffffffff].
3062 __ Sltiu(dst, lhs, rhs_imm + 1);
3063 if (cond == kCondA) {
3064 // Simulate lhs > rhs via !(lhs <= rhs) since there's
3065 // only the sltiu instruction but no sgtiu.
3066 __ Xori(dst, dst, 1);
3067 }
3068 } else {
3069 if (use_imm) {
3070 rhs_reg = TMP;
3071 __ LoadConst32(rhs_reg, rhs_imm);
3072 }
3073 __ Sltu(dst, rhs_reg, lhs);
3074 if (cond == kCondBE) {
3075 // Simulate lhs <= rhs via !(rhs < lhs) since there's
3076 // only the sltu instruction but no sleu.
3077 __ Xori(dst, dst, 1);
3078 }
3079 }
3080 break;
3081 }
3082}
3083
Alexey Frunze674b9ee2016-09-20 14:54:15 -07003084bool InstructionCodeGeneratorMIPS::MaterializeIntCompare(IfCondition cond,
3085 LocationSummary* input_locations,
3086 Register dst) {
3087 Register lhs = input_locations->InAt(0).AsRegister<Register>();
3088 Location rhs_location = input_locations->InAt(1);
3089 Register rhs_reg = ZERO;
3090 int64_t rhs_imm = 0;
3091 bool use_imm = rhs_location.IsConstant();
3092 if (use_imm) {
3093 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
3094 } else {
3095 rhs_reg = rhs_location.AsRegister<Register>();
3096 }
3097
3098 switch (cond) {
3099 case kCondEQ:
3100 case kCondNE:
3101 if (use_imm && IsInt<16>(-rhs_imm)) {
3102 __ Addiu(dst, lhs, -rhs_imm);
3103 } else if (use_imm && IsUint<16>(rhs_imm)) {
3104 __ Xori(dst, lhs, rhs_imm);
3105 } else {
3106 if (use_imm) {
3107 rhs_reg = TMP;
3108 __ LoadConst32(rhs_reg, rhs_imm);
3109 }
3110 __ Xor(dst, lhs, rhs_reg);
3111 }
3112 return (cond == kCondEQ);
3113
3114 case kCondLT:
3115 case kCondGE:
3116 if (use_imm && IsInt<16>(rhs_imm)) {
3117 __ Slti(dst, lhs, rhs_imm);
3118 } else {
3119 if (use_imm) {
3120 rhs_reg = TMP;
3121 __ LoadConst32(rhs_reg, rhs_imm);
3122 }
3123 __ Slt(dst, lhs, rhs_reg);
3124 }
3125 return (cond == kCondGE);
3126
3127 case kCondLE:
3128 case kCondGT:
3129 if (use_imm && IsInt<16>(rhs_imm + 1)) {
3130 // Simulate lhs <= rhs via lhs < rhs + 1.
3131 __ Slti(dst, lhs, rhs_imm + 1);
3132 return (cond == kCondGT);
3133 } else {
3134 if (use_imm) {
3135 rhs_reg = TMP;
3136 __ LoadConst32(rhs_reg, rhs_imm);
3137 }
3138 __ Slt(dst, rhs_reg, lhs);
3139 return (cond == kCondLE);
3140 }
3141
3142 case kCondB:
3143 case kCondAE:
3144 if (use_imm && IsInt<16>(rhs_imm)) {
3145 // Sltiu sign-extends its 16-bit immediate operand before
3146 // the comparison and thus lets us compare directly with
3147 // unsigned values in the ranges [0, 0x7fff] and
3148 // [0xffff8000, 0xffffffff].
3149 __ Sltiu(dst, lhs, rhs_imm);
3150 } else {
3151 if (use_imm) {
3152 rhs_reg = TMP;
3153 __ LoadConst32(rhs_reg, rhs_imm);
3154 }
3155 __ Sltu(dst, lhs, rhs_reg);
3156 }
3157 return (cond == kCondAE);
3158
3159 case kCondBE:
3160 case kCondA:
3161 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
3162 // Simulate lhs <= rhs via lhs < rhs + 1.
3163 // Note that this only works if rhs + 1 does not overflow
3164 // to 0, hence the check above.
3165 // Sltiu sign-extends its 16-bit immediate operand before
3166 // the comparison and thus lets us compare directly with
3167 // unsigned values in the ranges [0, 0x7fff] and
3168 // [0xffff8000, 0xffffffff].
3169 __ Sltiu(dst, lhs, rhs_imm + 1);
3170 return (cond == kCondA);
3171 } else {
3172 if (use_imm) {
3173 rhs_reg = TMP;
3174 __ LoadConst32(rhs_reg, rhs_imm);
3175 }
3176 __ Sltu(dst, rhs_reg, lhs);
3177 return (cond == kCondBE);
3178 }
3179 }
3180}
3181
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003182void InstructionCodeGeneratorMIPS::GenerateIntCompareAndBranch(IfCondition cond,
3183 LocationSummary* locations,
3184 MipsLabel* label) {
3185 Register lhs = locations->InAt(0).AsRegister<Register>();
3186 Location rhs_location = locations->InAt(1);
3187 Register rhs_reg = ZERO;
Alexey Frunzee7697712016-09-15 21:37:49 -07003188 int64_t rhs_imm = 0;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003189 bool use_imm = rhs_location.IsConstant();
3190 if (use_imm) {
3191 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
3192 } else {
3193 rhs_reg = rhs_location.AsRegister<Register>();
3194 }
3195
3196 if (use_imm && rhs_imm == 0) {
3197 switch (cond) {
3198 case kCondEQ:
3199 case kCondBE: // <= 0 if zero
3200 __ Beqz(lhs, label);
3201 break;
3202 case kCondNE:
3203 case kCondA: // > 0 if non-zero
3204 __ Bnez(lhs, label);
3205 break;
3206 case kCondLT:
3207 __ Bltz(lhs, label);
3208 break;
3209 case kCondGE:
3210 __ Bgez(lhs, label);
3211 break;
3212 case kCondLE:
3213 __ Blez(lhs, label);
3214 break;
3215 case kCondGT:
3216 __ Bgtz(lhs, label);
3217 break;
3218 case kCondB: // always false
3219 break;
3220 case kCondAE: // always true
3221 __ B(label);
3222 break;
3223 }
3224 } else {
Alexey Frunzee7697712016-09-15 21:37:49 -07003225 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3226 if (isR6 || !use_imm) {
3227 if (use_imm) {
3228 rhs_reg = TMP;
3229 __ LoadConst32(rhs_reg, rhs_imm);
3230 }
3231 switch (cond) {
3232 case kCondEQ:
3233 __ Beq(lhs, rhs_reg, label);
3234 break;
3235 case kCondNE:
3236 __ Bne(lhs, rhs_reg, label);
3237 break;
3238 case kCondLT:
3239 __ Blt(lhs, rhs_reg, label);
3240 break;
3241 case kCondGE:
3242 __ Bge(lhs, rhs_reg, label);
3243 break;
3244 case kCondLE:
3245 __ Bge(rhs_reg, lhs, label);
3246 break;
3247 case kCondGT:
3248 __ Blt(rhs_reg, lhs, label);
3249 break;
3250 case kCondB:
3251 __ Bltu(lhs, rhs_reg, label);
3252 break;
3253 case kCondAE:
3254 __ Bgeu(lhs, rhs_reg, label);
3255 break;
3256 case kCondBE:
3257 __ Bgeu(rhs_reg, lhs, label);
3258 break;
3259 case kCondA:
3260 __ Bltu(rhs_reg, lhs, label);
3261 break;
3262 }
3263 } else {
3264 // Special cases for more efficient comparison with constants on R2.
3265 switch (cond) {
3266 case kCondEQ:
3267 __ LoadConst32(TMP, rhs_imm);
3268 __ Beq(lhs, TMP, label);
3269 break;
3270 case kCondNE:
3271 __ LoadConst32(TMP, rhs_imm);
3272 __ Bne(lhs, TMP, label);
3273 break;
3274 case kCondLT:
3275 if (IsInt<16>(rhs_imm)) {
3276 __ Slti(TMP, lhs, rhs_imm);
3277 __ Bnez(TMP, label);
3278 } else {
3279 __ LoadConst32(TMP, rhs_imm);
3280 __ Blt(lhs, TMP, label);
3281 }
3282 break;
3283 case kCondGE:
3284 if (IsInt<16>(rhs_imm)) {
3285 __ Slti(TMP, lhs, rhs_imm);
3286 __ Beqz(TMP, label);
3287 } else {
3288 __ LoadConst32(TMP, rhs_imm);
3289 __ Bge(lhs, TMP, label);
3290 }
3291 break;
3292 case kCondLE:
3293 if (IsInt<16>(rhs_imm + 1)) {
3294 // Simulate lhs <= rhs via lhs < rhs + 1.
3295 __ Slti(TMP, lhs, rhs_imm + 1);
3296 __ Bnez(TMP, label);
3297 } else {
3298 __ LoadConst32(TMP, rhs_imm);
3299 __ Bge(TMP, lhs, label);
3300 }
3301 break;
3302 case kCondGT:
3303 if (IsInt<16>(rhs_imm + 1)) {
3304 // Simulate lhs > rhs via !(lhs < rhs + 1).
3305 __ Slti(TMP, lhs, rhs_imm + 1);
3306 __ Beqz(TMP, label);
3307 } else {
3308 __ LoadConst32(TMP, rhs_imm);
3309 __ Blt(TMP, lhs, label);
3310 }
3311 break;
3312 case kCondB:
3313 if (IsInt<16>(rhs_imm)) {
3314 __ Sltiu(TMP, lhs, rhs_imm);
3315 __ Bnez(TMP, label);
3316 } else {
3317 __ LoadConst32(TMP, rhs_imm);
3318 __ Bltu(lhs, TMP, label);
3319 }
3320 break;
3321 case kCondAE:
3322 if (IsInt<16>(rhs_imm)) {
3323 __ Sltiu(TMP, lhs, rhs_imm);
3324 __ Beqz(TMP, label);
3325 } else {
3326 __ LoadConst32(TMP, rhs_imm);
3327 __ Bgeu(lhs, TMP, label);
3328 }
3329 break;
3330 case kCondBE:
3331 if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
3332 // Simulate lhs <= rhs via lhs < rhs + 1.
3333 // Note that this only works if rhs + 1 does not overflow
3334 // to 0, hence the check above.
3335 __ Sltiu(TMP, lhs, rhs_imm + 1);
3336 __ Bnez(TMP, label);
3337 } else {
3338 __ LoadConst32(TMP, rhs_imm);
3339 __ Bgeu(TMP, lhs, label);
3340 }
3341 break;
3342 case kCondA:
3343 if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
3344 // Simulate lhs > rhs via !(lhs < rhs + 1).
3345 // Note that this only works if rhs + 1 does not overflow
3346 // to 0, hence the check above.
3347 __ Sltiu(TMP, lhs, rhs_imm + 1);
3348 __ Beqz(TMP, label);
3349 } else {
3350 __ LoadConst32(TMP, rhs_imm);
3351 __ Bltu(TMP, lhs, label);
3352 }
3353 break;
3354 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003355 }
3356 }
3357}
3358
3359void InstructionCodeGeneratorMIPS::GenerateLongCompareAndBranch(IfCondition cond,
3360 LocationSummary* locations,
3361 MipsLabel* label) {
3362 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
3363 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
3364 Location rhs_location = locations->InAt(1);
3365 Register rhs_high = ZERO;
3366 Register rhs_low = ZERO;
3367 int64_t imm = 0;
3368 uint32_t imm_high = 0;
3369 uint32_t imm_low = 0;
3370 bool use_imm = rhs_location.IsConstant();
3371 if (use_imm) {
3372 imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
3373 imm_high = High32Bits(imm);
3374 imm_low = Low32Bits(imm);
3375 } else {
3376 rhs_high = rhs_location.AsRegisterPairHigh<Register>();
3377 rhs_low = rhs_location.AsRegisterPairLow<Register>();
3378 }
3379
3380 if (use_imm && imm == 0) {
3381 switch (cond) {
3382 case kCondEQ:
3383 case kCondBE: // <= 0 if zero
3384 __ Or(TMP, lhs_high, lhs_low);
3385 __ Beqz(TMP, label);
3386 break;
3387 case kCondNE:
3388 case kCondA: // > 0 if non-zero
3389 __ Or(TMP, lhs_high, lhs_low);
3390 __ Bnez(TMP, label);
3391 break;
3392 case kCondLT:
3393 __ Bltz(lhs_high, label);
3394 break;
3395 case kCondGE:
3396 __ Bgez(lhs_high, label);
3397 break;
3398 case kCondLE:
3399 __ Or(TMP, lhs_high, lhs_low);
3400 __ Sra(AT, lhs_high, 31);
3401 __ Bgeu(AT, TMP, label);
3402 break;
3403 case kCondGT:
3404 __ Or(TMP, lhs_high, lhs_low);
3405 __ Sra(AT, lhs_high, 31);
3406 __ Bltu(AT, TMP, label);
3407 break;
3408 case kCondB: // always false
3409 break;
3410 case kCondAE: // always true
3411 __ B(label);
3412 break;
3413 }
3414 } else if (use_imm) {
3415 // TODO: more efficient comparison with constants without loading them into TMP/AT.
3416 switch (cond) {
3417 case kCondEQ:
3418 __ LoadConst32(TMP, imm_high);
3419 __ Xor(TMP, TMP, lhs_high);
3420 __ LoadConst32(AT, imm_low);
3421 __ Xor(AT, AT, lhs_low);
3422 __ Or(TMP, TMP, AT);
3423 __ Beqz(TMP, label);
3424 break;
3425 case kCondNE:
3426 __ LoadConst32(TMP, imm_high);
3427 __ Xor(TMP, TMP, lhs_high);
3428 __ LoadConst32(AT, imm_low);
3429 __ Xor(AT, AT, lhs_low);
3430 __ Or(TMP, TMP, AT);
3431 __ Bnez(TMP, label);
3432 break;
3433 case kCondLT:
3434 __ LoadConst32(TMP, imm_high);
3435 __ Blt(lhs_high, TMP, label);
3436 __ Slt(TMP, TMP, lhs_high);
3437 __ LoadConst32(AT, imm_low);
3438 __ Sltu(AT, lhs_low, AT);
3439 __ Blt(TMP, AT, label);
3440 break;
3441 case kCondGE:
3442 __ LoadConst32(TMP, imm_high);
3443 __ Blt(TMP, lhs_high, label);
3444 __ Slt(TMP, lhs_high, TMP);
3445 __ LoadConst32(AT, imm_low);
3446 __ Sltu(AT, lhs_low, AT);
3447 __ Or(TMP, TMP, AT);
3448 __ Beqz(TMP, label);
3449 break;
3450 case kCondLE:
3451 __ LoadConst32(TMP, imm_high);
3452 __ Blt(lhs_high, TMP, label);
3453 __ Slt(TMP, TMP, lhs_high);
3454 __ LoadConst32(AT, imm_low);
3455 __ Sltu(AT, AT, lhs_low);
3456 __ Or(TMP, TMP, AT);
3457 __ Beqz(TMP, label);
3458 break;
3459 case kCondGT:
3460 __ LoadConst32(TMP, imm_high);
3461 __ Blt(TMP, lhs_high, label);
3462 __ Slt(TMP, lhs_high, TMP);
3463 __ LoadConst32(AT, imm_low);
3464 __ Sltu(AT, AT, lhs_low);
3465 __ Blt(TMP, AT, label);
3466 break;
3467 case kCondB:
3468 __ LoadConst32(TMP, imm_high);
3469 __ Bltu(lhs_high, TMP, label);
3470 __ Sltu(TMP, TMP, lhs_high);
3471 __ LoadConst32(AT, imm_low);
3472 __ Sltu(AT, lhs_low, AT);
3473 __ Blt(TMP, AT, label);
3474 break;
3475 case kCondAE:
3476 __ LoadConst32(TMP, imm_high);
3477 __ Bltu(TMP, lhs_high, label);
3478 __ Sltu(TMP, lhs_high, TMP);
3479 __ LoadConst32(AT, imm_low);
3480 __ Sltu(AT, lhs_low, AT);
3481 __ Or(TMP, TMP, AT);
3482 __ Beqz(TMP, label);
3483 break;
3484 case kCondBE:
3485 __ LoadConst32(TMP, imm_high);
3486 __ Bltu(lhs_high, TMP, label);
3487 __ Sltu(TMP, TMP, lhs_high);
3488 __ LoadConst32(AT, imm_low);
3489 __ Sltu(AT, AT, lhs_low);
3490 __ Or(TMP, TMP, AT);
3491 __ Beqz(TMP, label);
3492 break;
3493 case kCondA:
3494 __ LoadConst32(TMP, imm_high);
3495 __ Bltu(TMP, lhs_high, label);
3496 __ Sltu(TMP, lhs_high, TMP);
3497 __ LoadConst32(AT, imm_low);
3498 __ Sltu(AT, AT, lhs_low);
3499 __ Blt(TMP, AT, label);
3500 break;
3501 }
3502 } else {
3503 switch (cond) {
3504 case kCondEQ:
3505 __ Xor(TMP, lhs_high, rhs_high);
3506 __ Xor(AT, lhs_low, rhs_low);
3507 __ Or(TMP, TMP, AT);
3508 __ Beqz(TMP, label);
3509 break;
3510 case kCondNE:
3511 __ Xor(TMP, lhs_high, rhs_high);
3512 __ Xor(AT, lhs_low, rhs_low);
3513 __ Or(TMP, TMP, AT);
3514 __ Bnez(TMP, label);
3515 break;
3516 case kCondLT:
3517 __ Blt(lhs_high, rhs_high, label);
3518 __ Slt(TMP, rhs_high, lhs_high);
3519 __ Sltu(AT, lhs_low, rhs_low);
3520 __ Blt(TMP, AT, label);
3521 break;
3522 case kCondGE:
3523 __ Blt(rhs_high, lhs_high, label);
3524 __ Slt(TMP, lhs_high, rhs_high);
3525 __ Sltu(AT, lhs_low, rhs_low);
3526 __ Or(TMP, TMP, AT);
3527 __ Beqz(TMP, label);
3528 break;
3529 case kCondLE:
3530 __ Blt(lhs_high, rhs_high, label);
3531 __ Slt(TMP, rhs_high, lhs_high);
3532 __ Sltu(AT, rhs_low, lhs_low);
3533 __ Or(TMP, TMP, AT);
3534 __ Beqz(TMP, label);
3535 break;
3536 case kCondGT:
3537 __ Blt(rhs_high, lhs_high, label);
3538 __ Slt(TMP, lhs_high, rhs_high);
3539 __ Sltu(AT, rhs_low, lhs_low);
3540 __ Blt(TMP, AT, label);
3541 break;
3542 case kCondB:
3543 __ Bltu(lhs_high, rhs_high, label);
3544 __ Sltu(TMP, rhs_high, lhs_high);
3545 __ Sltu(AT, lhs_low, rhs_low);
3546 __ Blt(TMP, AT, label);
3547 break;
3548 case kCondAE:
3549 __ Bltu(rhs_high, lhs_high, label);
3550 __ Sltu(TMP, lhs_high, rhs_high);
3551 __ Sltu(AT, lhs_low, rhs_low);
3552 __ Or(TMP, TMP, AT);
3553 __ Beqz(TMP, label);
3554 break;
3555 case kCondBE:
3556 __ Bltu(lhs_high, rhs_high, label);
3557 __ Sltu(TMP, rhs_high, lhs_high);
3558 __ Sltu(AT, rhs_low, lhs_low);
3559 __ Or(TMP, TMP, AT);
3560 __ Beqz(TMP, label);
3561 break;
3562 case kCondA:
3563 __ Bltu(rhs_high, lhs_high, label);
3564 __ Sltu(TMP, lhs_high, rhs_high);
3565 __ Sltu(AT, rhs_low, lhs_low);
3566 __ Blt(TMP, AT, label);
3567 break;
3568 }
3569 }
3570}
3571
Alexey Frunze2ddb7172016-09-06 17:04:55 -07003572void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
3573 bool gt_bias,
3574 Primitive::Type type,
3575 LocationSummary* locations) {
3576 Register dst = locations->Out().AsRegister<Register>();
3577 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3578 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3579 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3580 if (type == Primitive::kPrimFloat) {
3581 if (isR6) {
3582 switch (cond) {
3583 case kCondEQ:
3584 __ CmpEqS(FTMP, lhs, rhs);
3585 __ Mfc1(dst, FTMP);
3586 __ Andi(dst, dst, 1);
3587 break;
3588 case kCondNE:
3589 __ CmpEqS(FTMP, lhs, rhs);
3590 __ Mfc1(dst, FTMP);
3591 __ Addiu(dst, dst, 1);
3592 break;
3593 case kCondLT:
3594 if (gt_bias) {
3595 __ CmpLtS(FTMP, lhs, rhs);
3596 } else {
3597 __ CmpUltS(FTMP, lhs, rhs);
3598 }
3599 __ Mfc1(dst, FTMP);
3600 __ Andi(dst, dst, 1);
3601 break;
3602 case kCondLE:
3603 if (gt_bias) {
3604 __ CmpLeS(FTMP, lhs, rhs);
3605 } else {
3606 __ CmpUleS(FTMP, lhs, rhs);
3607 }
3608 __ Mfc1(dst, FTMP);
3609 __ Andi(dst, dst, 1);
3610 break;
3611 case kCondGT:
3612 if (gt_bias) {
3613 __ CmpUltS(FTMP, rhs, lhs);
3614 } else {
3615 __ CmpLtS(FTMP, rhs, lhs);
3616 }
3617 __ Mfc1(dst, FTMP);
3618 __ Andi(dst, dst, 1);
3619 break;
3620 case kCondGE:
3621 if (gt_bias) {
3622 __ CmpUleS(FTMP, rhs, lhs);
3623 } else {
3624 __ CmpLeS(FTMP, rhs, lhs);
3625 }
3626 __ Mfc1(dst, FTMP);
3627 __ Andi(dst, dst, 1);
3628 break;
3629 default:
3630 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3631 UNREACHABLE();
3632 }
3633 } else {
3634 switch (cond) {
3635 case kCondEQ:
3636 __ CeqS(0, lhs, rhs);
3637 __ LoadConst32(dst, 1);
3638 __ Movf(dst, ZERO, 0);
3639 break;
3640 case kCondNE:
3641 __ CeqS(0, lhs, rhs);
3642 __ LoadConst32(dst, 1);
3643 __ Movt(dst, ZERO, 0);
3644 break;
3645 case kCondLT:
3646 if (gt_bias) {
3647 __ ColtS(0, lhs, rhs);
3648 } else {
3649 __ CultS(0, lhs, rhs);
3650 }
3651 __ LoadConst32(dst, 1);
3652 __ Movf(dst, ZERO, 0);
3653 break;
3654 case kCondLE:
3655 if (gt_bias) {
3656 __ ColeS(0, lhs, rhs);
3657 } else {
3658 __ CuleS(0, lhs, rhs);
3659 }
3660 __ LoadConst32(dst, 1);
3661 __ Movf(dst, ZERO, 0);
3662 break;
3663 case kCondGT:
3664 if (gt_bias) {
3665 __ CultS(0, rhs, lhs);
3666 } else {
3667 __ ColtS(0, rhs, lhs);
3668 }
3669 __ LoadConst32(dst, 1);
3670 __ Movf(dst, ZERO, 0);
3671 break;
3672 case kCondGE:
3673 if (gt_bias) {
3674 __ CuleS(0, rhs, lhs);
3675 } else {
3676 __ ColeS(0, rhs, lhs);
3677 }
3678 __ LoadConst32(dst, 1);
3679 __ Movf(dst, ZERO, 0);
3680 break;
3681 default:
3682 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3683 UNREACHABLE();
3684 }
3685 }
3686 } else {
3687 DCHECK_EQ(type, Primitive::kPrimDouble);
3688 if (isR6) {
3689 switch (cond) {
3690 case kCondEQ:
3691 __ CmpEqD(FTMP, lhs, rhs);
3692 __ Mfc1(dst, FTMP);
3693 __ Andi(dst, dst, 1);
3694 break;
3695 case kCondNE:
3696 __ CmpEqD(FTMP, lhs, rhs);
3697 __ Mfc1(dst, FTMP);
3698 __ Addiu(dst, dst, 1);
3699 break;
3700 case kCondLT:
3701 if (gt_bias) {
3702 __ CmpLtD(FTMP, lhs, rhs);
3703 } else {
3704 __ CmpUltD(FTMP, lhs, rhs);
3705 }
3706 __ Mfc1(dst, FTMP);
3707 __ Andi(dst, dst, 1);
3708 break;
3709 case kCondLE:
3710 if (gt_bias) {
3711 __ CmpLeD(FTMP, lhs, rhs);
3712 } else {
3713 __ CmpUleD(FTMP, lhs, rhs);
3714 }
3715 __ Mfc1(dst, FTMP);
3716 __ Andi(dst, dst, 1);
3717 break;
3718 case kCondGT:
3719 if (gt_bias) {
3720 __ CmpUltD(FTMP, rhs, lhs);
3721 } else {
3722 __ CmpLtD(FTMP, rhs, lhs);
3723 }
3724 __ Mfc1(dst, FTMP);
3725 __ Andi(dst, dst, 1);
3726 break;
3727 case kCondGE:
3728 if (gt_bias) {
3729 __ CmpUleD(FTMP, rhs, lhs);
3730 } else {
3731 __ CmpLeD(FTMP, rhs, lhs);
3732 }
3733 __ Mfc1(dst, FTMP);
3734 __ Andi(dst, dst, 1);
3735 break;
3736 default:
3737 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3738 UNREACHABLE();
3739 }
3740 } else {
3741 switch (cond) {
3742 case kCondEQ:
3743 __ CeqD(0, lhs, rhs);
3744 __ LoadConst32(dst, 1);
3745 __ Movf(dst, ZERO, 0);
3746 break;
3747 case kCondNE:
3748 __ CeqD(0, lhs, rhs);
3749 __ LoadConst32(dst, 1);
3750 __ Movt(dst, ZERO, 0);
3751 break;
3752 case kCondLT:
3753 if (gt_bias) {
3754 __ ColtD(0, lhs, rhs);
3755 } else {
3756 __ CultD(0, lhs, rhs);
3757 }
3758 __ LoadConst32(dst, 1);
3759 __ Movf(dst, ZERO, 0);
3760 break;
3761 case kCondLE:
3762 if (gt_bias) {
3763 __ ColeD(0, lhs, rhs);
3764 } else {
3765 __ CuleD(0, lhs, rhs);
3766 }
3767 __ LoadConst32(dst, 1);
3768 __ Movf(dst, ZERO, 0);
3769 break;
3770 case kCondGT:
3771 if (gt_bias) {
3772 __ CultD(0, rhs, lhs);
3773 } else {
3774 __ ColtD(0, rhs, lhs);
3775 }
3776 __ LoadConst32(dst, 1);
3777 __ Movf(dst, ZERO, 0);
3778 break;
3779 case kCondGE:
3780 if (gt_bias) {
3781 __ CuleD(0, rhs, lhs);
3782 } else {
3783 __ ColeD(0, rhs, lhs);
3784 }
3785 __ LoadConst32(dst, 1);
3786 __ Movf(dst, ZERO, 0);
3787 break;
3788 default:
3789 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
3790 UNREACHABLE();
3791 }
3792 }
3793 }
3794}
3795
Alexey Frunze674b9ee2016-09-20 14:54:15 -07003796bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR2(IfCondition cond,
3797 bool gt_bias,
3798 Primitive::Type type,
3799 LocationSummary* input_locations,
3800 int cc) {
3801 FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
3802 FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
3803 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
3804 if (type == Primitive::kPrimFloat) {
3805 switch (cond) {
3806 case kCondEQ:
3807 __ CeqS(cc, lhs, rhs);
3808 return false;
3809 case kCondNE:
3810 __ CeqS(cc, lhs, rhs);
3811 return true;
3812 case kCondLT:
3813 if (gt_bias) {
3814 __ ColtS(cc, lhs, rhs);
3815 } else {
3816 __ CultS(cc, lhs, rhs);
3817 }
3818 return false;
3819 case kCondLE:
3820 if (gt_bias) {
3821 __ ColeS(cc, lhs, rhs);
3822 } else {
3823 __ CuleS(cc, lhs, rhs);
3824 }
3825 return false;
3826 case kCondGT:
3827 if (gt_bias) {
3828 __ CultS(cc, rhs, lhs);
3829 } else {
3830 __ ColtS(cc, rhs, lhs);
3831 }
3832 return false;
3833 case kCondGE:
3834 if (gt_bias) {
3835 __ CuleS(cc, rhs, lhs);
3836 } else {
3837 __ ColeS(cc, rhs, lhs);
3838 }
3839 return false;
3840 default:
3841 LOG(FATAL) << "Unexpected non-floating-point condition";
3842 UNREACHABLE();
3843 }
3844 } else {
3845 DCHECK_EQ(type, Primitive::kPrimDouble);
3846 switch (cond) {
3847 case kCondEQ:
3848 __ CeqD(cc, lhs, rhs);
3849 return false;
3850 case kCondNE:
3851 __ CeqD(cc, lhs, rhs);
3852 return true;
3853 case kCondLT:
3854 if (gt_bias) {
3855 __ ColtD(cc, lhs, rhs);
3856 } else {
3857 __ CultD(cc, lhs, rhs);
3858 }
3859 return false;
3860 case kCondLE:
3861 if (gt_bias) {
3862 __ ColeD(cc, lhs, rhs);
3863 } else {
3864 __ CuleD(cc, lhs, rhs);
3865 }
3866 return false;
3867 case kCondGT:
3868 if (gt_bias) {
3869 __ CultD(cc, rhs, lhs);
3870 } else {
3871 __ ColtD(cc, rhs, lhs);
3872 }
3873 return false;
3874 case kCondGE:
3875 if (gt_bias) {
3876 __ CuleD(cc, rhs, lhs);
3877 } else {
3878 __ ColeD(cc, rhs, lhs);
3879 }
3880 return false;
3881 default:
3882 LOG(FATAL) << "Unexpected non-floating-point condition";
3883 UNREACHABLE();
3884 }
3885 }
3886}
3887
3888bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR6(IfCondition cond,
3889 bool gt_bias,
3890 Primitive::Type type,
3891 LocationSummary* input_locations,
3892 FRegister dst) {
3893 FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
3894 FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
3895 CHECK(codegen_->GetInstructionSetFeatures().IsR6());
3896 if (type == Primitive::kPrimFloat) {
3897 switch (cond) {
3898 case kCondEQ:
3899 __ CmpEqS(dst, lhs, rhs);
3900 return false;
3901 case kCondNE:
3902 __ CmpEqS(dst, lhs, rhs);
3903 return true;
3904 case kCondLT:
3905 if (gt_bias) {
3906 __ CmpLtS(dst, lhs, rhs);
3907 } else {
3908 __ CmpUltS(dst, lhs, rhs);
3909 }
3910 return false;
3911 case kCondLE:
3912 if (gt_bias) {
3913 __ CmpLeS(dst, lhs, rhs);
3914 } else {
3915 __ CmpUleS(dst, lhs, rhs);
3916 }
3917 return false;
3918 case kCondGT:
3919 if (gt_bias) {
3920 __ CmpUltS(dst, rhs, lhs);
3921 } else {
3922 __ CmpLtS(dst, rhs, lhs);
3923 }
3924 return false;
3925 case kCondGE:
3926 if (gt_bias) {
3927 __ CmpUleS(dst, rhs, lhs);
3928 } else {
3929 __ CmpLeS(dst, rhs, lhs);
3930 }
3931 return false;
3932 default:
3933 LOG(FATAL) << "Unexpected non-floating-point condition";
3934 UNREACHABLE();
3935 }
3936 } else {
3937 DCHECK_EQ(type, Primitive::kPrimDouble);
3938 switch (cond) {
3939 case kCondEQ:
3940 __ CmpEqD(dst, lhs, rhs);
3941 return false;
3942 case kCondNE:
3943 __ CmpEqD(dst, lhs, rhs);
3944 return true;
3945 case kCondLT:
3946 if (gt_bias) {
3947 __ CmpLtD(dst, lhs, rhs);
3948 } else {
3949 __ CmpUltD(dst, lhs, rhs);
3950 }
3951 return false;
3952 case kCondLE:
3953 if (gt_bias) {
3954 __ CmpLeD(dst, lhs, rhs);
3955 } else {
3956 __ CmpUleD(dst, lhs, rhs);
3957 }
3958 return false;
3959 case kCondGT:
3960 if (gt_bias) {
3961 __ CmpUltD(dst, rhs, lhs);
3962 } else {
3963 __ CmpLtD(dst, rhs, lhs);
3964 }
3965 return false;
3966 case kCondGE:
3967 if (gt_bias) {
3968 __ CmpUleD(dst, rhs, lhs);
3969 } else {
3970 __ CmpLeD(dst, rhs, lhs);
3971 }
3972 return false;
3973 default:
3974 LOG(FATAL) << "Unexpected non-floating-point condition";
3975 UNREACHABLE();
3976 }
3977 }
3978}
3979
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003980void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
3981 bool gt_bias,
3982 Primitive::Type type,
3983 LocationSummary* locations,
3984 MipsLabel* label) {
3985 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3986 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3987 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3988 if (type == Primitive::kPrimFloat) {
3989 if (isR6) {
3990 switch (cond) {
3991 case kCondEQ:
3992 __ CmpEqS(FTMP, lhs, rhs);
3993 __ Bc1nez(FTMP, label);
3994 break;
3995 case kCondNE:
3996 __ CmpEqS(FTMP, lhs, rhs);
3997 __ Bc1eqz(FTMP, label);
3998 break;
3999 case kCondLT:
4000 if (gt_bias) {
4001 __ CmpLtS(FTMP, lhs, rhs);
4002 } else {
4003 __ CmpUltS(FTMP, lhs, rhs);
4004 }
4005 __ Bc1nez(FTMP, label);
4006 break;
4007 case kCondLE:
4008 if (gt_bias) {
4009 __ CmpLeS(FTMP, lhs, rhs);
4010 } else {
4011 __ CmpUleS(FTMP, lhs, rhs);
4012 }
4013 __ Bc1nez(FTMP, label);
4014 break;
4015 case kCondGT:
4016 if (gt_bias) {
4017 __ CmpUltS(FTMP, rhs, lhs);
4018 } else {
4019 __ CmpLtS(FTMP, rhs, lhs);
4020 }
4021 __ Bc1nez(FTMP, label);
4022 break;
4023 case kCondGE:
4024 if (gt_bias) {
4025 __ CmpUleS(FTMP, rhs, lhs);
4026 } else {
4027 __ CmpLeS(FTMP, rhs, lhs);
4028 }
4029 __ Bc1nez(FTMP, label);
4030 break;
4031 default:
4032 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004033 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004034 }
4035 } else {
4036 switch (cond) {
4037 case kCondEQ:
4038 __ CeqS(0, lhs, rhs);
4039 __ Bc1t(0, label);
4040 break;
4041 case kCondNE:
4042 __ CeqS(0, lhs, rhs);
4043 __ Bc1f(0, label);
4044 break;
4045 case kCondLT:
4046 if (gt_bias) {
4047 __ ColtS(0, lhs, rhs);
4048 } else {
4049 __ CultS(0, lhs, rhs);
4050 }
4051 __ Bc1t(0, label);
4052 break;
4053 case kCondLE:
4054 if (gt_bias) {
4055 __ ColeS(0, lhs, rhs);
4056 } else {
4057 __ CuleS(0, lhs, rhs);
4058 }
4059 __ Bc1t(0, label);
4060 break;
4061 case kCondGT:
4062 if (gt_bias) {
4063 __ CultS(0, rhs, lhs);
4064 } else {
4065 __ ColtS(0, rhs, lhs);
4066 }
4067 __ Bc1t(0, label);
4068 break;
4069 case kCondGE:
4070 if (gt_bias) {
4071 __ CuleS(0, rhs, lhs);
4072 } else {
4073 __ ColeS(0, rhs, lhs);
4074 }
4075 __ Bc1t(0, label);
4076 break;
4077 default:
4078 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004079 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004080 }
4081 }
4082 } else {
4083 DCHECK_EQ(type, Primitive::kPrimDouble);
4084 if (isR6) {
4085 switch (cond) {
4086 case kCondEQ:
4087 __ CmpEqD(FTMP, lhs, rhs);
4088 __ Bc1nez(FTMP, label);
4089 break;
4090 case kCondNE:
4091 __ CmpEqD(FTMP, lhs, rhs);
4092 __ Bc1eqz(FTMP, label);
4093 break;
4094 case kCondLT:
4095 if (gt_bias) {
4096 __ CmpLtD(FTMP, lhs, rhs);
4097 } else {
4098 __ CmpUltD(FTMP, lhs, rhs);
4099 }
4100 __ Bc1nez(FTMP, label);
4101 break;
4102 case kCondLE:
4103 if (gt_bias) {
4104 __ CmpLeD(FTMP, lhs, rhs);
4105 } else {
4106 __ CmpUleD(FTMP, lhs, rhs);
4107 }
4108 __ Bc1nez(FTMP, label);
4109 break;
4110 case kCondGT:
4111 if (gt_bias) {
4112 __ CmpUltD(FTMP, rhs, lhs);
4113 } else {
4114 __ CmpLtD(FTMP, rhs, lhs);
4115 }
4116 __ Bc1nez(FTMP, label);
4117 break;
4118 case kCondGE:
4119 if (gt_bias) {
4120 __ CmpUleD(FTMP, rhs, lhs);
4121 } else {
4122 __ CmpLeD(FTMP, rhs, lhs);
4123 }
4124 __ Bc1nez(FTMP, label);
4125 break;
4126 default:
4127 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004128 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004129 }
4130 } else {
4131 switch (cond) {
4132 case kCondEQ:
4133 __ CeqD(0, lhs, rhs);
4134 __ Bc1t(0, label);
4135 break;
4136 case kCondNE:
4137 __ CeqD(0, lhs, rhs);
4138 __ Bc1f(0, label);
4139 break;
4140 case kCondLT:
4141 if (gt_bias) {
4142 __ ColtD(0, lhs, rhs);
4143 } else {
4144 __ CultD(0, lhs, rhs);
4145 }
4146 __ Bc1t(0, label);
4147 break;
4148 case kCondLE:
4149 if (gt_bias) {
4150 __ ColeD(0, lhs, rhs);
4151 } else {
4152 __ CuleD(0, lhs, rhs);
4153 }
4154 __ Bc1t(0, label);
4155 break;
4156 case kCondGT:
4157 if (gt_bias) {
4158 __ CultD(0, rhs, lhs);
4159 } else {
4160 __ ColtD(0, rhs, lhs);
4161 }
4162 __ Bc1t(0, label);
4163 break;
4164 case kCondGE:
4165 if (gt_bias) {
4166 __ CuleD(0, rhs, lhs);
4167 } else {
4168 __ ColeD(0, rhs, lhs);
4169 }
4170 __ Bc1t(0, label);
4171 break;
4172 default:
4173 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004174 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004175 }
4176 }
4177 }
4178}
4179
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004180void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00004181 size_t condition_input_index,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004182 MipsLabel* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00004183 MipsLabel* false_target) {
4184 HInstruction* cond = instruction->InputAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004185
David Brazdil0debae72015-11-12 18:37:00 +00004186 if (true_target == nullptr && false_target == nullptr) {
4187 // Nothing to do. The code always falls through.
4188 return;
4189 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00004190 // Constant condition, statically compared against "true" (integer value 1).
4191 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00004192 if (true_target != nullptr) {
4193 __ B(true_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004194 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004195 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00004196 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00004197 if (false_target != nullptr) {
4198 __ B(false_target);
4199 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004200 }
David Brazdil0debae72015-11-12 18:37:00 +00004201 return;
4202 }
4203
4204 // The following code generates these patterns:
4205 // (1) true_target == nullptr && false_target != nullptr
4206 // - opposite condition true => branch to false_target
4207 // (2) true_target != nullptr && false_target == nullptr
4208 // - condition true => branch to true_target
4209 // (3) true_target != nullptr && false_target != nullptr
4210 // - condition true => branch to true_target
4211 // - branch to false_target
4212 if (IsBooleanValueOrMaterializedCondition(cond)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004213 // The condition instruction has been materialized, compare the output to 0.
David Brazdil0debae72015-11-12 18:37:00 +00004214 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004215 DCHECK(cond_val.IsRegister());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004216 if (true_target == nullptr) {
David Brazdil0debae72015-11-12 18:37:00 +00004217 __ Beqz(cond_val.AsRegister<Register>(), false_target);
4218 } else {
4219 __ Bnez(cond_val.AsRegister<Register>(), true_target);
4220 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004221 } else {
4222 // The condition instruction has not been materialized, use its inputs as
4223 // the comparison and its condition as the branch condition.
David Brazdil0debae72015-11-12 18:37:00 +00004224 HCondition* condition = cond->AsCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004225 Primitive::Type type = condition->InputAt(0)->GetType();
4226 LocationSummary* locations = cond->GetLocations();
4227 IfCondition if_cond = condition->GetCondition();
4228 MipsLabel* branch_target = true_target;
David Brazdil0debae72015-11-12 18:37:00 +00004229
David Brazdil0debae72015-11-12 18:37:00 +00004230 if (true_target == nullptr) {
4231 if_cond = condition->GetOppositeCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004232 branch_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00004233 }
4234
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004235 switch (type) {
4236 default:
4237 GenerateIntCompareAndBranch(if_cond, locations, branch_target);
4238 break;
4239 case Primitive::kPrimLong:
4240 GenerateLongCompareAndBranch(if_cond, locations, branch_target);
4241 break;
4242 case Primitive::kPrimFloat:
4243 case Primitive::kPrimDouble:
4244 GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
4245 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004246 }
4247 }
David Brazdil0debae72015-11-12 18:37:00 +00004248
4249 // If neither branch falls through (case 3), the conditional branch to `true_target`
4250 // was already emitted (case 2) and we need to emit a jump to `false_target`.
4251 if (true_target != nullptr && false_target != nullptr) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004252 __ B(false_target);
4253 }
4254}
4255
4256void LocationsBuilderMIPS::VisitIf(HIf* if_instr) {
4257 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
David Brazdil0debae72015-11-12 18:37:00 +00004258 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004259 locations->SetInAt(0, Location::RequiresRegister());
4260 }
4261}
4262
4263void InstructionCodeGeneratorMIPS::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00004264 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
4265 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
4266 MipsLabel* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
4267 nullptr : codegen_->GetLabelOf(true_successor);
4268 MipsLabel* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
4269 nullptr : codegen_->GetLabelOf(false_successor);
4270 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004271}
4272
4273void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
4274 LocationSummary* locations = new (GetGraph()->GetArena())
4275 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01004276 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
David Brazdil0debae72015-11-12 18:37:00 +00004277 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004278 locations->SetInAt(0, Location::RequiresRegister());
4279 }
4280}
4281
4282void InstructionCodeGeneratorMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08004283 SlowPathCodeMIPS* slow_path =
4284 deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathMIPS>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00004285 GenerateTestAndBranch(deoptimize,
4286 /* condition_input_index */ 0,
4287 slow_path->GetEntryLabel(),
4288 /* false_target */ nullptr);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004289}
4290
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004291// This function returns true if a conditional move can be generated for HSelect.
4292// Otherwise it returns false and HSelect must be implemented in terms of conditonal
4293// branches and regular moves.
4294//
4295// If `locations_to_set` isn't nullptr, its inputs and outputs are set for HSelect.
4296//
4297// While determining feasibility of a conditional move and setting inputs/outputs
4298// are two distinct tasks, this function does both because they share quite a bit
4299// of common logic.
4300static bool CanMoveConditionally(HSelect* select, bool is_r6, LocationSummary* locations_to_set) {
4301 bool materialized = IsBooleanValueOrMaterializedCondition(select->GetCondition());
4302 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
4303 HCondition* condition = cond->AsCondition();
4304
4305 Primitive::Type cond_type = materialized ? Primitive::kPrimInt : condition->InputAt(0)->GetType();
4306 Primitive::Type dst_type = select->GetType();
4307
4308 HConstant* cst_true_value = select->GetTrueValue()->AsConstant();
4309 HConstant* cst_false_value = select->GetFalseValue()->AsConstant();
4310 bool is_true_value_zero_constant =
4311 (cst_true_value != nullptr && cst_true_value->IsZeroBitPattern());
4312 bool is_false_value_zero_constant =
4313 (cst_false_value != nullptr && cst_false_value->IsZeroBitPattern());
4314
4315 bool can_move_conditionally = false;
4316 bool use_const_for_false_in = false;
4317 bool use_const_for_true_in = false;
4318
4319 if (!cond->IsConstant()) {
4320 switch (cond_type) {
4321 default:
4322 switch (dst_type) {
4323 default:
4324 // Moving int on int condition.
4325 if (is_r6) {
4326 if (is_true_value_zero_constant) {
4327 // seleqz out_reg, false_reg, cond_reg
4328 can_move_conditionally = true;
4329 use_const_for_true_in = true;
4330 } else if (is_false_value_zero_constant) {
4331 // selnez out_reg, true_reg, cond_reg
4332 can_move_conditionally = true;
4333 use_const_for_false_in = true;
4334 } else if (materialized) {
4335 // Not materializing unmaterialized int conditions
4336 // to keep the instruction count low.
4337 // selnez AT, true_reg, cond_reg
4338 // seleqz TMP, false_reg, cond_reg
4339 // or out_reg, AT, TMP
4340 can_move_conditionally = true;
4341 }
4342 } else {
4343 // movn out_reg, true_reg/ZERO, cond_reg
4344 can_move_conditionally = true;
4345 use_const_for_true_in = is_true_value_zero_constant;
4346 }
4347 break;
4348 case Primitive::kPrimLong:
4349 // Moving long on int condition.
4350 if (is_r6) {
4351 if (is_true_value_zero_constant) {
4352 // seleqz out_reg_lo, false_reg_lo, cond_reg
4353 // seleqz out_reg_hi, false_reg_hi, cond_reg
4354 can_move_conditionally = true;
4355 use_const_for_true_in = true;
4356 } else if (is_false_value_zero_constant) {
4357 // selnez out_reg_lo, true_reg_lo, cond_reg
4358 // selnez out_reg_hi, true_reg_hi, cond_reg
4359 can_move_conditionally = true;
4360 use_const_for_false_in = true;
4361 }
4362 // Other long conditional moves would generate 6+ instructions,
4363 // which is too many.
4364 } else {
4365 // movn out_reg_lo, true_reg_lo/ZERO, cond_reg
4366 // movn out_reg_hi, true_reg_hi/ZERO, cond_reg
4367 can_move_conditionally = true;
4368 use_const_for_true_in = is_true_value_zero_constant;
4369 }
4370 break;
4371 case Primitive::kPrimFloat:
4372 case Primitive::kPrimDouble:
4373 // Moving float/double on int condition.
4374 if (is_r6) {
4375 if (materialized) {
4376 // Not materializing unmaterialized int conditions
4377 // to keep the instruction count low.
4378 can_move_conditionally = true;
4379 if (is_true_value_zero_constant) {
4380 // sltu TMP, ZERO, cond_reg
4381 // mtc1 TMP, temp_cond_reg
4382 // seleqz.fmt out_reg, false_reg, temp_cond_reg
4383 use_const_for_true_in = true;
4384 } else if (is_false_value_zero_constant) {
4385 // sltu TMP, ZERO, cond_reg
4386 // mtc1 TMP, temp_cond_reg
4387 // selnez.fmt out_reg, true_reg, temp_cond_reg
4388 use_const_for_false_in = true;
4389 } else {
4390 // sltu TMP, ZERO, cond_reg
4391 // mtc1 TMP, temp_cond_reg
4392 // sel.fmt temp_cond_reg, false_reg, true_reg
4393 // mov.fmt out_reg, temp_cond_reg
4394 }
4395 }
4396 } else {
4397 // movn.fmt out_reg, true_reg, cond_reg
4398 can_move_conditionally = true;
4399 }
4400 break;
4401 }
4402 break;
4403 case Primitive::kPrimLong:
4404 // We don't materialize long comparison now
4405 // and use conditional branches instead.
4406 break;
4407 case Primitive::kPrimFloat:
4408 case Primitive::kPrimDouble:
4409 switch (dst_type) {
4410 default:
4411 // Moving int on float/double condition.
4412 if (is_r6) {
4413 if (is_true_value_zero_constant) {
4414 // mfc1 TMP, temp_cond_reg
4415 // seleqz out_reg, false_reg, TMP
4416 can_move_conditionally = true;
4417 use_const_for_true_in = true;
4418 } else if (is_false_value_zero_constant) {
4419 // mfc1 TMP, temp_cond_reg
4420 // selnez out_reg, true_reg, TMP
4421 can_move_conditionally = true;
4422 use_const_for_false_in = true;
4423 } else {
4424 // mfc1 TMP, temp_cond_reg
4425 // selnez AT, true_reg, TMP
4426 // seleqz TMP, false_reg, TMP
4427 // or out_reg, AT, TMP
4428 can_move_conditionally = true;
4429 }
4430 } else {
4431 // movt out_reg, true_reg/ZERO, cc
4432 can_move_conditionally = true;
4433 use_const_for_true_in = is_true_value_zero_constant;
4434 }
4435 break;
4436 case Primitive::kPrimLong:
4437 // Moving long on float/double condition.
4438 if (is_r6) {
4439 if (is_true_value_zero_constant) {
4440 // mfc1 TMP, temp_cond_reg
4441 // seleqz out_reg_lo, false_reg_lo, TMP
4442 // seleqz out_reg_hi, false_reg_hi, TMP
4443 can_move_conditionally = true;
4444 use_const_for_true_in = true;
4445 } else if (is_false_value_zero_constant) {
4446 // mfc1 TMP, temp_cond_reg
4447 // selnez out_reg_lo, true_reg_lo, TMP
4448 // selnez out_reg_hi, true_reg_hi, TMP
4449 can_move_conditionally = true;
4450 use_const_for_false_in = true;
4451 }
4452 // Other long conditional moves would generate 6+ instructions,
4453 // which is too many.
4454 } else {
4455 // movt out_reg_lo, true_reg_lo/ZERO, cc
4456 // movt out_reg_hi, true_reg_hi/ZERO, cc
4457 can_move_conditionally = true;
4458 use_const_for_true_in = is_true_value_zero_constant;
4459 }
4460 break;
4461 case Primitive::kPrimFloat:
4462 case Primitive::kPrimDouble:
4463 // Moving float/double on float/double condition.
4464 if (is_r6) {
4465 can_move_conditionally = true;
4466 if (is_true_value_zero_constant) {
4467 // seleqz.fmt out_reg, false_reg, temp_cond_reg
4468 use_const_for_true_in = true;
4469 } else if (is_false_value_zero_constant) {
4470 // selnez.fmt out_reg, true_reg, temp_cond_reg
4471 use_const_for_false_in = true;
4472 } else {
4473 // sel.fmt temp_cond_reg, false_reg, true_reg
4474 // mov.fmt out_reg, temp_cond_reg
4475 }
4476 } else {
4477 // movt.fmt out_reg, true_reg, cc
4478 can_move_conditionally = true;
4479 }
4480 break;
4481 }
4482 break;
4483 }
4484 }
4485
4486 if (can_move_conditionally) {
4487 DCHECK(!use_const_for_false_in || !use_const_for_true_in);
4488 } else {
4489 DCHECK(!use_const_for_false_in);
4490 DCHECK(!use_const_for_true_in);
4491 }
4492
4493 if (locations_to_set != nullptr) {
4494 if (use_const_for_false_in) {
4495 locations_to_set->SetInAt(0, Location::ConstantLocation(cst_false_value));
4496 } else {
4497 locations_to_set->SetInAt(0,
4498 Primitive::IsFloatingPointType(dst_type)
4499 ? Location::RequiresFpuRegister()
4500 : Location::RequiresRegister());
4501 }
4502 if (use_const_for_true_in) {
4503 locations_to_set->SetInAt(1, Location::ConstantLocation(cst_true_value));
4504 } else {
4505 locations_to_set->SetInAt(1,
4506 Primitive::IsFloatingPointType(dst_type)
4507 ? Location::RequiresFpuRegister()
4508 : Location::RequiresRegister());
4509 }
4510 if (materialized) {
4511 locations_to_set->SetInAt(2, Location::RequiresRegister());
4512 }
4513 // On R6 we don't require the output to be the same as the
4514 // first input for conditional moves unlike on R2.
4515 bool is_out_same_as_first_in = !can_move_conditionally || !is_r6;
4516 if (is_out_same_as_first_in) {
4517 locations_to_set->SetOut(Location::SameAsFirstInput());
4518 } else {
4519 locations_to_set->SetOut(Primitive::IsFloatingPointType(dst_type)
4520 ? Location::RequiresFpuRegister()
4521 : Location::RequiresRegister());
4522 }
4523 }
4524
4525 return can_move_conditionally;
4526}
4527
4528void InstructionCodeGeneratorMIPS::GenConditionalMoveR2(HSelect* select) {
4529 LocationSummary* locations = select->GetLocations();
4530 Location dst = locations->Out();
4531 Location src = locations->InAt(1);
4532 Register src_reg = ZERO;
4533 Register src_reg_high = ZERO;
4534 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
4535 Register cond_reg = TMP;
4536 int cond_cc = 0;
4537 Primitive::Type cond_type = Primitive::kPrimInt;
4538 bool cond_inverted = false;
4539 Primitive::Type dst_type = select->GetType();
4540
4541 if (IsBooleanValueOrMaterializedCondition(cond)) {
4542 cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
4543 } else {
4544 HCondition* condition = cond->AsCondition();
4545 LocationSummary* cond_locations = cond->GetLocations();
4546 IfCondition if_cond = condition->GetCondition();
4547 cond_type = condition->InputAt(0)->GetType();
4548 switch (cond_type) {
4549 default:
4550 DCHECK_NE(cond_type, Primitive::kPrimLong);
4551 cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
4552 break;
4553 case Primitive::kPrimFloat:
4554 case Primitive::kPrimDouble:
4555 cond_inverted = MaterializeFpCompareR2(if_cond,
4556 condition->IsGtBias(),
4557 cond_type,
4558 cond_locations,
4559 cond_cc);
4560 break;
4561 }
4562 }
4563
4564 DCHECK(dst.Equals(locations->InAt(0)));
4565 if (src.IsRegister()) {
4566 src_reg = src.AsRegister<Register>();
4567 } else if (src.IsRegisterPair()) {
4568 src_reg = src.AsRegisterPairLow<Register>();
4569 src_reg_high = src.AsRegisterPairHigh<Register>();
4570 } else if (src.IsConstant()) {
4571 DCHECK(src.GetConstant()->IsZeroBitPattern());
4572 }
4573
4574 switch (cond_type) {
4575 default:
4576 switch (dst_type) {
4577 default:
4578 if (cond_inverted) {
4579 __ Movz(dst.AsRegister<Register>(), src_reg, cond_reg);
4580 } else {
4581 __ Movn(dst.AsRegister<Register>(), src_reg, cond_reg);
4582 }
4583 break;
4584 case Primitive::kPrimLong:
4585 if (cond_inverted) {
4586 __ Movz(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
4587 __ Movz(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
4588 } else {
4589 __ Movn(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
4590 __ Movn(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
4591 }
4592 break;
4593 case Primitive::kPrimFloat:
4594 if (cond_inverted) {
4595 __ MovzS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
4596 } else {
4597 __ MovnS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
4598 }
4599 break;
4600 case Primitive::kPrimDouble:
4601 if (cond_inverted) {
4602 __ MovzD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
4603 } else {
4604 __ MovnD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
4605 }
4606 break;
4607 }
4608 break;
4609 case Primitive::kPrimLong:
4610 LOG(FATAL) << "Unreachable";
4611 UNREACHABLE();
4612 case Primitive::kPrimFloat:
4613 case Primitive::kPrimDouble:
4614 switch (dst_type) {
4615 default:
4616 if (cond_inverted) {
4617 __ Movf(dst.AsRegister<Register>(), src_reg, cond_cc);
4618 } else {
4619 __ Movt(dst.AsRegister<Register>(), src_reg, cond_cc);
4620 }
4621 break;
4622 case Primitive::kPrimLong:
4623 if (cond_inverted) {
4624 __ Movf(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
4625 __ Movf(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
4626 } else {
4627 __ Movt(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
4628 __ Movt(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
4629 }
4630 break;
4631 case Primitive::kPrimFloat:
4632 if (cond_inverted) {
4633 __ MovfS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
4634 } else {
4635 __ MovtS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
4636 }
4637 break;
4638 case Primitive::kPrimDouble:
4639 if (cond_inverted) {
4640 __ MovfD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
4641 } else {
4642 __ MovtD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
4643 }
4644 break;
4645 }
4646 break;
4647 }
4648}
4649
4650void InstructionCodeGeneratorMIPS::GenConditionalMoveR6(HSelect* select) {
4651 LocationSummary* locations = select->GetLocations();
4652 Location dst = locations->Out();
4653 Location false_src = locations->InAt(0);
4654 Location true_src = locations->InAt(1);
4655 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
4656 Register cond_reg = TMP;
4657 FRegister fcond_reg = FTMP;
4658 Primitive::Type cond_type = Primitive::kPrimInt;
4659 bool cond_inverted = false;
4660 Primitive::Type dst_type = select->GetType();
4661
4662 if (IsBooleanValueOrMaterializedCondition(cond)) {
4663 cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
4664 } else {
4665 HCondition* condition = cond->AsCondition();
4666 LocationSummary* cond_locations = cond->GetLocations();
4667 IfCondition if_cond = condition->GetCondition();
4668 cond_type = condition->InputAt(0)->GetType();
4669 switch (cond_type) {
4670 default:
4671 DCHECK_NE(cond_type, Primitive::kPrimLong);
4672 cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
4673 break;
4674 case Primitive::kPrimFloat:
4675 case Primitive::kPrimDouble:
4676 cond_inverted = MaterializeFpCompareR6(if_cond,
4677 condition->IsGtBias(),
4678 cond_type,
4679 cond_locations,
4680 fcond_reg);
4681 break;
4682 }
4683 }
4684
4685 if (true_src.IsConstant()) {
4686 DCHECK(true_src.GetConstant()->IsZeroBitPattern());
4687 }
4688 if (false_src.IsConstant()) {
4689 DCHECK(false_src.GetConstant()->IsZeroBitPattern());
4690 }
4691
4692 switch (dst_type) {
4693 default:
4694 if (Primitive::IsFloatingPointType(cond_type)) {
4695 __ Mfc1(cond_reg, fcond_reg);
4696 }
4697 if (true_src.IsConstant()) {
4698 if (cond_inverted) {
4699 __ Selnez(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
4700 } else {
4701 __ Seleqz(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
4702 }
4703 } else if (false_src.IsConstant()) {
4704 if (cond_inverted) {
4705 __ Seleqz(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
4706 } else {
4707 __ Selnez(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
4708 }
4709 } else {
4710 DCHECK_NE(cond_reg, AT);
4711 if (cond_inverted) {
4712 __ Seleqz(AT, true_src.AsRegister<Register>(), cond_reg);
4713 __ Selnez(TMP, false_src.AsRegister<Register>(), cond_reg);
4714 } else {
4715 __ Selnez(AT, true_src.AsRegister<Register>(), cond_reg);
4716 __ Seleqz(TMP, false_src.AsRegister<Register>(), cond_reg);
4717 }
4718 __ Or(dst.AsRegister<Register>(), AT, TMP);
4719 }
4720 break;
4721 case Primitive::kPrimLong: {
4722 if (Primitive::IsFloatingPointType(cond_type)) {
4723 __ Mfc1(cond_reg, fcond_reg);
4724 }
4725 Register dst_lo = dst.AsRegisterPairLow<Register>();
4726 Register dst_hi = dst.AsRegisterPairHigh<Register>();
4727 if (true_src.IsConstant()) {
4728 Register src_lo = false_src.AsRegisterPairLow<Register>();
4729 Register src_hi = false_src.AsRegisterPairHigh<Register>();
4730 if (cond_inverted) {
4731 __ Selnez(dst_lo, src_lo, cond_reg);
4732 __ Selnez(dst_hi, src_hi, cond_reg);
4733 } else {
4734 __ Seleqz(dst_lo, src_lo, cond_reg);
4735 __ Seleqz(dst_hi, src_hi, cond_reg);
4736 }
4737 } else {
4738 DCHECK(false_src.IsConstant());
4739 Register src_lo = true_src.AsRegisterPairLow<Register>();
4740 Register src_hi = true_src.AsRegisterPairHigh<Register>();
4741 if (cond_inverted) {
4742 __ Seleqz(dst_lo, src_lo, cond_reg);
4743 __ Seleqz(dst_hi, src_hi, cond_reg);
4744 } else {
4745 __ Selnez(dst_lo, src_lo, cond_reg);
4746 __ Selnez(dst_hi, src_hi, cond_reg);
4747 }
4748 }
4749 break;
4750 }
4751 case Primitive::kPrimFloat: {
4752 if (!Primitive::IsFloatingPointType(cond_type)) {
4753 // sel*.fmt tests bit 0 of the condition register, account for that.
4754 __ Sltu(TMP, ZERO, cond_reg);
4755 __ Mtc1(TMP, fcond_reg);
4756 }
4757 FRegister dst_reg = dst.AsFpuRegister<FRegister>();
4758 if (true_src.IsConstant()) {
4759 FRegister src_reg = false_src.AsFpuRegister<FRegister>();
4760 if (cond_inverted) {
4761 __ SelnezS(dst_reg, src_reg, fcond_reg);
4762 } else {
4763 __ SeleqzS(dst_reg, src_reg, fcond_reg);
4764 }
4765 } else if (false_src.IsConstant()) {
4766 FRegister src_reg = true_src.AsFpuRegister<FRegister>();
4767 if (cond_inverted) {
4768 __ SeleqzS(dst_reg, src_reg, fcond_reg);
4769 } else {
4770 __ SelnezS(dst_reg, src_reg, fcond_reg);
4771 }
4772 } else {
4773 if (cond_inverted) {
4774 __ SelS(fcond_reg,
4775 true_src.AsFpuRegister<FRegister>(),
4776 false_src.AsFpuRegister<FRegister>());
4777 } else {
4778 __ SelS(fcond_reg,
4779 false_src.AsFpuRegister<FRegister>(),
4780 true_src.AsFpuRegister<FRegister>());
4781 }
4782 __ MovS(dst_reg, fcond_reg);
4783 }
4784 break;
4785 }
4786 case Primitive::kPrimDouble: {
4787 if (!Primitive::IsFloatingPointType(cond_type)) {
4788 // sel*.fmt tests bit 0 of the condition register, account for that.
4789 __ Sltu(TMP, ZERO, cond_reg);
4790 __ Mtc1(TMP, fcond_reg);
4791 }
4792 FRegister dst_reg = dst.AsFpuRegister<FRegister>();
4793 if (true_src.IsConstant()) {
4794 FRegister src_reg = false_src.AsFpuRegister<FRegister>();
4795 if (cond_inverted) {
4796 __ SelnezD(dst_reg, src_reg, fcond_reg);
4797 } else {
4798 __ SeleqzD(dst_reg, src_reg, fcond_reg);
4799 }
4800 } else if (false_src.IsConstant()) {
4801 FRegister src_reg = true_src.AsFpuRegister<FRegister>();
4802 if (cond_inverted) {
4803 __ SeleqzD(dst_reg, src_reg, fcond_reg);
4804 } else {
4805 __ SelnezD(dst_reg, src_reg, fcond_reg);
4806 }
4807 } else {
4808 if (cond_inverted) {
4809 __ SelD(fcond_reg,
4810 true_src.AsFpuRegister<FRegister>(),
4811 false_src.AsFpuRegister<FRegister>());
4812 } else {
4813 __ SelD(fcond_reg,
4814 false_src.AsFpuRegister<FRegister>(),
4815 true_src.AsFpuRegister<FRegister>());
4816 }
4817 __ MovD(dst_reg, fcond_reg);
4818 }
4819 break;
4820 }
4821 }
4822}
4823
Goran Jakovljevicc6418422016-12-05 16:31:55 +01004824void LocationsBuilderMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
4825 LocationSummary* locations = new (GetGraph()->GetArena())
4826 LocationSummary(flag, LocationSummary::kNoCall);
4827 locations->SetOut(Location::RequiresRegister());
Mingyao Yang063fc772016-08-02 11:02:54 -07004828}
4829
Goran Jakovljevicc6418422016-12-05 16:31:55 +01004830void InstructionCodeGeneratorMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
4831 __ LoadFromOffset(kLoadWord,
4832 flag->GetLocations()->Out().AsRegister<Register>(),
4833 SP,
4834 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
Mingyao Yang063fc772016-08-02 11:02:54 -07004835}
4836
David Brazdil74eb1b22015-12-14 11:44:01 +00004837void LocationsBuilderMIPS::VisitSelect(HSelect* select) {
4838 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004839 CanMoveConditionally(select, codegen_->GetInstructionSetFeatures().IsR6(), locations);
David Brazdil74eb1b22015-12-14 11:44:01 +00004840}
4841
4842void InstructionCodeGeneratorMIPS::VisitSelect(HSelect* select) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004843 bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
4844 if (CanMoveConditionally(select, is_r6, /* locations_to_set */ nullptr)) {
4845 if (is_r6) {
4846 GenConditionalMoveR6(select);
4847 } else {
4848 GenConditionalMoveR2(select);
4849 }
4850 } else {
4851 LocationSummary* locations = select->GetLocations();
4852 MipsLabel false_target;
4853 GenerateTestAndBranch(select,
4854 /* condition_input_index */ 2,
4855 /* true_target */ nullptr,
4856 &false_target);
4857 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
4858 __ Bind(&false_target);
4859 }
David Brazdil74eb1b22015-12-14 11:44:01 +00004860}
4861
David Srbecky0cf44932015-12-09 14:09:59 +00004862void LocationsBuilderMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
4863 new (GetGraph()->GetArena()) LocationSummary(info);
4864}
4865
David Srbeckyd28f4a02016-03-14 17:14:24 +00004866void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo*) {
4867 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00004868}
4869
4870void CodeGeneratorMIPS::GenerateNop() {
4871 __ Nop();
David Srbecky0cf44932015-12-09 14:09:59 +00004872}
4873
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004874void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
4875 Primitive::Type field_type = field_info.GetFieldType();
4876 bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
4877 bool generate_volatile = field_info.IsVolatile() && is_wide;
4878 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004879 instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004880
4881 locations->SetInAt(0, Location::RequiresRegister());
4882 if (generate_volatile) {
4883 InvokeRuntimeCallingConvention calling_convention;
4884 // need A0 to hold base + offset
4885 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4886 if (field_type == Primitive::kPrimLong) {
4887 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimLong));
4888 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02004889 // Use Location::Any() to prevent situations when running out of available fp registers.
4890 locations->SetOut(Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004891 // Need some temp core regs since FP results are returned in core registers
4892 Location reg = calling_convention.GetReturnLocation(Primitive::kPrimLong);
4893 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairLow<Register>()));
4894 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairHigh<Register>()));
4895 }
4896 } else {
4897 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4898 locations->SetOut(Location::RequiresFpuRegister());
4899 } else {
4900 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4901 }
4902 }
4903}
4904
4905void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
4906 const FieldInfo& field_info,
4907 uint32_t dex_pc) {
4908 Primitive::Type type = field_info.GetFieldType();
4909 LocationSummary* locations = instruction->GetLocations();
4910 Register obj = locations->InAt(0).AsRegister<Register>();
4911 LoadOperandType load_type = kLoadUnsignedByte;
4912 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01004913 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Alexey Frunze2923db72016-08-20 01:55:47 -07004914 auto null_checker = GetImplicitNullChecker(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004915
4916 switch (type) {
4917 case Primitive::kPrimBoolean:
4918 load_type = kLoadUnsignedByte;
4919 break;
4920 case Primitive::kPrimByte:
4921 load_type = kLoadSignedByte;
4922 break;
4923 case Primitive::kPrimShort:
4924 load_type = kLoadSignedHalfword;
4925 break;
4926 case Primitive::kPrimChar:
4927 load_type = kLoadUnsignedHalfword;
4928 break;
4929 case Primitive::kPrimInt:
4930 case Primitive::kPrimFloat:
4931 case Primitive::kPrimNot:
4932 load_type = kLoadWord;
4933 break;
4934 case Primitive::kPrimLong:
4935 case Primitive::kPrimDouble:
4936 load_type = kLoadDoubleword;
4937 break;
4938 case Primitive::kPrimVoid:
4939 LOG(FATAL) << "Unreachable type " << type;
4940 UNREACHABLE();
4941 }
4942
4943 if (is_volatile && load_type == kLoadDoubleword) {
4944 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01004945 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004946 // Do implicit Null check
4947 __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
4948 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Serban Constantinescufca16662016-07-14 09:21:59 +01004949 codegen_->InvokeRuntime(kQuickA64Load, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004950 CheckEntrypointTypes<kQuickA64Load, int64_t, volatile const int64_t*>();
4951 if (type == Primitive::kPrimDouble) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02004952 // FP results are returned in core registers. Need to move them.
4953 Location out = locations->Out();
4954 if (out.IsFpuRegister()) {
4955 __ Mtc1(locations->GetTemp(1).AsRegister<Register>(), out.AsFpuRegister<FRegister>());
4956 __ MoveToFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
4957 out.AsFpuRegister<FRegister>());
4958 } else {
4959 DCHECK(out.IsDoubleStackSlot());
4960 __ StoreToOffset(kStoreWord,
4961 locations->GetTemp(1).AsRegister<Register>(),
4962 SP,
4963 out.GetStackIndex());
4964 __ StoreToOffset(kStoreWord,
4965 locations->GetTemp(2).AsRegister<Register>(),
4966 SP,
4967 out.GetStackIndex() + 4);
4968 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004969 }
4970 } else {
4971 if (!Primitive::IsFloatingPointType(type)) {
4972 Register dst;
4973 if (type == Primitive::kPrimLong) {
4974 DCHECK(locations->Out().IsRegisterPair());
4975 dst = locations->Out().AsRegisterPairLow<Register>();
4976 } else {
4977 DCHECK(locations->Out().IsRegister());
4978 dst = locations->Out().AsRegister<Register>();
4979 }
Alexey Frunze2923db72016-08-20 01:55:47 -07004980 __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
Alexey Frunzec061de12017-02-14 13:27:23 -08004981 if (type == Primitive::kPrimNot) {
4982 __ MaybeUnpoisonHeapReference(dst);
4983 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004984 } else {
4985 DCHECK(locations->Out().IsFpuRegister());
4986 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4987 if (type == Primitive::kPrimFloat) {
Alexey Frunze2923db72016-08-20 01:55:47 -07004988 __ LoadSFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004989 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07004990 __ LoadDFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004991 }
4992 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004993 }
4994
4995 if (is_volatile) {
4996 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4997 }
4998}
4999
5000void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
5001 Primitive::Type field_type = field_info.GetFieldType();
5002 bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
5003 bool generate_volatile = field_info.IsVolatile() && is_wide;
5004 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005005 instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005006
5007 locations->SetInAt(0, Location::RequiresRegister());
5008 if (generate_volatile) {
5009 InvokeRuntimeCallingConvention calling_convention;
5010 // need A0 to hold base + offset
5011 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5012 if (field_type == Primitive::kPrimLong) {
5013 locations->SetInAt(1, Location::RegisterPairLocation(
5014 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
5015 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02005016 // Use Location::Any() to prevent situations when running out of available fp registers.
5017 locations->SetInAt(1, Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005018 // Pass FP parameters in core registers.
5019 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
5020 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
5021 }
5022 } else {
5023 if (Primitive::IsFloatingPointType(field_type)) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005024 locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005025 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005026 locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005027 }
5028 }
5029}
5030
5031void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction,
5032 const FieldInfo& field_info,
Goran Jakovljevice114da22016-12-26 14:21:43 +01005033 uint32_t dex_pc,
5034 bool value_can_be_null) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005035 Primitive::Type type = field_info.GetFieldType();
5036 LocationSummary* locations = instruction->GetLocations();
5037 Register obj = locations->InAt(0).AsRegister<Register>();
Alexey Frunzef58b2482016-09-02 22:14:06 -07005038 Location value_location = locations->InAt(1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005039 StoreOperandType store_type = kStoreByte;
5040 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01005041 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Alexey Frunzec061de12017-02-14 13:27:23 -08005042 bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1));
Alexey Frunze2923db72016-08-20 01:55:47 -07005043 auto null_checker = GetImplicitNullChecker(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005044
5045 switch (type) {
5046 case Primitive::kPrimBoolean:
5047 case Primitive::kPrimByte:
5048 store_type = kStoreByte;
5049 break;
5050 case Primitive::kPrimShort:
5051 case Primitive::kPrimChar:
5052 store_type = kStoreHalfword;
5053 break;
5054 case Primitive::kPrimInt:
5055 case Primitive::kPrimFloat:
5056 case Primitive::kPrimNot:
5057 store_type = kStoreWord;
5058 break;
5059 case Primitive::kPrimLong:
5060 case Primitive::kPrimDouble:
5061 store_type = kStoreDoubleword;
5062 break;
5063 case Primitive::kPrimVoid:
5064 LOG(FATAL) << "Unreachable type " << type;
5065 UNREACHABLE();
5066 }
5067
5068 if (is_volatile) {
5069 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
5070 }
5071
5072 if (is_volatile && store_type == kStoreDoubleword) {
5073 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01005074 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005075 // Do implicit Null check.
5076 __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
5077 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
5078 if (type == Primitive::kPrimDouble) {
5079 // Pass FP parameters in core registers.
Alexey Frunzef58b2482016-09-02 22:14:06 -07005080 if (value_location.IsFpuRegister()) {
5081 __ Mfc1(locations->GetTemp(1).AsRegister<Register>(),
5082 value_location.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02005083 __ MoveFromFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
Alexey Frunzef58b2482016-09-02 22:14:06 -07005084 value_location.AsFpuRegister<FRegister>());
5085 } else if (value_location.IsDoubleStackSlot()) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02005086 __ LoadFromOffset(kLoadWord,
5087 locations->GetTemp(1).AsRegister<Register>(),
5088 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07005089 value_location.GetStackIndex());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02005090 __ LoadFromOffset(kLoadWord,
5091 locations->GetTemp(2).AsRegister<Register>(),
5092 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07005093 value_location.GetStackIndex() + 4);
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02005094 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005095 DCHECK(value_location.IsConstant());
5096 DCHECK(value_location.GetConstant()->IsDoubleConstant());
5097 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02005098 __ LoadConst64(locations->GetTemp(2).AsRegister<Register>(),
5099 locations->GetTemp(1).AsRegister<Register>(),
5100 value);
5101 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005102 }
Serban Constantinescufca16662016-07-14 09:21:59 +01005103 codegen_->InvokeRuntime(kQuickA64Store, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005104 CheckEntrypointTypes<kQuickA64Store, void, volatile int64_t *, int64_t>();
5105 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005106 if (value_location.IsConstant()) {
5107 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
5108 __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
5109 } else if (!Primitive::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005110 Register src;
5111 if (type == Primitive::kPrimLong) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005112 src = value_location.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005113 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005114 src = value_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005115 }
Alexey Frunzec061de12017-02-14 13:27:23 -08005116 if (kPoisonHeapReferences && needs_write_barrier) {
5117 // Note that in the case where `value` is a null reference,
5118 // we do not enter this block, as a null reference does not
5119 // need poisoning.
5120 DCHECK_EQ(type, Primitive::kPrimNot);
5121 __ PoisonHeapReference(TMP, src);
5122 __ StoreToOffset(store_type, TMP, obj, offset, null_checker);
5123 } else {
5124 __ StoreToOffset(store_type, src, obj, offset, null_checker);
5125 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005126 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005127 FRegister src = value_location.AsFpuRegister<FRegister>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005128 if (type == Primitive::kPrimFloat) {
Alexey Frunze2923db72016-08-20 01:55:47 -07005129 __ StoreSToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005130 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07005131 __ StoreDToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005132 }
5133 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005134 }
5135
5136 // TODO: memory barriers?
Alexey Frunzec061de12017-02-14 13:27:23 -08005137 if (needs_write_barrier) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07005138 Register src = value_location.AsRegister<Register>();
Goran Jakovljevice114da22016-12-26 14:21:43 +01005139 codegen_->MarkGCCard(obj, src, value_can_be_null);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005140 }
5141
5142 if (is_volatile) {
5143 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
5144 }
5145}
5146
5147void LocationsBuilderMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5148 HandleFieldGet(instruction, instruction->GetFieldInfo());
5149}
5150
5151void InstructionCodeGeneratorMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
5152 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
5153}
5154
5155void LocationsBuilderMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
5156 HandleFieldSet(instruction, instruction->GetFieldInfo());
5157}
5158
5159void InstructionCodeGeneratorMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01005160 HandleFieldSet(instruction,
5161 instruction->GetFieldInfo(),
5162 instruction->GetDexPc(),
5163 instruction->GetValueCanBeNull());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005164}
5165
Alexey Frunze06a46c42016-07-19 15:00:40 -07005166void InstructionCodeGeneratorMIPS::GenerateGcRootFieldLoad(
5167 HInstruction* instruction ATTRIBUTE_UNUSED,
5168 Location root,
5169 Register obj,
5170 uint32_t offset) {
5171 Register root_reg = root.AsRegister<Register>();
5172 if (kEmitCompilerReadBarrier) {
5173 UNIMPLEMENTED(FATAL) << "for read barrier";
5174 } else {
5175 // Plain GC root load with no read barrier.
5176 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
5177 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
5178 // Note that GC roots are not affected by heap poisoning, thus we
5179 // do not have to unpoison `root_reg` here.
5180 }
5181}
5182
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005183void LocationsBuilderMIPS::VisitInstanceOf(HInstanceOf* instruction) {
5184 LocationSummary::CallKind call_kind =
5185 instruction->IsExactCheck() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
5186 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
5187 locations->SetInAt(0, Location::RequiresRegister());
5188 locations->SetInAt(1, Location::RequiresRegister());
5189 // The output does overlap inputs.
5190 // Note that TypeCheckSlowPathMIPS uses this register too.
5191 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
5192}
5193
5194void InstructionCodeGeneratorMIPS::VisitInstanceOf(HInstanceOf* instruction) {
5195 LocationSummary* locations = instruction->GetLocations();
5196 Register obj = locations->InAt(0).AsRegister<Register>();
5197 Register cls = locations->InAt(1).AsRegister<Register>();
5198 Register out = locations->Out().AsRegister<Register>();
5199
5200 MipsLabel done;
5201
5202 // Return 0 if `obj` is null.
5203 // TODO: Avoid this check if we know `obj` is not null.
5204 __ Move(out, ZERO);
5205 __ Beqz(obj, &done);
5206
5207 // Compare the class of `obj` with `cls`.
5208 __ LoadFromOffset(kLoadWord, out, obj, mirror::Object::ClassOffset().Int32Value());
Alexey Frunzec061de12017-02-14 13:27:23 -08005209 __ MaybeUnpoisonHeapReference(out);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005210 if (instruction->IsExactCheck()) {
5211 // Classes must be equal for the instanceof to succeed.
5212 __ Xor(out, out, cls);
5213 __ Sltiu(out, out, 1);
5214 } else {
5215 // If the classes are not equal, we go into a slow path.
5216 DCHECK(locations->OnlyCallsOnSlowPath());
5217 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction);
5218 codegen_->AddSlowPath(slow_path);
5219 __ Bne(out, cls, slow_path->GetEntryLabel());
5220 __ LoadConst32(out, 1);
5221 __ Bind(slow_path->GetExitLabel());
5222 }
5223
5224 __ Bind(&done);
5225}
5226
5227void LocationsBuilderMIPS::VisitIntConstant(HIntConstant* constant) {
5228 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
5229 locations->SetOut(Location::ConstantLocation(constant));
5230}
5231
5232void InstructionCodeGeneratorMIPS::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
5233 // Will be generated at use site.
5234}
5235
5236void LocationsBuilderMIPS::VisitNullConstant(HNullConstant* constant) {
5237 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
5238 locations->SetOut(Location::ConstantLocation(constant));
5239}
5240
5241void InstructionCodeGeneratorMIPS::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
5242 // Will be generated at use site.
5243}
5244
5245void LocationsBuilderMIPS::HandleInvoke(HInvoke* invoke) {
5246 InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
5247 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
5248}
5249
5250void LocationsBuilderMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
5251 HandleInvoke(invoke);
Alexey Frunze1b8464d2016-11-12 17:22:05 -08005252 // The register T7 is required to be used for the hidden argument in
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005253 // art_quick_imt_conflict_trampoline, so add the hidden argument.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08005254 invoke->GetLocations()->AddTemp(Location::RegisterLocation(T7));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005255}
5256
5257void InstructionCodeGeneratorMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
5258 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
5259 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005260 Location receiver = invoke->GetLocations()->InAt(0);
5261 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07005262 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005263
5264 // Set the hidden argument.
5265 __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
5266 invoke->GetDexMethodIndex());
5267
5268 // temp = object->GetClass();
5269 if (receiver.IsStackSlot()) {
5270 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
5271 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
5272 } else {
5273 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
5274 }
5275 codegen_->MaybeRecordImplicitNullCheck(invoke);
Alexey Frunzec061de12017-02-14 13:27:23 -08005276 // Instead of simply (possibly) unpoisoning `temp` here, we should
5277 // emit a read barrier for the previous class reference load.
5278 // However this is not required in practice, as this is an
5279 // intermediate/temporary reference and because the current
5280 // concurrent copying collector keeps the from-space memory
5281 // intact/accessible until the end of the marking phase (the
5282 // concurrent copying collector may not in the future).
5283 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00005284 __ LoadFromOffset(kLoadWord, temp, temp,
5285 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
5286 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00005287 invoke->GetImtIndex(), kMipsPointerSize));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005288 // temp = temp->GetImtEntryAt(method_offset);
5289 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
5290 // T9 = temp->GetEntryPoint();
5291 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
5292 // T9();
5293 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005294 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005295 DCHECK(!codegen_->IsLeafMethod());
5296 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
5297}
5298
5299void LocationsBuilderMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Chris Larsen701566a2015-10-27 15:29:13 -07005300 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
5301 if (intrinsic.TryDispatch(invoke)) {
5302 return;
5303 }
5304
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005305 HandleInvoke(invoke);
5306}
5307
5308void LocationsBuilderMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00005309 // Explicit clinit checks triggered by static invokes must have been pruned by
5310 // art::PrepareForRegisterAllocation.
5311 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005312
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005313 bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
5314 bool has_extra_input = invoke->HasPcRelativeDexCache() && !is_r6;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005315
Chris Larsen701566a2015-10-27 15:29:13 -07005316 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
5317 if (intrinsic.TryDispatch(invoke)) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005318 if (invoke->GetLocations()->CanCall() && has_extra_input) {
5319 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
5320 }
Chris Larsen701566a2015-10-27 15:29:13 -07005321 return;
5322 }
5323
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005324 HandleInvoke(invoke);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005325
5326 // Add the extra input register if either the dex cache array base register
5327 // or the PC-relative base register for accessing literals is needed.
5328 if (has_extra_input) {
5329 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
5330 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005331}
5332
Orion Hodsonac141392017-01-13 11:53:47 +00005333void LocationsBuilderMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
5334 HandleInvoke(invoke);
5335}
5336
5337void InstructionCodeGeneratorMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
5338 codegen_->GenerateInvokePolymorphicCall(invoke);
5339}
5340
Chris Larsen701566a2015-10-27 15:29:13 -07005341static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005342 if (invoke->GetLocations()->Intrinsified()) {
Chris Larsen701566a2015-10-27 15:29:13 -07005343 IntrinsicCodeGeneratorMIPS intrinsic(codegen);
5344 intrinsic.Dispatch(invoke);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005345 return true;
5346 }
5347 return false;
5348}
5349
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005350HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
Alexey Frunze06a46c42016-07-19 15:00:40 -07005351 HLoadString::LoadKind desired_string_load_kind) {
5352 if (kEmitCompilerReadBarrier) {
5353 UNIMPLEMENTED(FATAL) << "for read barrier";
5354 }
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005355 // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
Alexey Frunze06a46c42016-07-19 15:00:40 -07005356 // is incompatible with it.
Vladimir Markoaad75c62016-10-03 08:46:48 +00005357 // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods
5358 // with irreducible loops.
Alexey Frunze06a46c42016-07-19 15:00:40 -07005359 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005360 bool is_r6 = GetInstructionSetFeatures().IsR6();
5361 bool fallback_load = has_irreducible_loops && !is_r6;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005362 switch (desired_string_load_kind) {
5363 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5364 DCHECK(!GetCompilerOptions().GetCompilePic());
5365 break;
5366 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
5367 DCHECK(GetCompilerOptions().GetCompilePic());
5368 break;
5369 case HLoadString::LoadKind::kBootImageAddress:
5370 break;
Vladimir Markoaad75c62016-10-03 08:46:48 +00005371 case HLoadString::LoadKind::kBssEntry:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005372 DCHECK(!Runtime::Current()->UseJitCompilation());
Alexey Frunze06a46c42016-07-19 15:00:40 -07005373 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005374 case HLoadString::LoadKind::kJitTableAddress:
5375 DCHECK(Runtime::Current()->UseJitCompilation());
Alexey Frunze627c1a02017-01-30 19:28:14 -08005376 fallback_load = false;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00005377 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005378 case HLoadString::LoadKind::kDexCacheViaMethod:
5379 fallback_load = false;
5380 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005381 }
5382 if (fallback_load) {
5383 desired_string_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
5384 }
5385 return desired_string_load_kind;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00005386}
5387
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005388HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind(
5389 HLoadClass::LoadKind desired_class_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07005390 if (kEmitCompilerReadBarrier) {
5391 UNIMPLEMENTED(FATAL) << "for read barrier";
5392 }
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005393 // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
Alexey Frunze06a46c42016-07-19 15:00:40 -07005394 // is incompatible with it.
5395 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005396 bool is_r6 = GetInstructionSetFeatures().IsR6();
5397 bool fallback_load = has_irreducible_loops && !is_r6;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005398 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00005399 case HLoadClass::LoadKind::kInvalid:
5400 LOG(FATAL) << "UNREACHABLE";
5401 UNREACHABLE();
Alexey Frunze06a46c42016-07-19 15:00:40 -07005402 case HLoadClass::LoadKind::kReferrersClass:
5403 fallback_load = false;
5404 break;
5405 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
5406 DCHECK(!GetCompilerOptions().GetCompilePic());
5407 break;
5408 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
5409 DCHECK(GetCompilerOptions().GetCompilePic());
5410 break;
5411 case HLoadClass::LoadKind::kBootImageAddress:
5412 break;
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005413 case HLoadClass::LoadKind::kBssEntry:
5414 DCHECK(!Runtime::Current()->UseJitCompilation());
5415 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005416 case HLoadClass::LoadKind::kJitTableAddress:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005417 DCHECK(Runtime::Current()->UseJitCompilation());
Alexey Frunze627c1a02017-01-30 19:28:14 -08005418 fallback_load = false;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005419 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005420 case HLoadClass::LoadKind::kDexCacheViaMethod:
5421 fallback_load = false;
5422 break;
5423 }
5424 if (fallback_load) {
5425 desired_class_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
5426 }
5427 return desired_class_load_kind;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01005428}
5429
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005430Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
5431 Register temp) {
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005432 CHECK(!GetInstructionSetFeatures().IsR6());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005433 CHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
5434 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
5435 if (!invoke->GetLocations()->Intrinsified()) {
5436 return location.AsRegister<Register>();
5437 }
5438 // For intrinsics we allow any location, so it may be on the stack.
5439 if (!location.IsRegister()) {
5440 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
5441 return temp;
5442 }
5443 // For register locations, check if the register was saved. If so, get it from the stack.
5444 // Note: There is a chance that the register was saved but not overwritten, so we could
5445 // save one load. However, since this is just an intrinsic slow path we prefer this
5446 // simple and more robust approach rather that trying to determine if that's the case.
5447 SlowPathCode* slow_path = GetCurrentSlowPath();
5448 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
5449 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
5450 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
5451 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
5452 return temp;
5453 }
5454 return location.AsRegister<Register>();
5455}
5456
Vladimir Markodc151b22015-10-15 18:02:30 +01005457HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
5458 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +01005459 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005460 HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info;
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005461 // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005462 // is incompatible with it.
5463 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005464 bool is_r6 = GetInstructionSetFeatures().IsR6();
5465 bool fallback_load = has_irreducible_loops && !is_r6;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005466 switch (dispatch_info.method_load_kind) {
Vladimir Markodc151b22015-10-15 18:02:30 +01005467 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005468 break;
Vladimir Markodc151b22015-10-15 18:02:30 +01005469 default:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005470 fallback_load = false;
Vladimir Markodc151b22015-10-15 18:02:30 +01005471 break;
5472 }
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005473 if (fallback_load) {
5474 dispatch_info.method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
5475 dispatch_info.method_load_data = 0;
5476 }
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005477 return dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01005478}
5479
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005480void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
5481 // All registers are assumed to be correctly set up per the calling convention.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005482 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005483 HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
5484 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005485 bool is_r6 = GetInstructionSetFeatures().IsR6();
5486 Register base_reg = (invoke->HasPcRelativeDexCache() && !is_r6)
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005487 ? GetInvokeStaticOrDirectExtraParameter(invoke, temp.AsRegister<Register>())
5488 : ZERO;
5489
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005490 switch (method_load_kind) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01005491 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005492 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01005493 uint32_t offset =
5494 GetThreadOffset<kMipsPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005495 __ LoadFromOffset(kLoadWord,
5496 temp.AsRegister<Register>(),
5497 TR,
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01005498 offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005499 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01005500 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005501 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00005502 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005503 break;
5504 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
5505 __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
5506 break;
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005507 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
5508 if (is_r6) {
5509 uint32_t offset = invoke->GetDexCacheArrayOffset();
5510 CodeGeneratorMIPS::PcRelativePatchInfo* info =
5511 NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset);
5512 bool reordering = __ SetReorder(false);
5513 EmitPcRelativeAddressPlaceholderHigh(info, TMP, ZERO);
5514 __ Lw(temp.AsRegister<Register>(), TMP, /* placeholder */ 0x5678);
5515 __ SetReorder(reordering);
5516 } else {
5517 HMipsDexCacheArraysBase* base =
5518 invoke->InputAt(invoke->GetSpecialInputIndex())->AsMipsDexCacheArraysBase();
5519 int32_t offset =
5520 invoke->GetDexCacheArrayOffset() - base->GetElementOffset() - kDexCacheArrayLwOffset;
5521 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset);
5522 }
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005523 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005524 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00005525 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005526 Register reg = temp.AsRegister<Register>();
5527 Register method_reg;
5528 if (current_method.IsRegister()) {
5529 method_reg = current_method.AsRegister<Register>();
5530 } else {
5531 // TODO: use the appropriate DCHECK() here if possible.
5532 // DCHECK(invoke->GetLocations()->Intrinsified());
5533 DCHECK(!current_method.IsValid());
5534 method_reg = reg;
5535 __ Lw(reg, SP, kCurrentMethodStackOffset);
5536 }
5537
5538 // temp = temp->dex_cache_resolved_methods_;
5539 __ LoadFromOffset(kLoadWord,
5540 reg,
5541 method_reg,
5542 ArtMethod::DexCacheResolvedMethodsOffset(kMipsPointerSize).Int32Value());
Vladimir Marko40ecb122016-04-06 17:33:41 +01005543 // temp = temp[index_in_cache];
5544 // Note: Don't use invoke->GetTargetMethod() as it may point to a different dex file.
5545 uint32_t index_in_cache = invoke->GetDexMethodIndex();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005546 __ LoadFromOffset(kLoadWord,
5547 reg,
5548 reg,
5549 CodeGenerator::GetCachePointerOffset(index_in_cache));
5550 break;
5551 }
5552 }
5553
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005554 switch (code_ptr_location) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005555 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07005556 __ Bal(&frame_entry_label_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005557 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005558 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
5559 // T9 = callee_method->entry_point_from_quick_compiled_code_;
Goran Jakovljevic1a878372015-10-26 14:28:52 +01005560 __ LoadFromOffset(kLoadWord,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005561 T9,
5562 callee_method.AsRegister<Register>(),
5563 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07005564 kMipsPointerSize).Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005565 // T9()
5566 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005567 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005568 break;
5569 }
5570 DCHECK(!IsLeafMethod());
5571}
5572
5573void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00005574 // Explicit clinit checks triggered by static invokes must have been pruned by
5575 // art::PrepareForRegisterAllocation.
5576 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005577
5578 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
5579 return;
5580 }
5581
5582 LocationSummary* locations = invoke->GetLocations();
5583 codegen_->GenerateStaticOrDirectCall(invoke,
5584 locations->HasTemps()
5585 ? locations->GetTemp(0)
5586 : Location::NoLocation());
5587 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
5588}
5589
Chris Larsen3acee732015-11-18 13:31:08 -08005590void CodeGeneratorMIPS::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
Goran Jakovljevice919b072016-10-04 10:17:34 +02005591 // Use the calling convention instead of the location of the receiver, as
5592 // intrinsics may have put the receiver in a different register. In the intrinsics
5593 // slow path, the arguments have been moved to the right place, so here we are
5594 // guaranteed that the receiver is the first register of the calling convention.
5595 InvokeDexCallingConvention calling_convention;
5596 Register receiver = calling_convention.GetRegisterAt(0);
5597
Chris Larsen3acee732015-11-18 13:31:08 -08005598 Register temp = temp_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005599 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5600 invoke->GetVTableIndex(), kMipsPointerSize).SizeValue();
5601 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07005602 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005603
5604 // temp = object->GetClass();
Goran Jakovljevice919b072016-10-04 10:17:34 +02005605 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Chris Larsen3acee732015-11-18 13:31:08 -08005606 MaybeRecordImplicitNullCheck(invoke);
Alexey Frunzec061de12017-02-14 13:27:23 -08005607 // Instead of simply (possibly) unpoisoning `temp` here, we should
5608 // emit a read barrier for the previous class reference load.
5609 // However this is not required in practice, as this is an
5610 // intermediate/temporary reference and because the current
5611 // concurrent copying collector keeps the from-space memory
5612 // intact/accessible until the end of the marking phase (the
5613 // concurrent copying collector may not in the future).
5614 __ MaybeUnpoisonHeapReference(temp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005615 // temp = temp->GetMethodAt(method_offset);
5616 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
5617 // T9 = temp->GetEntryPoint();
5618 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
5619 // T9();
5620 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07005621 __ NopIfNoReordering();
Chris Larsen3acee732015-11-18 13:31:08 -08005622}
5623
5624void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
5625 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
5626 return;
5627 }
5628
5629 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005630 DCHECK(!codegen_->IsLeafMethod());
5631 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
5632}
5633
5634void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00005635 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5636 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07005637 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko41559982017-01-06 14:04:23 +00005638 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(
Alexey Frunze06a46c42016-07-19 15:00:40 -07005639 cls,
5640 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko41559982017-01-06 14:04:23 +00005641 Location::RegisterLocation(V0));
Alexey Frunze06a46c42016-07-19 15:00:40 -07005642 return;
5643 }
Vladimir Marko41559982017-01-06 14:04:23 +00005644 DCHECK(!cls->NeedsAccessCheck());
Alexey Frunze06a46c42016-07-19 15:00:40 -07005645
5646 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
5647 ? LocationSummary::kCallOnSlowPath
5648 : LocationSummary::kNoCall;
5649 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005650 switch (load_kind) {
5651 // We need an extra register for PC-relative literals on R2.
5652 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005653 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005654 case HLoadClass::LoadKind::kBootImageAddress:
5655 case HLoadClass::LoadKind::kBssEntry:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005656 if (codegen_->GetInstructionSetFeatures().IsR6()) {
5657 break;
5658 }
5659 FALLTHROUGH_INTENDED;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005660 case HLoadClass::LoadKind::kReferrersClass:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005661 locations->SetInAt(0, Location::RequiresRegister());
5662 break;
5663 default:
5664 break;
5665 }
5666 locations->SetOut(Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005667}
5668
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005669// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5670// move.
5671void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00005672 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
5673 if (load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) {
5674 codegen_->GenerateLoadClassRuntimeCall(cls);
Pavle Batutae87a7182015-10-28 13:10:42 +01005675 return;
5676 }
Vladimir Marko41559982017-01-06 14:04:23 +00005677 DCHECK(!cls->NeedsAccessCheck());
Pavle Batutae87a7182015-10-28 13:10:42 +01005678
Vladimir Marko41559982017-01-06 14:04:23 +00005679 LocationSummary* locations = cls->GetLocations();
Alexey Frunze06a46c42016-07-19 15:00:40 -07005680 Location out_loc = locations->Out();
5681 Register out = out_loc.AsRegister<Register>();
5682 Register base_or_current_method_reg;
5683 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
5684 switch (load_kind) {
5685 // We need an extra register for PC-relative literals on R2.
5686 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005687 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005688 case HLoadClass::LoadKind::kBootImageAddress:
5689 case HLoadClass::LoadKind::kBssEntry:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005690 base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
5691 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005692 case HLoadClass::LoadKind::kReferrersClass:
5693 case HLoadClass::LoadKind::kDexCacheViaMethod:
5694 base_or_current_method_reg = locations->InAt(0).AsRegister<Register>();
5695 break;
5696 default:
5697 base_or_current_method_reg = ZERO;
5698 break;
5699 }
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00005700
Alexey Frunze06a46c42016-07-19 15:00:40 -07005701 bool generate_null_check = false;
5702 switch (load_kind) {
5703 case HLoadClass::LoadKind::kReferrersClass: {
5704 DCHECK(!cls->CanCallRuntime());
5705 DCHECK(!cls->MustGenerateClinitCheck());
5706 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
5707 GenerateGcRootFieldLoad(cls,
5708 out_loc,
5709 base_or_current_method_reg,
5710 ArtMethod::DeclaringClassOffset().Int32Value());
5711 break;
5712 }
5713 case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005714 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze06a46c42016-07-19 15:00:40 -07005715 __ LoadLiteral(out,
5716 base_or_current_method_reg,
5717 codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
5718 cls->GetTypeIndex()));
5719 break;
5720 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005721 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze06a46c42016-07-19 15:00:40 -07005722 CodeGeneratorMIPS::PcRelativePatchInfo* info =
5723 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005724 bool reordering = __ SetReorder(false);
5725 codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
5726 __ Addiu(out, out, /* placeholder */ 0x5678);
5727 __ SetReorder(reordering);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005728 break;
5729 }
5730 case HLoadClass::LoadKind::kBootImageAddress: {
5731 DCHECK(!kEmitCompilerReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00005732 uint32_t address = dchecked_integral_cast<uint32_t>(
5733 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
5734 DCHECK_NE(address, 0u);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005735 __ LoadLiteral(out,
5736 base_or_current_method_reg,
5737 codegen_->DeduplicateBootImageAddressLiteral(address));
5738 break;
5739 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005740 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005741 CodeGeneratorMIPS::PcRelativePatchInfo* info =
Vladimir Marko1998cd02017-01-13 13:02:58 +00005742 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005743 bool reordering = __ SetReorder(false);
5744 codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
Alexey Frunzec061de12017-02-14 13:27:23 -08005745 GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678);
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005746 __ SetReorder(reordering);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005747 generate_null_check = true;
5748 break;
5749 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00005750 case HLoadClass::LoadKind::kJitTableAddress: {
Alexey Frunze627c1a02017-01-30 19:28:14 -08005751 CodeGeneratorMIPS::JitPatchInfo* info = codegen_->NewJitRootClassPatch(cls->GetDexFile(),
5752 cls->GetTypeIndex(),
5753 cls->GetClass());
5754 bool reordering = __ SetReorder(false);
5755 __ Bind(&info->high_label);
5756 __ Lui(out, /* placeholder */ 0x1234);
5757 GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678);
5758 __ SetReorder(reordering);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005759 break;
5760 }
Vladimir Marko41559982017-01-06 14:04:23 +00005761 case HLoadClass::LoadKind::kDexCacheViaMethod:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00005762 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00005763 LOG(FATAL) << "UNREACHABLE";
5764 UNREACHABLE();
Alexey Frunze06a46c42016-07-19 15:00:40 -07005765 }
5766
5767 if (generate_null_check || cls->MustGenerateClinitCheck()) {
5768 DCHECK(cls->CanCallRuntime());
5769 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
5770 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5771 codegen_->AddSlowPath(slow_path);
5772 if (generate_null_check) {
5773 __ Beqz(out, slow_path->GetEntryLabel());
5774 }
5775 if (cls->MustGenerateClinitCheck()) {
5776 GenerateClassInitializationCheck(slow_path, out);
5777 } else {
5778 __ Bind(slow_path->GetExitLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005779 }
5780 }
5781}
5782
5783static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07005784 return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005785}
5786
5787void LocationsBuilderMIPS::VisitLoadException(HLoadException* load) {
5788 LocationSummary* locations =
5789 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5790 locations->SetOut(Location::RequiresRegister());
5791}
5792
5793void InstructionCodeGeneratorMIPS::VisitLoadException(HLoadException* load) {
5794 Register out = load->GetLocations()->Out().AsRegister<Register>();
5795 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
5796}
5797
5798void LocationsBuilderMIPS::VisitClearException(HClearException* clear) {
5799 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5800}
5801
5802void InstructionCodeGeneratorMIPS::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5803 __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
5804}
5805
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005806void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
Alexey Frunzef63f5692016-12-13 17:43:11 -08005807 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005808 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005809 HLoadString::LoadKind load_kind = load->GetLoadKind();
5810 switch (load_kind) {
5811 // We need an extra register for PC-relative literals on R2.
5812 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5813 case HLoadString::LoadKind::kBootImageAddress:
5814 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoaad75c62016-10-03 08:46:48 +00005815 case HLoadString::LoadKind::kBssEntry:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005816 if (codegen_->GetInstructionSetFeatures().IsR6()) {
5817 break;
5818 }
5819 FALLTHROUGH_INTENDED;
5820 // We need an extra register for PC-relative dex cache accesses.
Alexey Frunze06a46c42016-07-19 15:00:40 -07005821 case HLoadString::LoadKind::kDexCacheViaMethod:
5822 locations->SetInAt(0, Location::RequiresRegister());
5823 break;
5824 default:
5825 break;
5826 }
Alexey Frunzebb51df82016-11-01 16:07:32 -07005827 if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
5828 InvokeRuntimeCallingConvention calling_convention;
5829 locations->SetOut(calling_convention.GetReturnLocation(load->GetType()));
5830 } else {
5831 locations->SetOut(Location::RequiresRegister());
5832 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005833}
5834
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005835// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
5836// move.
5837void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Alexey Frunze06a46c42016-07-19 15:00:40 -07005838 HLoadString::LoadKind load_kind = load->GetLoadKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005839 LocationSummary* locations = load->GetLocations();
Alexey Frunze06a46c42016-07-19 15:00:40 -07005840 Location out_loc = locations->Out();
5841 Register out = out_loc.AsRegister<Register>();
5842 Register base_or_current_method_reg;
5843 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
5844 switch (load_kind) {
5845 // We need an extra register for PC-relative literals on R2.
5846 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
5847 case HLoadString::LoadKind::kBootImageAddress:
5848 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoaad75c62016-10-03 08:46:48 +00005849 case HLoadString::LoadKind::kBssEntry:
Alexey Frunze06a46c42016-07-19 15:00:40 -07005850 base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
5851 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005852 default:
5853 base_or_current_method_reg = ZERO;
5854 break;
5855 }
5856
5857 switch (load_kind) {
5858 case HLoadString::LoadKind::kBootImageLinkTimeAddress:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005859 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze06a46c42016-07-19 15:00:40 -07005860 __ LoadLiteral(out,
5861 base_or_current_method_reg,
5862 codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
5863 load->GetStringIndex()));
5864 return; // No dex cache slow path.
5865 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00005866 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze06a46c42016-07-19 15:00:40 -07005867 CodeGeneratorMIPS::PcRelativePatchInfo* info =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005868 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005869 bool reordering = __ SetReorder(false);
5870 codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
5871 __ Addiu(out, out, /* placeholder */ 0x5678);
5872 __ SetReorder(reordering);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005873 return; // No dex cache slow path.
5874 }
5875 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00005876 uint32_t address = dchecked_integral_cast<uint32_t>(
5877 reinterpret_cast<uintptr_t>(load->GetString().Get()));
5878 DCHECK_NE(address, 0u);
Alexey Frunze06a46c42016-07-19 15:00:40 -07005879 __ LoadLiteral(out,
5880 base_or_current_method_reg,
5881 codegen_->DeduplicateBootImageAddressLiteral(address));
5882 return; // No dex cache slow path.
5883 }
Vladimir Markoaad75c62016-10-03 08:46:48 +00005884 case HLoadString::LoadKind::kBssEntry: {
5885 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
5886 CodeGeneratorMIPS::PcRelativePatchInfo* info =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00005887 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005888 bool reordering = __ SetReorder(false);
5889 codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
Alexey Frunzec061de12017-02-14 13:27:23 -08005890 GenerateGcRootFieldLoad(load, out_loc, out, /* placeholder */ 0x5678);
Alexey Frunze6b892cd2017-01-03 17:11:38 -08005891 __ SetReorder(reordering);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005892 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
5893 codegen_->AddSlowPath(slow_path);
5894 __ Beqz(out, slow_path->GetEntryLabel());
5895 __ Bind(slow_path->GetExitLabel());
5896 return;
5897 }
Alexey Frunze627c1a02017-01-30 19:28:14 -08005898 case HLoadString::LoadKind::kJitTableAddress: {
5899 CodeGeneratorMIPS::JitPatchInfo* info =
5900 codegen_->NewJitRootStringPatch(load->GetDexFile(),
5901 load->GetStringIndex(),
5902 load->GetString());
5903 bool reordering = __ SetReorder(false);
5904 __ Bind(&info->high_label);
5905 __ Lui(out, /* placeholder */ 0x1234);
5906 GenerateGcRootFieldLoad(load, out_loc, out, /* placeholder */ 0x5678);
5907 __ SetReorder(reordering);
5908 return;
5909 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07005910 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07005911 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07005912 }
Nicolas Geoffray917d0162015-11-24 18:25:35 +00005913
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07005914 // TODO: Re-add the compiler code to do string dex cache lookup again.
Vladimir Markoaad75c62016-10-03 08:46:48 +00005915 DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
5916 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe8a0128a2016-11-28 07:38:35 -08005917 __ LoadConst32(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +00005918 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
5919 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005920}
5921
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005922void LocationsBuilderMIPS::VisitLongConstant(HLongConstant* constant) {
5923 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
5924 locations->SetOut(Location::ConstantLocation(constant));
5925}
5926
5927void InstructionCodeGeneratorMIPS::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
5928 // Will be generated at use site.
5929}
5930
5931void LocationsBuilderMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
5932 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01005933 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005934 InvokeRuntimeCallingConvention calling_convention;
5935 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5936}
5937
5938void InstructionCodeGeneratorMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
5939 if (instruction->IsEnter()) {
Serban Constantinescufca16662016-07-14 09:21:59 +01005940 codegen_->InvokeRuntime(kQuickLockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005941 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
5942 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01005943 codegen_->InvokeRuntime(kQuickUnlockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005944 }
5945 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
5946}
5947
5948void LocationsBuilderMIPS::VisitMul(HMul* mul) {
5949 LocationSummary* locations =
5950 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
5951 switch (mul->GetResultType()) {
5952 case Primitive::kPrimInt:
5953 case Primitive::kPrimLong:
5954 locations->SetInAt(0, Location::RequiresRegister());
5955 locations->SetInAt(1, Location::RequiresRegister());
5956 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5957 break;
5958
5959 case Primitive::kPrimFloat:
5960 case Primitive::kPrimDouble:
5961 locations->SetInAt(0, Location::RequiresFpuRegister());
5962 locations->SetInAt(1, Location::RequiresFpuRegister());
5963 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
5964 break;
5965
5966 default:
5967 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
5968 }
5969}
5970
5971void InstructionCodeGeneratorMIPS::VisitMul(HMul* instruction) {
5972 Primitive::Type type = instruction->GetType();
5973 LocationSummary* locations = instruction->GetLocations();
5974 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
5975
5976 switch (type) {
5977 case Primitive::kPrimInt: {
5978 Register dst = locations->Out().AsRegister<Register>();
5979 Register lhs = locations->InAt(0).AsRegister<Register>();
5980 Register rhs = locations->InAt(1).AsRegister<Register>();
5981
5982 if (isR6) {
5983 __ MulR6(dst, lhs, rhs);
5984 } else {
5985 __ MulR2(dst, lhs, rhs);
5986 }
5987 break;
5988 }
5989 case Primitive::kPrimLong: {
5990 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
5991 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
5992 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
5993 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
5994 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
5995 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
5996
5997 // Extra checks to protect caused by the existance of A1_A2.
5998 // The algorithm is wrong if dst_high is either lhs_lo or rhs_lo:
5999 // (e.g. lhs=a0_a1, rhs=a2_a3 and dst=a1_a2).
6000 DCHECK_NE(dst_high, lhs_low);
6001 DCHECK_NE(dst_high, rhs_low);
6002
6003 // A_B * C_D
6004 // dst_hi: [ low(A*D) + low(B*C) + hi(B*D) ]
6005 // dst_lo: [ low(B*D) ]
6006 // Note: R2 and R6 MUL produce the low 32 bit of the multiplication result.
6007
6008 if (isR6) {
6009 __ MulR6(TMP, lhs_high, rhs_low);
6010 __ MulR6(dst_high, lhs_low, rhs_high);
6011 __ Addu(dst_high, dst_high, TMP);
6012 __ MuhuR6(TMP, lhs_low, rhs_low);
6013 __ Addu(dst_high, dst_high, TMP);
6014 __ MulR6(dst_low, lhs_low, rhs_low);
6015 } else {
6016 __ MulR2(TMP, lhs_high, rhs_low);
6017 __ MulR2(dst_high, lhs_low, rhs_high);
6018 __ Addu(dst_high, dst_high, TMP);
6019 __ MultuR2(lhs_low, rhs_low);
6020 __ Mfhi(TMP);
6021 __ Addu(dst_high, dst_high, TMP);
6022 __ Mflo(dst_low);
6023 }
6024 break;
6025 }
6026 case Primitive::kPrimFloat:
6027 case Primitive::kPrimDouble: {
6028 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
6029 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
6030 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
6031 if (type == Primitive::kPrimFloat) {
6032 __ MulS(dst, lhs, rhs);
6033 } else {
6034 __ MulD(dst, lhs, rhs);
6035 }
6036 break;
6037 }
6038 default:
6039 LOG(FATAL) << "Unexpected mul type " << type;
6040 }
6041}
6042
6043void LocationsBuilderMIPS::VisitNeg(HNeg* neg) {
6044 LocationSummary* locations =
6045 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
6046 switch (neg->GetResultType()) {
6047 case Primitive::kPrimInt:
6048 case Primitive::kPrimLong:
6049 locations->SetInAt(0, Location::RequiresRegister());
6050 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6051 break;
6052
6053 case Primitive::kPrimFloat:
6054 case Primitive::kPrimDouble:
6055 locations->SetInAt(0, Location::RequiresFpuRegister());
6056 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6057 break;
6058
6059 default:
6060 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
6061 }
6062}
6063
6064void InstructionCodeGeneratorMIPS::VisitNeg(HNeg* instruction) {
6065 Primitive::Type type = instruction->GetType();
6066 LocationSummary* locations = instruction->GetLocations();
6067
6068 switch (type) {
6069 case Primitive::kPrimInt: {
6070 Register dst = locations->Out().AsRegister<Register>();
6071 Register src = locations->InAt(0).AsRegister<Register>();
6072 __ Subu(dst, ZERO, src);
6073 break;
6074 }
6075 case Primitive::kPrimLong: {
6076 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
6077 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
6078 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
6079 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
6080 __ Subu(dst_low, ZERO, src_low);
6081 __ Sltu(TMP, ZERO, dst_low);
6082 __ Subu(dst_high, ZERO, src_high);
6083 __ Subu(dst_high, dst_high, TMP);
6084 break;
6085 }
6086 case Primitive::kPrimFloat:
6087 case Primitive::kPrimDouble: {
6088 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
6089 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
6090 if (type == Primitive::kPrimFloat) {
6091 __ NegS(dst, src);
6092 } else {
6093 __ NegD(dst, src);
6094 }
6095 break;
6096 }
6097 default:
6098 LOG(FATAL) << "Unexpected neg type " << type;
6099 }
6100}
6101
6102void LocationsBuilderMIPS::VisitNewArray(HNewArray* instruction) {
6103 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006104 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006105 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006106 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00006107 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6108 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006109}
6110
6111void InstructionCodeGeneratorMIPS::VisitNewArray(HNewArray* instruction) {
Alexey Frunzec061de12017-02-14 13:27:23 -08006112 // Note: if heap poisoning is enabled, the entry point takes care
6113 // of poisoning the reference.
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00006114 codegen_->InvokeRuntime(kQuickAllocArrayResolved, instruction, instruction->GetDexPc());
6115 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006116}
6117
6118void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) {
6119 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006120 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006121 InvokeRuntimeCallingConvention calling_convention;
David Brazdil6de19382016-01-08 17:37:10 +00006122 if (instruction->IsStringAlloc()) {
6123 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
6124 } else {
6125 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00006126 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006127 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
6128}
6129
6130void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) {
Alexey Frunzec061de12017-02-14 13:27:23 -08006131 // Note: if heap poisoning is enabled, the entry point takes care
6132 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00006133 if (instruction->IsStringAlloc()) {
6134 // String is allocated through StringFactory. Call NewEmptyString entry point.
6135 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07006136 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00006137 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
6138 __ LoadFromOffset(kLoadWord, T9, temp, code_offset.Int32Value());
6139 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07006140 __ NopIfNoReordering();
David Brazdil6de19382016-01-08 17:37:10 +00006141 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
6142 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01006143 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00006144 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00006145 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006146}
6147
6148void LocationsBuilderMIPS::VisitNot(HNot* instruction) {
6149 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
6150 locations->SetInAt(0, Location::RequiresRegister());
6151 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6152}
6153
6154void InstructionCodeGeneratorMIPS::VisitNot(HNot* instruction) {
6155 Primitive::Type type = instruction->GetType();
6156 LocationSummary* locations = instruction->GetLocations();
6157
6158 switch (type) {
6159 case Primitive::kPrimInt: {
6160 Register dst = locations->Out().AsRegister<Register>();
6161 Register src = locations->InAt(0).AsRegister<Register>();
6162 __ Nor(dst, src, ZERO);
6163 break;
6164 }
6165
6166 case Primitive::kPrimLong: {
6167 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
6168 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
6169 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
6170 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
6171 __ Nor(dst_high, src_high, ZERO);
6172 __ Nor(dst_low, src_low, ZERO);
6173 break;
6174 }
6175
6176 default:
6177 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
6178 }
6179}
6180
6181void LocationsBuilderMIPS::VisitBooleanNot(HBooleanNot* instruction) {
6182 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
6183 locations->SetInAt(0, Location::RequiresRegister());
6184 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6185}
6186
6187void InstructionCodeGeneratorMIPS::VisitBooleanNot(HBooleanNot* instruction) {
6188 LocationSummary* locations = instruction->GetLocations();
6189 __ Xori(locations->Out().AsRegister<Register>(),
6190 locations->InAt(0).AsRegister<Register>(),
6191 1);
6192}
6193
6194void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01006195 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
6196 locations->SetInAt(0, Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006197}
6198
Calin Juravle2ae48182016-03-16 14:05:09 +00006199void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
6200 if (CanMoveNullCheckToUser(instruction)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006201 return;
6202 }
6203 Location obj = instruction->GetLocations()->InAt(0);
6204
6205 __ Lw(ZERO, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00006206 RecordPcInfo(instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006207}
6208
Calin Juravle2ae48182016-03-16 14:05:09 +00006209void CodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006210 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathMIPS(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00006211 AddSlowPath(slow_path);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006212
6213 Location obj = instruction->GetLocations()->InAt(0);
6214
6215 __ Beqz(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
6216}
6217
6218void InstructionCodeGeneratorMIPS::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00006219 codegen_->GenerateNullCheck(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006220}
6221
6222void LocationsBuilderMIPS::VisitOr(HOr* instruction) {
6223 HandleBinaryOp(instruction);
6224}
6225
6226void InstructionCodeGeneratorMIPS::VisitOr(HOr* instruction) {
6227 HandleBinaryOp(instruction);
6228}
6229
6230void LocationsBuilderMIPS::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
6231 LOG(FATAL) << "Unreachable";
6232}
6233
6234void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) {
6235 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
6236}
6237
6238void LocationsBuilderMIPS::VisitParameterValue(HParameterValue* instruction) {
6239 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
6240 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
6241 if (location.IsStackSlot()) {
6242 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
6243 } else if (location.IsDoubleStackSlot()) {
6244 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
6245 }
6246 locations->SetOut(location);
6247}
6248
6249void InstructionCodeGeneratorMIPS::VisitParameterValue(HParameterValue* instruction
6250 ATTRIBUTE_UNUSED) {
6251 // Nothing to do, the parameter is already at its location.
6252}
6253
6254void LocationsBuilderMIPS::VisitCurrentMethod(HCurrentMethod* instruction) {
6255 LocationSummary* locations =
6256 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
6257 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
6258}
6259
6260void InstructionCodeGeneratorMIPS::VisitCurrentMethod(HCurrentMethod* instruction
6261 ATTRIBUTE_UNUSED) {
6262 // Nothing to do, the method is already at its location.
6263}
6264
6265void LocationsBuilderMIPS::VisitPhi(HPhi* instruction) {
6266 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Vladimir Marko372f10e2016-05-17 16:30:10 +01006267 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006268 locations->SetInAt(i, Location::Any());
6269 }
6270 locations->SetOut(Location::Any());
6271}
6272
6273void InstructionCodeGeneratorMIPS::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
6274 LOG(FATAL) << "Unreachable";
6275}
6276
6277void LocationsBuilderMIPS::VisitRem(HRem* rem) {
6278 Primitive::Type type = rem->GetResultType();
6279 LocationSummary::CallKind call_kind =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006280 (type == Primitive::kPrimInt) ? LocationSummary::kNoCall : LocationSummary::kCallOnMainOnly;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006281 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
6282
6283 switch (type) {
6284 case Primitive::kPrimInt:
6285 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08006286 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006287 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6288 break;
6289
6290 case Primitive::kPrimLong: {
6291 InvokeRuntimeCallingConvention calling_convention;
6292 locations->SetInAt(0, Location::RegisterPairLocation(
6293 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
6294 locations->SetInAt(1, Location::RegisterPairLocation(
6295 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
6296 locations->SetOut(calling_convention.GetReturnLocation(type));
6297 break;
6298 }
6299
6300 case Primitive::kPrimFloat:
6301 case Primitive::kPrimDouble: {
6302 InvokeRuntimeCallingConvention calling_convention;
6303 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
6304 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
6305 locations->SetOut(calling_convention.GetReturnLocation(type));
6306 break;
6307 }
6308
6309 default:
6310 LOG(FATAL) << "Unexpected rem type " << type;
6311 }
6312}
6313
6314void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) {
6315 Primitive::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006316
6317 switch (type) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08006318 case Primitive::kPrimInt:
6319 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006320 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006321 case Primitive::kPrimLong: {
Serban Constantinescufca16662016-07-14 09:21:59 +01006322 codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006323 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
6324 break;
6325 }
6326 case Primitive::kPrimFloat: {
Serban Constantinescufca16662016-07-14 09:21:59 +01006327 codegen_->InvokeRuntime(kQuickFmodf, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006328 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006329 break;
6330 }
6331 case Primitive::kPrimDouble: {
Serban Constantinescufca16662016-07-14 09:21:59 +01006332 codegen_->InvokeRuntime(kQuickFmod, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00006333 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006334 break;
6335 }
6336 default:
6337 LOG(FATAL) << "Unexpected rem type " << type;
6338 }
6339}
6340
6341void LocationsBuilderMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
6342 memory_barrier->SetLocations(nullptr);
6343}
6344
6345void InstructionCodeGeneratorMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
6346 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
6347}
6348
6349void LocationsBuilderMIPS::VisitReturn(HReturn* ret) {
6350 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
6351 Primitive::Type return_type = ret->InputAt(0)->GetType();
6352 locations->SetInAt(0, MipsReturnLocation(return_type));
6353}
6354
6355void InstructionCodeGeneratorMIPS::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
6356 codegen_->GenerateFrameExit();
6357}
6358
6359void LocationsBuilderMIPS::VisitReturnVoid(HReturnVoid* ret) {
6360 ret->SetLocations(nullptr);
6361}
6362
6363void InstructionCodeGeneratorMIPS::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
6364 codegen_->GenerateFrameExit();
6365}
6366
Alexey Frunze92d90602015-12-18 18:16:36 -08006367void LocationsBuilderMIPS::VisitRor(HRor* ror) {
6368 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00006369}
6370
Alexey Frunze92d90602015-12-18 18:16:36 -08006371void InstructionCodeGeneratorMIPS::VisitRor(HRor* ror) {
6372 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00006373}
6374
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006375void LocationsBuilderMIPS::VisitShl(HShl* shl) {
6376 HandleShift(shl);
6377}
6378
6379void InstructionCodeGeneratorMIPS::VisitShl(HShl* shl) {
6380 HandleShift(shl);
6381}
6382
6383void LocationsBuilderMIPS::VisitShr(HShr* shr) {
6384 HandleShift(shr);
6385}
6386
6387void InstructionCodeGeneratorMIPS::VisitShr(HShr* shr) {
6388 HandleShift(shr);
6389}
6390
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006391void LocationsBuilderMIPS::VisitSub(HSub* instruction) {
6392 HandleBinaryOp(instruction);
6393}
6394
6395void InstructionCodeGeneratorMIPS::VisitSub(HSub* instruction) {
6396 HandleBinaryOp(instruction);
6397}
6398
6399void LocationsBuilderMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6400 HandleFieldGet(instruction, instruction->GetFieldInfo());
6401}
6402
6403void InstructionCodeGeneratorMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
6404 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
6405}
6406
6407void LocationsBuilderMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
6408 HandleFieldSet(instruction, instruction->GetFieldInfo());
6409}
6410
6411void InstructionCodeGeneratorMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01006412 HandleFieldSet(instruction,
6413 instruction->GetFieldInfo(),
6414 instruction->GetDexPc(),
6415 instruction->GetValueCanBeNull());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006416}
6417
6418void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldGet(
6419 HUnresolvedInstanceFieldGet* instruction) {
6420 FieldAccessCallingConventionMIPS calling_convention;
6421 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
6422 instruction->GetFieldType(),
6423 calling_convention);
6424}
6425
6426void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldGet(
6427 HUnresolvedInstanceFieldGet* instruction) {
6428 FieldAccessCallingConventionMIPS calling_convention;
6429 codegen_->GenerateUnresolvedFieldAccess(instruction,
6430 instruction->GetFieldType(),
6431 instruction->GetFieldIndex(),
6432 instruction->GetDexPc(),
6433 calling_convention);
6434}
6435
6436void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldSet(
6437 HUnresolvedInstanceFieldSet* instruction) {
6438 FieldAccessCallingConventionMIPS calling_convention;
6439 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
6440 instruction->GetFieldType(),
6441 calling_convention);
6442}
6443
6444void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldSet(
6445 HUnresolvedInstanceFieldSet* instruction) {
6446 FieldAccessCallingConventionMIPS calling_convention;
6447 codegen_->GenerateUnresolvedFieldAccess(instruction,
6448 instruction->GetFieldType(),
6449 instruction->GetFieldIndex(),
6450 instruction->GetDexPc(),
6451 calling_convention);
6452}
6453
6454void LocationsBuilderMIPS::VisitUnresolvedStaticFieldGet(
6455 HUnresolvedStaticFieldGet* instruction) {
6456 FieldAccessCallingConventionMIPS calling_convention;
6457 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
6458 instruction->GetFieldType(),
6459 calling_convention);
6460}
6461
6462void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldGet(
6463 HUnresolvedStaticFieldGet* instruction) {
6464 FieldAccessCallingConventionMIPS calling_convention;
6465 codegen_->GenerateUnresolvedFieldAccess(instruction,
6466 instruction->GetFieldType(),
6467 instruction->GetFieldIndex(),
6468 instruction->GetDexPc(),
6469 calling_convention);
6470}
6471
6472void LocationsBuilderMIPS::VisitUnresolvedStaticFieldSet(
6473 HUnresolvedStaticFieldSet* instruction) {
6474 FieldAccessCallingConventionMIPS calling_convention;
6475 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
6476 instruction->GetFieldType(),
6477 calling_convention);
6478}
6479
6480void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldSet(
6481 HUnresolvedStaticFieldSet* instruction) {
6482 FieldAccessCallingConventionMIPS calling_convention;
6483 codegen_->GenerateUnresolvedFieldAccess(instruction,
6484 instruction->GetFieldType(),
6485 instruction->GetFieldIndex(),
6486 instruction->GetDexPc(),
6487 calling_convention);
6488}
6489
6490void LocationsBuilderMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Marko70e97462016-08-09 11:04:26 +01006491 LocationSummary* locations =
6492 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
Vladimir Marko804b03f2016-09-14 16:26:36 +01006493 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006494}
6495
6496void InstructionCodeGeneratorMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
6497 HBasicBlock* block = instruction->GetBlock();
6498 if (block->GetLoopInformation() != nullptr) {
6499 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
6500 // The back edge will generate the suspend check.
6501 return;
6502 }
6503 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
6504 // The goto will generate the suspend check.
6505 return;
6506 }
6507 GenerateSuspendCheck(instruction, nullptr);
6508}
6509
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006510void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
6511 LocationSummary* locations =
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006512 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006513 InvokeRuntimeCallingConvention calling_convention;
6514 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
6515}
6516
6517void InstructionCodeGeneratorMIPS::VisitThrow(HThrow* instruction) {
Serban Constantinescufca16662016-07-14 09:21:59 +01006518 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006519 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
6520}
6521
6522void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
6523 Primitive::Type input_type = conversion->GetInputType();
6524 Primitive::Type result_type = conversion->GetResultType();
6525 DCHECK_NE(input_type, result_type);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006526 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006527
6528 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
6529 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
6530 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
6531 }
6532
6533 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006534 if (!isR6 &&
6535 ((Primitive::IsFloatingPointType(result_type) && input_type == Primitive::kPrimLong) ||
6536 (result_type == Primitive::kPrimLong && Primitive::IsFloatingPointType(input_type)))) {
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006537 call_kind = LocationSummary::kCallOnMainOnly;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006538 }
6539
6540 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
6541
6542 if (call_kind == LocationSummary::kNoCall) {
6543 if (Primitive::IsFloatingPointType(input_type)) {
6544 locations->SetInAt(0, Location::RequiresFpuRegister());
6545 } else {
6546 locations->SetInAt(0, Location::RequiresRegister());
6547 }
6548
6549 if (Primitive::IsFloatingPointType(result_type)) {
6550 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
6551 } else {
6552 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
6553 }
6554 } else {
6555 InvokeRuntimeCallingConvention calling_convention;
6556
6557 if (Primitive::IsFloatingPointType(input_type)) {
6558 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
6559 } else {
6560 DCHECK_EQ(input_type, Primitive::kPrimLong);
6561 locations->SetInAt(0, Location::RegisterPairLocation(
6562 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
6563 }
6564
6565 locations->SetOut(calling_convention.GetReturnLocation(result_type));
6566 }
6567}
6568
6569void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversion) {
6570 LocationSummary* locations = conversion->GetLocations();
6571 Primitive::Type result_type = conversion->GetResultType();
6572 Primitive::Type input_type = conversion->GetInputType();
6573 bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006574 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006575
6576 DCHECK_NE(input_type, result_type);
6577
6578 if (result_type == Primitive::kPrimLong && Primitive::IsIntegralType(input_type)) {
6579 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
6580 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
6581 Register src = locations->InAt(0).AsRegister<Register>();
6582
Alexey Frunzea871ef12016-06-27 15:20:11 -07006583 if (dst_low != src) {
6584 __ Move(dst_low, src);
6585 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006586 __ Sra(dst_high, src, 31);
6587 } else if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
6588 Register dst = locations->Out().AsRegister<Register>();
6589 Register src = (input_type == Primitive::kPrimLong)
6590 ? locations->InAt(0).AsRegisterPairLow<Register>()
6591 : locations->InAt(0).AsRegister<Register>();
6592
6593 switch (result_type) {
6594 case Primitive::kPrimChar:
6595 __ Andi(dst, src, 0xFFFF);
6596 break;
6597 case Primitive::kPrimByte:
6598 if (has_sign_extension) {
6599 __ Seb(dst, src);
6600 } else {
6601 __ Sll(dst, src, 24);
6602 __ Sra(dst, dst, 24);
6603 }
6604 break;
6605 case Primitive::kPrimShort:
6606 if (has_sign_extension) {
6607 __ Seh(dst, src);
6608 } else {
6609 __ Sll(dst, src, 16);
6610 __ Sra(dst, dst, 16);
6611 }
6612 break;
6613 case Primitive::kPrimInt:
Alexey Frunzea871ef12016-06-27 15:20:11 -07006614 if (dst != src) {
6615 __ Move(dst, src);
6616 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006617 break;
6618
6619 default:
6620 LOG(FATAL) << "Unexpected type conversion from " << input_type
6621 << " to " << result_type;
6622 }
6623 } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006624 if (input_type == Primitive::kPrimLong) {
6625 if (isR6) {
6626 // cvt.s.l/cvt.d.l requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
6627 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
6628 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
6629 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
6630 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
6631 __ Mtc1(src_low, FTMP);
6632 __ Mthc1(src_high, FTMP);
6633 if (result_type == Primitive::kPrimFloat) {
6634 __ Cvtsl(dst, FTMP);
6635 } else {
6636 __ Cvtdl(dst, FTMP);
6637 }
6638 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01006639 QuickEntrypointEnum entrypoint = (result_type == Primitive::kPrimFloat) ? kQuickL2f
6640 : kQuickL2d;
6641 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006642 if (result_type == Primitive::kPrimFloat) {
6643 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
6644 } else {
6645 CheckEntrypointTypes<kQuickL2d, double, int64_t>();
6646 }
6647 }
6648 } else {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006649 Register src = locations->InAt(0).AsRegister<Register>();
6650 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
6651 __ Mtc1(src, FTMP);
6652 if (result_type == Primitive::kPrimFloat) {
6653 __ Cvtsw(dst, FTMP);
6654 } else {
6655 __ Cvtdw(dst, FTMP);
6656 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006657 }
6658 } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
6659 CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006660 if (result_type == Primitive::kPrimLong) {
6661 if (isR6) {
6662 // trunc.l.s/trunc.l.d requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
6663 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
6664 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
6665 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
6666 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
6667 MipsLabel truncate;
6668 MipsLabel done;
6669
6670 // When NAN2008=0 (R2 and before), the truncate instruction produces the maximum positive
6671 // value when the input is either a NaN or is outside of the range of the output type
6672 // after the truncation. IOW, the three special cases (NaN, too small, too big) produce
6673 // the same result.
6674 //
6675 // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
6676 // value of the output type if the input is outside of the range after the truncation or
6677 // produces 0 when the input is a NaN. IOW, the three special cases produce three distinct
6678 // results. This matches the desired float/double-to-int/long conversion exactly.
6679 //
6680 // So, NAN2008 affects handling of negative values and NaNs by the truncate instruction.
6681 //
6682 // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
6683 // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
6684 // even though it must be NAN2008=1 on R6.
6685 //
6686 // The code takes care of the different behaviors by first comparing the input to the
6687 // minimum output value (-2**-63 for truncating to long, -2**-31 for truncating to int).
6688 // If the input is greater than or equal to the minimum, it procedes to the truncate
6689 // instruction, which will handle such an input the same way irrespective of NAN2008.
6690 // Otherwise the input is compared to itself to determine whether it is a NaN or not
6691 // in order to return either zero or the minimum value.
6692 //
6693 // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
6694 // truncate instruction for MIPS64R6.
6695 if (input_type == Primitive::kPrimFloat) {
6696 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int64_t>::min());
6697 __ LoadConst32(TMP, min_val);
6698 __ Mtc1(TMP, FTMP);
6699 __ CmpLeS(FTMP, FTMP, src);
6700 } else {
6701 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int64_t>::min());
6702 __ LoadConst32(TMP, High32Bits(min_val));
6703 __ Mtc1(ZERO, FTMP);
6704 __ Mthc1(TMP, FTMP);
6705 __ CmpLeD(FTMP, FTMP, src);
6706 }
6707
6708 __ Bc1nez(FTMP, &truncate);
6709
6710 if (input_type == Primitive::kPrimFloat) {
6711 __ CmpEqS(FTMP, src, src);
6712 } else {
6713 __ CmpEqD(FTMP, src, src);
6714 }
6715 __ Move(dst_low, ZERO);
6716 __ LoadConst32(dst_high, std::numeric_limits<int32_t>::min());
6717 __ Mfc1(TMP, FTMP);
6718 __ And(dst_high, dst_high, TMP);
6719
6720 __ B(&done);
6721
6722 __ Bind(&truncate);
6723
6724 if (input_type == Primitive::kPrimFloat) {
6725 __ TruncLS(FTMP, src);
6726 } else {
6727 __ TruncLD(FTMP, src);
6728 }
6729 __ Mfc1(dst_low, FTMP);
6730 __ Mfhc1(dst_high, FTMP);
6731
6732 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006733 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01006734 QuickEntrypointEnum entrypoint = (input_type == Primitive::kPrimFloat) ? kQuickF2l
6735 : kQuickD2l;
6736 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006737 if (input_type == Primitive::kPrimFloat) {
6738 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
6739 } else {
6740 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
6741 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006742 }
6743 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006744 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
6745 Register dst = locations->Out().AsRegister<Register>();
6746 MipsLabel truncate;
6747 MipsLabel done;
6748
6749 // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
6750 // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
6751 // even though it must be NAN2008=1 on R6.
6752 //
6753 // For details see the large comment above for the truncation of float/double to long on R6.
6754 //
6755 // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
6756 // truncate instruction for MIPS64R6.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006757 if (input_type == Primitive::kPrimFloat) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006758 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
6759 __ LoadConst32(TMP, min_val);
6760 __ Mtc1(TMP, FTMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006761 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006762 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int32_t>::min());
6763 __ LoadConst32(TMP, High32Bits(min_val));
6764 __ Mtc1(ZERO, FTMP);
Alexey Frunzea871ef12016-06-27 15:20:11 -07006765 __ MoveToFpuHigh(TMP, FTMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006766 }
Alexey Frunzebaf60b72015-12-22 15:15:03 -08006767
6768 if (isR6) {
6769 if (input_type == Primitive::kPrimFloat) {
6770 __ CmpLeS(FTMP, FTMP, src);
6771 } else {
6772 __ CmpLeD(FTMP, FTMP, src);
6773 }
6774 __ Bc1nez(FTMP, &truncate);
6775
6776 if (input_type == Primitive::kPrimFloat) {
6777 __ CmpEqS(FTMP, src, src);
6778 } else {
6779 __ CmpEqD(FTMP, src, src);
6780 }
6781 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
6782 __ Mfc1(TMP, FTMP);
6783 __ And(dst, dst, TMP);
6784 } else {
6785 if (input_type == Primitive::kPrimFloat) {
6786 __ ColeS(0, FTMP, src);
6787 } else {
6788 __ ColeD(0, FTMP, src);
6789 }
6790 __ Bc1t(0, &truncate);
6791
6792 if (input_type == Primitive::kPrimFloat) {
6793 __ CeqS(0, src, src);
6794 } else {
6795 __ CeqD(0, src, src);
6796 }
6797 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
6798 __ Movf(dst, ZERO, 0);
6799 }
6800
6801 __ B(&done);
6802
6803 __ Bind(&truncate);
6804
6805 if (input_type == Primitive::kPrimFloat) {
6806 __ TruncWS(FTMP, src);
6807 } else {
6808 __ TruncWD(FTMP, src);
6809 }
6810 __ Mfc1(dst, FTMP);
6811
6812 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006813 }
6814 } else if (Primitive::IsFloatingPointType(result_type) &&
6815 Primitive::IsFloatingPointType(input_type)) {
6816 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
6817 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
6818 if (result_type == Primitive::kPrimFloat) {
6819 __ Cvtsd(dst, src);
6820 } else {
6821 __ Cvtds(dst, src);
6822 }
6823 } else {
6824 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
6825 << " to " << result_type;
6826 }
6827}
6828
6829void LocationsBuilderMIPS::VisitUShr(HUShr* ushr) {
6830 HandleShift(ushr);
6831}
6832
6833void InstructionCodeGeneratorMIPS::VisitUShr(HUShr* ushr) {
6834 HandleShift(ushr);
6835}
6836
6837void LocationsBuilderMIPS::VisitXor(HXor* instruction) {
6838 HandleBinaryOp(instruction);
6839}
6840
6841void InstructionCodeGeneratorMIPS::VisitXor(HXor* instruction) {
6842 HandleBinaryOp(instruction);
6843}
6844
6845void LocationsBuilderMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6846 // Nothing to do, this should be removed during prepare for register allocator.
6847 LOG(FATAL) << "Unreachable";
6848}
6849
6850void InstructionCodeGeneratorMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
6851 // Nothing to do, this should be removed during prepare for register allocator.
6852 LOG(FATAL) << "Unreachable";
6853}
6854
6855void LocationsBuilderMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006856 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006857}
6858
6859void InstructionCodeGeneratorMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006860 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006861}
6862
6863void LocationsBuilderMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006864 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006865}
6866
6867void InstructionCodeGeneratorMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006868 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006869}
6870
6871void LocationsBuilderMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006872 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006873}
6874
6875void InstructionCodeGeneratorMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006876 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006877}
6878
6879void LocationsBuilderMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006880 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006881}
6882
6883void InstructionCodeGeneratorMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006884 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006885}
6886
6887void LocationsBuilderMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006888 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006889}
6890
6891void InstructionCodeGeneratorMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006892 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006893}
6894
6895void LocationsBuilderMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006896 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006897}
6898
6899void InstructionCodeGeneratorMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006900 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006901}
6902
6903void LocationsBuilderMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006904 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006905}
6906
6907void InstructionCodeGeneratorMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006908 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006909}
6910
6911void LocationsBuilderMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006912 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006913}
6914
6915void InstructionCodeGeneratorMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006916 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006917}
6918
6919void LocationsBuilderMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006920 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006921}
6922
6923void InstructionCodeGeneratorMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006924 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006925}
6926
6927void LocationsBuilderMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006928 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006929}
6930
6931void InstructionCodeGeneratorMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00006932 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006933}
6934
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006935void LocationsBuilderMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
6936 LocationSummary* locations =
6937 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
6938 locations->SetInAt(0, Location::RequiresRegister());
6939}
6940
Alexey Frunze96b66822016-09-10 02:32:44 -07006941void InstructionCodeGeneratorMIPS::GenPackedSwitchWithCompares(Register value_reg,
6942 int32_t lower_bound,
6943 uint32_t num_entries,
6944 HBasicBlock* switch_block,
6945 HBasicBlock* default_block) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006946 // Create a set of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006947 Register temp_reg = TMP;
6948 __ Addiu32(temp_reg, value_reg, -lower_bound);
6949 // Jump to default if index is negative
6950 // Note: We don't check the case that index is positive while value < lower_bound, because in
6951 // this case, index >= num_entries must be true. So that we can save one branch instruction.
6952 __ Bltz(temp_reg, codegen_->GetLabelOf(default_block));
6953
Alexey Frunze96b66822016-09-10 02:32:44 -07006954 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006955 // Jump to successors[0] if value == lower_bound.
6956 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[0]));
6957 int32_t last_index = 0;
6958 for (; num_entries - last_index > 2; last_index += 2) {
6959 __ Addiu(temp_reg, temp_reg, -2);
6960 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
6961 __ Bltz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
6962 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
6963 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 2]));
6964 }
6965 if (num_entries - last_index == 2) {
6966 // The last missing case_value.
6967 __ Addiu(temp_reg, temp_reg, -1);
6968 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006969 }
6970
Vladimir Markof3e0ee22015-12-17 15:23:13 +00006971 // And the default for any other value.
Alexey Frunze96b66822016-09-10 02:32:44 -07006972 if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006973 __ B(codegen_->GetLabelOf(default_block));
6974 }
6975}
6976
Alexey Frunze96b66822016-09-10 02:32:44 -07006977void InstructionCodeGeneratorMIPS::GenTableBasedPackedSwitch(Register value_reg,
6978 Register constant_area,
6979 int32_t lower_bound,
6980 uint32_t num_entries,
6981 HBasicBlock* switch_block,
6982 HBasicBlock* default_block) {
6983 // Create a jump table.
6984 std::vector<MipsLabel*> labels(num_entries);
6985 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
6986 for (uint32_t i = 0; i < num_entries; i++) {
6987 labels[i] = codegen_->GetLabelOf(successors[i]);
6988 }
6989 JumpTable* table = __ CreateJumpTable(std::move(labels));
6990
6991 // Is the value in range?
6992 __ Addiu32(TMP, value_reg, -lower_bound);
6993 if (IsInt<16>(static_cast<int32_t>(num_entries))) {
6994 __ Sltiu(AT, TMP, num_entries);
6995 __ Beqz(AT, codegen_->GetLabelOf(default_block));
6996 } else {
6997 __ LoadConst32(AT, num_entries);
6998 __ Bgeu(TMP, AT, codegen_->GetLabelOf(default_block));
6999 }
7000
7001 // We are in the range of the table.
7002 // Load the target address from the jump table, indexing by the value.
7003 __ LoadLabelAddress(AT, constant_area, table->GetLabel());
7004 __ Sll(TMP, TMP, 2);
7005 __ Addu(TMP, TMP, AT);
7006 __ Lw(TMP, TMP, 0);
7007 // Compute the absolute target address by adding the table start address
7008 // (the table contains offsets to targets relative to its start).
7009 __ Addu(TMP, TMP, AT);
7010 // And jump.
7011 __ Jr(TMP);
7012 __ NopIfNoReordering();
7013}
7014
7015void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
7016 int32_t lower_bound = switch_instr->GetStartValue();
7017 uint32_t num_entries = switch_instr->GetNumEntries();
7018 LocationSummary* locations = switch_instr->GetLocations();
7019 Register value_reg = locations->InAt(0).AsRegister<Register>();
7020 HBasicBlock* switch_block = switch_instr->GetBlock();
7021 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
7022
7023 if (codegen_->GetInstructionSetFeatures().IsR6() &&
7024 num_entries > kPackedSwitchJumpTableThreshold) {
7025 // R6 uses PC-relative addressing to access the jump table.
7026 // R2, OTOH, requires an HMipsComputeBaseMethodAddress input to access
7027 // the jump table and it is implemented by changing HPackedSwitch to
7028 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress.
7029 // See VisitMipsPackedSwitch() for the table-based implementation on R2.
7030 GenTableBasedPackedSwitch(value_reg,
7031 ZERO,
7032 lower_bound,
7033 num_entries,
7034 switch_block,
7035 default_block);
7036 } else {
7037 GenPackedSwitchWithCompares(value_reg,
7038 lower_bound,
7039 num_entries,
7040 switch_block,
7041 default_block);
7042 }
7043}
7044
7045void LocationsBuilderMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
7046 LocationSummary* locations =
7047 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
7048 locations->SetInAt(0, Location::RequiresRegister());
7049 // Constant area pointer (HMipsComputeBaseMethodAddress).
7050 locations->SetInAt(1, Location::RequiresRegister());
7051}
7052
7053void InstructionCodeGeneratorMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
7054 int32_t lower_bound = switch_instr->GetStartValue();
7055 uint32_t num_entries = switch_instr->GetNumEntries();
7056 LocationSummary* locations = switch_instr->GetLocations();
7057 Register value_reg = locations->InAt(0).AsRegister<Register>();
7058 Register constant_area = locations->InAt(1).AsRegister<Register>();
7059 HBasicBlock* switch_block = switch_instr->GetBlock();
7060 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
7061
7062 // This is an R2-only path. HPackedSwitch has been changed to
7063 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress
7064 // required to address the jump table relative to PC.
7065 GenTableBasedPackedSwitch(value_reg,
7066 constant_area,
7067 lower_bound,
7068 num_entries,
7069 switch_block,
7070 default_block);
7071}
7072
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007073void LocationsBuilderMIPS::VisitMipsComputeBaseMethodAddress(
7074 HMipsComputeBaseMethodAddress* insn) {
7075 LocationSummary* locations =
7076 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
7077 locations->SetOut(Location::RequiresRegister());
7078}
7079
7080void InstructionCodeGeneratorMIPS::VisitMipsComputeBaseMethodAddress(
7081 HMipsComputeBaseMethodAddress* insn) {
7082 LocationSummary* locations = insn->GetLocations();
7083 Register reg = locations->Out().AsRegister<Register>();
7084
7085 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
7086
7087 // Generate a dummy PC-relative call to obtain PC.
7088 __ Nal();
7089 // Grab the return address off RA.
7090 __ Move(reg, RA);
Alexey Frunze06a46c42016-07-19 15:00:40 -07007091 // TODO: Can we share this code with that of VisitMipsDexCacheArraysBase()?
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007092
7093 // Remember this offset (the obtained PC value) for later use with constant area.
7094 __ BindPcRelBaseLabel();
7095}
7096
7097void LocationsBuilderMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
7098 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base);
7099 locations->SetOut(Location::RequiresRegister());
7100}
7101
7102void InstructionCodeGeneratorMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) {
7103 Register reg = base->GetLocations()->Out().AsRegister<Register>();
7104 CodeGeneratorMIPS::PcRelativePatchInfo* info =
7105 codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007106 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
7107 bool reordering = __ SetReorder(false);
Vladimir Markoaad75c62016-10-03 08:46:48 +00007108 // TODO: Reuse MipsComputeBaseMethodAddress on R2 instead of passing ZERO to force emitting NAL.
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007109 codegen_->EmitPcRelativeAddressPlaceholderHigh(info, reg, ZERO);
7110 __ Addiu(reg, reg, /* placeholder */ 0x5678);
7111 __ SetReorder(reordering);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007112}
7113
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007114void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
7115 // The trampoline uses the same calling convention as dex calling conventions,
7116 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
7117 // the method_idx.
7118 HandleInvoke(invoke);
7119}
7120
7121void InstructionCodeGeneratorMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
7122 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
7123}
7124
Roland Levillain2aba7cd2016-02-03 12:27:20 +00007125void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet* instruction) {
7126 LocationSummary* locations =
7127 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
7128 locations->SetInAt(0, Location::RequiresRegister());
7129 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007130}
7131
Roland Levillain2aba7cd2016-02-03 12:27:20 +00007132void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
7133 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00007134 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007135 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Roland Levillain2aba7cd2016-02-03 12:27:20 +00007136 instruction->GetIndex(), kMipsPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007137 __ LoadFromOffset(kLoadWord,
7138 locations->Out().AsRegister<Register>(),
7139 locations->InAt(0).AsRegister<Register>(),
7140 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +00007141 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007142 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00007143 instruction->GetIndex(), kMipsPointerSize));
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00007144 __ LoadFromOffset(kLoadWord,
7145 locations->Out().AsRegister<Register>(),
7146 locations->InAt(0).AsRegister<Register>(),
7147 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01007148 __ LoadFromOffset(kLoadWord,
7149 locations->Out().AsRegister<Register>(),
7150 locations->Out().AsRegister<Register>(),
7151 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +00007152 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00007153}
7154
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007155#undef __
7156#undef QUICK_ENTRY_POINT
7157
7158} // namespace mips
7159} // namespace art