blob: 112eb517b52a7bf01b8d484becc3e2b53b3f03ca [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
Alexey Frunze4147fcc2017-06-17 19:57:27 -070019#include "arch/mips/asm_support_mips.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020020#include "arch/mips/entrypoints_direct_mips.h"
21#include "arch/mips/instruction_set_features_mips.h"
22#include "art_method.h"
Vladimir Marko94ec2db2017-09-06 17:21:03 +010023#include "class_table.h"
Chris Larsen701566a2015-10-27 15:29:13 -070024#include "code_generator_utils.h"
Vladimir Marko3a21e382016-09-02 12:38:38 +010025#include "compiled_method.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020026#include "entrypoints/quick/quick_entrypoints.h"
27#include "entrypoints/quick/quick_entrypoints_enum.h"
28#include "gc/accounting/card_table.h"
Vladimir Markoeebb8212018-06-05 14:57:24 +010029#include "gc/space/image_space.h"
Andreas Gampe09659c22017-09-18 18:23:32 -070030#include "heap_poisoning.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020031#include "intrinsics.h"
Chris Larsen701566a2015-10-27 15:29:13 -070032#include "intrinsics_mips.h"
Vladimir Markod8dbc8d2017-09-20 13:37:47 +010033#include "linker/linker_patch.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020034#include "mirror/array-inl.h"
35#include "mirror/class-inl.h"
36#include "offsets.h"
Vladimir Marko174b2e22017-10-12 13:34:49 +010037#include "stack_map_stream.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020038#include "thread.h"
39#include "utils/assembler.h"
40#include "utils/mips/assembler_mips.h"
41#include "utils/stack_checks.h"
42
43namespace art {
44namespace mips {
45
46static constexpr int kCurrentMethodStackOffset = 0;
47static constexpr Register kMethodRegisterArgument = A0;
48
Alexey Frunze4147fcc2017-06-17 19:57:27 -070049// Flags controlling the use of thunks for Baker read barriers.
50constexpr bool kBakerReadBarrierThunksEnableForFields = true;
51constexpr bool kBakerReadBarrierThunksEnableForArrays = true;
52constexpr bool kBakerReadBarrierThunksEnableForGcRoots = true;
53
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010054Location MipsReturnLocation(DataType::Type return_type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020055 switch (return_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010056 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010057 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010058 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010059 case DataType::Type::kInt8:
60 case DataType::Type::kUint16:
61 case DataType::Type::kInt16:
Aart Bik66c158e2018-01-31 12:55:04 -080062 case DataType::Type::kUint32:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010063 case DataType::Type::kInt32:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020064 return Location::RegisterLocation(V0);
65
Aart Bik66c158e2018-01-31 12:55:04 -080066 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010067 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020068 return Location::RegisterPairLocation(V0, V1);
69
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010070 case DataType::Type::kFloat32:
71 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020072 return Location::FpuRegisterLocation(F0);
73
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010074 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020075 return Location();
76 }
77 UNREACHABLE();
78}
79
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010080Location InvokeDexCallingConventionVisitorMIPS::GetReturnLocation(DataType::Type type) const {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020081 return MipsReturnLocation(type);
82}
83
84Location InvokeDexCallingConventionVisitorMIPS::GetMethodLocation() const {
85 return Location::RegisterLocation(kMethodRegisterArgument);
86}
87
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010088Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(DataType::Type type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020089 Location next_location;
90
91 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010092 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010093 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010094 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010095 case DataType::Type::kInt8:
96 case DataType::Type::kUint16:
97 case DataType::Type::kInt16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010098 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020099 uint32_t gp_index = gp_index_++;
100 if (gp_index < calling_convention.GetNumberOfRegisters()) {
101 next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index));
102 } else {
103 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
104 next_location = Location::StackSlot(stack_offset);
105 }
106 break;
107 }
108
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100109 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200110 uint32_t gp_index = gp_index_;
111 gp_index_ += 2;
112 if (gp_index + 1 < calling_convention.GetNumberOfRegisters()) {
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800113 Register reg = calling_convention.GetRegisterAt(gp_index);
114 if (reg == A1 || reg == A3) {
115 gp_index_++; // Skip A1(A3), and use A2_A3(T0_T1) instead.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200116 gp_index++;
117 }
118 Register low_even = calling_convention.GetRegisterAt(gp_index);
119 Register high_odd = calling_convention.GetRegisterAt(gp_index + 1);
120 DCHECK_EQ(low_even + 1, high_odd);
121 next_location = Location::RegisterPairLocation(low_even, high_odd);
122 } else {
123 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
124 next_location = Location::DoubleStackSlot(stack_offset);
125 }
126 break;
127 }
128
129 // Note: both float and double types are stored in even FPU registers. On 32 bit FPU, double
130 // will take up the even/odd pair, while floats are stored in even regs only.
131 // On 64 bit FPU, both double and float are stored in even registers only.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100132 case DataType::Type::kFloat32:
133 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200134 uint32_t float_index = float_index_++;
135 if (float_index < calling_convention.GetNumberOfFpuRegisters()) {
136 next_location = Location::FpuRegisterLocation(
137 calling_convention.GetFpuRegisterAt(float_index));
138 } else {
139 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100140 next_location = DataType::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
141 : Location::StackSlot(stack_offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200142 }
143 break;
144 }
145
Aart Bik66c158e2018-01-31 12:55:04 -0800146 case DataType::Type::kUint32:
147 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100148 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200149 LOG(FATAL) << "Unexpected parameter type " << type;
150 break;
151 }
152
153 // Space on the stack is reserved for all arguments.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100154 stack_index_ += DataType::Is64BitType(type) ? 2 : 1;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200155
156 return next_location;
157}
158
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100159Location InvokeRuntimeCallingConvention::GetReturnLocation(DataType::Type type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200160 return MipsReturnLocation(type);
161}
162
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100163// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
164#define __ down_cast<CodeGeneratorMIPS*>(codegen)->GetAssembler()-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -0700165#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200166
167class BoundsCheckSlowPathMIPS : public SlowPathCodeMIPS {
168 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000169 explicit BoundsCheckSlowPathMIPS(HBoundsCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200170
171 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
172 LocationSummary* locations = instruction_->GetLocations();
173 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
174 __ Bind(GetEntryLabel());
175 if (instruction_->CanThrowIntoCatchBlock()) {
176 // Live registers will be restored in the catch block if caught.
177 SaveLiveRegisters(codegen, instruction_->GetLocations());
178 }
179 // We're moving two locations to locations that could overlap, so we need a parallel
180 // move resolver.
181 InvokeRuntimeCallingConvention calling_convention;
182 codegen->EmitParallelMoves(locations->InAt(0),
183 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100184 DataType::Type::kInt32,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200185 locations->InAt(1),
186 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100187 DataType::Type::kInt32);
Serban Constantinescufca16662016-07-14 09:21:59 +0100188 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
189 ? kQuickThrowStringBounds
190 : kQuickThrowArrayBounds;
191 mips_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100192 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200193 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
194 }
195
196 bool IsFatal() const OVERRIDE { return true; }
197
198 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS"; }
199
200 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200201 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathMIPS);
202};
203
204class DivZeroCheckSlowPathMIPS : public SlowPathCodeMIPS {
205 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000206 explicit DivZeroCheckSlowPathMIPS(HDivZeroCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200207
208 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
209 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
210 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100211 mips_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200212 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
213 }
214
215 bool IsFatal() const OVERRIDE { return true; }
216
217 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS"; }
218
219 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200220 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS);
221};
222
223class LoadClassSlowPathMIPS : public SlowPathCodeMIPS {
224 public:
225 LoadClassSlowPathMIPS(HLoadClass* cls,
226 HInstruction* at,
227 uint32_t dex_pc,
Vladimir Markof3c52b42017-11-17 17:32:12 +0000228 bool do_clinit)
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700229 : SlowPathCodeMIPS(at),
230 cls_(cls),
231 dex_pc_(dex_pc),
Vladimir Markof3c52b42017-11-17 17:32:12 +0000232 do_clinit_(do_clinit) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200233 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
234 }
235
236 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000237 LocationSummary* locations = instruction_->GetLocations();
Alexey Frunzec61c0762017-04-10 13:54:23 -0700238 Location out = locations->Out();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200239 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Alexey Frunzec61c0762017-04-10 13:54:23 -0700240 InvokeRuntimeCallingConvention calling_convention;
241 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200242 __ Bind(GetEntryLabel());
243 SaveLiveRegisters(codegen, locations);
244
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000245 dex::TypeIndex type_index = cls_->GetTypeIndex();
246 __ LoadConst32(calling_convention.GetRegisterAt(0), type_index.index_);
Serban Constantinescufca16662016-07-14 09:21:59 +0100247 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
248 : kQuickInitializeType;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000249 mips_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200250 if (do_clinit_) {
251 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
252 } else {
253 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
254 }
255
256 // Move the class to the desired location.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200257 if (out.IsValid()) {
258 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100259 DataType::Type type = instruction_->GetType();
Alexey Frunzec61c0762017-04-10 13:54:23 -0700260 mips_codegen->MoveLocation(out,
261 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
262 type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200263 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200264 RestoreLiveRegisters(codegen, locations);
Alexey Frunzec61c0762017-04-10 13:54:23 -0700265
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:
Vladimir Markof3c52b42017-11-17 17:32:12 +0000286 explicit LoadStringSlowPathMIPS(HLoadString* instruction)
287 : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200288
289 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexey Frunzec61c0762017-04-10 13:54:23 -0700290 DCHECK(instruction_->IsLoadString());
291 DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200292 LocationSummary* locations = instruction_->GetLocations();
293 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Vladimir Markof3c52b42017-11-17 17:32:12 +0000294 const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200295 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Alexey Frunzec61c0762017-04-10 13:54:23 -0700296 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200297 __ Bind(GetEntryLabel());
298 SaveLiveRegisters(codegen, locations);
299
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000300 __ LoadConst32(calling_convention.GetRegisterAt(0), string_index.index_);
Serban Constantinescufca16662016-07-14 09:21:59 +0100301 mips_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200302 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Alexey Frunzec61c0762017-04-10 13:54:23 -0700303
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100304 DataType::Type type = instruction_->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200305 mips_codegen->MoveLocation(locations->Out(),
Alexey Frunzec61c0762017-04-10 13:54:23 -0700306 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200307 type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200308 RestoreLiveRegisters(codegen, locations);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000309
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200310 __ B(GetExitLabel());
311 }
312
313 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
314
315 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200316 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
317};
318
319class NullCheckSlowPathMIPS : public SlowPathCodeMIPS {
320 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000321 explicit NullCheckSlowPathMIPS(HNullCheck* instr) : SlowPathCodeMIPS(instr) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200322
323 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
324 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
325 __ Bind(GetEntryLabel());
326 if (instruction_->CanThrowIntoCatchBlock()) {
327 // Live registers will be restored in the catch block if caught.
328 SaveLiveRegisters(codegen, instruction_->GetLocations());
329 }
Serban Constantinescufca16662016-07-14 09:21:59 +0100330 mips_codegen->InvokeRuntime(kQuickThrowNullPointer,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200331 instruction_,
332 instruction_->GetDexPc(),
Serban Constantinescufca16662016-07-14 09:21:59 +0100333 this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200334 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
335 }
336
337 bool IsFatal() const OVERRIDE { return true; }
338
339 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS"; }
340
341 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200342 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathMIPS);
343};
344
345class SuspendCheckSlowPathMIPS : public SlowPathCodeMIPS {
346 public:
347 SuspendCheckSlowPathMIPS(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000348 : SlowPathCodeMIPS(instruction), successor_(successor) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200349
350 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Lena Djokicca8c2952017-05-29 11:31:46 +0200351 LocationSummary* locations = instruction_->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200352 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
353 __ Bind(GetEntryLabel());
Lena Djokicca8c2952017-05-29 11:31:46 +0200354 SaveLiveRegisters(codegen, locations); // Only saves live vector registers for SIMD.
Serban Constantinescufca16662016-07-14 09:21:59 +0100355 mips_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200356 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Lena Djokicca8c2952017-05-29 11:31:46 +0200357 RestoreLiveRegisters(codegen, locations); // Only restores live vector registers for SIMD.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200358 if (successor_ == nullptr) {
359 __ B(GetReturnLabel());
360 } else {
361 __ B(mips_codegen->GetLabelOf(successor_));
362 }
363 }
364
365 MipsLabel* GetReturnLabel() {
366 DCHECK(successor_ == nullptr);
367 return &return_label_;
368 }
369
370 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS"; }
371
Chris Larsena2045912017-11-02 12:39:54 -0700372 HBasicBlock* GetSuccessor() const {
373 return successor_;
374 }
375
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200376 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200377 // If not null, the block to branch to after the suspend check.
378 HBasicBlock* const successor_;
379
380 // If `successor_` is null, the label to branch to after the suspend check.
381 MipsLabel return_label_;
382
383 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathMIPS);
384};
385
386class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS {
387 public:
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800388 explicit TypeCheckSlowPathMIPS(HInstruction* instruction, bool is_fatal)
389 : SlowPathCodeMIPS(instruction), is_fatal_(is_fatal) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200390
391 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
392 LocationSummary* locations = instruction_->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200393 uint32_t dex_pc = instruction_->GetDexPc();
394 DCHECK(instruction_->IsCheckCast()
395 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
396 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
397
398 __ Bind(GetEntryLabel());
Alexey Frunzedfc30af2018-01-24 16:25:10 -0800399 if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800400 SaveLiveRegisters(codegen, locations);
401 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200402
403 // We're moving two locations to locations that could overlap, so we need a parallel
404 // move resolver.
405 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800406 codegen->EmitParallelMoves(locations->InAt(0),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200407 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100408 DataType::Type::kReference,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800409 locations->InAt(1),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200410 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100411 DataType::Type::kReference);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200412 if (instruction_->IsInstanceOf()) {
Serban Constantinescufca16662016-07-14 09:21:59 +0100413 mips_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800414 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100415 DataType::Type ret_type = instruction_->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200416 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
417 mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200418 } else {
419 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800420 mips_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
421 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200422 }
423
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800424 if (!is_fatal_) {
425 RestoreLiveRegisters(codegen, locations);
426 __ B(GetExitLabel());
427 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200428 }
429
430 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS"; }
431
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800432 bool IsFatal() const OVERRIDE { return is_fatal_; }
433
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200434 private:
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800435 const bool is_fatal_;
436
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200437 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathMIPS);
438};
439
440class DeoptimizationSlowPathMIPS : public SlowPathCodeMIPS {
441 public:
Aart Bik42249c32016-01-07 15:33:50 -0800442 explicit DeoptimizationSlowPathMIPS(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000443 : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200444
445 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800446 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200447 __ Bind(GetEntryLabel());
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100448 LocationSummary* locations = instruction_->GetLocations();
449 SaveLiveRegisters(codegen, locations);
450 InvokeRuntimeCallingConvention calling_convention;
451 __ LoadConst32(calling_convention.GetRegisterAt(0),
452 static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
Serban Constantinescufca16662016-07-14 09:21:59 +0100453 mips_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100454 CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200455 }
456
457 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS"; }
458
459 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200460 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS);
461};
462
Alexey Frunze15958152017-02-09 19:08:30 -0800463class ArraySetSlowPathMIPS : public SlowPathCodeMIPS {
464 public:
465 explicit ArraySetSlowPathMIPS(HInstruction* instruction) : SlowPathCodeMIPS(instruction) {}
466
467 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
468 LocationSummary* locations = instruction_->GetLocations();
469 __ Bind(GetEntryLabel());
470 SaveLiveRegisters(codegen, locations);
471
472 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100473 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Alexey Frunze15958152017-02-09 19:08:30 -0800474 parallel_move.AddMove(
475 locations->InAt(0),
476 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100477 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800478 nullptr);
479 parallel_move.AddMove(
480 locations->InAt(1),
481 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100482 DataType::Type::kInt32,
Alexey Frunze15958152017-02-09 19:08:30 -0800483 nullptr);
484 parallel_move.AddMove(
485 locations->InAt(2),
486 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100487 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800488 nullptr);
489 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
490
491 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
492 mips_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
493 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
494 RestoreLiveRegisters(codegen, locations);
495 __ B(GetExitLabel());
496 }
497
498 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathMIPS"; }
499
500 private:
501 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathMIPS);
502};
503
504// Slow path marking an object reference `ref` during a read
505// barrier. The field `obj.field` in the object `obj` holding this
506// reference does not get updated by this slow path after marking (see
507// ReadBarrierMarkAndUpdateFieldSlowPathMIPS below for that).
508//
509// This means that after the execution of this slow path, `ref` will
510// always be up-to-date, but `obj.field` may not; i.e., after the
511// flip, `ref` will be a to-space reference, but `obj.field` will
512// probably still be a from-space reference (unless it gets updated by
513// another thread, or if another thread installed another object
514// reference (different from `ref`) in `obj.field`).
515//
516// If `entrypoint` is a valid location it is assumed to already be
517// holding the entrypoint. The case where the entrypoint is passed in
518// is for the GcRoot read barrier.
519class ReadBarrierMarkSlowPathMIPS : public SlowPathCodeMIPS {
520 public:
521 ReadBarrierMarkSlowPathMIPS(HInstruction* instruction,
522 Location ref,
523 Location entrypoint = Location::NoLocation())
524 : SlowPathCodeMIPS(instruction), ref_(ref), entrypoint_(entrypoint) {
525 DCHECK(kEmitCompilerReadBarrier);
526 }
527
528 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathMIPS"; }
529
530 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
531 LocationSummary* locations = instruction_->GetLocations();
532 Register ref_reg = ref_.AsRegister<Register>();
533 DCHECK(locations->CanCall());
534 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
535 DCHECK(instruction_->IsInstanceFieldGet() ||
536 instruction_->IsStaticFieldGet() ||
537 instruction_->IsArrayGet() ||
538 instruction_->IsArraySet() ||
539 instruction_->IsLoadClass() ||
540 instruction_->IsLoadString() ||
541 instruction_->IsInstanceOf() ||
542 instruction_->IsCheckCast() ||
543 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
544 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
545 << "Unexpected instruction in read barrier marking slow path: "
546 << instruction_->DebugName();
547
548 __ Bind(GetEntryLabel());
549 // No need to save live registers; it's taken care of by the
550 // entrypoint. Also, there is no need to update the stack mask,
551 // as this runtime call will not trigger a garbage collection.
552 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
553 DCHECK((V0 <= ref_reg && ref_reg <= T7) ||
554 (S2 <= ref_reg && ref_reg <= S7) ||
555 (ref_reg == FP)) << ref_reg;
556 // "Compact" slow path, saving two moves.
557 //
558 // Instead of using the standard runtime calling convention (input
559 // and output in A0 and V0 respectively):
560 //
561 // A0 <- ref
562 // V0 <- ReadBarrierMark(A0)
563 // ref <- V0
564 //
565 // we just use rX (the register containing `ref`) as input and output
566 // of a dedicated entrypoint:
567 //
568 // rX <- ReadBarrierMarkRegX(rX)
569 //
570 if (entrypoint_.IsValid()) {
571 mips_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
572 DCHECK_EQ(entrypoint_.AsRegister<Register>(), T9);
573 __ Jalr(entrypoint_.AsRegister<Register>());
574 __ NopIfNoReordering();
575 } else {
576 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100577 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(ref_reg - 1);
Alexey Frunze15958152017-02-09 19:08:30 -0800578 // This runtime call does not require a stack map.
579 mips_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
580 instruction_,
581 this,
582 /* direct */ false);
583 }
584 __ B(GetExitLabel());
585 }
586
587 private:
588 // The location (register) of the marked object reference.
589 const Location ref_;
590
591 // The location of the entrypoint if already loaded.
592 const Location entrypoint_;
593
594 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathMIPS);
595};
596
597// Slow path marking an object reference `ref` during a read barrier,
598// and if needed, atomically updating the field `obj.field` in the
599// object `obj` holding this reference after marking (contrary to
600// ReadBarrierMarkSlowPathMIPS above, which never tries to update
601// `obj.field`).
602//
603// This means that after the execution of this slow path, both `ref`
604// and `obj.field` will be up-to-date; i.e., after the flip, both will
605// hold the same to-space reference (unless another thread installed
606// another object reference (different from `ref`) in `obj.field`).
607class ReadBarrierMarkAndUpdateFieldSlowPathMIPS : public SlowPathCodeMIPS {
608 public:
609 ReadBarrierMarkAndUpdateFieldSlowPathMIPS(HInstruction* instruction,
610 Location ref,
611 Register obj,
612 Location field_offset,
613 Register temp1)
614 : SlowPathCodeMIPS(instruction),
615 ref_(ref),
616 obj_(obj),
617 field_offset_(field_offset),
618 temp1_(temp1) {
619 DCHECK(kEmitCompilerReadBarrier);
620 }
621
622 const char* GetDescription() const OVERRIDE {
623 return "ReadBarrierMarkAndUpdateFieldSlowPathMIPS";
624 }
625
626 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
627 LocationSummary* locations = instruction_->GetLocations();
628 Register ref_reg = ref_.AsRegister<Register>();
629 DCHECK(locations->CanCall());
630 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
631 // This slow path is only used by the UnsafeCASObject intrinsic.
632 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
633 << "Unexpected instruction in read barrier marking and field updating slow path: "
634 << instruction_->DebugName();
635 DCHECK(instruction_->GetLocations()->Intrinsified());
636 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
637 DCHECK(field_offset_.IsRegisterPair()) << field_offset_;
638
639 __ Bind(GetEntryLabel());
640
641 // Save the old reference.
642 // Note that we cannot use AT or TMP to save the old reference, as those
643 // are used by the code that follows, but we need the old reference after
644 // the call to the ReadBarrierMarkRegX entry point.
645 DCHECK_NE(temp1_, AT);
646 DCHECK_NE(temp1_, TMP);
647 __ Move(temp1_, ref_reg);
648
649 // No need to save live registers; it's taken care of by the
650 // entrypoint. Also, there is no need to update the stack mask,
651 // as this runtime call will not trigger a garbage collection.
652 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
653 DCHECK((V0 <= ref_reg && ref_reg <= T7) ||
654 (S2 <= ref_reg && ref_reg <= S7) ||
655 (ref_reg == FP)) << ref_reg;
656 // "Compact" slow path, saving two moves.
657 //
658 // Instead of using the standard runtime calling convention (input
659 // and output in A0 and V0 respectively):
660 //
661 // A0 <- ref
662 // V0 <- ReadBarrierMark(A0)
663 // ref <- V0
664 //
665 // we just use rX (the register containing `ref`) as input and output
666 // of a dedicated entrypoint:
667 //
668 // rX <- ReadBarrierMarkRegX(rX)
669 //
670 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100671 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(ref_reg - 1);
Alexey Frunze15958152017-02-09 19:08:30 -0800672 // This runtime call does not require a stack map.
673 mips_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
674 instruction_,
675 this,
676 /* direct */ false);
677
678 // If the new reference is different from the old reference,
679 // update the field in the holder (`*(obj_ + field_offset_)`).
680 //
681 // Note that this field could also hold a different object, if
682 // another thread had concurrently changed it. In that case, the
683 // the compare-and-set (CAS) loop below would abort, leaving the
684 // field as-is.
685 MipsLabel done;
686 __ Beq(temp1_, ref_reg, &done);
687
688 // Update the the holder's field atomically. This may fail if
689 // mutator updates before us, but it's OK. This is achieved
690 // using a strong compare-and-set (CAS) operation with relaxed
691 // memory synchronization ordering, where the expected value is
692 // the old reference and the desired value is the new reference.
693
694 // Convenience aliases.
695 Register base = obj_;
696 // The UnsafeCASObject intrinsic uses a register pair as field
697 // offset ("long offset"), of which only the low part contains
698 // data.
699 Register offset = field_offset_.AsRegisterPairLow<Register>();
700 Register expected = temp1_;
701 Register value = ref_reg;
702 Register tmp_ptr = TMP; // Pointer to actual memory.
703 Register tmp = AT; // Value in memory.
704
705 __ Addu(tmp_ptr, base, offset);
706
707 if (kPoisonHeapReferences) {
708 __ PoisonHeapReference(expected);
709 // Do not poison `value` if it is the same register as
710 // `expected`, which has just been poisoned.
711 if (value != expected) {
712 __ PoisonHeapReference(value);
713 }
714 }
715
716 // do {
717 // tmp = [r_ptr] - expected;
718 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
719
720 bool is_r6 = mips_codegen->GetInstructionSetFeatures().IsR6();
721 MipsLabel loop_head, exit_loop;
722 __ Bind(&loop_head);
723 if (is_r6) {
724 __ LlR6(tmp, tmp_ptr);
725 } else {
726 __ LlR2(tmp, tmp_ptr);
727 }
728 __ Bne(tmp, expected, &exit_loop);
729 __ Move(tmp, value);
730 if (is_r6) {
731 __ ScR6(tmp, tmp_ptr);
732 } else {
733 __ ScR2(tmp, tmp_ptr);
734 }
735 __ Beqz(tmp, &loop_head);
736 __ Bind(&exit_loop);
737
738 if (kPoisonHeapReferences) {
739 __ UnpoisonHeapReference(expected);
740 // Do not unpoison `value` if it is the same register as
741 // `expected`, which has just been unpoisoned.
742 if (value != expected) {
743 __ UnpoisonHeapReference(value);
744 }
745 }
746
747 __ Bind(&done);
748 __ B(GetExitLabel());
749 }
750
751 private:
752 // The location (register) of the marked object reference.
753 const Location ref_;
754 // The register containing the object holding the marked object reference field.
755 const Register obj_;
756 // The location of the offset of the marked reference field within `obj_`.
757 Location field_offset_;
758
759 const Register temp1_;
760
761 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathMIPS);
762};
763
764// Slow path generating a read barrier for a heap reference.
765class ReadBarrierForHeapReferenceSlowPathMIPS : public SlowPathCodeMIPS {
766 public:
767 ReadBarrierForHeapReferenceSlowPathMIPS(HInstruction* instruction,
768 Location out,
769 Location ref,
770 Location obj,
771 uint32_t offset,
772 Location index)
773 : SlowPathCodeMIPS(instruction),
774 out_(out),
775 ref_(ref),
776 obj_(obj),
777 offset_(offset),
778 index_(index) {
779 DCHECK(kEmitCompilerReadBarrier);
780 // If `obj` is equal to `out` or `ref`, it means the initial object
781 // has been overwritten by (or after) the heap object reference load
782 // to be instrumented, e.g.:
783 //
784 // __ LoadFromOffset(kLoadWord, out, out, offset);
785 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
786 //
787 // In that case, we have lost the information about the original
788 // object, and the emitted read barrier cannot work properly.
789 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
790 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
791 }
792
793 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
794 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
795 LocationSummary* locations = instruction_->GetLocations();
796 Register reg_out = out_.AsRegister<Register>();
797 DCHECK(locations->CanCall());
798 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
799 DCHECK(instruction_->IsInstanceFieldGet() ||
800 instruction_->IsStaticFieldGet() ||
801 instruction_->IsArrayGet() ||
802 instruction_->IsInstanceOf() ||
803 instruction_->IsCheckCast() ||
804 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
805 << "Unexpected instruction in read barrier for heap reference slow path: "
806 << instruction_->DebugName();
807
808 __ Bind(GetEntryLabel());
809 SaveLiveRegisters(codegen, locations);
810
811 // We may have to change the index's value, but as `index_` is a
812 // constant member (like other "inputs" of this slow path),
813 // introduce a copy of it, `index`.
814 Location index = index_;
815 if (index_.IsValid()) {
816 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
817 if (instruction_->IsArrayGet()) {
818 // Compute the actual memory offset and store it in `index`.
819 Register index_reg = index_.AsRegister<Register>();
820 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
821 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
822 // We are about to change the value of `index_reg` (see the
823 // calls to art::mips::MipsAssembler::Sll and
824 // art::mips::MipsAssembler::Addiu32 below), but it has
825 // not been saved by the previous call to
826 // art::SlowPathCode::SaveLiveRegisters, as it is a
827 // callee-save register --
828 // art::SlowPathCode::SaveLiveRegisters does not consider
829 // callee-save registers, as it has been designed with the
830 // assumption that callee-save registers are supposed to be
831 // handled by the called function. So, as a callee-save
832 // register, `index_reg` _would_ eventually be saved onto
833 // the stack, but it would be too late: we would have
834 // changed its value earlier. Therefore, we manually save
835 // it here into another freely available register,
836 // `free_reg`, chosen of course among the caller-save
837 // registers (as a callee-save `free_reg` register would
838 // exhibit the same problem).
839 //
840 // Note we could have requested a temporary register from
841 // the register allocator instead; but we prefer not to, as
842 // this is a slow path, and we know we can find a
843 // caller-save register that is available.
844 Register free_reg = FindAvailableCallerSaveRegister(codegen);
845 __ Move(free_reg, index_reg);
846 index_reg = free_reg;
847 index = Location::RegisterLocation(index_reg);
848 } else {
849 // The initial register stored in `index_` has already been
850 // saved in the call to art::SlowPathCode::SaveLiveRegisters
851 // (as it is not a callee-save register), so we can freely
852 // use it.
853 }
854 // Shifting the index value contained in `index_reg` by the scale
855 // factor (2) cannot overflow in practice, as the runtime is
856 // unable to allocate object arrays with a size larger than
857 // 2^26 - 1 (that is, 2^28 - 4 bytes).
858 __ Sll(index_reg, index_reg, TIMES_4);
859 static_assert(
860 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
861 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
862 __ Addiu32(index_reg, index_reg, offset_);
863 } else {
864 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
865 // intrinsics, `index_` is not shifted by a scale factor of 2
866 // (as in the case of ArrayGet), as it is actually an offset
867 // to an object field within an object.
868 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
869 DCHECK(instruction_->GetLocations()->Intrinsified());
870 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
871 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
872 << instruction_->AsInvoke()->GetIntrinsic();
873 DCHECK_EQ(offset_, 0U);
874 DCHECK(index_.IsRegisterPair());
875 // UnsafeGet's offset location is a register pair, the low
876 // part contains the correct offset.
877 index = index_.ToLow();
878 }
879 }
880
881 // We're moving two or three locations to locations that could
882 // overlap, so we need a parallel move resolver.
883 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100884 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Alexey Frunze15958152017-02-09 19:08:30 -0800885 parallel_move.AddMove(ref_,
886 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100887 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800888 nullptr);
889 parallel_move.AddMove(obj_,
890 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100891 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800892 nullptr);
893 if (index.IsValid()) {
894 parallel_move.AddMove(index,
895 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100896 DataType::Type::kInt32,
Alexey Frunze15958152017-02-09 19:08:30 -0800897 nullptr);
898 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
899 } else {
900 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
901 __ LoadConst32(calling_convention.GetRegisterAt(2), offset_);
902 }
903 mips_codegen->InvokeRuntime(kQuickReadBarrierSlow,
904 instruction_,
905 instruction_->GetDexPc(),
906 this);
907 CheckEntrypointTypes<
908 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
Lena Djokic8098da92017-06-28 12:07:50 +0200909 mips_codegen->MoveLocation(out_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100910 calling_convention.GetReturnLocation(DataType::Type::kReference),
911 DataType::Type::kReference);
Alexey Frunze15958152017-02-09 19:08:30 -0800912
913 RestoreLiveRegisters(codegen, locations);
914 __ B(GetExitLabel());
915 }
916
917 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathMIPS"; }
918
919 private:
920 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
921 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
922 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
923 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
924 if (i != ref &&
925 i != obj &&
926 !codegen->IsCoreCalleeSaveRegister(i) &&
927 !codegen->IsBlockedCoreRegister(i)) {
928 return static_cast<Register>(i);
929 }
930 }
931 // We shall never fail to find a free caller-save register, as
932 // there are more than two core caller-save registers on MIPS
933 // (meaning it is possible to find one which is different from
934 // `ref` and `obj`).
935 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
936 LOG(FATAL) << "Could not find a free caller-save register";
937 UNREACHABLE();
938 }
939
940 const Location out_;
941 const Location ref_;
942 const Location obj_;
943 const uint32_t offset_;
944 // An additional location containing an index to an array.
945 // Only used for HArrayGet and the UnsafeGetObject &
946 // UnsafeGetObjectVolatile intrinsics.
947 const Location index_;
948
949 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathMIPS);
950};
951
952// Slow path generating a read barrier for a GC root.
953class ReadBarrierForRootSlowPathMIPS : public SlowPathCodeMIPS {
954 public:
955 ReadBarrierForRootSlowPathMIPS(HInstruction* instruction, Location out, Location root)
956 : SlowPathCodeMIPS(instruction), out_(out), root_(root) {
957 DCHECK(kEmitCompilerReadBarrier);
958 }
959
960 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
961 LocationSummary* locations = instruction_->GetLocations();
962 Register reg_out = out_.AsRegister<Register>();
963 DCHECK(locations->CanCall());
964 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
965 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
966 << "Unexpected instruction in read barrier for GC root slow path: "
967 << instruction_->DebugName();
968
969 __ Bind(GetEntryLabel());
970 SaveLiveRegisters(codegen, locations);
971
972 InvokeRuntimeCallingConvention calling_convention;
973 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Lena Djokic8098da92017-06-28 12:07:50 +0200974 mips_codegen->MoveLocation(Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
975 root_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100976 DataType::Type::kReference);
Alexey Frunze15958152017-02-09 19:08:30 -0800977 mips_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
978 instruction_,
979 instruction_->GetDexPc(),
980 this);
981 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
Lena Djokic8098da92017-06-28 12:07:50 +0200982 mips_codegen->MoveLocation(out_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100983 calling_convention.GetReturnLocation(DataType::Type::kReference),
984 DataType::Type::kReference);
Alexey Frunze15958152017-02-09 19:08:30 -0800985
986 RestoreLiveRegisters(codegen, locations);
987 __ B(GetExitLabel());
988 }
989
990 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathMIPS"; }
991
992 private:
993 const Location out_;
994 const Location root_;
995
996 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathMIPS);
997};
998
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200999CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph,
1000 const MipsInstructionSetFeatures& isa_features,
1001 const CompilerOptions& compiler_options,
1002 OptimizingCompilerStats* stats)
1003 : CodeGenerator(graph,
1004 kNumberOfCoreRegisters,
1005 kNumberOfFRegisters,
1006 kNumberOfRegisterPairs,
1007 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1008 arraysize(kCoreCalleeSaves)),
1009 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1010 arraysize(kFpuCalleeSaves)),
1011 compiler_options,
1012 stats),
1013 block_labels_(nullptr),
1014 location_builder_(graph, this),
1015 instruction_visitor_(graph, this),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001016 move_resolver_(graph->GetAllocator(), this),
1017 assembler_(graph->GetAllocator(), &isa_features),
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001018 isa_features_(isa_features),
Alexey Frunze06a46c42016-07-19 15:00:40 -07001019 uint32_literals_(std::less<uint32_t>(),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001020 graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001021 boot_image_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001022 method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001023 boot_image_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001024 type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001025 boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001026 string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1027 jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1028 jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Alexey Frunze06a46c42016-07-19 15:00:40 -07001029 clobbered_ra_(false) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001030 // Save RA (containing the return address) to mimic Quick.
1031 AddAllocatedRegister(Location::RegisterLocation(RA));
1032}
1033
1034#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +01001035// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1036#define __ down_cast<MipsAssembler*>(GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -07001037#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001038
1039void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) {
1040 // Ensure that we fix up branches.
1041 __ FinalizeCode();
1042
1043 // Adjust native pc offsets in stack maps.
Vladimir Marko174b2e22017-10-12 13:34:49 +01001044 StackMapStream* stack_map_stream = GetStackMapStream();
1045 for (size_t i = 0, num = stack_map_stream->GetNumberOfStackMaps(); i != num; ++i) {
David Srbeckyd02b23f2018-05-29 23:27:22 +01001046 uint32_t old_position = stack_map_stream->GetStackMapNativePcOffset(i);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001047 uint32_t new_position = __ GetAdjustedPosition(old_position);
1048 DCHECK_GE(new_position, old_position);
Vladimir Marko174b2e22017-10-12 13:34:49 +01001049 stack_map_stream->SetStackMapNativePcOffset(i, new_position);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001050 }
1051
1052 // Adjust pc offsets for the disassembly information.
1053 if (disasm_info_ != nullptr) {
1054 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
1055 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
1056 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
1057 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
1058 it.second.start = __ GetAdjustedPosition(it.second.start);
1059 it.second.end = __ GetAdjustedPosition(it.second.end);
1060 }
1061 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
1062 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
1063 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
1064 }
1065 }
1066
1067 CodeGenerator::Finalize(allocator);
1068}
1069
1070MipsAssembler* ParallelMoveResolverMIPS::GetAssembler() const {
1071 return codegen_->GetAssembler();
1072}
1073
1074void ParallelMoveResolverMIPS::EmitMove(size_t index) {
1075 DCHECK_LT(index, moves_.size());
1076 MoveOperands* move = moves_[index];
1077 codegen_->MoveLocation(move->GetDestination(), move->GetSource(), move->GetType());
1078}
1079
1080void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
1081 DCHECK_LT(index, moves_.size());
1082 MoveOperands* move = moves_[index];
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001083 DataType::Type type = move->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001084 Location loc1 = move->GetDestination();
1085 Location loc2 = move->GetSource();
1086
1087 DCHECK(!loc1.IsConstant());
1088 DCHECK(!loc2.IsConstant());
1089
1090 if (loc1.Equals(loc2)) {
1091 return;
1092 }
1093
1094 if (loc1.IsRegister() && loc2.IsRegister()) {
1095 // Swap 2 GPRs.
1096 Register r1 = loc1.AsRegister<Register>();
1097 Register r2 = loc2.AsRegister<Register>();
1098 __ Move(TMP, r2);
1099 __ Move(r2, r1);
1100 __ Move(r1, TMP);
1101 } else if (loc1.IsFpuRegister() && loc2.IsFpuRegister()) {
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +01001102 if (codegen_->GetGraph()->HasSIMD()) {
1103 __ MoveV(static_cast<VectorRegister>(FTMP), VectorRegisterFrom(loc1));
1104 __ MoveV(VectorRegisterFrom(loc1), VectorRegisterFrom(loc2));
1105 __ MoveV(VectorRegisterFrom(loc2), static_cast<VectorRegister>(FTMP));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001106 } else {
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +01001107 FRegister f1 = loc1.AsFpuRegister<FRegister>();
1108 FRegister f2 = loc2.AsFpuRegister<FRegister>();
1109 if (type == DataType::Type::kFloat32) {
1110 __ MovS(FTMP, f2);
1111 __ MovS(f2, f1);
1112 __ MovS(f1, FTMP);
1113 } else {
1114 DCHECK_EQ(type, DataType::Type::kFloat64);
1115 __ MovD(FTMP, f2);
1116 __ MovD(f2, f1);
1117 __ MovD(f1, FTMP);
1118 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001119 }
1120 } else if ((loc1.IsRegister() && loc2.IsFpuRegister()) ||
1121 (loc1.IsFpuRegister() && loc2.IsRegister())) {
1122 // Swap FPR and GPR.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001123 DCHECK_EQ(type, DataType::Type::kFloat32); // Can only swap a float.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001124 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
1125 : loc2.AsFpuRegister<FRegister>();
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +02001126 Register r2 = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001127 __ Move(TMP, r2);
1128 __ Mfc1(r2, f1);
1129 __ Mtc1(TMP, f1);
1130 } else if (loc1.IsRegisterPair() && loc2.IsRegisterPair()) {
1131 // Swap 2 GPR register pairs.
1132 Register r1 = loc1.AsRegisterPairLow<Register>();
1133 Register r2 = loc2.AsRegisterPairLow<Register>();
1134 __ Move(TMP, r2);
1135 __ Move(r2, r1);
1136 __ Move(r1, TMP);
1137 r1 = loc1.AsRegisterPairHigh<Register>();
1138 r2 = loc2.AsRegisterPairHigh<Register>();
1139 __ Move(TMP, r2);
1140 __ Move(r2, r1);
1141 __ Move(r1, TMP);
1142 } else if ((loc1.IsRegisterPair() && loc2.IsFpuRegister()) ||
1143 (loc1.IsFpuRegister() && loc2.IsRegisterPair())) {
1144 // Swap FPR and GPR register pair.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001145 DCHECK_EQ(type, DataType::Type::kFloat64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001146 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
1147 : loc2.AsFpuRegister<FRegister>();
1148 Register r2_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
1149 : loc2.AsRegisterPairLow<Register>();
1150 Register r2_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
1151 : loc2.AsRegisterPairHigh<Register>();
1152 // Use 2 temporary registers because we can't first swap the low 32 bits of an FPR and
1153 // then swap the high 32 bits of the same FPR. mtc1 makes the high 32 bits of an FPR
1154 // unpredictable and the following mfch1 will fail.
1155 __ Mfc1(TMP, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001156 __ MoveFromFpuHigh(AT, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001157 __ Mtc1(r2_l, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -08001158 __ MoveToFpuHigh(r2_h, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001159 __ Move(r2_l, TMP);
1160 __ Move(r2_h, AT);
1161 } else if (loc1.IsStackSlot() && loc2.IsStackSlot()) {
1162 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ false);
1163 } else if (loc1.IsDoubleStackSlot() && loc2.IsDoubleStackSlot()) {
1164 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ true);
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +01001165 } else if (loc1.IsSIMDStackSlot() && loc2.IsSIMDStackSlot()) {
1166 ExchangeQuadSlots(loc1.GetStackIndex(), loc2.GetStackIndex());
David Brazdilcc0f3112016-01-28 17:14:52 +00001167 } else if ((loc1.IsRegister() && loc2.IsStackSlot()) ||
1168 (loc1.IsStackSlot() && loc2.IsRegister())) {
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +02001169 Register reg = loc1.IsRegister() ? loc1.AsRegister<Register>() : loc2.AsRegister<Register>();
1170 intptr_t offset = loc1.IsStackSlot() ? loc1.GetStackIndex() : loc2.GetStackIndex();
David Brazdilcc0f3112016-01-28 17:14:52 +00001171 __ Move(TMP, reg);
1172 __ LoadFromOffset(kLoadWord, reg, SP, offset);
1173 __ StoreToOffset(kStoreWord, TMP, SP, offset);
1174 } else if ((loc1.IsRegisterPair() && loc2.IsDoubleStackSlot()) ||
1175 (loc1.IsDoubleStackSlot() && loc2.IsRegisterPair())) {
1176 Register reg_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
1177 : loc2.AsRegisterPairLow<Register>();
1178 Register reg_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
1179 : loc2.AsRegisterPairHigh<Register>();
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +02001180 intptr_t offset_l = loc1.IsDoubleStackSlot() ? loc1.GetStackIndex() : loc2.GetStackIndex();
David Brazdilcc0f3112016-01-28 17:14:52 +00001181 intptr_t offset_h = loc1.IsDoubleStackSlot() ? loc1.GetHighStackIndex(kMipsWordSize)
1182 : loc2.GetHighStackIndex(kMipsWordSize);
1183 __ Move(TMP, reg_l);
David Brazdilcc0f3112016-01-28 17:14:52 +00001184 __ LoadFromOffset(kLoadWord, reg_l, SP, offset_l);
David Brazdilcc0f3112016-01-28 17:14:52 +00001185 __ StoreToOffset(kStoreWord, TMP, SP, offset_l);
David Brazdil04d3e872016-01-29 09:50:09 +00001186 __ Move(TMP, reg_h);
1187 __ LoadFromOffset(kLoadWord, reg_h, SP, offset_h);
1188 __ StoreToOffset(kStoreWord, TMP, SP, offset_h);
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +01001189 } else if ((loc1.IsFpuRegister() && loc2.IsSIMDStackSlot()) ||
1190 (loc1.IsSIMDStackSlot() && loc2.IsFpuRegister())) {
1191 Location fp_loc = loc1.IsFpuRegister() ? loc1 : loc2;
1192 intptr_t offset = loc1.IsFpuRegister() ? loc2.GetStackIndex() : loc1.GetStackIndex();
1193 __ MoveV(static_cast<VectorRegister>(FTMP), VectorRegisterFrom(fp_loc));
1194 __ LoadQFromOffset(fp_loc.AsFpuRegister<FRegister>(), SP, offset);
1195 __ StoreQToOffset(FTMP, SP, offset);
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +02001196 } else if (loc1.IsFpuRegister() || loc2.IsFpuRegister()) {
1197 FRegister reg = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
1198 : loc2.AsFpuRegister<FRegister>();
1199 intptr_t offset = loc1.IsFpuRegister() ? loc2.GetStackIndex() : loc1.GetStackIndex();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001200 if (type == DataType::Type::kFloat32) {
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +02001201 __ MovS(FTMP, reg);
1202 __ LoadSFromOffset(reg, SP, offset);
1203 __ StoreSToOffset(FTMP, SP, offset);
1204 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001205 DCHECK_EQ(type, DataType::Type::kFloat64);
Goran Jakovljevic35dfcaa2016-09-22 09:26:01 +02001206 __ MovD(FTMP, reg);
1207 __ LoadDFromOffset(reg, SP, offset);
1208 __ StoreDToOffset(FTMP, SP, offset);
1209 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001210 } else {
1211 LOG(FATAL) << "Swap between " << loc1 << " and " << loc2 << " is unsupported";
1212 }
1213}
1214
1215void ParallelMoveResolverMIPS::RestoreScratch(int reg) {
1216 __ Pop(static_cast<Register>(reg));
1217}
1218
1219void ParallelMoveResolverMIPS::SpillScratch(int reg) {
1220 __ Push(static_cast<Register>(reg));
1221}
1222
1223void ParallelMoveResolverMIPS::Exchange(int index1, int index2, bool double_slot) {
1224 // Allocate a scratch register other than TMP, if available.
1225 // Else, spill V0 (arbitrary choice) and use it as a scratch register (it will be
1226 // automatically unspilled when the scratch scope object is destroyed).
1227 ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters());
1228 // If V0 spills onto the stack, SP-relative offsets need to be adjusted.
Chris Larsen715f43e2017-10-23 11:00:32 -07001229 int stack_offset = ensure_scratch.IsSpilled() ? kStackAlignment : 0;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001230 for (int i = 0; i <= (double_slot ? 1 : 0); i++, stack_offset += kMipsWordSize) {
1231 __ LoadFromOffset(kLoadWord,
1232 Register(ensure_scratch.GetRegister()),
1233 SP,
1234 index1 + stack_offset);
1235 __ LoadFromOffset(kLoadWord,
1236 TMP,
1237 SP,
1238 index2 + stack_offset);
1239 __ StoreToOffset(kStoreWord,
1240 Register(ensure_scratch.GetRegister()),
1241 SP,
1242 index2 + stack_offset);
1243 __ StoreToOffset(kStoreWord, TMP, SP, index1 + stack_offset);
1244 }
1245}
1246
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +01001247void ParallelMoveResolverMIPS::ExchangeQuadSlots(int index1, int index2) {
1248 __ LoadQFromOffset(FTMP, SP, index1);
1249 __ LoadQFromOffset(FTMP2, SP, index2);
1250 __ StoreQToOffset(FTMP, SP, index2);
1251 __ StoreQToOffset(FTMP2, SP, index1);
1252}
1253
Alexey Frunze73296a72016-06-03 22:51:46 -07001254void CodeGeneratorMIPS::ComputeSpillMask() {
1255 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_;
1256 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_;
1257 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved";
1258 // If there're FPU callee-saved registers and there's an odd number of GPR callee-saved
1259 // registers, include the ZERO register to force alignment of FPU callee-saved registers
1260 // within the stack frame.
1261 if ((fpu_spill_mask_ != 0) && (POPCOUNT(core_spill_mask_) % 2 != 0)) {
1262 core_spill_mask_ |= (1 << ZERO);
1263 }
Alexey Frunze58320ce2016-08-30 21:40:46 -07001264}
1265
1266bool CodeGeneratorMIPS::HasAllocatedCalleeSaveRegisters() const {
Alexey Frunze06a46c42016-07-19 15:00:40 -07001267 // If RA is clobbered by PC-relative operations on R2 and it's the only spilled register
Alexey Frunze58320ce2016-08-30 21:40:46 -07001268 // (this can happen in leaf methods), force CodeGenerator::InitializeCodeGeneration()
1269 // into the path that creates a stack frame so that RA can be explicitly saved and restored.
1270 // RA can't otherwise be saved/restored when it's the only spilled register.
Alexey Frunze58320ce2016-08-30 21:40:46 -07001271 return CodeGenerator::HasAllocatedCalleeSaveRegisters() || clobbered_ra_;
Alexey Frunze73296a72016-06-03 22:51:46 -07001272}
1273
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001274static dwarf::Reg DWARFReg(Register reg) {
1275 return dwarf::Reg::MipsCore(static_cast<int>(reg));
1276}
1277
1278// TODO: mapping of floating-point registers to DWARF.
1279
1280void CodeGeneratorMIPS::GenerateFrameEntry() {
1281 __ Bind(&frame_entry_label_);
1282
Nicolas Geoffray8d728322018-01-18 22:44:32 +00001283 if (GetCompilerOptions().CountHotnessInCompiledCode()) {
Goran Jakovljevicfeec1672018-02-08 10:20:14 +01001284 __ Lhu(TMP, kMethodRegisterArgument, ArtMethod::HotnessCountOffset().Int32Value());
1285 __ Addiu(TMP, TMP, 1);
1286 __ Sh(TMP, kMethodRegisterArgument, ArtMethod::HotnessCountOffset().Int32Value());
Nicolas Geoffray8d728322018-01-18 22:44:32 +00001287 }
1288
Vladimir Marko33bff252017-11-01 14:35:42 +00001289 bool do_overflow_check =
1290 FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kMips) || !IsLeafMethod();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001291
1292 if (do_overflow_check) {
1293 __ LoadFromOffset(kLoadWord,
1294 ZERO,
1295 SP,
Vladimir Marko33bff252017-11-01 14:35:42 +00001296 -static_cast<int32_t>(GetStackOverflowReservedBytes(InstructionSet::kMips)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001297 RecordPcInfo(nullptr, 0);
1298 }
1299
1300 if (HasEmptyFrame()) {
Alexey Frunze58320ce2016-08-30 21:40:46 -07001301 CHECK_EQ(fpu_spill_mask_, 0u);
1302 CHECK_EQ(core_spill_mask_, 1u << RA);
1303 CHECK(!clobbered_ra_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001304 return;
1305 }
1306
1307 // Make sure the frame size isn't unreasonably large.
Vladimir Marko33bff252017-11-01 14:35:42 +00001308 if (GetFrameSize() > GetStackOverflowReservedBytes(InstructionSet::kMips)) {
1309 LOG(FATAL) << "Stack frame larger than "
1310 << GetStackOverflowReservedBytes(InstructionSet::kMips) << " bytes";
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001311 }
1312
1313 // Spill callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001314
Alexey Frunze73296a72016-06-03 22:51:46 -07001315 uint32_t ofs = GetFrameSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001316 __ IncreaseFrameSize(ofs);
1317
Alexey Frunze73296a72016-06-03 22:51:46 -07001318 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
1319 Register reg = static_cast<Register>(MostSignificantBit(mask));
1320 mask ^= 1u << reg;
1321 ofs -= kMipsWordSize;
1322 // The ZERO register is only included for alignment.
1323 if (reg != ZERO) {
1324 __ StoreToOffset(kStoreWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001325 __ cfi().RelOffset(DWARFReg(reg), ofs);
1326 }
1327 }
1328
Alexey Frunze73296a72016-06-03 22:51:46 -07001329 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
1330 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
1331 mask ^= 1u << reg;
1332 ofs -= kMipsDoublewordSize;
1333 __ StoreDToOffset(reg, SP, ofs);
1334 // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001335 }
1336
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01001337 // Save the current method if we need it. Note that we do not
1338 // do this in HCurrentMethod, as the instruction might have been removed
1339 // in the SSA graph.
1340 if (RequiresCurrentMethod()) {
1341 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, kCurrentMethodStackOffset);
1342 }
Goran Jakovljevicc6418422016-12-05 16:31:55 +01001343
1344 if (GetGraph()->HasShouldDeoptimizeFlag()) {
1345 // Initialize should deoptimize flag to 0.
1346 __ StoreToOffset(kStoreWord, ZERO, SP, GetStackOffsetOfShouldDeoptimizeFlag());
1347 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001348}
1349
1350void CodeGeneratorMIPS::GenerateFrameExit() {
1351 __ cfi().RememberState();
1352
1353 if (!HasEmptyFrame()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001354 // Restore callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001355
Alexey Frunze73296a72016-06-03 22:51:46 -07001356 // For better instruction scheduling restore RA before other registers.
1357 uint32_t ofs = GetFrameSize();
1358 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
1359 Register reg = static_cast<Register>(MostSignificantBit(mask));
1360 mask ^= 1u << reg;
1361 ofs -= kMipsWordSize;
1362 // The ZERO register is only included for alignment.
1363 if (reg != ZERO) {
1364 __ LoadFromOffset(kLoadWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001365 __ cfi().Restore(DWARFReg(reg));
1366 }
1367 }
1368
Alexey Frunze73296a72016-06-03 22:51:46 -07001369 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
1370 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
1371 mask ^= 1u << reg;
1372 ofs -= kMipsDoublewordSize;
1373 __ LoadDFromOffset(reg, SP, ofs);
1374 // TODO: __ cfi().Restore(DWARFReg(reg));
1375 }
1376
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001377 size_t frame_size = GetFrameSize();
1378 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
1379 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
1380 bool reordering = __ SetReorder(false);
1381 if (exchange) {
1382 __ Jr(RA);
1383 __ DecreaseFrameSize(frame_size); // Single instruction in delay slot.
1384 } else {
1385 __ DecreaseFrameSize(frame_size);
1386 __ Jr(RA);
1387 __ Nop(); // In delay slot.
1388 }
1389 __ SetReorder(reordering);
1390 } else {
1391 __ Jr(RA);
1392 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001393 }
1394
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001395 __ cfi().RestoreState();
1396 __ cfi().DefCFAOffset(GetFrameSize());
1397}
1398
1399void CodeGeneratorMIPS::Bind(HBasicBlock* block) {
1400 __ Bind(GetLabelOf(block));
1401}
1402
Lena Djokicca8c2952017-05-29 11:31:46 +02001403VectorRegister VectorRegisterFrom(Location location) {
1404 DCHECK(location.IsFpuRegister());
1405 return static_cast<VectorRegister>(location.AsFpuRegister<FRegister>());
1406}
1407
Lena Djokic8098da92017-06-28 12:07:50 +02001408void CodeGeneratorMIPS::MoveLocation(Location destination,
1409 Location source,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001410 DataType::Type dst_type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001411 if (source.Equals(destination)) {
1412 return;
1413 }
1414
Lena Djokic8098da92017-06-28 12:07:50 +02001415 if (source.IsConstant()) {
1416 MoveConstant(destination, source.GetConstant());
1417 } else {
1418 if (destination.IsRegister()) {
1419 if (source.IsRegister()) {
1420 __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
1421 } else if (source.IsFpuRegister()) {
1422 __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
1423 } else {
1424 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001425 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Lena Djokic8098da92017-06-28 12:07:50 +02001426 }
1427 } else if (destination.IsRegisterPair()) {
1428 if (source.IsRegisterPair()) {
1429 __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
1430 __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
1431 } else if (source.IsFpuRegister()) {
1432 Register dst_high = destination.AsRegisterPairHigh<Register>();
1433 Register dst_low = destination.AsRegisterPairLow<Register>();
1434 FRegister src = source.AsFpuRegister<FRegister>();
1435 __ Mfc1(dst_low, src);
1436 __ MoveFromFpuHigh(dst_high, src);
1437 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001438 DCHECK(source.IsDoubleStackSlot())
1439 << "Cannot move from " << source << " to " << destination;
Lena Djokic8098da92017-06-28 12:07:50 +02001440 int32_t off = source.GetStackIndex();
1441 Register r = destination.AsRegisterPairLow<Register>();
1442 __ LoadFromOffset(kLoadDoubleword, r, SP, off);
1443 }
1444 } else if (destination.IsFpuRegister()) {
1445 if (source.IsRegister()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001446 DCHECK(!DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001447 __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
1448 } else if (source.IsRegisterPair()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001449 DCHECK(DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001450 FRegister dst = destination.AsFpuRegister<FRegister>();
1451 Register src_high = source.AsRegisterPairHigh<Register>();
1452 Register src_low = source.AsRegisterPairLow<Register>();
1453 __ Mtc1(src_low, dst);
1454 __ MoveToFpuHigh(src_high, dst);
1455 } else if (source.IsFpuRegister()) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001456 if (GetGraph()->HasSIMD()) {
1457 __ MoveV(VectorRegisterFrom(destination),
1458 VectorRegisterFrom(source));
Lena Djokic8098da92017-06-28 12:07:50 +02001459 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001460 if (DataType::Is64BitType(dst_type)) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001461 __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
1462 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001463 DCHECK_EQ(dst_type, DataType::Type::kFloat32);
Lena Djokicca8c2952017-05-29 11:31:46 +02001464 __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
1465 }
Lena Djokic8098da92017-06-28 12:07:50 +02001466 }
Lena Djokicca8c2952017-05-29 11:31:46 +02001467 } else if (source.IsSIMDStackSlot()) {
1468 __ LoadQFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
Lena Djokic8098da92017-06-28 12:07:50 +02001469 } else if (source.IsDoubleStackSlot()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001470 DCHECK(DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001471 __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
1472 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001473 DCHECK(!DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001474 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
1475 __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
1476 }
Lena Djokicca8c2952017-05-29 11:31:46 +02001477 } else if (destination.IsSIMDStackSlot()) {
1478 if (source.IsFpuRegister()) {
1479 __ StoreQToOffset(source.AsFpuRegister<FRegister>(), SP, destination.GetStackIndex());
1480 } else {
1481 DCHECK(source.IsSIMDStackSlot());
1482 __ LoadQFromOffset(FTMP, SP, source.GetStackIndex());
1483 __ StoreQToOffset(FTMP, SP, destination.GetStackIndex());
1484 }
Lena Djokic8098da92017-06-28 12:07:50 +02001485 } else if (destination.IsDoubleStackSlot()) {
1486 int32_t dst_offset = destination.GetStackIndex();
1487 if (source.IsRegisterPair()) {
1488 __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, dst_offset);
1489 } else if (source.IsFpuRegister()) {
1490 __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, dst_offset);
1491 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001492 DCHECK(source.IsDoubleStackSlot())
1493 << "Cannot move from " << source << " to " << destination;
Lena Djokic8098da92017-06-28 12:07:50 +02001494 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
1495 __ StoreToOffset(kStoreWord, TMP, SP, dst_offset);
1496 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
1497 __ StoreToOffset(kStoreWord, TMP, SP, dst_offset + 4);
1498 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001499 } else {
Lena Djokic8098da92017-06-28 12:07:50 +02001500 DCHECK(destination.IsStackSlot()) << destination;
1501 int32_t dst_offset = destination.GetStackIndex();
1502 if (source.IsRegister()) {
1503 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, dst_offset);
1504 } else if (source.IsFpuRegister()) {
1505 __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, dst_offset);
1506 } else {
1507 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
1508 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
1509 __ StoreToOffset(kStoreWord, TMP, SP, dst_offset);
1510 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001511 }
1512 }
1513}
1514
1515void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) {
1516 if (c->IsIntConstant() || c->IsNullConstant()) {
1517 // Move 32 bit constant.
1518 int32_t value = GetInt32ValueOf(c);
1519 if (destination.IsRegister()) {
1520 Register dst = destination.AsRegister<Register>();
1521 __ LoadConst32(dst, value);
1522 } else {
1523 DCHECK(destination.IsStackSlot())
1524 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001525 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001526 }
1527 } else if (c->IsLongConstant()) {
1528 // Move 64 bit constant.
1529 int64_t value = GetInt64ValueOf(c);
1530 if (destination.IsRegisterPair()) {
1531 Register r_h = destination.AsRegisterPairHigh<Register>();
1532 Register r_l = destination.AsRegisterPairLow<Register>();
1533 __ LoadConst64(r_h, r_l, value);
1534 } else {
1535 DCHECK(destination.IsDoubleStackSlot())
1536 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001537 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001538 }
1539 } else if (c->IsFloatConstant()) {
1540 // Move 32 bit float constant.
1541 int32_t value = GetInt32ValueOf(c);
1542 if (destination.IsFpuRegister()) {
1543 __ LoadSConst32(destination.AsFpuRegister<FRegister>(), value, TMP);
1544 } else {
1545 DCHECK(destination.IsStackSlot())
1546 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001547 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001548 }
1549 } else {
1550 // Move 64 bit double constant.
1551 DCHECK(c->IsDoubleConstant()) << c->DebugName();
1552 int64_t value = GetInt64ValueOf(c);
1553 if (destination.IsFpuRegister()) {
1554 FRegister fd = destination.AsFpuRegister<FRegister>();
1555 __ LoadDConst64(fd, value, TMP);
1556 } else {
1557 DCHECK(destination.IsDoubleStackSlot())
1558 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001559 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001560 }
1561 }
1562}
1563
1564void CodeGeneratorMIPS::MoveConstant(Location destination, int32_t value) {
1565 DCHECK(destination.IsRegister());
1566 Register dst = destination.AsRegister<Register>();
1567 __ LoadConst32(dst, value);
1568}
1569
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001570void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
1571 if (location.IsRegister()) {
1572 locations->AddTemp(location);
Alexey Frunzec9e94f32015-10-26 16:11:39 -07001573 } else if (location.IsRegisterPair()) {
1574 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1575 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001576 } else {
1577 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1578 }
1579}
1580
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001581template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
Vladimir Markoaad75c62016-10-03 08:46:48 +00001582inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches(
1583 const ArenaDeque<PcRelativePatchInfo>& infos,
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001584 ArenaVector<linker::LinkerPatch>* linker_patches) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00001585 for (const PcRelativePatchInfo& info : infos) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001586 const DexFile* dex_file = info.target_dex_file;
Vladimir Markoaad75c62016-10-03 08:46:48 +00001587 size_t offset_or_index = info.offset_or_index;
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001588 DCHECK(info.label.IsBound());
1589 uint32_t literal_offset = __ GetLabelLocation(&info.label);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001590 // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
1591 // the assembler's base label used for PC-relative addressing.
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001592 const PcRelativePatchInfo& info_high = info.patch_info_high ? *info.patch_info_high : info;
1593 uint32_t pc_rel_offset = info_high.pc_rel_label.IsBound()
1594 ? __ GetLabelLocation(&info_high.pc_rel_label)
Vladimir Markoaad75c62016-10-03 08:46:48 +00001595 : __ GetPcRelBaseLabelLocation();
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001596 linker_patches->push_back(Factory(literal_offset, dex_file, pc_rel_offset, offset_or_index));
Vladimir Markoaad75c62016-10-03 08:46:48 +00001597 }
1598}
1599
Vladimir Markob066d432018-01-03 13:14:37 +00001600linker::LinkerPatch DataBimgRelRoPatchAdapter(size_t literal_offset,
1601 const DexFile* target_dex_file,
1602 uint32_t pc_insn_offset,
1603 uint32_t boot_image_offset) {
1604 DCHECK(target_dex_file == nullptr); // Unused for DataBimgRelRoPatch(), should be null.
1605 return linker::LinkerPatch::DataBimgRelRoPatch(literal_offset, pc_insn_offset, boot_image_offset);
1606}
1607
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001608void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001609 DCHECK(linker_patches->empty());
1610 size_t size =
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001611 boot_image_method_patches_.size() +
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001612 method_bss_entry_patches_.size() +
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001613 boot_image_type_patches_.size() +
Vladimir Marko65979462017-05-19 17:25:12 +01001614 type_bss_entry_patches_.size() +
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001615 boot_image_string_patches_.size() +
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001616 string_bss_entry_patches_.size();
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001617 linker_patches->reserve(size);
Vladimir Marko65979462017-05-19 17:25:12 +01001618 if (GetCompilerOptions().IsBootImage()) {
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001619 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001620 boot_image_method_patches_, linker_patches);
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001621 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001622 boot_image_type_patches_, linker_patches);
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001623 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001624 boot_image_string_patches_, linker_patches);
Vladimir Marko65979462017-05-19 17:25:12 +01001625 } else {
Vladimir Markob066d432018-01-03 13:14:37 +00001626 EmitPcRelativeLinkerPatches<DataBimgRelRoPatchAdapter>(
1627 boot_image_method_patches_, linker_patches);
Vladimir Markoe47f60c2018-02-21 13:43:28 +00001628 DCHECK(boot_image_type_patches_.empty());
1629 DCHECK(boot_image_string_patches_.empty());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001630 }
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001631 EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
1632 method_bss_entry_patches_, linker_patches);
1633 EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
1634 type_bss_entry_patches_, linker_patches);
1635 EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
1636 string_bss_entry_patches_, linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001637 DCHECK_EQ(size, linker_patches->size());
Alexey Frunze06a46c42016-07-19 15:00:40 -07001638}
1639
Vladimir Markob066d432018-01-03 13:14:37 +00001640CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageRelRoPatch(
1641 uint32_t boot_image_offset,
1642 const PcRelativePatchInfo* info_high) {
1643 return NewPcRelativePatch(
1644 /* dex_file */ nullptr, boot_image_offset, info_high, &boot_image_method_patches_);
1645}
1646
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001647CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageMethodPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001648 MethodReference target_method,
1649 const PcRelativePatchInfo* info_high) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001650 return NewPcRelativePatch(
1651 target_method.dex_file, target_method.index, info_high, &boot_image_method_patches_);
Alexey Frunze06a46c42016-07-19 15:00:40 -07001652}
1653
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001654CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewMethodBssEntryPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001655 MethodReference target_method,
1656 const PcRelativePatchInfo* info_high) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001657 return NewPcRelativePatch(
1658 target_method.dex_file, target_method.index, info_high, &method_bss_entry_patches_);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001659}
1660
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001661CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageTypePatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001662 const DexFile& dex_file,
1663 dex::TypeIndex type_index,
1664 const PcRelativePatchInfo* info_high) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001665 return NewPcRelativePatch(&dex_file, type_index.index_, info_high, &boot_image_type_patches_);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001666}
1667
Vladimir Marko1998cd02017-01-13 13:02:58 +00001668CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewTypeBssEntryPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001669 const DexFile& dex_file,
1670 dex::TypeIndex type_index,
1671 const PcRelativePatchInfo* info_high) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001672 return NewPcRelativePatch(&dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001673}
1674
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001675CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewBootImageStringPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001676 const DexFile& dex_file,
1677 dex::StringIndex string_index,
1678 const PcRelativePatchInfo* info_high) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001679 return NewPcRelativePatch(
1680 &dex_file, string_index.index_, info_high, &boot_image_string_patches_);
Vladimir Marko65979462017-05-19 17:25:12 +01001681}
1682
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001683CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewStringBssEntryPatch(
1684 const DexFile& dex_file,
1685 dex::StringIndex string_index,
1686 const PcRelativePatchInfo* info_high) {
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001687 return NewPcRelativePatch(&dex_file, string_index.index_, info_high, &string_bss_entry_patches_);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001688}
1689
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001690CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
Vladimir Marko59eb30f2018-02-20 11:52:34 +00001691 const DexFile* dex_file,
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001692 uint32_t offset_or_index,
1693 const PcRelativePatchInfo* info_high,
1694 ArenaDeque<PcRelativePatchInfo>* patches) {
1695 patches->emplace_back(dex_file, offset_or_index, info_high);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001696 return &patches->back();
1697}
1698
Alexey Frunze06a46c42016-07-19 15:00:40 -07001699Literal* CodeGeneratorMIPS::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
1700 return map->GetOrCreate(
1701 value,
1702 [this, value]() { return __ NewLiteral<uint32_t>(value); });
1703}
1704
Alexey Frunze06a46c42016-07-19 15:00:40 -07001705Literal* CodeGeneratorMIPS::DeduplicateBootImageAddressLiteral(uint32_t address) {
Richard Uhlerc52f3032017-03-02 13:45:45 +00001706 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
Alexey Frunze06a46c42016-07-19 15:00:40 -07001707}
1708
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001709void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001710 Register out,
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001711 Register base) {
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001712 DCHECK(!info_high->patch_info_high);
Alexey Frunze6079dca2017-05-28 19:10:28 -07001713 DCHECK_NE(out, base);
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001714 bool reordering = __ SetReorder(false);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001715 if (GetInstructionSetFeatures().IsR6()) {
1716 DCHECK_EQ(base, ZERO);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001717 __ Bind(&info_high->label);
1718 __ Bind(&info_high->pc_rel_label);
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001719 // Add the high half of a 32-bit offset to PC.
Vladimir Markoaad75c62016-10-03 08:46:48 +00001720 __ Auipc(out, /* placeholder */ 0x1234);
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001721 __ SetReorder(reordering);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001722 } else {
1723 // If base is ZERO, emit NAL to obtain the actual base.
1724 if (base == ZERO) {
1725 // Generate a dummy PC-relative call to obtain PC.
1726 __ Nal();
1727 }
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001728 __ Bind(&info_high->label);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001729 __ Lui(out, /* placeholder */ 0x1234);
1730 // If we emitted the NAL, bind the pc_rel_label, otherwise base is a register holding
1731 // the HMipsComputeBaseMethodAddress which has its own label stored in MipsAssembler.
1732 if (base == ZERO) {
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001733 __ Bind(&info_high->pc_rel_label);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001734 }
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001735 __ SetReorder(reordering);
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001736 // Add the high half of a 32-bit offset to PC.
Vladimir Markoaad75c62016-10-03 08:46:48 +00001737 __ Addu(out, out, (base == ZERO) ? RA : base);
1738 }
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001739 // A following instruction will add the sign-extended low half of the 32-bit
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001740 // offset to `out` (e.g. lw, jialc, addiu).
Vladimir Markoaad75c62016-10-03 08:46:48 +00001741}
1742
Vladimir Markoeebb8212018-06-05 14:57:24 +01001743void CodeGeneratorMIPS::LoadBootImageAddress(Register reg, uint32_t boot_image_offset) {
1744 DCHECK(!GetCompilerOptions().IsBootImage());
1745 if (GetCompilerOptions().GetCompilePic()) {
1746 DCHECK(Runtime::Current()->IsAotCompiler());
1747 PcRelativePatchInfo* info_high = NewBootImageRelRoPatch(boot_image_offset);
1748 PcRelativePatchInfo* info_low = NewBootImageRelRoPatch(boot_image_offset, info_high);
1749 EmitPcRelativeAddressPlaceholderHigh(info_high, reg, /* base */ ZERO);
1750 __ Lw(reg, reg, /* placeholder */ 0x5678, &info_low->label);
1751 } else {
1752 gc::Heap* heap = Runtime::Current()->GetHeap();
1753 DCHECK(!heap->GetBootImageSpaces().empty());
1754 const uint8_t* address = heap->GetBootImageSpaces()[0]->Begin() + boot_image_offset;
1755 __ LoadConst32(reg, dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(address)));
1756 }
1757}
1758
Alexey Frunze627c1a02017-01-30 19:28:14 -08001759CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootStringPatch(
1760 const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01001761 dex::StringIndex string_index,
Alexey Frunze627c1a02017-01-30 19:28:14 -08001762 Handle<mirror::String> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001763 ReserveJitStringRoot(StringReference(&dex_file, string_index), handle);
1764 jit_string_patches_.emplace_back(dex_file, string_index.index_);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001765 return &jit_string_patches_.back();
1766}
1767
1768CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootClassPatch(
1769 const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01001770 dex::TypeIndex type_index,
Alexey Frunze627c1a02017-01-30 19:28:14 -08001771 Handle<mirror::Class> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001772 ReserveJitClassRoot(TypeReference(&dex_file, type_index), handle);
1773 jit_class_patches_.emplace_back(dex_file, type_index.index_);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001774 return &jit_class_patches_.back();
1775}
1776
1777void CodeGeneratorMIPS::PatchJitRootUse(uint8_t* code,
1778 const uint8_t* roots_data,
1779 const CodeGeneratorMIPS::JitPatchInfo& info,
1780 uint64_t index_in_table) const {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001781 uint32_t high_literal_offset = GetAssembler().GetLabelLocation(&info.high_label);
1782 uint32_t low_literal_offset = GetAssembler().GetLabelLocation(&info.low_label);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001783 uintptr_t address =
1784 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
1785 uint32_t addr32 = dchecked_integral_cast<uint32_t>(address);
1786 // lui reg, addr32_high
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001787 DCHECK_EQ(code[high_literal_offset + 0], 0x34);
1788 DCHECK_EQ(code[high_literal_offset + 1], 0x12);
1789 DCHECK_EQ((code[high_literal_offset + 2] & 0xE0), 0x00);
1790 DCHECK_EQ(code[high_literal_offset + 3], 0x3C);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001791 // instr reg, reg, addr32_low
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001792 DCHECK_EQ(code[low_literal_offset + 0], 0x78);
1793 DCHECK_EQ(code[low_literal_offset + 1], 0x56);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001794 addr32 += (addr32 & 0x8000) << 1; // Account for sign extension in "instr reg, reg, addr32_low".
Alexey Frunze627c1a02017-01-30 19:28:14 -08001795 // lui reg, addr32_high
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001796 code[high_literal_offset + 0] = static_cast<uint8_t>(addr32 >> 16);
1797 code[high_literal_offset + 1] = static_cast<uint8_t>(addr32 >> 24);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001798 // instr reg, reg, addr32_low
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001799 code[low_literal_offset + 0] = static_cast<uint8_t>(addr32 >> 0);
1800 code[low_literal_offset + 1] = static_cast<uint8_t>(addr32 >> 8);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001801}
1802
1803void CodeGeneratorMIPS::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
1804 for (const JitPatchInfo& info : jit_string_patches_) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001805 StringReference string_reference(&info.target_dex_file, dex::StringIndex(info.index));
1806 uint64_t index_in_table = GetJitStringRootIndex(string_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01001807 PatchJitRootUse(code, roots_data, info, index_in_table);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001808 }
1809 for (const JitPatchInfo& info : jit_class_patches_) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001810 TypeReference type_reference(&info.target_dex_file, dex::TypeIndex(info.index));
1811 uint64_t index_in_table = GetJitClassRootIndex(type_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01001812 PatchJitRootUse(code, roots_data, info, index_in_table);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001813 }
1814}
1815
Goran Jakovljevice114da22016-12-26 14:21:43 +01001816void CodeGeneratorMIPS::MarkGCCard(Register object,
1817 Register value,
1818 bool value_can_be_null) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001819 MipsLabel done;
1820 Register card = AT;
1821 Register temp = TMP;
Goran Jakovljevice114da22016-12-26 14:21:43 +01001822 if (value_can_be_null) {
1823 __ Beqz(value, &done);
1824 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001825 __ LoadFromOffset(kLoadWord,
1826 card,
1827 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07001828 Thread::CardTableOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001829 __ Srl(temp, object, gc::accounting::CardTable::kCardShift);
1830 __ Addu(temp, card, temp);
1831 __ Sb(card, temp, 0);
Goran Jakovljevice114da22016-12-26 14:21:43 +01001832 if (value_can_be_null) {
1833 __ Bind(&done);
1834 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001835}
1836
David Brazdil58282f42016-01-14 12:45:10 +00001837void CodeGeneratorMIPS::SetupBlockedRegisters() const {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001838 // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated.
1839 blocked_core_registers_[ZERO] = true;
1840 blocked_core_registers_[K0] = true;
1841 blocked_core_registers_[K1] = true;
1842 blocked_core_registers_[GP] = true;
1843 blocked_core_registers_[SP] = true;
1844 blocked_core_registers_[RA] = true;
1845
1846 // AT and TMP(T8) are used as temporary/scratch registers
1847 // (similar to how AT is used by MIPS assemblers).
1848 blocked_core_registers_[AT] = true;
1849 blocked_core_registers_[TMP] = true;
1850 blocked_fpu_registers_[FTMP] = true;
1851
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +01001852 if (GetInstructionSetFeatures().HasMsa()) {
1853 // To be used just for MSA instructions.
1854 blocked_fpu_registers_[FTMP2] = true;
1855 }
1856
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001857 // Reserve suspend and thread registers.
1858 blocked_core_registers_[S0] = true;
1859 blocked_core_registers_[TR] = true;
1860
1861 // Reserve T9 for function calls
1862 blocked_core_registers_[T9] = true;
1863
1864 // Reserve odd-numbered FPU registers.
1865 for (size_t i = 1; i < kNumberOfFRegisters; i += 2) {
1866 blocked_fpu_registers_[i] = true;
1867 }
1868
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02001869 if (GetGraph()->IsDebuggable()) {
1870 // Stubs do not save callee-save floating point registers. If the graph
1871 // is debuggable, we need to deal with these registers differently. For
1872 // now, just block them.
1873 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1874 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
1875 }
1876 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001877}
1878
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001879size_t CodeGeneratorMIPS::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1880 __ StoreToOffset(kStoreWord, Register(reg_id), SP, stack_index);
1881 return kMipsWordSize;
1882}
1883
1884size_t CodeGeneratorMIPS::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1885 __ LoadFromOffset(kLoadWord, Register(reg_id), SP, stack_index);
1886 return kMipsWordSize;
1887}
1888
1889size_t CodeGeneratorMIPS::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001890 if (GetGraph()->HasSIMD()) {
1891 __ StoreQToOffset(FRegister(reg_id), SP, stack_index);
1892 } else {
1893 __ StoreDToOffset(FRegister(reg_id), SP, stack_index);
1894 }
1895 return GetFloatingPointSpillSlotSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001896}
1897
1898size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001899 if (GetGraph()->HasSIMD()) {
1900 __ LoadQFromOffset(FRegister(reg_id), SP, stack_index);
1901 } else {
1902 __ LoadDFromOffset(FRegister(reg_id), SP, stack_index);
1903 }
1904 return GetFloatingPointSpillSlotSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001905}
1906
1907void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001908 stream << Register(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001909}
1910
1911void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001912 stream << FRegister(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001913}
1914
Serban Constantinescufca16662016-07-14 09:21:59 +01001915constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16;
1916
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001917void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
1918 HInstruction* instruction,
1919 uint32_t dex_pc,
1920 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001921 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Alexey Frunze15958152017-02-09 19:08:30 -08001922 GenerateInvokeRuntime(GetThreadOffset<kMipsPointerSize>(entrypoint).Int32Value(),
1923 IsDirectEntrypoint(entrypoint));
1924 if (EntrypointRequiresStackMap(entrypoint)) {
1925 RecordPcInfo(instruction, dex_pc, slow_path);
1926 }
1927}
1928
1929void CodeGeneratorMIPS::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1930 HInstruction* instruction,
1931 SlowPathCode* slow_path,
1932 bool direct) {
1933 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
1934 GenerateInvokeRuntime(entry_point_offset, direct);
1935}
1936
1937void CodeGeneratorMIPS::GenerateInvokeRuntime(int32_t entry_point_offset, bool direct) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001938 bool reordering = __ SetReorder(false);
Alexey Frunze15958152017-02-09 19:08:30 -08001939 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001940 __ Jalr(T9);
Alexey Frunze15958152017-02-09 19:08:30 -08001941 if (direct) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001942 // Reserve argument space on stack (for $a0-$a3) for
1943 // entrypoints that directly reference native implementations.
1944 // Called function may use this space to store $a0-$a3 regs.
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001945 __ IncreaseFrameSize(kMipsDirectEntrypointRuntimeOffset); // Single instruction in delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001946 __ DecreaseFrameSize(kMipsDirectEntrypointRuntimeOffset);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001947 } else {
1948 __ Nop(); // In delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001949 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001950 __ SetReorder(reordering);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001951}
1952
1953void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
1954 Register class_reg) {
Vladimir Markodc682aa2018-01-04 18:42:57 +00001955 constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
1956 const size_t status_byte_offset =
1957 mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
1958 constexpr uint32_t shifted_initialized_value =
1959 enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
1960
1961 __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, status_byte_offset);
Lena Djokic3177e102018-02-28 11:32:40 +01001962 __ Sltiu(TMP, TMP, shifted_initialized_value);
1963 __ Bnez(TMP, slow_path->GetEntryLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001964 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1965 __ Sync(0);
1966 __ Bind(slow_path->GetExitLabel());
1967}
1968
Vladimir Marko175e7862018-03-27 09:03:13 +00001969void InstructionCodeGeneratorMIPS::GenerateBitstringTypeCheckCompare(HTypeCheckInstruction* check,
1970 Register temp) {
1971 uint32_t path_to_root = check->GetBitstringPathToRoot();
1972 uint32_t mask = check->GetBitstringMask();
1973 DCHECK(IsPowerOfTwo(mask + 1));
1974 size_t mask_bits = WhichPowerOf2(mask + 1);
1975
1976 if (mask_bits == 16u) {
1977 // Load only the bitstring part of the status word.
1978 __ LoadFromOffset(
1979 kLoadUnsignedHalfword, temp, temp, mirror::Class::StatusOffset().Int32Value());
1980 // Compare the bitstring bits using XOR.
1981 __ Xori(temp, temp, dchecked_integral_cast<uint16_t>(path_to_root));
1982 } else {
1983 // /* uint32_t */ temp = temp->status_
1984 __ LoadFromOffset(kLoadWord, temp, temp, mirror::Class::StatusOffset().Int32Value());
1985 // Compare the bitstring bits using XOR.
1986 if (IsUint<16>(path_to_root)) {
1987 __ Xori(temp, temp, dchecked_integral_cast<uint16_t>(path_to_root));
1988 } else {
1989 __ LoadConst32(TMP, path_to_root);
1990 __ Xor(temp, temp, TMP);
1991 }
1992 // Shift out bits that do not contribute to the comparison.
1993 __ Sll(temp, temp, 32 - mask_bits);
1994 }
1995}
1996
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001997void InstructionCodeGeneratorMIPS::GenerateMemoryBarrier(MemBarrierKind kind ATTRIBUTE_UNUSED) {
1998 __ Sync(0); // Only stype 0 is supported.
1999}
2000
2001void InstructionCodeGeneratorMIPS::GenerateSuspendCheck(HSuspendCheck* instruction,
2002 HBasicBlock* successor) {
2003 SuspendCheckSlowPathMIPS* slow_path =
Chris Larsena2045912017-11-02 12:39:54 -07002004 down_cast<SuspendCheckSlowPathMIPS*>(instruction->GetSlowPath());
2005
2006 if (slow_path == nullptr) {
2007 slow_path =
2008 new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathMIPS(instruction, successor);
2009 instruction->SetSlowPath(slow_path);
2010 codegen_->AddSlowPath(slow_path);
2011 if (successor != nullptr) {
2012 DCHECK(successor->IsLoopHeader());
2013 }
2014 } else {
2015 DCHECK_EQ(slow_path->GetSuccessor(), successor);
2016 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002017
2018 __ LoadFromOffset(kLoadUnsignedHalfword,
2019 TMP,
2020 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07002021 Thread::ThreadFlagsOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002022 if (successor == nullptr) {
2023 __ Bnez(TMP, slow_path->GetEntryLabel());
2024 __ Bind(slow_path->GetReturnLabel());
2025 } else {
2026 __ Beqz(TMP, codegen_->GetLabelOf(successor));
2027 __ B(slow_path->GetEntryLabel());
2028 // slow_path will return to GetLabelOf(successor).
2029 }
2030}
2031
2032InstructionCodeGeneratorMIPS::InstructionCodeGeneratorMIPS(HGraph* graph,
2033 CodeGeneratorMIPS* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08002034 : InstructionCodeGenerator(graph, codegen),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002035 assembler_(codegen->GetAssembler()),
2036 codegen_(codegen) {}
2037
2038void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
2039 DCHECK_EQ(instruction->InputCount(), 2U);
Vladimir Markoca6fff82017-10-03 14:49:14 +01002040 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002041 DataType::Type type = instruction->GetResultType();
Lena Djokic38530172017-11-16 11:11:50 +01002042 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002043 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002044 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002045 locations->SetInAt(0, Location::RequiresRegister());
2046 HInstruction* right = instruction->InputAt(1);
2047 bool can_use_imm = false;
2048 if (right->IsConstant()) {
2049 int32_t imm = CodeGenerator::GetInt32ValueOf(right->AsConstant());
2050 if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
2051 can_use_imm = IsUint<16>(imm);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002052 } else {
Lena Djokic38530172017-11-16 11:11:50 +01002053 DCHECK(instruction->IsSub() || instruction->IsAdd());
2054 if (instruction->IsSub()) {
2055 imm = -imm;
2056 }
2057 if (isR6) {
2058 bool single_use = right->GetUses().HasExactlyOneElement();
2059 int16_t imm_high = High16Bits(imm);
2060 int16_t imm_low = Low16Bits(imm);
2061 if (imm_low < 0) {
2062 imm_high += 1;
2063 }
2064 can_use_imm = !((imm_high != 0) && (imm_low != 0)) || single_use;
2065 } else {
2066 can_use_imm = IsInt<16>(imm);
2067 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002068 }
2069 }
2070 if (can_use_imm)
2071 locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
2072 else
2073 locations->SetInAt(1, Location::RequiresRegister());
2074 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2075 break;
2076 }
2077
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002078 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002079 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002080 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2081 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002082 break;
2083 }
2084
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002085 case DataType::Type::kFloat32:
2086 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002087 DCHECK(instruction->IsAdd() || instruction->IsSub());
2088 locations->SetInAt(0, Location::RequiresFpuRegister());
2089 locations->SetInAt(1, Location::RequiresFpuRegister());
2090 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2091 break;
2092
2093 default:
2094 LOG(FATAL) << "Unexpected " << instruction->DebugName() << " type " << type;
2095 }
2096}
2097
2098void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002099 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002100 LocationSummary* locations = instruction->GetLocations();
Lena Djokic38530172017-11-16 11:11:50 +01002101 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002102
2103 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002104 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002105 Register dst = locations->Out().AsRegister<Register>();
2106 Register lhs = locations->InAt(0).AsRegister<Register>();
2107 Location rhs_location = locations->InAt(1);
2108
2109 Register rhs_reg = ZERO;
2110 int32_t rhs_imm = 0;
2111 bool use_imm = rhs_location.IsConstant();
2112 if (use_imm) {
2113 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
2114 } else {
2115 rhs_reg = rhs_location.AsRegister<Register>();
2116 }
2117
2118 if (instruction->IsAnd()) {
2119 if (use_imm)
2120 __ Andi(dst, lhs, rhs_imm);
2121 else
2122 __ And(dst, lhs, rhs_reg);
2123 } else if (instruction->IsOr()) {
2124 if (use_imm)
2125 __ Ori(dst, lhs, rhs_imm);
2126 else
2127 __ Or(dst, lhs, rhs_reg);
2128 } else if (instruction->IsXor()) {
2129 if (use_imm)
2130 __ Xori(dst, lhs, rhs_imm);
2131 else
2132 __ Xor(dst, lhs, rhs_reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002133 } else {
Lena Djokic38530172017-11-16 11:11:50 +01002134 DCHECK(instruction->IsAdd() || instruction->IsSub());
2135 if (use_imm) {
2136 if (instruction->IsSub()) {
2137 rhs_imm = -rhs_imm;
2138 }
2139 if (IsInt<16>(rhs_imm)) {
2140 __ Addiu(dst, lhs, rhs_imm);
2141 } else {
2142 DCHECK(isR6);
2143 int16_t rhs_imm_high = High16Bits(rhs_imm);
2144 int16_t rhs_imm_low = Low16Bits(rhs_imm);
2145 if (rhs_imm_low < 0) {
2146 rhs_imm_high += 1;
2147 }
2148 __ Aui(dst, lhs, rhs_imm_high);
2149 if (rhs_imm_low != 0) {
2150 __ Addiu(dst, dst, rhs_imm_low);
2151 }
2152 }
2153 } else if (instruction->IsAdd()) {
2154 __ Addu(dst, lhs, rhs_reg);
2155 } else {
2156 DCHECK(instruction->IsSub());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002157 __ Subu(dst, lhs, rhs_reg);
Lena Djokic38530172017-11-16 11:11:50 +01002158 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002159 }
2160 break;
2161 }
2162
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002163 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002164 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
2165 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
2166 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2167 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002168 Location rhs_location = locations->InAt(1);
2169 bool use_imm = rhs_location.IsConstant();
2170 if (!use_imm) {
2171 Register rhs_high = rhs_location.AsRegisterPairHigh<Register>();
2172 Register rhs_low = rhs_location.AsRegisterPairLow<Register>();
2173 if (instruction->IsAnd()) {
2174 __ And(dst_low, lhs_low, rhs_low);
2175 __ And(dst_high, lhs_high, rhs_high);
2176 } else if (instruction->IsOr()) {
2177 __ Or(dst_low, lhs_low, rhs_low);
2178 __ Or(dst_high, lhs_high, rhs_high);
2179 } else if (instruction->IsXor()) {
2180 __ Xor(dst_low, lhs_low, rhs_low);
2181 __ Xor(dst_high, lhs_high, rhs_high);
2182 } else if (instruction->IsAdd()) {
2183 if (lhs_low == rhs_low) {
2184 // Special case for lhs = rhs and the sum potentially overwriting both lhs and rhs.
2185 __ Slt(TMP, lhs_low, ZERO);
2186 __ Addu(dst_low, lhs_low, rhs_low);
2187 } else {
2188 __ Addu(dst_low, lhs_low, rhs_low);
2189 // If the sum overwrites rhs, lhs remains unchanged, otherwise rhs remains unchanged.
2190 __ Sltu(TMP, dst_low, (dst_low == rhs_low) ? lhs_low : rhs_low);
2191 }
2192 __ Addu(dst_high, lhs_high, rhs_high);
2193 __ Addu(dst_high, dst_high, TMP);
2194 } else {
2195 DCHECK(instruction->IsSub());
2196 __ Sltu(TMP, lhs_low, rhs_low);
2197 __ Subu(dst_low, lhs_low, rhs_low);
2198 __ Subu(dst_high, lhs_high, rhs_high);
2199 __ Subu(dst_high, dst_high, TMP);
2200 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002201 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002202 int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
2203 if (instruction->IsOr()) {
2204 uint32_t low = Low32Bits(value);
2205 uint32_t high = High32Bits(value);
2206 if (IsUint<16>(low)) {
2207 if (dst_low != lhs_low || low != 0) {
2208 __ Ori(dst_low, lhs_low, low);
2209 }
2210 } else {
2211 __ LoadConst32(TMP, low);
2212 __ Or(dst_low, lhs_low, TMP);
2213 }
2214 if (IsUint<16>(high)) {
2215 if (dst_high != lhs_high || high != 0) {
2216 __ Ori(dst_high, lhs_high, high);
2217 }
2218 } else {
2219 if (high != low) {
2220 __ LoadConst32(TMP, high);
2221 }
2222 __ Or(dst_high, lhs_high, TMP);
2223 }
2224 } else if (instruction->IsXor()) {
2225 uint32_t low = Low32Bits(value);
2226 uint32_t high = High32Bits(value);
2227 if (IsUint<16>(low)) {
2228 if (dst_low != lhs_low || low != 0) {
2229 __ Xori(dst_low, lhs_low, low);
2230 }
2231 } else {
2232 __ LoadConst32(TMP, low);
2233 __ Xor(dst_low, lhs_low, TMP);
2234 }
2235 if (IsUint<16>(high)) {
2236 if (dst_high != lhs_high || high != 0) {
2237 __ Xori(dst_high, lhs_high, high);
2238 }
2239 } else {
2240 if (high != low) {
2241 __ LoadConst32(TMP, high);
2242 }
2243 __ Xor(dst_high, lhs_high, TMP);
2244 }
2245 } else if (instruction->IsAnd()) {
2246 uint32_t low = Low32Bits(value);
2247 uint32_t high = High32Bits(value);
2248 if (IsUint<16>(low)) {
2249 __ Andi(dst_low, lhs_low, low);
2250 } else if (low != 0xFFFFFFFF) {
2251 __ LoadConst32(TMP, low);
2252 __ And(dst_low, lhs_low, TMP);
2253 } else if (dst_low != lhs_low) {
2254 __ Move(dst_low, lhs_low);
2255 }
2256 if (IsUint<16>(high)) {
2257 __ Andi(dst_high, lhs_high, high);
2258 } else if (high != 0xFFFFFFFF) {
2259 if (high != low) {
2260 __ LoadConst32(TMP, high);
2261 }
2262 __ And(dst_high, lhs_high, TMP);
2263 } else if (dst_high != lhs_high) {
2264 __ Move(dst_high, lhs_high);
2265 }
2266 } else {
2267 if (instruction->IsSub()) {
2268 value = -value;
2269 } else {
2270 DCHECK(instruction->IsAdd());
2271 }
2272 int32_t low = Low32Bits(value);
2273 int32_t high = High32Bits(value);
2274 if (IsInt<16>(low)) {
2275 if (dst_low != lhs_low || low != 0) {
2276 __ Addiu(dst_low, lhs_low, low);
2277 }
2278 if (low != 0) {
2279 __ Sltiu(AT, dst_low, low);
2280 }
2281 } else {
2282 __ LoadConst32(TMP, low);
2283 __ Addu(dst_low, lhs_low, TMP);
2284 __ Sltu(AT, dst_low, TMP);
2285 }
2286 if (IsInt<16>(high)) {
2287 if (dst_high != lhs_high || high != 0) {
2288 __ Addiu(dst_high, lhs_high, high);
2289 }
2290 } else {
2291 if (high != low) {
2292 __ LoadConst32(TMP, high);
2293 }
2294 __ Addu(dst_high, lhs_high, TMP);
2295 }
2296 if (low != 0) {
2297 __ Addu(dst_high, dst_high, AT);
2298 }
2299 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002300 }
2301 break;
2302 }
2303
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002304 case DataType::Type::kFloat32:
2305 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002306 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
2307 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2308 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2309 if (instruction->IsAdd()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002310 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002311 __ AddS(dst, lhs, rhs);
2312 } else {
2313 __ AddD(dst, lhs, rhs);
2314 }
2315 } else {
2316 DCHECK(instruction->IsSub());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002317 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002318 __ SubS(dst, lhs, rhs);
2319 } else {
2320 __ SubD(dst, lhs, rhs);
2321 }
2322 }
2323 break;
2324 }
2325
2326 default:
2327 LOG(FATAL) << "Unexpected binary operation type " << type;
2328 }
2329}
2330
2331void LocationsBuilderMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002332 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002333
Vladimir Markoca6fff82017-10-03 14:49:14 +01002334 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instr);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002335 DataType::Type type = instr->GetResultType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002336 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002337 case DataType::Type::kInt32:
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002338 locations->SetInAt(0, Location::RequiresRegister());
2339 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
2340 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2341 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002342 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002343 locations->SetInAt(0, Location::RequiresRegister());
2344 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
2345 locations->SetOut(Location::RequiresRegister());
2346 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002347 default:
2348 LOG(FATAL) << "Unexpected shift type " << type;
2349 }
2350}
2351
2352static constexpr size_t kMipsBitsPerWord = kMipsWordSize * kBitsPerByte;
2353
2354void InstructionCodeGeneratorMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002355 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002356 LocationSummary* locations = instr->GetLocations();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002357 DataType::Type type = instr->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002358
2359 Location rhs_location = locations->InAt(1);
2360 bool use_imm = rhs_location.IsConstant();
2361 Register rhs_reg = use_imm ? ZERO : rhs_location.AsRegister<Register>();
2362 int64_t rhs_imm = use_imm ? CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()) : 0;
Roland Levillain5b5b9312016-03-22 14:57:31 +00002363 const uint32_t shift_mask =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002364 (type == DataType::Type::kInt32) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002365 const uint32_t shift_value = rhs_imm & shift_mask;
Alexey Frunze92d90602015-12-18 18:16:36 -08002366 // Are the INS (Insert Bit Field) and ROTR instructions supported?
2367 bool has_ins_rotr = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002368
2369 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002370 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002371 Register dst = locations->Out().AsRegister<Register>();
2372 Register lhs = locations->InAt(0).AsRegister<Register>();
2373 if (use_imm) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002374 if (shift_value == 0) {
2375 if (dst != lhs) {
2376 __ Move(dst, lhs);
2377 }
2378 } else if (instr->IsShl()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002379 __ Sll(dst, lhs, shift_value);
2380 } else if (instr->IsShr()) {
2381 __ Sra(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002382 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002383 __ Srl(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002384 } else {
2385 if (has_ins_rotr) {
2386 __ Rotr(dst, lhs, shift_value);
2387 } else {
2388 __ Sll(TMP, lhs, (kMipsBitsPerWord - shift_value) & shift_mask);
2389 __ Srl(dst, lhs, shift_value);
2390 __ Or(dst, dst, TMP);
2391 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002392 }
2393 } else {
2394 if (instr->IsShl()) {
2395 __ Sllv(dst, lhs, rhs_reg);
2396 } else if (instr->IsShr()) {
2397 __ Srav(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08002398 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002399 __ Srlv(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08002400 } else {
2401 if (has_ins_rotr) {
2402 __ Rotrv(dst, lhs, rhs_reg);
2403 } else {
2404 __ Subu(TMP, ZERO, rhs_reg);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002405 // 32-bit shift instructions use the 5 least significant bits of the shift count, so
2406 // shifting by `-rhs_reg` is equivalent to shifting by `(32 - rhs_reg) & 31`. The case
2407 // when `rhs_reg & 31 == 0` is OK even though we don't shift `lhs` left all the way out
2408 // by 32, because the result in this case is computed as `(lhs >> 0) | (lhs << 0)`,
2409 // IOW, the OR'd values are equal.
Alexey Frunze92d90602015-12-18 18:16:36 -08002410 __ Sllv(TMP, lhs, TMP);
2411 __ Srlv(dst, lhs, rhs_reg);
2412 __ Or(dst, dst, TMP);
2413 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002414 }
2415 }
2416 break;
2417 }
2418
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002419 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002420 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
2421 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
2422 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2423 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2424 if (use_imm) {
2425 if (shift_value == 0) {
Lena Djokic8098da92017-06-28 12:07:50 +02002426 codegen_->MoveLocation(locations->Out(), locations->InAt(0), type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002427 } else if (shift_value < kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002428 if (has_ins_rotr) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002429 if (instr->IsShl()) {
2430 __ Srl(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
2431 __ Ins(dst_high, lhs_high, shift_value, kMipsBitsPerWord - shift_value);
2432 __ Sll(dst_low, lhs_low, shift_value);
2433 } else if (instr->IsShr()) {
2434 __ Srl(dst_low, lhs_low, shift_value);
2435 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2436 __ Sra(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002437 } else if (instr->IsUShr()) {
2438 __ Srl(dst_low, lhs_low, shift_value);
2439 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2440 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002441 } else {
2442 __ Srl(dst_low, lhs_low, shift_value);
2443 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2444 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002445 __ Ins(dst_high, lhs_low, kMipsBitsPerWord - shift_value, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002446 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002447 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002448 if (instr->IsShl()) {
2449 __ Sll(dst_low, lhs_low, shift_value);
2450 __ Srl(TMP, lhs_low, kMipsBitsPerWord - shift_value);
2451 __ Sll(dst_high, lhs_high, shift_value);
2452 __ Or(dst_high, dst_high, TMP);
2453 } else if (instr->IsShr()) {
2454 __ Sra(dst_high, lhs_high, shift_value);
2455 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
2456 __ Srl(dst_low, lhs_low, shift_value);
2457 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08002458 } else if (instr->IsUShr()) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002459 __ Srl(dst_high, lhs_high, shift_value);
2460 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
2461 __ Srl(dst_low, lhs_low, shift_value);
2462 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08002463 } else {
2464 __ Srl(TMP, lhs_low, shift_value);
2465 __ Sll(dst_low, lhs_high, kMipsBitsPerWord - shift_value);
2466 __ Or(dst_low, dst_low, TMP);
2467 __ Srl(TMP, lhs_high, shift_value);
2468 __ Sll(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
2469 __ Or(dst_high, dst_high, TMP);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002470 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002471 }
2472 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002473 const uint32_t shift_value_high = shift_value - kMipsBitsPerWord;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002474 if (instr->IsShl()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002475 __ Sll(dst_high, lhs_low, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002476 __ Move(dst_low, ZERO);
2477 } else if (instr->IsShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002478 __ Sra(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002479 __ Sra(dst_high, dst_low, kMipsBitsPerWord - 1);
Alexey Frunze92d90602015-12-18 18:16:36 -08002480 } else if (instr->IsUShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002481 __ Srl(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002482 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08002483 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002484 if (shift_value == kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002485 // 64-bit rotation by 32 is just a swap.
2486 __ Move(dst_low, lhs_high);
2487 __ Move(dst_high, lhs_low);
2488 } else {
2489 if (has_ins_rotr) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002490 __ Srl(dst_low, lhs_high, shift_value_high);
2491 __ Ins(dst_low, lhs_low, kMipsBitsPerWord - shift_value_high, shift_value_high);
2492 __ Srl(dst_high, lhs_low, shift_value_high);
2493 __ Ins(dst_high, lhs_high, kMipsBitsPerWord - shift_value_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08002494 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002495 __ Sll(TMP, lhs_low, kMipsBitsPerWord - shift_value_high);
2496 __ Srl(dst_low, lhs_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08002497 __ Or(dst_low, dst_low, TMP);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002498 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value_high);
2499 __ Srl(dst_high, lhs_low, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08002500 __ Or(dst_high, dst_high, TMP);
2501 }
2502 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002503 }
2504 }
2505 } else {
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002506 const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002507 MipsLabel done;
2508 if (instr->IsShl()) {
2509 __ Sllv(dst_low, lhs_low, rhs_reg);
2510 __ Nor(AT, ZERO, rhs_reg);
2511 __ Srl(TMP, lhs_low, 1);
2512 __ Srlv(TMP, TMP, AT);
2513 __ Sllv(dst_high, lhs_high, rhs_reg);
2514 __ Or(dst_high, dst_high, TMP);
2515 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002516 if (isR6) {
2517 __ Beqzc(TMP, &done, /* is_bare */ true);
2518 __ Move(dst_high, dst_low);
2519 __ Move(dst_low, ZERO);
2520 } else {
2521 __ Movn(dst_high, dst_low, TMP);
2522 __ Movn(dst_low, ZERO, TMP);
2523 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002524 } else if (instr->IsShr()) {
2525 __ Srav(dst_high, lhs_high, rhs_reg);
2526 __ Nor(AT, ZERO, rhs_reg);
2527 __ Sll(TMP, lhs_high, 1);
2528 __ Sllv(TMP, TMP, AT);
2529 __ Srlv(dst_low, lhs_low, rhs_reg);
2530 __ Or(dst_low, dst_low, TMP);
2531 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002532 if (isR6) {
2533 __ Beqzc(TMP, &done, /* is_bare */ true);
2534 __ Move(dst_low, dst_high);
2535 __ Sra(dst_high, dst_high, 31);
2536 } else {
2537 __ Sra(AT, dst_high, 31);
2538 __ Movn(dst_low, dst_high, TMP);
2539 __ Movn(dst_high, AT, TMP);
2540 }
Alexey Frunze92d90602015-12-18 18:16:36 -08002541 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002542 __ Srlv(dst_high, lhs_high, rhs_reg);
2543 __ Nor(AT, ZERO, rhs_reg);
2544 __ Sll(TMP, lhs_high, 1);
2545 __ Sllv(TMP, TMP, AT);
2546 __ Srlv(dst_low, lhs_low, rhs_reg);
2547 __ Or(dst_low, dst_low, TMP);
2548 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002549 if (isR6) {
2550 __ Beqzc(TMP, &done, /* is_bare */ true);
2551 __ Move(dst_low, dst_high);
2552 __ Move(dst_high, ZERO);
2553 } else {
2554 __ Movn(dst_low, dst_high, TMP);
2555 __ Movn(dst_high, ZERO, TMP);
2556 }
2557 } else { // Rotate.
Alexey Frunze92d90602015-12-18 18:16:36 -08002558 __ Nor(AT, ZERO, rhs_reg);
2559 __ Srlv(TMP, lhs_low, rhs_reg);
2560 __ Sll(dst_low, lhs_high, 1);
2561 __ Sllv(dst_low, dst_low, AT);
2562 __ Or(dst_low, dst_low, TMP);
2563 __ Srlv(TMP, lhs_high, rhs_reg);
2564 __ Sll(dst_high, lhs_low, 1);
2565 __ Sllv(dst_high, dst_high, AT);
2566 __ Or(dst_high, dst_high, TMP);
2567 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002568 if (isR6) {
2569 __ Beqzc(TMP, &done, /* is_bare */ true);
2570 __ Move(TMP, dst_high);
2571 __ Move(dst_high, dst_low);
2572 __ Move(dst_low, TMP);
2573 } else {
2574 __ Movn(AT, dst_high, TMP);
2575 __ Movn(dst_high, dst_low, TMP);
2576 __ Movn(dst_low, AT, TMP);
2577 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002578 }
2579 __ Bind(&done);
2580 }
2581 break;
2582 }
2583
2584 default:
2585 LOG(FATAL) << "Unexpected shift operation type " << type;
2586 }
2587}
2588
2589void LocationsBuilderMIPS::VisitAdd(HAdd* instruction) {
2590 HandleBinaryOp(instruction);
2591}
2592
2593void InstructionCodeGeneratorMIPS::VisitAdd(HAdd* instruction) {
2594 HandleBinaryOp(instruction);
2595}
2596
2597void LocationsBuilderMIPS::VisitAnd(HAnd* instruction) {
2598 HandleBinaryOp(instruction);
2599}
2600
2601void InstructionCodeGeneratorMIPS::VisitAnd(HAnd* instruction) {
2602 HandleBinaryOp(instruction);
2603}
2604
2605void LocationsBuilderMIPS::VisitArrayGet(HArrayGet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002606 DataType::Type type = instruction->GetType();
Alexey Frunze15958152017-02-09 19:08:30 -08002607 bool object_array_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002608 kEmitCompilerReadBarrier && (type == DataType::Type::kReference);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002609 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002610 new (GetGraph()->GetAllocator()) LocationSummary(instruction,
2611 object_array_get_with_read_barrier
2612 ? LocationSummary::kCallOnSlowPath
2613 : LocationSummary::kNoCall);
Alexey Frunzec61c0762017-04-10 13:54:23 -07002614 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
2615 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
2616 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002617 locations->SetInAt(0, Location::RequiresRegister());
2618 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002619 if (DataType::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002620 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2621 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08002622 // The output overlaps in the case of an object array get with
2623 // read barriers enabled: we do not want the move to overwrite the
2624 // array's location, as we need it to emit the read barrier.
2625 locations->SetOut(Location::RequiresRegister(),
2626 object_array_get_with_read_barrier
2627 ? Location::kOutputOverlap
2628 : Location::kNoOutputOverlap);
2629 }
2630 // We need a temporary register for the read barrier marking slow
2631 // path in CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier.
2632 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002633 bool temp_needed = instruction->GetIndex()->IsConstant()
2634 ? !kBakerReadBarrierThunksEnableForFields
2635 : !kBakerReadBarrierThunksEnableForArrays;
2636 if (temp_needed) {
2637 locations->AddTemp(Location::RequiresRegister());
2638 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002639 }
2640}
2641
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002642static auto GetImplicitNullChecker(HInstruction* instruction, CodeGeneratorMIPS* codegen) {
2643 auto null_checker = [codegen, instruction]() {
2644 codegen->MaybeRecordImplicitNullCheck(instruction);
Alexey Frunze2923db72016-08-20 01:55:47 -07002645 };
2646 return null_checker;
2647}
2648
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002649void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
2650 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08002651 Location obj_loc = locations->InAt(0);
2652 Register obj = obj_loc.AsRegister<Register>();
2653 Location out_loc = locations->Out();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002654 Location index = locations->InAt(1);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01002655 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002656 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002657
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002658 DataType::Type type = instruction->GetType();
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002659 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
2660 instruction->IsStringCharAt();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002661 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002662 case DataType::Type::kBool:
2663 case DataType::Type::kUint8: {
Alexey Frunze15958152017-02-09 19:08:30 -08002664 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002665 if (index.IsConstant()) {
2666 size_t offset =
2667 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002668 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002669 } else {
2670 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07002671 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002672 }
2673 break;
2674 }
2675
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002676 case DataType::Type::kInt8: {
Alexey Frunze15958152017-02-09 19:08:30 -08002677 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002678 if (index.IsConstant()) {
2679 size_t offset =
2680 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002681 __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002682 } else {
2683 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07002684 __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002685 }
2686 break;
2687 }
2688
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002689 case DataType::Type::kUint16: {
Alexey Frunze15958152017-02-09 19:08:30 -08002690 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002691 if (maybe_compressed_char_at) {
2692 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2693 __ LoadFromOffset(kLoadWord, TMP, obj, count_offset, null_checker);
2694 __ Sll(TMP, TMP, 31); // Extract compression flag into the most significant bit of TMP.
2695 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2696 "Expecting 0=compressed, 1=uncompressed");
2697 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002698 if (index.IsConstant()) {
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002699 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
2700 if (maybe_compressed_char_at) {
2701 MipsLabel uncompressed_load, done;
2702 __ Bnez(TMP, &uncompressed_load);
2703 __ LoadFromOffset(kLoadUnsignedByte,
2704 out,
2705 obj,
2706 data_offset + (const_index << TIMES_1));
2707 __ B(&done);
2708 __ Bind(&uncompressed_load);
2709 __ LoadFromOffset(kLoadUnsignedHalfword,
2710 out,
2711 obj,
2712 data_offset + (const_index << TIMES_2));
2713 __ Bind(&done);
2714 } else {
2715 __ LoadFromOffset(kLoadUnsignedHalfword,
2716 out,
2717 obj,
2718 data_offset + (const_index << TIMES_2),
2719 null_checker);
2720 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002721 } else {
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002722 Register index_reg = index.AsRegister<Register>();
2723 if (maybe_compressed_char_at) {
2724 MipsLabel uncompressed_load, done;
2725 __ Bnez(TMP, &uncompressed_load);
2726 __ Addu(TMP, obj, index_reg);
2727 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
2728 __ B(&done);
2729 __ Bind(&uncompressed_load);
Chris Larsencd0295d2017-03-31 15:26:54 -07002730 __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002731 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
2732 __ Bind(&done);
Lena Djokica2901602017-09-21 13:50:52 +02002733 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2734 __ Addu(TMP, index_reg, obj);
2735 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002736 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002737 __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002738 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
2739 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002740 }
2741 break;
2742 }
2743
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002744 case DataType::Type::kInt16: {
2745 Register out = out_loc.AsRegister<Register>();
2746 if (index.IsConstant()) {
2747 size_t offset =
2748 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2749 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002750 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2751 __ Addu(TMP, index.AsRegister<Register>(), obj);
2752 __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002753 } else {
2754 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_2, TMP);
2755 __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
2756 }
2757 break;
2758 }
2759
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002760 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002761 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
Alexey Frunze15958152017-02-09 19:08:30 -08002762 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002763 if (index.IsConstant()) {
2764 size_t offset =
2765 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002766 __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002767 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2768 __ Addu(TMP, index.AsRegister<Register>(), obj);
2769 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002770 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002771 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002772 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002773 }
2774 break;
2775 }
2776
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002777 case DataType::Type::kReference: {
Alexey Frunze15958152017-02-09 19:08:30 -08002778 static_assert(
2779 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
2780 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
2781 // /* HeapReference<Object> */ out =
2782 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
2783 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002784 bool temp_needed = index.IsConstant()
2785 ? !kBakerReadBarrierThunksEnableForFields
2786 : !kBakerReadBarrierThunksEnableForArrays;
2787 Location temp = temp_needed ? locations->GetTemp(0) : Location::NoLocation();
Alexey Frunze15958152017-02-09 19:08:30 -08002788 // Note that a potential implicit null check is handled in this
2789 // CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier call.
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002790 DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
2791 if (index.IsConstant()) {
2792 // Array load with a constant index can be treated as a field load.
2793 size_t offset =
2794 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2795 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
2796 out_loc,
2797 obj,
2798 offset,
2799 temp,
2800 /* needs_null_check */ false);
2801 } else {
2802 codegen_->GenerateArrayLoadWithBakerReadBarrier(instruction,
2803 out_loc,
2804 obj,
2805 data_offset,
2806 index,
2807 temp,
2808 /* needs_null_check */ false);
2809 }
Alexey Frunze15958152017-02-09 19:08:30 -08002810 } else {
2811 Register out = out_loc.AsRegister<Register>();
2812 if (index.IsConstant()) {
2813 size_t offset =
2814 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2815 __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
2816 // If read barriers are enabled, emit read barriers other than
2817 // Baker's using a slow path (and also unpoison the loaded
2818 // reference, if heap poisoning is enabled).
2819 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
2820 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002821 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
Alexey Frunze15958152017-02-09 19:08:30 -08002822 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
2823 // If read barriers are enabled, emit read barriers other than
2824 // Baker's using a slow path (and also unpoison the loaded
2825 // reference, if heap poisoning is enabled).
2826 codegen_->MaybeGenerateReadBarrierSlow(instruction,
2827 out_loc,
2828 out_loc,
2829 obj_loc,
2830 data_offset,
2831 index);
2832 }
2833 }
2834 break;
2835 }
2836
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002837 case DataType::Type::kInt64: {
Alexey Frunze15958152017-02-09 19:08:30 -08002838 Register out = out_loc.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002839 if (index.IsConstant()) {
2840 size_t offset =
2841 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002842 __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002843 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2844 __ Addu(TMP, index.AsRegister<Register>(), obj);
2845 __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002846 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002847 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002848 __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002849 }
2850 break;
2851 }
2852
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002853 case DataType::Type::kFloat32: {
Alexey Frunze15958152017-02-09 19:08:30 -08002854 FRegister out = out_loc.AsFpuRegister<FRegister>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002855 if (index.IsConstant()) {
2856 size_t offset =
2857 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002858 __ LoadSFromOffset(out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002859 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2860 __ Addu(TMP, index.AsRegister<Register>(), obj);
2861 __ LoadSFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002862 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002863 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002864 __ LoadSFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002865 }
2866 break;
2867 }
2868
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002869 case DataType::Type::kFloat64: {
Alexey Frunze15958152017-02-09 19:08:30 -08002870 FRegister out = out_loc.AsFpuRegister<FRegister>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002871 if (index.IsConstant()) {
2872 size_t offset =
2873 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002874 __ LoadDFromOffset(out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002875 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2876 __ Addu(TMP, index.AsRegister<Register>(), obj);
2877 __ LoadDFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002878 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002879 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002880 __ LoadDFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002881 }
2882 break;
2883 }
2884
Aart Bik66c158e2018-01-31 12:55:04 -08002885 case DataType::Type::kUint32:
2886 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002887 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002888 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2889 UNREACHABLE();
2890 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002891}
2892
2893void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002894 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002895 locations->SetInAt(0, Location::RequiresRegister());
2896 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2897}
2898
2899void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) {
2900 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01002901 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002902 Register obj = locations->InAt(0).AsRegister<Register>();
2903 Register out = locations->Out().AsRegister<Register>();
2904 __ LoadFromOffset(kLoadWord, out, obj, offset);
2905 codegen_->MaybeRecordImplicitNullCheck(instruction);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002906 // Mask out compression flag from String's array length.
2907 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
2908 __ Srl(out, out, 1u);
2909 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002910}
2911
Alexey Frunzef58b2482016-09-02 22:14:06 -07002912Location LocationsBuilderMIPS::RegisterOrZeroConstant(HInstruction* instruction) {
2913 return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern())
2914 ? Location::ConstantLocation(instruction->AsConstant())
2915 : Location::RequiresRegister();
2916}
2917
2918Location LocationsBuilderMIPS::FpuRegisterOrConstantForStore(HInstruction* instruction) {
2919 // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register.
2920 // We can store a non-zero float or double constant without first loading it into the FPU,
2921 // but we should only prefer this if the constant has a single use.
2922 if (instruction->IsConstant() &&
2923 (instruction->AsConstant()->IsZeroBitPattern() ||
2924 instruction->GetUses().HasExactlyOneElement())) {
2925 return Location::ConstantLocation(instruction->AsConstant());
2926 // Otherwise fall through and require an FPU register for the constant.
2927 }
2928 return Location::RequiresFpuRegister();
2929}
2930
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002931void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002932 DataType::Type value_type = instruction->GetComponentType();
Alexey Frunze15958152017-02-09 19:08:30 -08002933
2934 bool needs_write_barrier =
2935 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2936 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
2937
Vladimir Markoca6fff82017-10-03 14:49:14 +01002938 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002939 instruction,
Alexey Frunze15958152017-02-09 19:08:30 -08002940 may_need_runtime_call_for_type_check ?
2941 LocationSummary::kCallOnSlowPath :
2942 LocationSummary::kNoCall);
2943
2944 locations->SetInAt(0, Location::RequiresRegister());
2945 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002946 if (DataType::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
Alexey Frunze15958152017-02-09 19:08:30 -08002947 locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002948 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08002949 locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
2950 }
2951 if (needs_write_barrier) {
2952 // Temporary register for the write barrier.
2953 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002954 }
2955}
2956
2957void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
2958 LocationSummary* locations = instruction->GetLocations();
2959 Register obj = locations->InAt(0).AsRegister<Register>();
2960 Location index = locations->InAt(1);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002961 Location value_location = locations->InAt(2);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002962 DataType::Type value_type = instruction->GetComponentType();
Alexey Frunze15958152017-02-09 19:08:30 -08002963 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002964 bool needs_write_barrier =
2965 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002966 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002967 Register base_reg = index.IsConstant() ? obj : TMP;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002968
2969 switch (value_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002970 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002971 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002972 case DataType::Type::kInt8: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002973 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002974 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002975 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002976 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002977 __ Addu(base_reg, obj, index.AsRegister<Register>());
2978 }
2979 if (value_location.IsConstant()) {
2980 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2981 __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker);
2982 } else {
2983 Register value = value_location.AsRegister<Register>();
2984 __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002985 }
2986 break;
2987 }
2988
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002989 case DataType::Type::kUint16:
2990 case DataType::Type::kInt16: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002991 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002992 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002993 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
Lena Djokica2901602017-09-21 13:50:52 +02002994 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2995 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002996 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002997 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_2, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002998 }
2999 if (value_location.IsConstant()) {
3000 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
3001 __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker);
3002 } else {
3003 Register value = value_location.AsRegister<Register>();
3004 __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003005 }
3006 break;
3007 }
3008
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003009 case DataType::Type::kInt32: {
Alexey Frunze15958152017-02-09 19:08:30 -08003010 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3011 if (index.IsConstant()) {
3012 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Lena Djokica2901602017-09-21 13:50:52 +02003013 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3014 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Alexey Frunze15958152017-02-09 19:08:30 -08003015 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003016 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunze15958152017-02-09 19:08:30 -08003017 }
3018 if (value_location.IsConstant()) {
3019 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
3020 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
3021 } else {
3022 Register value = value_location.AsRegister<Register>();
3023 __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
3024 }
3025 break;
3026 }
3027
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003028 case DataType::Type::kReference: {
Alexey Frunze15958152017-02-09 19:08:30 -08003029 if (value_location.IsConstant()) {
3030 // Just setting null.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003031 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003032 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003033 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003034 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003035 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003036 }
Alexey Frunze15958152017-02-09 19:08:30 -08003037 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
3038 DCHECK_EQ(value, 0);
3039 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
3040 DCHECK(!needs_write_barrier);
3041 DCHECK(!may_need_runtime_call_for_type_check);
3042 break;
3043 }
3044
3045 DCHECK(needs_write_barrier);
3046 Register value = value_location.AsRegister<Register>();
3047 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
3048 Register temp2 = TMP; // Doesn't need to survive slow path.
3049 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3050 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3051 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3052 MipsLabel done;
3053 SlowPathCodeMIPS* slow_path = nullptr;
3054
3055 if (may_need_runtime_call_for_type_check) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01003056 slow_path = new (codegen_->GetScopedAllocator()) ArraySetSlowPathMIPS(instruction);
Alexey Frunze15958152017-02-09 19:08:30 -08003057 codegen_->AddSlowPath(slow_path);
3058 if (instruction->GetValueCanBeNull()) {
3059 MipsLabel non_zero;
3060 __ Bnez(value, &non_zero);
3061 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3062 if (index.IsConstant()) {
3063 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Lena Djokica2901602017-09-21 13:50:52 +02003064 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3065 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Alexey Frunzec061de12017-02-14 13:27:23 -08003066 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003067 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunzec061de12017-02-14 13:27:23 -08003068 }
Alexey Frunze15958152017-02-09 19:08:30 -08003069 __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
3070 __ B(&done);
3071 __ Bind(&non_zero);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003072 }
Alexey Frunze15958152017-02-09 19:08:30 -08003073
3074 // Note that when read barriers are enabled, the type checks
3075 // are performed without read barriers. This is fine, even in
3076 // the case where a class object is in the from-space after
3077 // the flip, as a comparison involving such a type would not
3078 // produce a false positive; it may of course produce a false
3079 // negative, in which case we would take the ArraySet slow
3080 // path.
3081
3082 // /* HeapReference<Class> */ temp1 = obj->klass_
3083 __ LoadFromOffset(kLoadWord, temp1, obj, class_offset, null_checker);
3084 __ MaybeUnpoisonHeapReference(temp1);
3085
3086 // /* HeapReference<Class> */ temp1 = temp1->component_type_
3087 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
3088 // /* HeapReference<Class> */ temp2 = value->klass_
3089 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
3090 // If heap poisoning is enabled, no need to unpoison `temp1`
3091 // nor `temp2`, as we are comparing two poisoned references.
3092
3093 if (instruction->StaticTypeOfArrayIsObjectArray()) {
3094 MipsLabel do_put;
3095 __ Beq(temp1, temp2, &do_put);
3096 // If heap poisoning is enabled, the `temp1` reference has
3097 // not been unpoisoned yet; unpoison it now.
3098 __ MaybeUnpoisonHeapReference(temp1);
3099
3100 // /* HeapReference<Class> */ temp1 = temp1->super_class_
3101 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
3102 // If heap poisoning is enabled, no need to unpoison
3103 // `temp1`, as we are comparing against null below.
3104 __ Bnez(temp1, slow_path->GetEntryLabel());
3105 __ Bind(&do_put);
3106 } else {
3107 __ Bne(temp1, temp2, slow_path->GetEntryLabel());
3108 }
3109 }
3110
3111 Register source = value;
3112 if (kPoisonHeapReferences) {
3113 // Note that in the case where `value` is a null reference,
3114 // we do not enter this block, as a null reference does not
3115 // need poisoning.
3116 __ Move(temp1, value);
3117 __ PoisonHeapReference(temp1);
3118 source = temp1;
3119 }
3120
3121 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3122 if (index.IsConstant()) {
3123 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003124 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003125 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunze15958152017-02-09 19:08:30 -08003126 }
3127 __ StoreToOffset(kStoreWord, source, base_reg, data_offset);
3128
3129 if (!may_need_runtime_call_for_type_check) {
3130 codegen_->MaybeRecordImplicitNullCheck(instruction);
3131 }
3132
3133 codegen_->MarkGCCard(obj, value, instruction->GetValueCanBeNull());
3134
3135 if (done.IsLinked()) {
3136 __ Bind(&done);
3137 }
3138
3139 if (slow_path != nullptr) {
3140 __ Bind(slow_path->GetExitLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003141 }
3142 break;
3143 }
3144
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003145 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003146 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003147 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003148 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Lena Djokica2901602017-09-21 13:50:52 +02003149 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3150 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003151 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003152 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07003153 }
3154 if (value_location.IsConstant()) {
3155 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
3156 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
3157 } else {
3158 Register value = value_location.AsRegisterPairLow<Register>();
3159 __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003160 }
3161 break;
3162 }
3163
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003164 case DataType::Type::kFloat32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003165 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003166 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003167 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Lena Djokica2901602017-09-21 13:50:52 +02003168 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3169 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003170 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003171 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07003172 }
3173 if (value_location.IsConstant()) {
3174 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
3175 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
3176 } else {
3177 FRegister value = value_location.AsFpuRegister<FRegister>();
3178 __ StoreSToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003179 }
3180 break;
3181 }
3182
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003183 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003184 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003185 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003186 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Lena Djokica2901602017-09-21 13:50:52 +02003187 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3188 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003189 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003190 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07003191 }
3192 if (value_location.IsConstant()) {
3193 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
3194 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
3195 } else {
3196 FRegister value = value_location.AsFpuRegister<FRegister>();
3197 __ StoreDToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003198 }
3199 break;
3200 }
3201
Aart Bik66c158e2018-01-31 12:55:04 -08003202 case DataType::Type::kUint32:
3203 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003204 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003205 LOG(FATAL) << "Unreachable type " << instruction->GetType();
3206 UNREACHABLE();
3207 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003208}
3209
Lena Djokica2901602017-09-21 13:50:52 +02003210void LocationsBuilderMIPS::VisitIntermediateArrayAddressIndex(
3211 HIntermediateArrayAddressIndex* instruction) {
3212 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003213 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Lena Djokica2901602017-09-21 13:50:52 +02003214
3215 HIntConstant* shift = instruction->GetShift()->AsIntConstant();
3216
3217 locations->SetInAt(0, Location::RequiresRegister());
3218 locations->SetInAt(1, Location::ConstantLocation(shift));
3219 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3220}
3221
3222void InstructionCodeGeneratorMIPS::VisitIntermediateArrayAddressIndex(
3223 HIntermediateArrayAddressIndex* instruction) {
3224 LocationSummary* locations = instruction->GetLocations();
3225 Register index_reg = locations->InAt(0).AsRegister<Register>();
3226 uint32_t shift = instruction->GetShift()->AsIntConstant()->GetValue();
3227 __ Sll(locations->Out().AsRegister<Register>(), index_reg, shift);
3228}
3229
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003230void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01003231 RegisterSet caller_saves = RegisterSet::Empty();
3232 InvokeRuntimeCallingConvention calling_convention;
3233 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3234 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3235 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003236
3237 HInstruction* index = instruction->InputAt(0);
3238 HInstruction* length = instruction->InputAt(1);
3239
3240 bool const_index = false;
3241 bool const_length = false;
3242
3243 if (index->IsConstant()) {
3244 if (length->IsConstant()) {
3245 const_index = true;
3246 const_length = true;
3247 } else {
3248 int32_t index_value = index->AsIntConstant()->GetValue();
3249 if (index_value < 0 || IsInt<16>(index_value + 1)) {
3250 const_index = true;
3251 }
3252 }
3253 } else if (length->IsConstant()) {
3254 int32_t length_value = length->AsIntConstant()->GetValue();
3255 if (IsUint<15>(length_value)) {
3256 const_length = true;
3257 }
3258 }
3259
3260 locations->SetInAt(0, const_index
3261 ? Location::ConstantLocation(index->AsConstant())
3262 : Location::RequiresRegister());
3263 locations->SetInAt(1, const_length
3264 ? Location::ConstantLocation(length->AsConstant())
3265 : Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003266}
3267
3268void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
3269 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003270 Location index_loc = locations->InAt(0);
3271 Location length_loc = locations->InAt(1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003272
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003273 if (length_loc.IsConstant()) {
3274 int32_t length = length_loc.GetConstant()->AsIntConstant()->GetValue();
3275 if (index_loc.IsConstant()) {
3276 int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
3277 if (index < 0 || index >= length) {
3278 BoundsCheckSlowPathMIPS* slow_path =
3279 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
3280 codegen_->AddSlowPath(slow_path);
3281 __ B(slow_path->GetEntryLabel());
3282 } else {
3283 // Nothing to be done.
3284 }
3285 return;
3286 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003287
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003288 BoundsCheckSlowPathMIPS* slow_path =
3289 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
3290 codegen_->AddSlowPath(slow_path);
3291 Register index = index_loc.AsRegister<Register>();
3292 if (length == 0) {
3293 __ B(slow_path->GetEntryLabel());
3294 } else if (length == 1) {
3295 __ Bnez(index, slow_path->GetEntryLabel());
3296 } else {
3297 DCHECK(IsUint<15>(length)) << length;
3298 __ Sltiu(TMP, index, length);
3299 __ Beqz(TMP, slow_path->GetEntryLabel());
3300 }
3301 } else {
3302 Register length = length_loc.AsRegister<Register>();
3303 BoundsCheckSlowPathMIPS* slow_path =
3304 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
3305 codegen_->AddSlowPath(slow_path);
3306 if (index_loc.IsConstant()) {
3307 int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
3308 if (index < 0) {
3309 __ B(slow_path->GetEntryLabel());
3310 } else if (index == 0) {
3311 __ Blez(length, slow_path->GetEntryLabel());
3312 } else {
3313 DCHECK(IsInt<16>(index + 1)) << index;
3314 __ Sltiu(TMP, length, index + 1);
3315 __ Bnez(TMP, slow_path->GetEntryLabel());
3316 }
3317 } else {
3318 Register index = index_loc.AsRegister<Register>();
3319 __ Bgeu(index, length, slow_path->GetEntryLabel());
3320 }
3321 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003322}
3323
Alexey Frunze15958152017-02-09 19:08:30 -08003324// Temp is used for read barrier.
3325static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
3326 if (kEmitCompilerReadBarrier &&
Alexey Frunze4147fcc2017-06-17 19:57:27 -07003327 !(kUseBakerReadBarrier && kBakerReadBarrierThunksEnableForFields) &&
Alexey Frunze15958152017-02-09 19:08:30 -08003328 (kUseBakerReadBarrier ||
3329 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
3330 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
3331 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
3332 return 1;
3333 }
3334 return 0;
3335}
3336
3337// Extra temp is used for read barrier.
3338static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
3339 return 1 + NumberOfInstanceOfTemps(type_check_kind);
3340}
3341
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003342void LocationsBuilderMIPS::VisitCheckCast(HCheckCast* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003343 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Alexey Frunzedfc30af2018-01-24 16:25:10 -08003344 LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
Vladimir Markoca6fff82017-10-03 14:49:14 +01003345 LocationSummary* locations =
3346 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003347 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko175e7862018-03-27 09:03:13 +00003348 if (type_check_kind == TypeCheckKind::kBitstringCheck) {
3349 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
3350 locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
3351 locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)->AsConstant()));
3352 } else {
3353 locations->SetInAt(1, Location::RequiresRegister());
3354 }
Alexey Frunze15958152017-02-09 19:08:30 -08003355 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003356}
3357
3358void InstructionCodeGeneratorMIPS::VisitCheckCast(HCheckCast* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003359 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003360 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08003361 Location obj_loc = locations->InAt(0);
3362 Register obj = obj_loc.AsRegister<Register>();
Vladimir Marko175e7862018-03-27 09:03:13 +00003363 Location cls = locations->InAt(1);
Alexey Frunze15958152017-02-09 19:08:30 -08003364 Location temp_loc = locations->GetTemp(0);
3365 Register temp = temp_loc.AsRegister<Register>();
3366 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
3367 DCHECK_LE(num_temps, 2u);
3368 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003369 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3370 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3371 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3372 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
3373 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
3374 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
3375 const uint32_t object_array_data_offset =
3376 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
3377 MipsLabel done;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003378
Alexey Frunzedfc30af2018-01-24 16:25:10 -08003379 bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003380 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01003381 new (codegen_->GetScopedAllocator()) TypeCheckSlowPathMIPS(
3382 instruction, is_type_check_slow_path_fatal);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003383 codegen_->AddSlowPath(slow_path);
3384
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003385 // Avoid this check if we know `obj` is not null.
3386 if (instruction->MustDoNullCheck()) {
3387 __ Beqz(obj, &done);
3388 }
3389
3390 switch (type_check_kind) {
3391 case TypeCheckKind::kExactCheck:
3392 case TypeCheckKind::kArrayCheck: {
3393 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003394 GenerateReferenceLoadTwoRegisters(instruction,
3395 temp_loc,
3396 obj_loc,
3397 class_offset,
3398 maybe_temp2_loc,
3399 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003400 // Jump to slow path for throwing the exception or doing a
3401 // more involved array check.
Vladimir Marko175e7862018-03-27 09:03:13 +00003402 __ Bne(temp, cls.AsRegister<Register>(), slow_path->GetEntryLabel());
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003403 break;
3404 }
3405
3406 case TypeCheckKind::kAbstractClassCheck: {
3407 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003408 GenerateReferenceLoadTwoRegisters(instruction,
3409 temp_loc,
3410 obj_loc,
3411 class_offset,
3412 maybe_temp2_loc,
3413 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003414 // If the class is abstract, we eagerly fetch the super class of the
3415 // object to avoid doing a comparison we know will fail.
3416 MipsLabel loop;
3417 __ Bind(&loop);
3418 // /* HeapReference<Class> */ temp = temp->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08003419 GenerateReferenceLoadOneRegister(instruction,
3420 temp_loc,
3421 super_offset,
3422 maybe_temp2_loc,
3423 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003424 // If the class reference currently in `temp` is null, jump to the slow path to throw the
3425 // exception.
3426 __ Beqz(temp, slow_path->GetEntryLabel());
3427 // Otherwise, compare the classes.
Vladimir Marko175e7862018-03-27 09:03:13 +00003428 __ Bne(temp, cls.AsRegister<Register>(), &loop);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003429 break;
3430 }
3431
3432 case TypeCheckKind::kClassHierarchyCheck: {
3433 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003434 GenerateReferenceLoadTwoRegisters(instruction,
3435 temp_loc,
3436 obj_loc,
3437 class_offset,
3438 maybe_temp2_loc,
3439 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003440 // Walk over the class hierarchy to find a match.
3441 MipsLabel loop;
3442 __ Bind(&loop);
Vladimir Marko175e7862018-03-27 09:03:13 +00003443 __ Beq(temp, cls.AsRegister<Register>(), &done);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003444 // /* HeapReference<Class> */ temp = temp->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08003445 GenerateReferenceLoadOneRegister(instruction,
3446 temp_loc,
3447 super_offset,
3448 maybe_temp2_loc,
3449 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003450 // If the class reference currently in `temp` is null, jump to the slow path to throw the
3451 // exception. Otherwise, jump to the beginning of the loop.
3452 __ Bnez(temp, &loop);
3453 __ B(slow_path->GetEntryLabel());
3454 break;
3455 }
3456
3457 case TypeCheckKind::kArrayObjectCheck: {
3458 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003459 GenerateReferenceLoadTwoRegisters(instruction,
3460 temp_loc,
3461 obj_loc,
3462 class_offset,
3463 maybe_temp2_loc,
3464 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003465 // Do an exact check.
Vladimir Marko175e7862018-03-27 09:03:13 +00003466 __ Beq(temp, cls.AsRegister<Register>(), &done);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003467 // Otherwise, we need to check that the object's class is a non-primitive array.
3468 // /* HeapReference<Class> */ temp = temp->component_type_
Alexey Frunze15958152017-02-09 19:08:30 -08003469 GenerateReferenceLoadOneRegister(instruction,
3470 temp_loc,
3471 component_offset,
3472 maybe_temp2_loc,
3473 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003474 // If the component type is null, jump to the slow path to throw the exception.
3475 __ Beqz(temp, slow_path->GetEntryLabel());
3476 // Otherwise, the object is indeed an array, further check that this component
3477 // type is not a primitive type.
3478 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
3479 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
3480 __ Bnez(temp, slow_path->GetEntryLabel());
3481 break;
3482 }
3483
3484 case TypeCheckKind::kUnresolvedCheck:
3485 // We always go into the type check slow path for the unresolved check case.
3486 // We cannot directly call the CheckCast runtime entry point
3487 // without resorting to a type checking slow path here (i.e. by
3488 // calling InvokeRuntime directly), as it would require to
3489 // assign fixed registers for the inputs of this HInstanceOf
3490 // instruction (following the runtime calling convention), which
3491 // might be cluttered by the potential first read barrier
3492 // emission at the beginning of this method.
3493 __ B(slow_path->GetEntryLabel());
3494 break;
3495
3496 case TypeCheckKind::kInterfaceCheck: {
3497 // Avoid read barriers to improve performance of the fast path. We can not get false
3498 // positives by doing this.
3499 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003500 GenerateReferenceLoadTwoRegisters(instruction,
3501 temp_loc,
3502 obj_loc,
3503 class_offset,
3504 maybe_temp2_loc,
3505 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003506 // /* HeapReference<Class> */ temp = temp->iftable_
Alexey Frunze15958152017-02-09 19:08:30 -08003507 GenerateReferenceLoadTwoRegisters(instruction,
3508 temp_loc,
3509 temp_loc,
3510 iftable_offset,
3511 maybe_temp2_loc,
3512 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003513 // Iftable is never null.
3514 __ Lw(TMP, temp, array_length_offset);
3515 // Loop through the iftable and check if any class matches.
3516 MipsLabel loop;
3517 __ Bind(&loop);
3518 __ Addiu(temp, temp, 2 * kHeapReferenceSize); // Possibly in delay slot on R2.
3519 __ Beqz(TMP, slow_path->GetEntryLabel());
3520 __ Lw(AT, temp, object_array_data_offset - 2 * kHeapReferenceSize);
3521 __ MaybeUnpoisonHeapReference(AT);
3522 // Go to next interface.
3523 __ Addiu(TMP, TMP, -2);
3524 // Compare the classes and continue the loop if they do not match.
Vladimir Marko175e7862018-03-27 09:03:13 +00003525 __ Bne(AT, cls.AsRegister<Register>(), &loop);
3526 break;
3527 }
3528
3529 case TypeCheckKind::kBitstringCheck: {
3530 // /* HeapReference<Class> */ temp = obj->klass_
3531 GenerateReferenceLoadTwoRegisters(instruction,
3532 temp_loc,
3533 obj_loc,
3534 class_offset,
3535 maybe_temp2_loc,
3536 kWithoutReadBarrier);
3537
3538 GenerateBitstringTypeCheckCompare(instruction, temp);
3539 __ Bnez(temp, slow_path->GetEntryLabel());
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003540 break;
3541 }
3542 }
3543
3544 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003545 __ Bind(slow_path->GetExitLabel());
3546}
3547
3548void LocationsBuilderMIPS::VisitClinitCheck(HClinitCheck* check) {
3549 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003550 new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003551 locations->SetInAt(0, Location::RequiresRegister());
3552 if (check->HasUses()) {
3553 locations->SetOut(Location::SameAsFirstInput());
3554 }
3555}
3556
3557void InstructionCodeGeneratorMIPS::VisitClinitCheck(HClinitCheck* check) {
3558 // We assume the class is not null.
Vladimir Marko174b2e22017-10-12 13:34:49 +01003559 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathMIPS(
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003560 check->GetLoadClass(),
3561 check,
3562 check->GetDexPc(),
3563 true);
3564 codegen_->AddSlowPath(slow_path);
3565 GenerateClassInitializationCheck(slow_path,
3566 check->GetLocations()->InAt(0).AsRegister<Register>());
3567}
3568
3569void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003570 DataType::Type in_type = compare->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003571
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003572 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003573 new (GetGraph()->GetAllocator()) LocationSummary(compare, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003574
3575 switch (in_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003576 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003577 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003578 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003579 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003580 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003581 case DataType::Type::kInt32:
Alexey Frunzee7697712016-09-15 21:37:49 -07003582 locations->SetInAt(0, Location::RequiresRegister());
3583 locations->SetInAt(1, Location::RequiresRegister());
3584 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3585 break;
3586
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003587 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003588 locations->SetInAt(0, Location::RequiresRegister());
3589 locations->SetInAt(1, Location::RequiresRegister());
3590 // Output overlaps because it is written before doing the low comparison.
3591 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3592 break;
3593
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003594 case DataType::Type::kFloat32:
3595 case DataType::Type::kFloat64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003596 locations->SetInAt(0, Location::RequiresFpuRegister());
3597 locations->SetInAt(1, Location::RequiresFpuRegister());
3598 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003599 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003600
3601 default:
3602 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
3603 }
3604}
3605
3606void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
3607 LocationSummary* locations = instruction->GetLocations();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003608 Register res = locations->Out().AsRegister<Register>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003609 DataType::Type in_type = instruction->InputAt(0)->GetType();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003610 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003611
3612 // 0 if: left == right
3613 // 1 if: left > right
3614 // -1 if: left < right
3615 switch (in_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003616 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003617 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003618 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003619 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003620 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003621 case DataType::Type::kInt32: {
Aart Bika19616e2016-02-01 18:57:58 -08003622 Register lhs = locations->InAt(0).AsRegister<Register>();
3623 Register rhs = locations->InAt(1).AsRegister<Register>();
3624 __ Slt(TMP, lhs, rhs);
3625 __ Slt(res, rhs, lhs);
3626 __ Subu(res, res, TMP);
3627 break;
3628 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003629 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003630 MipsLabel done;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003631 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
3632 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
3633 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
3634 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
3635 // TODO: more efficient (direct) comparison with a constant.
3636 __ Slt(TMP, lhs_high, rhs_high);
3637 __ Slt(AT, rhs_high, lhs_high); // Inverted: is actually gt.
3638 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
3639 __ Bnez(res, &done); // If we compared ==, check if lower bits are also equal.
3640 __ Sltu(TMP, lhs_low, rhs_low);
3641 __ Sltu(AT, rhs_low, lhs_low); // Inverted: is actually gt.
3642 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
3643 __ Bind(&done);
3644 break;
3645 }
3646
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003647 case DataType::Type::kFloat32: {
Roland Levillain32ca3752016-02-17 16:49:37 +00003648 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003649 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3650 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3651 MipsLabel done;
3652 if (isR6) {
3653 __ CmpEqS(FTMP, lhs, rhs);
3654 __ LoadConst32(res, 0);
3655 __ Bc1nez(FTMP, &done);
3656 if (gt_bias) {
3657 __ CmpLtS(FTMP, lhs, rhs);
3658 __ LoadConst32(res, -1);
3659 __ Bc1nez(FTMP, &done);
3660 __ LoadConst32(res, 1);
3661 } else {
3662 __ CmpLtS(FTMP, rhs, lhs);
3663 __ LoadConst32(res, 1);
3664 __ Bc1nez(FTMP, &done);
3665 __ LoadConst32(res, -1);
3666 }
3667 } else {
3668 if (gt_bias) {
3669 __ ColtS(0, lhs, rhs);
3670 __ LoadConst32(res, -1);
3671 __ Bc1t(0, &done);
3672 __ CeqS(0, lhs, rhs);
3673 __ LoadConst32(res, 1);
3674 __ Movt(res, ZERO, 0);
3675 } else {
3676 __ ColtS(0, rhs, lhs);
3677 __ LoadConst32(res, 1);
3678 __ Bc1t(0, &done);
3679 __ CeqS(0, lhs, rhs);
3680 __ LoadConst32(res, -1);
3681 __ Movt(res, ZERO, 0);
3682 }
3683 }
3684 __ Bind(&done);
3685 break;
3686 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003687 case DataType::Type::kFloat64: {
Roland Levillain32ca3752016-02-17 16:49:37 +00003688 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003689 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3690 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3691 MipsLabel done;
3692 if (isR6) {
3693 __ CmpEqD(FTMP, lhs, rhs);
3694 __ LoadConst32(res, 0);
3695 __ Bc1nez(FTMP, &done);
3696 if (gt_bias) {
3697 __ CmpLtD(FTMP, lhs, rhs);
3698 __ LoadConst32(res, -1);
3699 __ Bc1nez(FTMP, &done);
3700 __ LoadConst32(res, 1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003701 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003702 __ CmpLtD(FTMP, rhs, lhs);
3703 __ LoadConst32(res, 1);
3704 __ Bc1nez(FTMP, &done);
3705 __ LoadConst32(res, -1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003706 }
3707 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003708 if (gt_bias) {
3709 __ ColtD(0, lhs, rhs);
3710 __ LoadConst32(res, -1);
3711 __ Bc1t(0, &done);
3712 __ CeqD(0, lhs, rhs);
3713 __ LoadConst32(res, 1);
3714 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003715 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003716 __ ColtD(0, rhs, lhs);
3717 __ LoadConst32(res, 1);
3718 __ Bc1t(0, &done);
3719 __ CeqD(0, lhs, rhs);
3720 __ LoadConst32(res, -1);
3721 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003722 }
3723 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003724 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003725 break;
3726 }
3727
3728 default:
3729 LOG(FATAL) << "Unimplemented compare type " << in_type;
3730 }
3731}
3732
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003733void LocationsBuilderMIPS::HandleCondition(HCondition* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01003734 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003735 switch (instruction->InputAt(0)->GetType()) {
3736 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003737 case DataType::Type::kInt64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003738 locations->SetInAt(0, Location::RequiresRegister());
3739 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3740 break;
3741
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003742 case DataType::Type::kFloat32:
3743 case DataType::Type::kFloat64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003744 locations->SetInAt(0, Location::RequiresFpuRegister());
3745 locations->SetInAt(1, Location::RequiresFpuRegister());
3746 break;
3747 }
David Brazdilb3e773e2016-01-26 11:28:37 +00003748 if (!instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003749 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3750 }
3751}
3752
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003753void InstructionCodeGeneratorMIPS::HandleCondition(HCondition* instruction) {
David Brazdilb3e773e2016-01-26 11:28:37 +00003754 if (instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003755 return;
3756 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003757
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003758 DataType::Type type = instruction->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003759 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003760
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003761 switch (type) {
3762 default:
3763 // Integer case.
3764 GenerateIntCompare(instruction->GetCondition(), locations);
3765 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003766
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003767 case DataType::Type::kInt64:
Tijana Jakovljevic6d482aa2017-02-03 13:24:08 +01003768 GenerateLongCompare(instruction->GetCondition(), locations);
3769 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003770
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003771 case DataType::Type::kFloat32:
3772 case DataType::Type::kFloat64:
Alexey Frunze2ddb7172016-09-06 17:04:55 -07003773 GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
3774 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003775 }
3776}
3777
Alexey Frunze7e99e052015-11-24 19:28:01 -08003778void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3779 DCHECK(instruction->IsDiv() || instruction->IsRem());
Alexey Frunze7e99e052015-11-24 19:28:01 -08003780
3781 LocationSummary* locations = instruction->GetLocations();
3782 Location second = locations->InAt(1);
3783 DCHECK(second.IsConstant());
Lena Djokic4b8025c2017-12-21 16:15:50 +01003784 int64_t imm = Int64FromConstant(second.GetConstant());
Alexey Frunze7e99e052015-11-24 19:28:01 -08003785 DCHECK(imm == 1 || imm == -1);
3786
Lena Djokic4b8025c2017-12-21 16:15:50 +01003787 if (instruction->GetResultType() == DataType::Type::kInt32) {
3788 Register out = locations->Out().AsRegister<Register>();
3789 Register dividend = locations->InAt(0).AsRegister<Register>();
3790
3791 if (instruction->IsRem()) {
3792 __ Move(out, ZERO);
3793 } else {
3794 if (imm == -1) {
3795 __ Subu(out, ZERO, dividend);
3796 } else if (out != dividend) {
3797 __ Move(out, dividend);
3798 }
3799 }
Alexey Frunze7e99e052015-11-24 19:28:01 -08003800 } else {
Lena Djokic4b8025c2017-12-21 16:15:50 +01003801 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
3802 Register out_high = locations->Out().AsRegisterPairHigh<Register>();
3803 Register out_low = locations->Out().AsRegisterPairLow<Register>();
3804 Register in_high = locations->InAt(0).AsRegisterPairHigh<Register>();
3805 Register in_low = locations->InAt(0).AsRegisterPairLow<Register>();
3806
3807 if (instruction->IsRem()) {
3808 __ Move(out_high, ZERO);
3809 __ Move(out_low, ZERO);
3810 } else {
3811 if (imm == -1) {
3812 __ Subu(out_low, ZERO, in_low);
3813 __ Sltu(AT, ZERO, out_low);
3814 __ Subu(out_high, ZERO, in_high);
3815 __ Subu(out_high, out_high, AT);
3816 } else {
3817 __ Move(out_low, in_low);
3818 __ Move(out_high, in_high);
3819 }
Alexey Frunze7e99e052015-11-24 19:28:01 -08003820 }
3821 }
3822}
3823
3824void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
3825 DCHECK(instruction->IsDiv() || instruction->IsRem());
Alexey Frunze7e99e052015-11-24 19:28:01 -08003826
3827 LocationSummary* locations = instruction->GetLocations();
3828 Location second = locations->InAt(1);
Lena Djokic4b8025c2017-12-21 16:15:50 +01003829 const bool is_r2_or_newer = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
3830 const bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
Alexey Frunze7e99e052015-11-24 19:28:01 -08003831 DCHECK(second.IsConstant());
3832
Lena Djokic4b8025c2017-12-21 16:15:50 +01003833 if (instruction->GetResultType() == DataType::Type::kInt32) {
3834 Register out = locations->Out().AsRegister<Register>();
3835 Register dividend = locations->InAt(0).AsRegister<Register>();
3836 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3837 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
3838 int ctz_imm = CTZ(abs_imm);
Alexey Frunze7e99e052015-11-24 19:28:01 -08003839
Lena Djokic4b8025c2017-12-21 16:15:50 +01003840 if (instruction->IsDiv()) {
3841 if (ctz_imm == 1) {
3842 // Fast path for division by +/-2, which is very common.
3843 __ Srl(TMP, dividend, 31);
3844 } else {
3845 __ Sra(TMP, dividend, 31);
3846 __ Srl(TMP, TMP, 32 - ctz_imm);
3847 }
3848 __ Addu(out, dividend, TMP);
3849 __ Sra(out, out, ctz_imm);
3850 if (imm < 0) {
3851 __ Subu(out, ZERO, out);
3852 }
Alexey Frunze7e99e052015-11-24 19:28:01 -08003853 } else {
Lena Djokic4b8025c2017-12-21 16:15:50 +01003854 if (ctz_imm == 1) {
3855 // Fast path for modulo +/-2, which is very common.
3856 __ Sra(TMP, dividend, 31);
3857 __ Subu(out, dividend, TMP);
3858 __ Andi(out, out, 1);
3859 __ Addu(out, out, TMP);
3860 } else {
3861 __ Sra(TMP, dividend, 31);
3862 __ Srl(TMP, TMP, 32 - ctz_imm);
3863 __ Addu(out, dividend, TMP);
3864 if (IsUint<16>(abs_imm - 1)) {
3865 __ Andi(out, out, abs_imm - 1);
3866 } else {
3867 if (is_r2_or_newer) {
3868 __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm);
3869 } else {
3870 __ Sll(out, out, 32 - ctz_imm);
3871 __ Srl(out, out, 32 - ctz_imm);
3872 }
3873 }
3874 __ Subu(out, out, TMP);
3875 }
Alexey Frunze7e99e052015-11-24 19:28:01 -08003876 }
3877 } else {
Lena Djokic4b8025c2017-12-21 16:15:50 +01003878 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt64);
3879 Register out_high = locations->Out().AsRegisterPairHigh<Register>();
3880 Register out_low = locations->Out().AsRegisterPairLow<Register>();
3881 Register in_high = locations->InAt(0).AsRegisterPairHigh<Register>();
3882 Register in_low = locations->InAt(0).AsRegisterPairLow<Register>();
3883 int64_t imm = Int64FromConstant(second.GetConstant());
3884 uint64_t abs_imm = static_cast<uint64_t>(AbsOrMin(imm));
3885 int ctz_imm = CTZ(abs_imm);
3886
3887 if (instruction->IsDiv()) {
3888 if (ctz_imm < 32) {
3889 if (ctz_imm == 1) {
3890 __ Srl(AT, in_high, 31);
Lena Djokica556e6b2017-12-13 12:09:42 +01003891 } else {
Lena Djokic4b8025c2017-12-21 16:15:50 +01003892 __ Sra(AT, in_high, 31);
3893 __ Srl(AT, AT, 32 - ctz_imm);
Lena Djokica556e6b2017-12-13 12:09:42 +01003894 }
Lena Djokic4b8025c2017-12-21 16:15:50 +01003895 __ Addu(AT, AT, in_low);
3896 __ Sltu(TMP, AT, in_low);
3897 __ Addu(out_high, in_high, TMP);
3898 __ Srl(out_low, AT, ctz_imm);
3899 if (is_r2_or_newer) {
3900 __ Ins(out_low, out_high, 32 - ctz_imm, ctz_imm);
3901 __ Sra(out_high, out_high, ctz_imm);
3902 } else {
3903 __ Sll(AT, out_high, 32 - ctz_imm);
3904 __ Sra(out_high, out_high, ctz_imm);
3905 __ Or(out_low, out_low, AT);
3906 }
3907 if (imm < 0) {
3908 __ Subu(out_low, ZERO, out_low);
3909 __ Sltu(AT, ZERO, out_low);
3910 __ Subu(out_high, ZERO, out_high);
3911 __ Subu(out_high, out_high, AT);
3912 }
3913 } else if (ctz_imm == 32) {
3914 __ Sra(AT, in_high, 31);
3915 __ Addu(AT, AT, in_low);
3916 __ Sltu(AT, AT, in_low);
3917 __ Addu(out_low, in_high, AT);
3918 if (imm < 0) {
3919 __ Srl(TMP, out_low, 31);
3920 __ Subu(out_low, ZERO, out_low);
3921 __ Sltu(AT, ZERO, out_low);
3922 __ Subu(out_high, TMP, AT);
3923 } else {
3924 __ Sra(out_high, out_low, 31);
3925 }
3926 } else if (ctz_imm < 63) {
3927 __ Sra(AT, in_high, 31);
3928 __ Srl(TMP, AT, 64 - ctz_imm);
3929 __ Addu(AT, AT, in_low);
3930 __ Sltu(AT, AT, in_low);
3931 __ Addu(out_low, in_high, AT);
3932 __ Addu(out_low, out_low, TMP);
3933 __ Sra(out_low, out_low, ctz_imm - 32);
3934 if (imm < 0) {
3935 __ Subu(out_low, ZERO, out_low);
3936 }
3937 __ Sra(out_high, out_low, 31);
3938 } else {
3939 DCHECK_LT(imm, 0);
3940 if (is_r6) {
3941 __ Aui(AT, in_high, 0x8000);
3942 } else {
3943 __ Lui(AT, 0x8000);
3944 __ Xor(AT, AT, in_high);
3945 }
3946 __ Or(AT, AT, in_low);
3947 __ Sltiu(out_low, AT, 1);
3948 __ Move(out_high, ZERO);
Alexey Frunze7e99e052015-11-24 19:28:01 -08003949 }
Lena Djokic4b8025c2017-12-21 16:15:50 +01003950 } else {
3951 if ((ctz_imm == 1) && !is_r6) {
3952 __ Andi(AT, in_low, 1);
3953 __ Sll(TMP, in_low, 31);
3954 __ And(TMP, in_high, TMP);
3955 __ Sra(out_high, TMP, 31);
3956 __ Or(out_low, out_high, AT);
3957 } else if (ctz_imm < 32) {
3958 __ Sra(AT, in_high, 31);
3959 if (ctz_imm <= 16) {
3960 __ Andi(out_low, in_low, abs_imm - 1);
3961 } else if (is_r2_or_newer) {
3962 __ Ext(out_low, in_low, 0, ctz_imm);
3963 } else {
3964 __ Sll(out_low, in_low, 32 - ctz_imm);
3965 __ Srl(out_low, out_low, 32 - ctz_imm);
3966 }
3967 if (is_r6) {
3968 __ Selnez(out_high, AT, out_low);
3969 } else {
3970 __ Movz(AT, ZERO, out_low);
3971 __ Move(out_high, AT);
3972 }
3973 if (is_r2_or_newer) {
3974 __ Ins(out_low, out_high, ctz_imm, 32 - ctz_imm);
3975 } else {
3976 __ Sll(AT, out_high, ctz_imm);
3977 __ Or(out_low, out_low, AT);
3978 }
3979 } else if (ctz_imm == 32) {
3980 __ Sra(AT, in_high, 31);
3981 __ Move(out_low, in_low);
3982 if (is_r6) {
3983 __ Selnez(out_high, AT, out_low);
3984 } else {
3985 __ Movz(AT, ZERO, out_low);
3986 __ Move(out_high, AT);
3987 }
3988 } else if (ctz_imm < 63) {
3989 __ Sra(AT, in_high, 31);
3990 __ Move(TMP, in_low);
3991 if (ctz_imm - 32 <= 16) {
3992 __ Andi(out_high, in_high, (1 << (ctz_imm - 32)) - 1);
3993 } else if (is_r2_or_newer) {
3994 __ Ext(out_high, in_high, 0, ctz_imm - 32);
3995 } else {
3996 __ Sll(out_high, in_high, 64 - ctz_imm);
3997 __ Srl(out_high, out_high, 64 - ctz_imm);
3998 }
3999 __ Move(out_low, TMP);
4000 __ Or(TMP, TMP, out_high);
4001 if (is_r6) {
4002 __ Selnez(AT, AT, TMP);
4003 } else {
4004 __ Movz(AT, ZERO, TMP);
4005 }
4006 if (is_r2_or_newer) {
4007 __ Ins(out_high, AT, ctz_imm - 32, 64 - ctz_imm);
4008 } else {
4009 __ Sll(AT, AT, ctz_imm - 32);
4010 __ Or(out_high, out_high, AT);
4011 }
4012 } else {
4013 if (is_r6) {
4014 __ Aui(AT, in_high, 0x8000);
4015 } else {
4016 __ Lui(AT, 0x8000);
4017 __ Xor(AT, AT, in_high);
4018 }
4019 __ Or(AT, AT, in_low);
4020 __ Sltiu(AT, AT, 1);
4021 __ Sll(AT, AT, 31);
4022 __ Move(out_low, in_low);
4023 __ Xor(out_high, in_high, AT);
4024 }
Alexey Frunze7e99e052015-11-24 19:28:01 -08004025 }
4026 }
4027}
4028
4029void InstructionCodeGeneratorMIPS::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
4030 DCHECK(instruction->IsDiv() || instruction->IsRem());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004031 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
Alexey Frunze7e99e052015-11-24 19:28:01 -08004032
4033 LocationSummary* locations = instruction->GetLocations();
4034 Location second = locations->InAt(1);
4035 DCHECK(second.IsConstant());
4036
4037 Register out = locations->Out().AsRegister<Register>();
4038 Register dividend = locations->InAt(0).AsRegister<Register>();
4039 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4040
4041 int64_t magic;
4042 int shift;
4043 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
4044
4045 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4046
4047 __ LoadConst32(TMP, magic);
4048 if (isR6) {
4049 __ MuhR6(TMP, dividend, TMP);
4050 } else {
4051 __ MultR2(dividend, TMP);
4052 __ Mfhi(TMP);
4053 }
4054 if (imm > 0 && magic < 0) {
4055 __ Addu(TMP, TMP, dividend);
4056 } else if (imm < 0 && magic > 0) {
4057 __ Subu(TMP, TMP, dividend);
4058 }
4059
4060 if (shift != 0) {
4061 __ Sra(TMP, TMP, shift);
4062 }
4063
4064 if (instruction->IsDiv()) {
4065 __ Sra(out, TMP, 31);
4066 __ Subu(out, TMP, out);
4067 } else {
4068 __ Sra(AT, TMP, 31);
4069 __ Subu(AT, TMP, AT);
4070 __ LoadConst32(TMP, imm);
4071 if (isR6) {
4072 __ MulR6(TMP, AT, TMP);
4073 } else {
4074 __ MulR2(TMP, AT, TMP);
4075 }
4076 __ Subu(out, dividend, TMP);
4077 }
4078}
4079
4080void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* instruction) {
4081 DCHECK(instruction->IsDiv() || instruction->IsRem());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004082 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
Alexey Frunze7e99e052015-11-24 19:28:01 -08004083
4084 LocationSummary* locations = instruction->GetLocations();
4085 Register out = locations->Out().AsRegister<Register>();
4086 Location second = locations->InAt(1);
4087
4088 if (second.IsConstant()) {
4089 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
4090 if (imm == 0) {
4091 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
4092 } else if (imm == 1 || imm == -1) {
4093 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00004094 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08004095 DivRemByPowerOfTwo(instruction);
4096 } else {
4097 DCHECK(imm <= -2 || imm >= 2);
4098 GenerateDivRemWithAnyConstant(instruction);
4099 }
4100 } else {
4101 Register dividend = locations->InAt(0).AsRegister<Register>();
4102 Register divisor = second.AsRegister<Register>();
4103 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4104 if (instruction->IsDiv()) {
4105 if (isR6) {
4106 __ DivR6(out, dividend, divisor);
4107 } else {
4108 __ DivR2(out, dividend, divisor);
4109 }
4110 } else {
4111 if (isR6) {
4112 __ ModR6(out, dividend, divisor);
4113 } else {
4114 __ ModR2(out, dividend, divisor);
4115 }
4116 }
4117 }
4118}
4119
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004120void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004121 DataType::Type type = div->GetResultType();
Lena Djokic4b8025c2017-12-21 16:15:50 +01004122 bool call_long_div = false;
4123 if (type == DataType::Type::kInt64) {
4124 if (div->InputAt(1)->IsConstant()) {
4125 int64_t imm = CodeGenerator::GetInt64ValueOf(div->InputAt(1)->AsConstant());
4126 call_long_div = (imm != 0) && !IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm)));
4127 } else {
4128 call_long_div = true;
4129 }
4130 }
4131 LocationSummary::CallKind call_kind = call_long_div
Serban Constantinescu54ff4822016-07-07 18:03:19 +01004132 ? LocationSummary::kCallOnMainOnly
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004133 : LocationSummary::kNoCall;
4134
Vladimir Markoca6fff82017-10-03 14:49:14 +01004135 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(div, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004136
4137 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004138 case DataType::Type::kInt32:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004139 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08004140 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004141 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4142 break;
4143
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004144 case DataType::Type::kInt64: {
Lena Djokic4b8025c2017-12-21 16:15:50 +01004145 if (call_long_div) {
4146 InvokeRuntimeCallingConvention calling_convention;
4147 locations->SetInAt(0, Location::RegisterPairLocation(
4148 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4149 locations->SetInAt(1, Location::RegisterPairLocation(
4150 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4151 locations->SetOut(calling_convention.GetReturnLocation(type));
4152 } else {
4153 locations->SetInAt(0, Location::RequiresRegister());
4154 locations->SetInAt(1, Location::ConstantLocation(div->InputAt(1)->AsConstant()));
4155 locations->SetOut(Location::RequiresRegister());
4156 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004157 break;
4158 }
4159
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004160 case DataType::Type::kFloat32:
4161 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004162 locations->SetInAt(0, Location::RequiresFpuRegister());
4163 locations->SetInAt(1, Location::RequiresFpuRegister());
4164 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4165 break;
4166
4167 default:
4168 LOG(FATAL) << "Unexpected div type " << type;
4169 }
4170}
4171
4172void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004173 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004174 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004175
4176 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004177 case DataType::Type::kInt32:
Alexey Frunze7e99e052015-11-24 19:28:01 -08004178 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004179 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004180 case DataType::Type::kInt64: {
Lena Djokic4b8025c2017-12-21 16:15:50 +01004181 if (locations->InAt(1).IsConstant()) {
4182 int64_t imm = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue();
4183 if (imm == 0) {
4184 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
4185 } else if (imm == 1 || imm == -1) {
4186 DivRemOneOrMinusOne(instruction);
4187 } else {
4188 DCHECK(IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm))));
4189 DivRemByPowerOfTwo(instruction);
4190 }
4191 } else {
4192 codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
4193 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
4194 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004195 break;
4196 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004197 case DataType::Type::kFloat32:
4198 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004199 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4200 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
4201 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004202 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004203 __ DivS(dst, lhs, rhs);
4204 } else {
4205 __ DivD(dst, lhs, rhs);
4206 }
4207 break;
4208 }
4209 default:
4210 LOG(FATAL) << "Unexpected div type " << type;
4211 }
4212}
4213
4214void LocationsBuilderMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01004215 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004216 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004217}
4218
4219void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01004220 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01004221 new (codegen_->GetScopedAllocator()) DivZeroCheckSlowPathMIPS(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004222 codegen_->AddSlowPath(slow_path);
4223 Location value = instruction->GetLocations()->InAt(0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004224 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004225
4226 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004227 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01004228 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004229 case DataType::Type::kInt8:
4230 case DataType::Type::kUint16:
4231 case DataType::Type::kInt16:
4232 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004233 if (value.IsConstant()) {
4234 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
4235 __ B(slow_path->GetEntryLabel());
4236 } else {
4237 // A division by a non-null constant is valid. We don't need to perform
4238 // any check, so simply fall through.
4239 }
4240 } else {
4241 DCHECK(value.IsRegister()) << value;
4242 __ Beqz(value.AsRegister<Register>(), slow_path->GetEntryLabel());
4243 }
4244 break;
4245 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004246 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004247 if (value.IsConstant()) {
4248 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
4249 __ B(slow_path->GetEntryLabel());
4250 } else {
4251 // A division by a non-null constant is valid. We don't need to perform
4252 // any check, so simply fall through.
4253 }
4254 } else {
4255 DCHECK(value.IsRegisterPair()) << value;
4256 __ Or(TMP, value.AsRegisterPairHigh<Register>(), value.AsRegisterPairLow<Register>());
4257 __ Beqz(TMP, slow_path->GetEntryLabel());
4258 }
4259 break;
4260 }
4261 default:
4262 LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
4263 }
4264}
4265
4266void LocationsBuilderMIPS::VisitDoubleConstant(HDoubleConstant* constant) {
4267 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004268 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004269 locations->SetOut(Location::ConstantLocation(constant));
4270}
4271
4272void InstructionCodeGeneratorMIPS::VisitDoubleConstant(HDoubleConstant* cst ATTRIBUTE_UNUSED) {
4273 // Will be generated at use site.
4274}
4275
4276void LocationsBuilderMIPS::VisitExit(HExit* exit) {
4277 exit->SetLocations(nullptr);
4278}
4279
4280void InstructionCodeGeneratorMIPS::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
4281}
4282
4283void LocationsBuilderMIPS::VisitFloatConstant(HFloatConstant* constant) {
4284 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004285 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004286 locations->SetOut(Location::ConstantLocation(constant));
4287}
4288
4289void InstructionCodeGeneratorMIPS::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
4290 // Will be generated at use site.
4291}
4292
4293void LocationsBuilderMIPS::VisitGoto(HGoto* got) {
4294 got->SetLocations(nullptr);
4295}
4296
4297void InstructionCodeGeneratorMIPS::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Aart Bika8b8e9b2018-01-09 11:01:02 -08004298 if (successor->IsExitBlock()) {
4299 DCHECK(got->GetPrevious()->AlwaysThrows());
4300 return; // no code needed
4301 }
4302
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004303 HBasicBlock* block = got->GetBlock();
4304 HInstruction* previous = got->GetPrevious();
4305 HLoopInformation* info = block->GetLoopInformation();
4306
4307 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Goran Jakovljevicfeec1672018-02-08 10:20:14 +01004308 if (codegen_->GetCompilerOptions().CountHotnessInCompiledCode()) {
4309 __ Lw(AT, SP, kCurrentMethodStackOffset);
4310 __ Lhu(TMP, AT, ArtMethod::HotnessCountOffset().Int32Value());
4311 __ Addiu(TMP, TMP, 1);
4312 __ Sh(TMP, AT, ArtMethod::HotnessCountOffset().Int32Value());
4313 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004314 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
4315 return;
4316 }
4317 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
4318 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
4319 }
4320 if (!codegen_->GoesToNextBlock(block, successor)) {
4321 __ B(codegen_->GetLabelOf(successor));
4322 }
4323}
4324
4325void InstructionCodeGeneratorMIPS::VisitGoto(HGoto* got) {
4326 HandleGoto(got, got->GetSuccessor());
4327}
4328
4329void LocationsBuilderMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
4330 try_boundary->SetLocations(nullptr);
4331}
4332
4333void InstructionCodeGeneratorMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
4334 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
4335 if (!successor->IsExitBlock()) {
4336 HandleGoto(try_boundary, successor);
4337 }
4338}
4339
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004340void InstructionCodeGeneratorMIPS::GenerateIntCompare(IfCondition cond,
4341 LocationSummary* locations) {
4342 Register dst = locations->Out().AsRegister<Register>();
4343 Register lhs = locations->InAt(0).AsRegister<Register>();
4344 Location rhs_location = locations->InAt(1);
4345 Register rhs_reg = ZERO;
4346 int64_t rhs_imm = 0;
4347 bool use_imm = rhs_location.IsConstant();
4348 if (use_imm) {
4349 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
4350 } else {
4351 rhs_reg = rhs_location.AsRegister<Register>();
4352 }
4353
4354 switch (cond) {
4355 case kCondEQ:
4356 case kCondNE:
Alexey Frunzee7697712016-09-15 21:37:49 -07004357 if (use_imm && IsInt<16>(-rhs_imm)) {
4358 if (rhs_imm == 0) {
4359 if (cond == kCondEQ) {
4360 __ Sltiu(dst, lhs, 1);
4361 } else {
4362 __ Sltu(dst, ZERO, lhs);
4363 }
4364 } else {
4365 __ Addiu(dst, lhs, -rhs_imm);
4366 if (cond == kCondEQ) {
4367 __ Sltiu(dst, dst, 1);
4368 } else {
4369 __ Sltu(dst, ZERO, dst);
4370 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004371 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004372 } else {
Alexey Frunzee7697712016-09-15 21:37:49 -07004373 if (use_imm && IsUint<16>(rhs_imm)) {
4374 __ Xori(dst, lhs, rhs_imm);
4375 } else {
4376 if (use_imm) {
4377 rhs_reg = TMP;
4378 __ LoadConst32(rhs_reg, rhs_imm);
4379 }
4380 __ Xor(dst, lhs, rhs_reg);
4381 }
4382 if (cond == kCondEQ) {
4383 __ Sltiu(dst, dst, 1);
4384 } else {
4385 __ Sltu(dst, ZERO, dst);
4386 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004387 }
4388 break;
4389
4390 case kCondLT:
4391 case kCondGE:
4392 if (use_imm && IsInt<16>(rhs_imm)) {
4393 __ Slti(dst, lhs, rhs_imm);
4394 } else {
4395 if (use_imm) {
4396 rhs_reg = TMP;
4397 __ LoadConst32(rhs_reg, rhs_imm);
4398 }
4399 __ Slt(dst, lhs, rhs_reg);
4400 }
4401 if (cond == kCondGE) {
4402 // Simulate lhs >= rhs via !(lhs < rhs) since there's
4403 // only the slt instruction but no sge.
4404 __ Xori(dst, dst, 1);
4405 }
4406 break;
4407
4408 case kCondLE:
4409 case kCondGT:
4410 if (use_imm && IsInt<16>(rhs_imm + 1)) {
4411 // Simulate lhs <= rhs via lhs < rhs + 1.
4412 __ Slti(dst, lhs, rhs_imm + 1);
4413 if (cond == kCondGT) {
4414 // Simulate lhs > rhs via !(lhs <= rhs) since there's
4415 // only the slti instruction but no sgti.
4416 __ Xori(dst, dst, 1);
4417 }
4418 } else {
4419 if (use_imm) {
4420 rhs_reg = TMP;
4421 __ LoadConst32(rhs_reg, rhs_imm);
4422 }
4423 __ Slt(dst, rhs_reg, lhs);
4424 if (cond == kCondLE) {
4425 // Simulate lhs <= rhs via !(rhs < lhs) since there's
4426 // only the slt instruction but no sle.
4427 __ Xori(dst, dst, 1);
4428 }
4429 }
4430 break;
4431
4432 case kCondB:
4433 case kCondAE:
4434 if (use_imm && IsInt<16>(rhs_imm)) {
4435 // Sltiu sign-extends its 16-bit immediate operand before
4436 // the comparison and thus lets us compare directly with
4437 // unsigned values in the ranges [0, 0x7fff] and
4438 // [0xffff8000, 0xffffffff].
4439 __ Sltiu(dst, lhs, rhs_imm);
4440 } else {
4441 if (use_imm) {
4442 rhs_reg = TMP;
4443 __ LoadConst32(rhs_reg, rhs_imm);
4444 }
4445 __ Sltu(dst, lhs, rhs_reg);
4446 }
4447 if (cond == kCondAE) {
4448 // Simulate lhs >= rhs via !(lhs < rhs) since there's
4449 // only the sltu instruction but no sgeu.
4450 __ Xori(dst, dst, 1);
4451 }
4452 break;
4453
4454 case kCondBE:
4455 case kCondA:
4456 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4457 // Simulate lhs <= rhs via lhs < rhs + 1.
4458 // Note that this only works if rhs + 1 does not overflow
4459 // to 0, hence the check above.
4460 // Sltiu sign-extends its 16-bit immediate operand before
4461 // the comparison and thus lets us compare directly with
4462 // unsigned values in the ranges [0, 0x7fff] and
4463 // [0xffff8000, 0xffffffff].
4464 __ Sltiu(dst, lhs, rhs_imm + 1);
4465 if (cond == kCondA) {
4466 // Simulate lhs > rhs via !(lhs <= rhs) since there's
4467 // only the sltiu instruction but no sgtiu.
4468 __ Xori(dst, dst, 1);
4469 }
4470 } else {
4471 if (use_imm) {
4472 rhs_reg = TMP;
4473 __ LoadConst32(rhs_reg, rhs_imm);
4474 }
4475 __ Sltu(dst, rhs_reg, lhs);
4476 if (cond == kCondBE) {
4477 // Simulate lhs <= rhs via !(rhs < lhs) since there's
4478 // only the sltu instruction but no sleu.
4479 __ Xori(dst, dst, 1);
4480 }
4481 }
4482 break;
4483 }
4484}
4485
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004486bool InstructionCodeGeneratorMIPS::MaterializeIntCompare(IfCondition cond,
4487 LocationSummary* input_locations,
4488 Register dst) {
4489 Register lhs = input_locations->InAt(0).AsRegister<Register>();
4490 Location rhs_location = input_locations->InAt(1);
4491 Register rhs_reg = ZERO;
4492 int64_t rhs_imm = 0;
4493 bool use_imm = rhs_location.IsConstant();
4494 if (use_imm) {
4495 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
4496 } else {
4497 rhs_reg = rhs_location.AsRegister<Register>();
4498 }
4499
4500 switch (cond) {
4501 case kCondEQ:
4502 case kCondNE:
4503 if (use_imm && IsInt<16>(-rhs_imm)) {
4504 __ Addiu(dst, lhs, -rhs_imm);
4505 } else if (use_imm && IsUint<16>(rhs_imm)) {
4506 __ Xori(dst, lhs, rhs_imm);
4507 } else {
4508 if (use_imm) {
4509 rhs_reg = TMP;
4510 __ LoadConst32(rhs_reg, rhs_imm);
4511 }
4512 __ Xor(dst, lhs, rhs_reg);
4513 }
4514 return (cond == kCondEQ);
4515
4516 case kCondLT:
4517 case kCondGE:
4518 if (use_imm && IsInt<16>(rhs_imm)) {
4519 __ Slti(dst, lhs, rhs_imm);
4520 } else {
4521 if (use_imm) {
4522 rhs_reg = TMP;
4523 __ LoadConst32(rhs_reg, rhs_imm);
4524 }
4525 __ Slt(dst, lhs, rhs_reg);
4526 }
4527 return (cond == kCondGE);
4528
4529 case kCondLE:
4530 case kCondGT:
4531 if (use_imm && IsInt<16>(rhs_imm + 1)) {
4532 // Simulate lhs <= rhs via lhs < rhs + 1.
4533 __ Slti(dst, lhs, rhs_imm + 1);
4534 return (cond == kCondGT);
4535 } else {
4536 if (use_imm) {
4537 rhs_reg = TMP;
4538 __ LoadConst32(rhs_reg, rhs_imm);
4539 }
4540 __ Slt(dst, rhs_reg, lhs);
4541 return (cond == kCondLE);
4542 }
4543
4544 case kCondB:
4545 case kCondAE:
4546 if (use_imm && IsInt<16>(rhs_imm)) {
4547 // Sltiu sign-extends its 16-bit immediate operand before
4548 // the comparison and thus lets us compare directly with
4549 // unsigned values in the ranges [0, 0x7fff] and
4550 // [0xffff8000, 0xffffffff].
4551 __ Sltiu(dst, lhs, rhs_imm);
4552 } else {
4553 if (use_imm) {
4554 rhs_reg = TMP;
4555 __ LoadConst32(rhs_reg, rhs_imm);
4556 }
4557 __ Sltu(dst, lhs, rhs_reg);
4558 }
4559 return (cond == kCondAE);
4560
4561 case kCondBE:
4562 case kCondA:
4563 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4564 // Simulate lhs <= rhs via lhs < rhs + 1.
4565 // Note that this only works if rhs + 1 does not overflow
4566 // to 0, hence the check above.
4567 // Sltiu sign-extends its 16-bit immediate operand before
4568 // the comparison and thus lets us compare directly with
4569 // unsigned values in the ranges [0, 0x7fff] and
4570 // [0xffff8000, 0xffffffff].
4571 __ Sltiu(dst, lhs, rhs_imm + 1);
4572 return (cond == kCondA);
4573 } else {
4574 if (use_imm) {
4575 rhs_reg = TMP;
4576 __ LoadConst32(rhs_reg, rhs_imm);
4577 }
4578 __ Sltu(dst, rhs_reg, lhs);
4579 return (cond == kCondBE);
4580 }
4581 }
4582}
4583
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004584void InstructionCodeGeneratorMIPS::GenerateIntCompareAndBranch(IfCondition cond,
4585 LocationSummary* locations,
4586 MipsLabel* label) {
4587 Register lhs = locations->InAt(0).AsRegister<Register>();
4588 Location rhs_location = locations->InAt(1);
4589 Register rhs_reg = ZERO;
Alexey Frunzee7697712016-09-15 21:37:49 -07004590 int64_t rhs_imm = 0;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004591 bool use_imm = rhs_location.IsConstant();
4592 if (use_imm) {
4593 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
4594 } else {
4595 rhs_reg = rhs_location.AsRegister<Register>();
4596 }
4597
4598 if (use_imm && rhs_imm == 0) {
4599 switch (cond) {
4600 case kCondEQ:
4601 case kCondBE: // <= 0 if zero
4602 __ Beqz(lhs, label);
4603 break;
4604 case kCondNE:
4605 case kCondA: // > 0 if non-zero
4606 __ Bnez(lhs, label);
4607 break;
4608 case kCondLT:
4609 __ Bltz(lhs, label);
4610 break;
4611 case kCondGE:
4612 __ Bgez(lhs, label);
4613 break;
4614 case kCondLE:
4615 __ Blez(lhs, label);
4616 break;
4617 case kCondGT:
4618 __ Bgtz(lhs, label);
4619 break;
4620 case kCondB: // always false
4621 break;
4622 case kCondAE: // always true
4623 __ B(label);
4624 break;
4625 }
4626 } else {
Alexey Frunzee7697712016-09-15 21:37:49 -07004627 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4628 if (isR6 || !use_imm) {
4629 if (use_imm) {
4630 rhs_reg = TMP;
4631 __ LoadConst32(rhs_reg, rhs_imm);
4632 }
4633 switch (cond) {
4634 case kCondEQ:
4635 __ Beq(lhs, rhs_reg, label);
4636 break;
4637 case kCondNE:
4638 __ Bne(lhs, rhs_reg, label);
4639 break;
4640 case kCondLT:
4641 __ Blt(lhs, rhs_reg, label);
4642 break;
4643 case kCondGE:
4644 __ Bge(lhs, rhs_reg, label);
4645 break;
4646 case kCondLE:
4647 __ Bge(rhs_reg, lhs, label);
4648 break;
4649 case kCondGT:
4650 __ Blt(rhs_reg, lhs, label);
4651 break;
4652 case kCondB:
4653 __ Bltu(lhs, rhs_reg, label);
4654 break;
4655 case kCondAE:
4656 __ Bgeu(lhs, rhs_reg, label);
4657 break;
4658 case kCondBE:
4659 __ Bgeu(rhs_reg, lhs, label);
4660 break;
4661 case kCondA:
4662 __ Bltu(rhs_reg, lhs, label);
4663 break;
4664 }
4665 } else {
4666 // Special cases for more efficient comparison with constants on R2.
4667 switch (cond) {
4668 case kCondEQ:
4669 __ LoadConst32(TMP, rhs_imm);
4670 __ Beq(lhs, TMP, label);
4671 break;
4672 case kCondNE:
4673 __ LoadConst32(TMP, rhs_imm);
4674 __ Bne(lhs, TMP, label);
4675 break;
4676 case kCondLT:
4677 if (IsInt<16>(rhs_imm)) {
4678 __ Slti(TMP, lhs, rhs_imm);
4679 __ Bnez(TMP, label);
4680 } else {
4681 __ LoadConst32(TMP, rhs_imm);
4682 __ Blt(lhs, TMP, label);
4683 }
4684 break;
4685 case kCondGE:
4686 if (IsInt<16>(rhs_imm)) {
4687 __ Slti(TMP, lhs, rhs_imm);
4688 __ Beqz(TMP, label);
4689 } else {
4690 __ LoadConst32(TMP, rhs_imm);
4691 __ Bge(lhs, TMP, label);
4692 }
4693 break;
4694 case kCondLE:
4695 if (IsInt<16>(rhs_imm + 1)) {
4696 // Simulate lhs <= rhs via lhs < rhs + 1.
4697 __ Slti(TMP, lhs, rhs_imm + 1);
4698 __ Bnez(TMP, label);
4699 } else {
4700 __ LoadConst32(TMP, rhs_imm);
4701 __ Bge(TMP, lhs, label);
4702 }
4703 break;
4704 case kCondGT:
4705 if (IsInt<16>(rhs_imm + 1)) {
4706 // Simulate lhs > rhs via !(lhs < rhs + 1).
4707 __ Slti(TMP, lhs, rhs_imm + 1);
4708 __ Beqz(TMP, label);
4709 } else {
4710 __ LoadConst32(TMP, rhs_imm);
4711 __ Blt(TMP, lhs, label);
4712 }
4713 break;
4714 case kCondB:
4715 if (IsInt<16>(rhs_imm)) {
4716 __ Sltiu(TMP, lhs, rhs_imm);
4717 __ Bnez(TMP, label);
4718 } else {
4719 __ LoadConst32(TMP, rhs_imm);
4720 __ Bltu(lhs, TMP, label);
4721 }
4722 break;
4723 case kCondAE:
4724 if (IsInt<16>(rhs_imm)) {
4725 __ Sltiu(TMP, lhs, rhs_imm);
4726 __ Beqz(TMP, label);
4727 } else {
4728 __ LoadConst32(TMP, rhs_imm);
4729 __ Bgeu(lhs, TMP, label);
4730 }
4731 break;
4732 case kCondBE:
4733 if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4734 // Simulate lhs <= rhs via lhs < rhs + 1.
4735 // Note that this only works if rhs + 1 does not overflow
4736 // to 0, hence the check above.
4737 __ Sltiu(TMP, lhs, rhs_imm + 1);
4738 __ Bnez(TMP, label);
4739 } else {
4740 __ LoadConst32(TMP, rhs_imm);
4741 __ Bgeu(TMP, lhs, label);
4742 }
4743 break;
4744 case kCondA:
4745 if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4746 // Simulate lhs > rhs via !(lhs < rhs + 1).
4747 // Note that this only works if rhs + 1 does not overflow
4748 // to 0, hence the check above.
4749 __ Sltiu(TMP, lhs, rhs_imm + 1);
4750 __ Beqz(TMP, label);
4751 } else {
4752 __ LoadConst32(TMP, rhs_imm);
4753 __ Bltu(TMP, lhs, label);
4754 }
4755 break;
4756 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004757 }
4758 }
4759}
4760
Tijana Jakovljevic6d482aa2017-02-03 13:24:08 +01004761void InstructionCodeGeneratorMIPS::GenerateLongCompare(IfCondition cond,
4762 LocationSummary* locations) {
4763 Register dst = locations->Out().AsRegister<Register>();
4764 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4765 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
4766 Location rhs_location = locations->InAt(1);
4767 Register rhs_high = ZERO;
4768 Register rhs_low = ZERO;
4769 int64_t imm = 0;
4770 uint32_t imm_high = 0;
4771 uint32_t imm_low = 0;
4772 bool use_imm = rhs_location.IsConstant();
4773 if (use_imm) {
4774 imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
4775 imm_high = High32Bits(imm);
4776 imm_low = Low32Bits(imm);
4777 } else {
4778 rhs_high = rhs_location.AsRegisterPairHigh<Register>();
4779 rhs_low = rhs_location.AsRegisterPairLow<Register>();
4780 }
4781 if (use_imm && imm == 0) {
4782 switch (cond) {
4783 case kCondEQ:
4784 case kCondBE: // <= 0 if zero
4785 __ Or(dst, lhs_high, lhs_low);
4786 __ Sltiu(dst, dst, 1);
4787 break;
4788 case kCondNE:
4789 case kCondA: // > 0 if non-zero
4790 __ Or(dst, lhs_high, lhs_low);
4791 __ Sltu(dst, ZERO, dst);
4792 break;
4793 case kCondLT:
4794 __ Slt(dst, lhs_high, ZERO);
4795 break;
4796 case kCondGE:
4797 __ Slt(dst, lhs_high, ZERO);
4798 __ Xori(dst, dst, 1);
4799 break;
4800 case kCondLE:
4801 __ Or(TMP, lhs_high, lhs_low);
4802 __ Sra(AT, lhs_high, 31);
4803 __ Sltu(dst, AT, TMP);
4804 __ Xori(dst, dst, 1);
4805 break;
4806 case kCondGT:
4807 __ Or(TMP, lhs_high, lhs_low);
4808 __ Sra(AT, lhs_high, 31);
4809 __ Sltu(dst, AT, TMP);
4810 break;
4811 case kCondB: // always false
4812 __ Andi(dst, dst, 0);
4813 break;
4814 case kCondAE: // always true
4815 __ Ori(dst, ZERO, 1);
4816 break;
4817 }
4818 } else if (use_imm) {
4819 // TODO: more efficient comparison with constants without loading them into TMP/AT.
4820 switch (cond) {
4821 case kCondEQ:
4822 __ LoadConst32(TMP, imm_high);
4823 __ Xor(TMP, TMP, lhs_high);
4824 __ LoadConst32(AT, imm_low);
4825 __ Xor(AT, AT, lhs_low);
4826 __ Or(dst, TMP, AT);
4827 __ Sltiu(dst, dst, 1);
4828 break;
4829 case kCondNE:
4830 __ LoadConst32(TMP, imm_high);
4831 __ Xor(TMP, TMP, lhs_high);
4832 __ LoadConst32(AT, imm_low);
4833 __ Xor(AT, AT, lhs_low);
4834 __ Or(dst, TMP, AT);
4835 __ Sltu(dst, ZERO, dst);
4836 break;
4837 case kCondLT:
4838 case kCondGE:
4839 if (dst == lhs_low) {
4840 __ LoadConst32(TMP, imm_low);
4841 __ Sltu(dst, lhs_low, TMP);
4842 }
4843 __ LoadConst32(TMP, imm_high);
4844 __ Slt(AT, lhs_high, TMP);
4845 __ Slt(TMP, TMP, lhs_high);
4846 if (dst != lhs_low) {
4847 __ LoadConst32(dst, imm_low);
4848 __ Sltu(dst, lhs_low, dst);
4849 }
4850 __ Slt(dst, TMP, dst);
4851 __ Or(dst, dst, AT);
4852 if (cond == kCondGE) {
4853 __ Xori(dst, dst, 1);
4854 }
4855 break;
4856 case kCondGT:
4857 case kCondLE:
4858 if (dst == lhs_low) {
4859 __ LoadConst32(TMP, imm_low);
4860 __ Sltu(dst, TMP, lhs_low);
4861 }
4862 __ LoadConst32(TMP, imm_high);
4863 __ Slt(AT, TMP, lhs_high);
4864 __ Slt(TMP, lhs_high, TMP);
4865 if (dst != lhs_low) {
4866 __ LoadConst32(dst, imm_low);
4867 __ Sltu(dst, dst, lhs_low);
4868 }
4869 __ Slt(dst, TMP, dst);
4870 __ Or(dst, dst, AT);
4871 if (cond == kCondLE) {
4872 __ Xori(dst, dst, 1);
4873 }
4874 break;
4875 case kCondB:
4876 case kCondAE:
4877 if (dst == lhs_low) {
4878 __ LoadConst32(TMP, imm_low);
4879 __ Sltu(dst, lhs_low, TMP);
4880 }
4881 __ LoadConst32(TMP, imm_high);
4882 __ Sltu(AT, lhs_high, TMP);
4883 __ Sltu(TMP, TMP, lhs_high);
4884 if (dst != lhs_low) {
4885 __ LoadConst32(dst, imm_low);
4886 __ Sltu(dst, lhs_low, dst);
4887 }
4888 __ Slt(dst, TMP, dst);
4889 __ Or(dst, dst, AT);
4890 if (cond == kCondAE) {
4891 __ Xori(dst, dst, 1);
4892 }
4893 break;
4894 case kCondA:
4895 case kCondBE:
4896 if (dst == lhs_low) {
4897 __ LoadConst32(TMP, imm_low);
4898 __ Sltu(dst, TMP, lhs_low);
4899 }
4900 __ LoadConst32(TMP, imm_high);
4901 __ Sltu(AT, TMP, lhs_high);
4902 __ Sltu(TMP, lhs_high, TMP);
4903 if (dst != lhs_low) {
4904 __ LoadConst32(dst, imm_low);
4905 __ Sltu(dst, dst, lhs_low);
4906 }
4907 __ Slt(dst, TMP, dst);
4908 __ Or(dst, dst, AT);
4909 if (cond == kCondBE) {
4910 __ Xori(dst, dst, 1);
4911 }
4912 break;
4913 }
4914 } else {
4915 switch (cond) {
4916 case kCondEQ:
4917 __ Xor(TMP, lhs_high, rhs_high);
4918 __ Xor(AT, lhs_low, rhs_low);
4919 __ Or(dst, TMP, AT);
4920 __ Sltiu(dst, dst, 1);
4921 break;
4922 case kCondNE:
4923 __ Xor(TMP, lhs_high, rhs_high);
4924 __ Xor(AT, lhs_low, rhs_low);
4925 __ Or(dst, TMP, AT);
4926 __ Sltu(dst, ZERO, dst);
4927 break;
4928 case kCondLT:
4929 case kCondGE:
4930 __ Slt(TMP, rhs_high, lhs_high);
4931 __ Sltu(AT, lhs_low, rhs_low);
4932 __ Slt(TMP, TMP, AT);
4933 __ Slt(AT, lhs_high, rhs_high);
4934 __ Or(dst, AT, TMP);
4935 if (cond == kCondGE) {
4936 __ Xori(dst, dst, 1);
4937 }
4938 break;
4939 case kCondGT:
4940 case kCondLE:
4941 __ Slt(TMP, lhs_high, rhs_high);
4942 __ Sltu(AT, rhs_low, lhs_low);
4943 __ Slt(TMP, TMP, AT);
4944 __ Slt(AT, rhs_high, lhs_high);
4945 __ Or(dst, AT, TMP);
4946 if (cond == kCondLE) {
4947 __ Xori(dst, dst, 1);
4948 }
4949 break;
4950 case kCondB:
4951 case kCondAE:
4952 __ Sltu(TMP, rhs_high, lhs_high);
4953 __ Sltu(AT, lhs_low, rhs_low);
4954 __ Slt(TMP, TMP, AT);
4955 __ Sltu(AT, lhs_high, rhs_high);
4956 __ Or(dst, AT, TMP);
4957 if (cond == kCondAE) {
4958 __ Xori(dst, dst, 1);
4959 }
4960 break;
4961 case kCondA:
4962 case kCondBE:
4963 __ Sltu(TMP, lhs_high, rhs_high);
4964 __ Sltu(AT, rhs_low, lhs_low);
4965 __ Slt(TMP, TMP, AT);
4966 __ Sltu(AT, rhs_high, lhs_high);
4967 __ Or(dst, AT, TMP);
4968 if (cond == kCondBE) {
4969 __ Xori(dst, dst, 1);
4970 }
4971 break;
4972 }
4973 }
4974}
4975
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004976void InstructionCodeGeneratorMIPS::GenerateLongCompareAndBranch(IfCondition cond,
4977 LocationSummary* locations,
4978 MipsLabel* label) {
4979 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4980 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
4981 Location rhs_location = locations->InAt(1);
4982 Register rhs_high = ZERO;
4983 Register rhs_low = ZERO;
4984 int64_t imm = 0;
4985 uint32_t imm_high = 0;
4986 uint32_t imm_low = 0;
4987 bool use_imm = rhs_location.IsConstant();
4988 if (use_imm) {
4989 imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
4990 imm_high = High32Bits(imm);
4991 imm_low = Low32Bits(imm);
4992 } else {
4993 rhs_high = rhs_location.AsRegisterPairHigh<Register>();
4994 rhs_low = rhs_location.AsRegisterPairLow<Register>();
4995 }
4996
4997 if (use_imm && imm == 0) {
4998 switch (cond) {
4999 case kCondEQ:
5000 case kCondBE: // <= 0 if zero
5001 __ Or(TMP, lhs_high, lhs_low);
5002 __ Beqz(TMP, label);
5003 break;
5004 case kCondNE:
5005 case kCondA: // > 0 if non-zero
5006 __ Or(TMP, lhs_high, lhs_low);
5007 __ Bnez(TMP, label);
5008 break;
5009 case kCondLT:
5010 __ Bltz(lhs_high, label);
5011 break;
5012 case kCondGE:
5013 __ Bgez(lhs_high, label);
5014 break;
5015 case kCondLE:
5016 __ Or(TMP, lhs_high, lhs_low);
5017 __ Sra(AT, lhs_high, 31);
5018 __ Bgeu(AT, TMP, label);
5019 break;
5020 case kCondGT:
5021 __ Or(TMP, lhs_high, lhs_low);
5022 __ Sra(AT, lhs_high, 31);
5023 __ Bltu(AT, TMP, label);
5024 break;
5025 case kCondB: // always false
5026 break;
5027 case kCondAE: // always true
5028 __ B(label);
5029 break;
5030 }
5031 } else if (use_imm) {
5032 // TODO: more efficient comparison with constants without loading them into TMP/AT.
5033 switch (cond) {
5034 case kCondEQ:
5035 __ LoadConst32(TMP, imm_high);
5036 __ Xor(TMP, TMP, lhs_high);
5037 __ LoadConst32(AT, imm_low);
5038 __ Xor(AT, AT, lhs_low);
5039 __ Or(TMP, TMP, AT);
5040 __ Beqz(TMP, label);
5041 break;
5042 case kCondNE:
5043 __ LoadConst32(TMP, imm_high);
5044 __ Xor(TMP, TMP, lhs_high);
5045 __ LoadConst32(AT, imm_low);
5046 __ Xor(AT, AT, lhs_low);
5047 __ Or(TMP, TMP, AT);
5048 __ Bnez(TMP, label);
5049 break;
5050 case kCondLT:
5051 __ LoadConst32(TMP, imm_high);
5052 __ Blt(lhs_high, TMP, label);
5053 __ Slt(TMP, TMP, lhs_high);
5054 __ LoadConst32(AT, imm_low);
5055 __ Sltu(AT, lhs_low, AT);
5056 __ Blt(TMP, AT, label);
5057 break;
5058 case kCondGE:
5059 __ LoadConst32(TMP, imm_high);
5060 __ Blt(TMP, lhs_high, label);
5061 __ Slt(TMP, lhs_high, TMP);
5062 __ LoadConst32(AT, imm_low);
5063 __ Sltu(AT, lhs_low, AT);
5064 __ Or(TMP, TMP, AT);
5065 __ Beqz(TMP, label);
5066 break;
5067 case kCondLE:
5068 __ LoadConst32(TMP, imm_high);
5069 __ Blt(lhs_high, TMP, label);
5070 __ Slt(TMP, TMP, lhs_high);
5071 __ LoadConst32(AT, imm_low);
5072 __ Sltu(AT, AT, lhs_low);
5073 __ Or(TMP, TMP, AT);
5074 __ Beqz(TMP, label);
5075 break;
5076 case kCondGT:
5077 __ LoadConst32(TMP, imm_high);
5078 __ Blt(TMP, lhs_high, label);
5079 __ Slt(TMP, lhs_high, TMP);
5080 __ LoadConst32(AT, imm_low);
5081 __ Sltu(AT, AT, lhs_low);
5082 __ Blt(TMP, AT, label);
5083 break;
5084 case kCondB:
5085 __ LoadConst32(TMP, imm_high);
5086 __ Bltu(lhs_high, TMP, label);
5087 __ Sltu(TMP, TMP, lhs_high);
5088 __ LoadConst32(AT, imm_low);
5089 __ Sltu(AT, lhs_low, AT);
5090 __ Blt(TMP, AT, label);
5091 break;
5092 case kCondAE:
5093 __ LoadConst32(TMP, imm_high);
5094 __ Bltu(TMP, lhs_high, label);
5095 __ Sltu(TMP, lhs_high, TMP);
5096 __ LoadConst32(AT, imm_low);
5097 __ Sltu(AT, lhs_low, AT);
5098 __ Or(TMP, TMP, AT);
5099 __ Beqz(TMP, label);
5100 break;
5101 case kCondBE:
5102 __ LoadConst32(TMP, imm_high);
5103 __ Bltu(lhs_high, TMP, label);
5104 __ Sltu(TMP, TMP, lhs_high);
5105 __ LoadConst32(AT, imm_low);
5106 __ Sltu(AT, AT, lhs_low);
5107 __ Or(TMP, TMP, AT);
5108 __ Beqz(TMP, label);
5109 break;
5110 case kCondA:
5111 __ LoadConst32(TMP, imm_high);
5112 __ Bltu(TMP, lhs_high, label);
5113 __ Sltu(TMP, lhs_high, TMP);
5114 __ LoadConst32(AT, imm_low);
5115 __ Sltu(AT, AT, lhs_low);
5116 __ Blt(TMP, AT, label);
5117 break;
5118 }
5119 } else {
5120 switch (cond) {
5121 case kCondEQ:
5122 __ Xor(TMP, lhs_high, rhs_high);
5123 __ Xor(AT, lhs_low, rhs_low);
5124 __ Or(TMP, TMP, AT);
5125 __ Beqz(TMP, label);
5126 break;
5127 case kCondNE:
5128 __ Xor(TMP, lhs_high, rhs_high);
5129 __ Xor(AT, lhs_low, rhs_low);
5130 __ Or(TMP, TMP, AT);
5131 __ Bnez(TMP, label);
5132 break;
5133 case kCondLT:
5134 __ Blt(lhs_high, rhs_high, label);
5135 __ Slt(TMP, rhs_high, lhs_high);
5136 __ Sltu(AT, lhs_low, rhs_low);
5137 __ Blt(TMP, AT, label);
5138 break;
5139 case kCondGE:
5140 __ Blt(rhs_high, lhs_high, label);
5141 __ Slt(TMP, lhs_high, rhs_high);
5142 __ Sltu(AT, lhs_low, rhs_low);
5143 __ Or(TMP, TMP, AT);
5144 __ Beqz(TMP, label);
5145 break;
5146 case kCondLE:
5147 __ Blt(lhs_high, rhs_high, label);
5148 __ Slt(TMP, rhs_high, lhs_high);
5149 __ Sltu(AT, rhs_low, lhs_low);
5150 __ Or(TMP, TMP, AT);
5151 __ Beqz(TMP, label);
5152 break;
5153 case kCondGT:
5154 __ Blt(rhs_high, lhs_high, label);
5155 __ Slt(TMP, lhs_high, rhs_high);
5156 __ Sltu(AT, rhs_low, lhs_low);
5157 __ Blt(TMP, AT, label);
5158 break;
5159 case kCondB:
5160 __ Bltu(lhs_high, rhs_high, label);
5161 __ Sltu(TMP, rhs_high, lhs_high);
5162 __ Sltu(AT, lhs_low, rhs_low);
5163 __ Blt(TMP, AT, label);
5164 break;
5165 case kCondAE:
5166 __ Bltu(rhs_high, lhs_high, label);
5167 __ Sltu(TMP, lhs_high, rhs_high);
5168 __ Sltu(AT, lhs_low, rhs_low);
5169 __ Or(TMP, TMP, AT);
5170 __ Beqz(TMP, label);
5171 break;
5172 case kCondBE:
5173 __ Bltu(lhs_high, rhs_high, label);
5174 __ Sltu(TMP, rhs_high, lhs_high);
5175 __ Sltu(AT, rhs_low, lhs_low);
5176 __ Or(TMP, TMP, AT);
5177 __ Beqz(TMP, label);
5178 break;
5179 case kCondA:
5180 __ Bltu(rhs_high, lhs_high, label);
5181 __ Sltu(TMP, lhs_high, rhs_high);
5182 __ Sltu(AT, rhs_low, lhs_low);
5183 __ Blt(TMP, AT, label);
5184 break;
5185 }
5186 }
5187}
5188
Alexey Frunze2ddb7172016-09-06 17:04:55 -07005189void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
5190 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005191 DataType::Type type,
Alexey Frunze2ddb7172016-09-06 17:04:55 -07005192 LocationSummary* locations) {
5193 Register dst = locations->Out().AsRegister<Register>();
5194 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
5195 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
5196 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005197 if (type == DataType::Type::kFloat32) {
Alexey Frunze2ddb7172016-09-06 17:04:55 -07005198 if (isR6) {
5199 switch (cond) {
5200 case kCondEQ:
5201 __ CmpEqS(FTMP, lhs, rhs);
5202 __ Mfc1(dst, FTMP);
5203 __ Andi(dst, dst, 1);
5204 break;
5205 case kCondNE:
5206 __ CmpEqS(FTMP, lhs, rhs);
5207 __ Mfc1(dst, FTMP);
5208 __ Addiu(dst, dst, 1);
5209 break;
5210 case kCondLT:
5211 if (gt_bias) {
5212 __ CmpLtS(FTMP, lhs, rhs);
5213 } else {
5214 __ CmpUltS(FTMP, lhs, rhs);
5215 }
5216 __ Mfc1(dst, FTMP);
5217 __ Andi(dst, dst, 1);
5218 break;
5219 case kCondLE:
5220 if (gt_bias) {
5221 __ CmpLeS(FTMP, lhs, rhs);
5222 } else {
5223 __ CmpUleS(FTMP, lhs, rhs);
5224 }
5225 __ Mfc1(dst, FTMP);
5226 __ Andi(dst, dst, 1);
5227 break;
5228 case kCondGT:
5229 if (gt_bias) {
5230 __ CmpUltS(FTMP, rhs, lhs);
5231 } else {
5232 __ CmpLtS(FTMP, rhs, lhs);
5233 }
5234 __ Mfc1(dst, FTMP);
5235 __ Andi(dst, dst, 1);
5236 break;
5237 case kCondGE:
5238 if (gt_bias) {
5239 __ CmpUleS(FTMP, rhs, lhs);
5240 } else {
5241 __ CmpLeS(FTMP, rhs, lhs);
5242 }
5243 __ Mfc1(dst, FTMP);
5244 __ Andi(dst, dst, 1);
5245 break;
5246 default:
5247 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
5248 UNREACHABLE();
5249 }
5250 } else {
5251 switch (cond) {
5252 case kCondEQ:
5253 __ CeqS(0, lhs, rhs);
5254 __ LoadConst32(dst, 1);
5255 __ Movf(dst, ZERO, 0);
5256 break;
5257 case kCondNE:
5258 __ CeqS(0, lhs, rhs);
5259 __ LoadConst32(dst, 1);
5260 __ Movt(dst, ZERO, 0);
5261 break;
5262 case kCondLT:
5263 if (gt_bias) {
5264 __ ColtS(0, lhs, rhs);
5265 } else {
5266 __ CultS(0, lhs, rhs);
5267 }
5268 __ LoadConst32(dst, 1);
5269 __ Movf(dst, ZERO, 0);
5270 break;
5271 case kCondLE:
5272 if (gt_bias) {
5273 __ ColeS(0, lhs, rhs);
5274 } else {
5275 __ CuleS(0, lhs, rhs);
5276 }
5277 __ LoadConst32(dst, 1);
5278 __ Movf(dst, ZERO, 0);
5279 break;
5280 case kCondGT:
5281 if (gt_bias) {
5282 __ CultS(0, rhs, lhs);
5283 } else {
5284 __ ColtS(0, rhs, lhs);
5285 }
5286 __ LoadConst32(dst, 1);
5287 __ Movf(dst, ZERO, 0);
5288 break;
5289 case kCondGE:
5290 if (gt_bias) {
5291 __ CuleS(0, rhs, lhs);
5292 } else {
5293 __ ColeS(0, rhs, lhs);
5294 }
5295 __ LoadConst32(dst, 1);
5296 __ Movf(dst, ZERO, 0);
5297 break;
5298 default:
5299 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
5300 UNREACHABLE();
5301 }
5302 }
5303 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005304 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunze2ddb7172016-09-06 17:04:55 -07005305 if (isR6) {
5306 switch (cond) {
5307 case kCondEQ:
5308 __ CmpEqD(FTMP, lhs, rhs);
5309 __ Mfc1(dst, FTMP);
5310 __ Andi(dst, dst, 1);
5311 break;
5312 case kCondNE:
5313 __ CmpEqD(FTMP, lhs, rhs);
5314 __ Mfc1(dst, FTMP);
5315 __ Addiu(dst, dst, 1);
5316 break;
5317 case kCondLT:
5318 if (gt_bias) {
5319 __ CmpLtD(FTMP, lhs, rhs);
5320 } else {
5321 __ CmpUltD(FTMP, lhs, rhs);
5322 }
5323 __ Mfc1(dst, FTMP);
5324 __ Andi(dst, dst, 1);
5325 break;
5326 case kCondLE:
5327 if (gt_bias) {
5328 __ CmpLeD(FTMP, lhs, rhs);
5329 } else {
5330 __ CmpUleD(FTMP, lhs, rhs);
5331 }
5332 __ Mfc1(dst, FTMP);
5333 __ Andi(dst, dst, 1);
5334 break;
5335 case kCondGT:
5336 if (gt_bias) {
5337 __ CmpUltD(FTMP, rhs, lhs);
5338 } else {
5339 __ CmpLtD(FTMP, rhs, lhs);
5340 }
5341 __ Mfc1(dst, FTMP);
5342 __ Andi(dst, dst, 1);
5343 break;
5344 case kCondGE:
5345 if (gt_bias) {
5346 __ CmpUleD(FTMP, rhs, lhs);
5347 } else {
5348 __ CmpLeD(FTMP, rhs, lhs);
5349 }
5350 __ Mfc1(dst, FTMP);
5351 __ Andi(dst, dst, 1);
5352 break;
5353 default:
5354 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
5355 UNREACHABLE();
5356 }
5357 } else {
5358 switch (cond) {
5359 case kCondEQ:
5360 __ CeqD(0, lhs, rhs);
5361 __ LoadConst32(dst, 1);
5362 __ Movf(dst, ZERO, 0);
5363 break;
5364 case kCondNE:
5365 __ CeqD(0, lhs, rhs);
5366 __ LoadConst32(dst, 1);
5367 __ Movt(dst, ZERO, 0);
5368 break;
5369 case kCondLT:
5370 if (gt_bias) {
5371 __ ColtD(0, lhs, rhs);
5372 } else {
5373 __ CultD(0, lhs, rhs);
5374 }
5375 __ LoadConst32(dst, 1);
5376 __ Movf(dst, ZERO, 0);
5377 break;
5378 case kCondLE:
5379 if (gt_bias) {
5380 __ ColeD(0, lhs, rhs);
5381 } else {
5382 __ CuleD(0, lhs, rhs);
5383 }
5384 __ LoadConst32(dst, 1);
5385 __ Movf(dst, ZERO, 0);
5386 break;
5387 case kCondGT:
5388 if (gt_bias) {
5389 __ CultD(0, rhs, lhs);
5390 } else {
5391 __ ColtD(0, rhs, lhs);
5392 }
5393 __ LoadConst32(dst, 1);
5394 __ Movf(dst, ZERO, 0);
5395 break;
5396 case kCondGE:
5397 if (gt_bias) {
5398 __ CuleD(0, rhs, lhs);
5399 } else {
5400 __ ColeD(0, rhs, lhs);
5401 }
5402 __ LoadConst32(dst, 1);
5403 __ Movf(dst, ZERO, 0);
5404 break;
5405 default:
5406 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
5407 UNREACHABLE();
5408 }
5409 }
5410 }
5411}
5412
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005413bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR2(IfCondition cond,
5414 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005415 DataType::Type type,
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005416 LocationSummary* input_locations,
5417 int cc) {
5418 FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
5419 FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
5420 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005421 if (type == DataType::Type::kFloat32) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005422 switch (cond) {
5423 case kCondEQ:
5424 __ CeqS(cc, lhs, rhs);
5425 return false;
5426 case kCondNE:
5427 __ CeqS(cc, lhs, rhs);
5428 return true;
5429 case kCondLT:
5430 if (gt_bias) {
5431 __ ColtS(cc, lhs, rhs);
5432 } else {
5433 __ CultS(cc, lhs, rhs);
5434 }
5435 return false;
5436 case kCondLE:
5437 if (gt_bias) {
5438 __ ColeS(cc, lhs, rhs);
5439 } else {
5440 __ CuleS(cc, lhs, rhs);
5441 }
5442 return false;
5443 case kCondGT:
5444 if (gt_bias) {
5445 __ CultS(cc, rhs, lhs);
5446 } else {
5447 __ ColtS(cc, rhs, lhs);
5448 }
5449 return false;
5450 case kCondGE:
5451 if (gt_bias) {
5452 __ CuleS(cc, rhs, lhs);
5453 } else {
5454 __ ColeS(cc, rhs, lhs);
5455 }
5456 return false;
5457 default:
5458 LOG(FATAL) << "Unexpected non-floating-point condition";
5459 UNREACHABLE();
5460 }
5461 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005462 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005463 switch (cond) {
5464 case kCondEQ:
5465 __ CeqD(cc, lhs, rhs);
5466 return false;
5467 case kCondNE:
5468 __ CeqD(cc, lhs, rhs);
5469 return true;
5470 case kCondLT:
5471 if (gt_bias) {
5472 __ ColtD(cc, lhs, rhs);
5473 } else {
5474 __ CultD(cc, lhs, rhs);
5475 }
5476 return false;
5477 case kCondLE:
5478 if (gt_bias) {
5479 __ ColeD(cc, lhs, rhs);
5480 } else {
5481 __ CuleD(cc, lhs, rhs);
5482 }
5483 return false;
5484 case kCondGT:
5485 if (gt_bias) {
5486 __ CultD(cc, rhs, lhs);
5487 } else {
5488 __ ColtD(cc, rhs, lhs);
5489 }
5490 return false;
5491 case kCondGE:
5492 if (gt_bias) {
5493 __ CuleD(cc, rhs, lhs);
5494 } else {
5495 __ ColeD(cc, rhs, lhs);
5496 }
5497 return false;
5498 default:
5499 LOG(FATAL) << "Unexpected non-floating-point condition";
5500 UNREACHABLE();
5501 }
5502 }
5503}
5504
5505bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR6(IfCondition cond,
5506 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005507 DataType::Type type,
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005508 LocationSummary* input_locations,
5509 FRegister dst) {
5510 FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
5511 FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
5512 CHECK(codegen_->GetInstructionSetFeatures().IsR6());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005513 if (type == DataType::Type::kFloat32) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005514 switch (cond) {
5515 case kCondEQ:
5516 __ CmpEqS(dst, lhs, rhs);
5517 return false;
5518 case kCondNE:
5519 __ CmpEqS(dst, lhs, rhs);
5520 return true;
5521 case kCondLT:
5522 if (gt_bias) {
5523 __ CmpLtS(dst, lhs, rhs);
5524 } else {
5525 __ CmpUltS(dst, lhs, rhs);
5526 }
5527 return false;
5528 case kCondLE:
5529 if (gt_bias) {
5530 __ CmpLeS(dst, lhs, rhs);
5531 } else {
5532 __ CmpUleS(dst, lhs, rhs);
5533 }
5534 return false;
5535 case kCondGT:
5536 if (gt_bias) {
5537 __ CmpUltS(dst, rhs, lhs);
5538 } else {
5539 __ CmpLtS(dst, rhs, lhs);
5540 }
5541 return false;
5542 case kCondGE:
5543 if (gt_bias) {
5544 __ CmpUleS(dst, rhs, lhs);
5545 } else {
5546 __ CmpLeS(dst, rhs, lhs);
5547 }
5548 return false;
5549 default:
5550 LOG(FATAL) << "Unexpected non-floating-point condition";
5551 UNREACHABLE();
5552 }
5553 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005554 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005555 switch (cond) {
5556 case kCondEQ:
5557 __ CmpEqD(dst, lhs, rhs);
5558 return false;
5559 case kCondNE:
5560 __ CmpEqD(dst, lhs, rhs);
5561 return true;
5562 case kCondLT:
5563 if (gt_bias) {
5564 __ CmpLtD(dst, lhs, rhs);
5565 } else {
5566 __ CmpUltD(dst, lhs, rhs);
5567 }
5568 return false;
5569 case kCondLE:
5570 if (gt_bias) {
5571 __ CmpLeD(dst, lhs, rhs);
5572 } else {
5573 __ CmpUleD(dst, lhs, rhs);
5574 }
5575 return false;
5576 case kCondGT:
5577 if (gt_bias) {
5578 __ CmpUltD(dst, rhs, lhs);
5579 } else {
5580 __ CmpLtD(dst, rhs, lhs);
5581 }
5582 return false;
5583 case kCondGE:
5584 if (gt_bias) {
5585 __ CmpUleD(dst, rhs, lhs);
5586 } else {
5587 __ CmpLeD(dst, rhs, lhs);
5588 }
5589 return false;
5590 default:
5591 LOG(FATAL) << "Unexpected non-floating-point condition";
5592 UNREACHABLE();
5593 }
5594 }
5595}
5596
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005597void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
5598 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005599 DataType::Type type,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005600 LocationSummary* locations,
5601 MipsLabel* label) {
5602 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
5603 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
5604 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005605 if (type == DataType::Type::kFloat32) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005606 if (isR6) {
5607 switch (cond) {
5608 case kCondEQ:
5609 __ CmpEqS(FTMP, lhs, rhs);
5610 __ Bc1nez(FTMP, label);
5611 break;
5612 case kCondNE:
5613 __ CmpEqS(FTMP, lhs, rhs);
5614 __ Bc1eqz(FTMP, label);
5615 break;
5616 case kCondLT:
5617 if (gt_bias) {
5618 __ CmpLtS(FTMP, lhs, rhs);
5619 } else {
5620 __ CmpUltS(FTMP, lhs, rhs);
5621 }
5622 __ Bc1nez(FTMP, label);
5623 break;
5624 case kCondLE:
5625 if (gt_bias) {
5626 __ CmpLeS(FTMP, lhs, rhs);
5627 } else {
5628 __ CmpUleS(FTMP, lhs, rhs);
5629 }
5630 __ Bc1nez(FTMP, label);
5631 break;
5632 case kCondGT:
5633 if (gt_bias) {
5634 __ CmpUltS(FTMP, rhs, lhs);
5635 } else {
5636 __ CmpLtS(FTMP, rhs, lhs);
5637 }
5638 __ Bc1nez(FTMP, label);
5639 break;
5640 case kCondGE:
5641 if (gt_bias) {
5642 __ CmpUleS(FTMP, rhs, lhs);
5643 } else {
5644 __ CmpLeS(FTMP, rhs, lhs);
5645 }
5646 __ Bc1nez(FTMP, label);
5647 break;
5648 default:
5649 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005650 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005651 }
5652 } else {
5653 switch (cond) {
5654 case kCondEQ:
5655 __ CeqS(0, lhs, rhs);
5656 __ Bc1t(0, label);
5657 break;
5658 case kCondNE:
5659 __ CeqS(0, lhs, rhs);
5660 __ Bc1f(0, label);
5661 break;
5662 case kCondLT:
5663 if (gt_bias) {
5664 __ ColtS(0, lhs, rhs);
5665 } else {
5666 __ CultS(0, lhs, rhs);
5667 }
5668 __ Bc1t(0, label);
5669 break;
5670 case kCondLE:
5671 if (gt_bias) {
5672 __ ColeS(0, lhs, rhs);
5673 } else {
5674 __ CuleS(0, lhs, rhs);
5675 }
5676 __ Bc1t(0, label);
5677 break;
5678 case kCondGT:
5679 if (gt_bias) {
5680 __ CultS(0, rhs, lhs);
5681 } else {
5682 __ ColtS(0, rhs, lhs);
5683 }
5684 __ Bc1t(0, label);
5685 break;
5686 case kCondGE:
5687 if (gt_bias) {
5688 __ CuleS(0, rhs, lhs);
5689 } else {
5690 __ ColeS(0, rhs, lhs);
5691 }
5692 __ Bc1t(0, label);
5693 break;
5694 default:
5695 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005696 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005697 }
5698 }
5699 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005700 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005701 if (isR6) {
5702 switch (cond) {
5703 case kCondEQ:
5704 __ CmpEqD(FTMP, lhs, rhs);
5705 __ Bc1nez(FTMP, label);
5706 break;
5707 case kCondNE:
5708 __ CmpEqD(FTMP, lhs, rhs);
5709 __ Bc1eqz(FTMP, label);
5710 break;
5711 case kCondLT:
5712 if (gt_bias) {
5713 __ CmpLtD(FTMP, lhs, rhs);
5714 } else {
5715 __ CmpUltD(FTMP, lhs, rhs);
5716 }
5717 __ Bc1nez(FTMP, label);
5718 break;
5719 case kCondLE:
5720 if (gt_bias) {
5721 __ CmpLeD(FTMP, lhs, rhs);
5722 } else {
5723 __ CmpUleD(FTMP, lhs, rhs);
5724 }
5725 __ Bc1nez(FTMP, label);
5726 break;
5727 case kCondGT:
5728 if (gt_bias) {
5729 __ CmpUltD(FTMP, rhs, lhs);
5730 } else {
5731 __ CmpLtD(FTMP, rhs, lhs);
5732 }
5733 __ Bc1nez(FTMP, label);
5734 break;
5735 case kCondGE:
5736 if (gt_bias) {
5737 __ CmpUleD(FTMP, rhs, lhs);
5738 } else {
5739 __ CmpLeD(FTMP, rhs, lhs);
5740 }
5741 __ Bc1nez(FTMP, label);
5742 break;
5743 default:
5744 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005745 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005746 }
5747 } else {
5748 switch (cond) {
5749 case kCondEQ:
5750 __ CeqD(0, lhs, rhs);
5751 __ Bc1t(0, label);
5752 break;
5753 case kCondNE:
5754 __ CeqD(0, lhs, rhs);
5755 __ Bc1f(0, label);
5756 break;
5757 case kCondLT:
5758 if (gt_bias) {
5759 __ ColtD(0, lhs, rhs);
5760 } else {
5761 __ CultD(0, lhs, rhs);
5762 }
5763 __ Bc1t(0, label);
5764 break;
5765 case kCondLE:
5766 if (gt_bias) {
5767 __ ColeD(0, lhs, rhs);
5768 } else {
5769 __ CuleD(0, lhs, rhs);
5770 }
5771 __ Bc1t(0, label);
5772 break;
5773 case kCondGT:
5774 if (gt_bias) {
5775 __ CultD(0, rhs, lhs);
5776 } else {
5777 __ ColtD(0, rhs, lhs);
5778 }
5779 __ Bc1t(0, label);
5780 break;
5781 case kCondGE:
5782 if (gt_bias) {
5783 __ CuleD(0, rhs, lhs);
5784 } else {
5785 __ ColeD(0, rhs, lhs);
5786 }
5787 __ Bc1t(0, label);
5788 break;
5789 default:
5790 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005791 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005792 }
5793 }
5794 }
5795}
5796
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005797void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00005798 size_t condition_input_index,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005799 MipsLabel* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00005800 MipsLabel* false_target) {
5801 HInstruction* cond = instruction->InputAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005802
David Brazdil0debae72015-11-12 18:37:00 +00005803 if (true_target == nullptr && false_target == nullptr) {
5804 // Nothing to do. The code always falls through.
5805 return;
5806 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00005807 // Constant condition, statically compared against "true" (integer value 1).
5808 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00005809 if (true_target != nullptr) {
5810 __ B(true_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005811 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005812 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00005813 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00005814 if (false_target != nullptr) {
5815 __ B(false_target);
5816 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005817 }
David Brazdil0debae72015-11-12 18:37:00 +00005818 return;
5819 }
5820
5821 // The following code generates these patterns:
5822 // (1) true_target == nullptr && false_target != nullptr
5823 // - opposite condition true => branch to false_target
5824 // (2) true_target != nullptr && false_target == nullptr
5825 // - condition true => branch to true_target
5826 // (3) true_target != nullptr && false_target != nullptr
5827 // - condition true => branch to true_target
5828 // - branch to false_target
5829 if (IsBooleanValueOrMaterializedCondition(cond)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005830 // The condition instruction has been materialized, compare the output to 0.
David Brazdil0debae72015-11-12 18:37:00 +00005831 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005832 DCHECK(cond_val.IsRegister());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005833 if (true_target == nullptr) {
David Brazdil0debae72015-11-12 18:37:00 +00005834 __ Beqz(cond_val.AsRegister<Register>(), false_target);
5835 } else {
5836 __ Bnez(cond_val.AsRegister<Register>(), true_target);
5837 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005838 } else {
5839 // The condition instruction has not been materialized, use its inputs as
5840 // the comparison and its condition as the branch condition.
David Brazdil0debae72015-11-12 18:37:00 +00005841 HCondition* condition = cond->AsCondition();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005842 DataType::Type type = condition->InputAt(0)->GetType();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005843 LocationSummary* locations = cond->GetLocations();
5844 IfCondition if_cond = condition->GetCondition();
5845 MipsLabel* branch_target = true_target;
David Brazdil0debae72015-11-12 18:37:00 +00005846
David Brazdil0debae72015-11-12 18:37:00 +00005847 if (true_target == nullptr) {
5848 if_cond = condition->GetOppositeCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005849 branch_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00005850 }
5851
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005852 switch (type) {
5853 default:
5854 GenerateIntCompareAndBranch(if_cond, locations, branch_target);
5855 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005856 case DataType::Type::kInt64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005857 GenerateLongCompareAndBranch(if_cond, locations, branch_target);
5858 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005859 case DataType::Type::kFloat32:
5860 case DataType::Type::kFloat64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005861 GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
5862 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005863 }
5864 }
David Brazdil0debae72015-11-12 18:37:00 +00005865
5866 // If neither branch falls through (case 3), the conditional branch to `true_target`
5867 // was already emitted (case 2) and we need to emit a jump to `false_target`.
5868 if (true_target != nullptr && false_target != nullptr) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005869 __ B(false_target);
5870 }
5871}
5872
5873void LocationsBuilderMIPS::VisitIf(HIf* if_instr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01005874 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(if_instr);
David Brazdil0debae72015-11-12 18:37:00 +00005875 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005876 locations->SetInAt(0, Location::RequiresRegister());
5877 }
5878}
5879
5880void InstructionCodeGeneratorMIPS::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00005881 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
5882 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
5883 MipsLabel* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
5884 nullptr : codegen_->GetLabelOf(true_successor);
5885 MipsLabel* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
5886 nullptr : codegen_->GetLabelOf(false_successor);
5887 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005888}
5889
5890void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01005891 LocationSummary* locations = new (GetGraph()->GetAllocator())
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005892 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01005893 InvokeRuntimeCallingConvention calling_convention;
5894 RegisterSet caller_saves = RegisterSet::Empty();
5895 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5896 locations->SetCustomSlowPathCallerSaves(caller_saves);
David Brazdil0debae72015-11-12 18:37:00 +00005897 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005898 locations->SetInAt(0, Location::RequiresRegister());
5899 }
5900}
5901
5902void InstructionCodeGeneratorMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08005903 SlowPathCodeMIPS* slow_path =
5904 deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathMIPS>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00005905 GenerateTestAndBranch(deoptimize,
5906 /* condition_input_index */ 0,
5907 slow_path->GetEntryLabel(),
5908 /* false_target */ nullptr);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005909}
5910
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005911// This function returns true if a conditional move can be generated for HSelect.
5912// Otherwise it returns false and HSelect must be implemented in terms of conditonal
5913// branches and regular moves.
5914//
5915// If `locations_to_set` isn't nullptr, its inputs and outputs are set for HSelect.
5916//
5917// While determining feasibility of a conditional move and setting inputs/outputs
5918// are two distinct tasks, this function does both because they share quite a bit
5919// of common logic.
5920static bool CanMoveConditionally(HSelect* select, bool is_r6, LocationSummary* locations_to_set) {
5921 bool materialized = IsBooleanValueOrMaterializedCondition(select->GetCondition());
5922 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
5923 HCondition* condition = cond->AsCondition();
5924
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005925 DataType::Type cond_type =
5926 materialized ? DataType::Type::kInt32 : condition->InputAt(0)->GetType();
5927 DataType::Type dst_type = select->GetType();
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005928
5929 HConstant* cst_true_value = select->GetTrueValue()->AsConstant();
5930 HConstant* cst_false_value = select->GetFalseValue()->AsConstant();
5931 bool is_true_value_zero_constant =
5932 (cst_true_value != nullptr && cst_true_value->IsZeroBitPattern());
5933 bool is_false_value_zero_constant =
5934 (cst_false_value != nullptr && cst_false_value->IsZeroBitPattern());
5935
5936 bool can_move_conditionally = false;
5937 bool use_const_for_false_in = false;
5938 bool use_const_for_true_in = false;
5939
5940 if (!cond->IsConstant()) {
5941 switch (cond_type) {
5942 default:
5943 switch (dst_type) {
5944 default:
5945 // Moving int on int condition.
5946 if (is_r6) {
5947 if (is_true_value_zero_constant) {
5948 // seleqz out_reg, false_reg, cond_reg
5949 can_move_conditionally = true;
5950 use_const_for_true_in = true;
5951 } else if (is_false_value_zero_constant) {
5952 // selnez out_reg, true_reg, cond_reg
5953 can_move_conditionally = true;
5954 use_const_for_false_in = true;
5955 } else if (materialized) {
5956 // Not materializing unmaterialized int conditions
5957 // to keep the instruction count low.
5958 // selnez AT, true_reg, cond_reg
5959 // seleqz TMP, false_reg, cond_reg
5960 // or out_reg, AT, TMP
5961 can_move_conditionally = true;
5962 }
5963 } else {
5964 // movn out_reg, true_reg/ZERO, cond_reg
5965 can_move_conditionally = true;
5966 use_const_for_true_in = is_true_value_zero_constant;
5967 }
5968 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005969 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005970 // Moving long on int condition.
5971 if (is_r6) {
5972 if (is_true_value_zero_constant) {
5973 // seleqz out_reg_lo, false_reg_lo, cond_reg
5974 // seleqz out_reg_hi, false_reg_hi, cond_reg
5975 can_move_conditionally = true;
5976 use_const_for_true_in = true;
5977 } else if (is_false_value_zero_constant) {
5978 // selnez out_reg_lo, true_reg_lo, cond_reg
5979 // selnez out_reg_hi, true_reg_hi, cond_reg
5980 can_move_conditionally = true;
5981 use_const_for_false_in = true;
5982 }
5983 // Other long conditional moves would generate 6+ instructions,
5984 // which is too many.
5985 } else {
5986 // movn out_reg_lo, true_reg_lo/ZERO, cond_reg
5987 // movn out_reg_hi, true_reg_hi/ZERO, cond_reg
5988 can_move_conditionally = true;
5989 use_const_for_true_in = is_true_value_zero_constant;
5990 }
5991 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005992 case DataType::Type::kFloat32:
5993 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005994 // Moving float/double on int condition.
5995 if (is_r6) {
5996 if (materialized) {
5997 // Not materializing unmaterialized int conditions
5998 // to keep the instruction count low.
5999 can_move_conditionally = true;
6000 if (is_true_value_zero_constant) {
6001 // sltu TMP, ZERO, cond_reg
6002 // mtc1 TMP, temp_cond_reg
6003 // seleqz.fmt out_reg, false_reg, temp_cond_reg
6004 use_const_for_true_in = true;
6005 } else if (is_false_value_zero_constant) {
6006 // sltu TMP, ZERO, cond_reg
6007 // mtc1 TMP, temp_cond_reg
6008 // selnez.fmt out_reg, true_reg, temp_cond_reg
6009 use_const_for_false_in = true;
6010 } else {
6011 // sltu TMP, ZERO, cond_reg
6012 // mtc1 TMP, temp_cond_reg
6013 // sel.fmt temp_cond_reg, false_reg, true_reg
6014 // mov.fmt out_reg, temp_cond_reg
6015 }
6016 }
6017 } else {
6018 // movn.fmt out_reg, true_reg, cond_reg
6019 can_move_conditionally = true;
6020 }
6021 break;
6022 }
6023 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006024 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006025 // We don't materialize long comparison now
6026 // and use conditional branches instead.
6027 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006028 case DataType::Type::kFloat32:
6029 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006030 switch (dst_type) {
6031 default:
6032 // Moving int on float/double condition.
6033 if (is_r6) {
6034 if (is_true_value_zero_constant) {
6035 // mfc1 TMP, temp_cond_reg
6036 // seleqz out_reg, false_reg, TMP
6037 can_move_conditionally = true;
6038 use_const_for_true_in = true;
6039 } else if (is_false_value_zero_constant) {
6040 // mfc1 TMP, temp_cond_reg
6041 // selnez out_reg, true_reg, TMP
6042 can_move_conditionally = true;
6043 use_const_for_false_in = true;
6044 } else {
6045 // mfc1 TMP, temp_cond_reg
6046 // selnez AT, true_reg, TMP
6047 // seleqz TMP, false_reg, TMP
6048 // or out_reg, AT, TMP
6049 can_move_conditionally = true;
6050 }
6051 } else {
6052 // movt out_reg, true_reg/ZERO, cc
6053 can_move_conditionally = true;
6054 use_const_for_true_in = is_true_value_zero_constant;
6055 }
6056 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006057 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006058 // Moving long on float/double condition.
6059 if (is_r6) {
6060 if (is_true_value_zero_constant) {
6061 // mfc1 TMP, temp_cond_reg
6062 // seleqz out_reg_lo, false_reg_lo, TMP
6063 // seleqz out_reg_hi, false_reg_hi, TMP
6064 can_move_conditionally = true;
6065 use_const_for_true_in = true;
6066 } else if (is_false_value_zero_constant) {
6067 // mfc1 TMP, temp_cond_reg
6068 // selnez out_reg_lo, true_reg_lo, TMP
6069 // selnez out_reg_hi, true_reg_hi, TMP
6070 can_move_conditionally = true;
6071 use_const_for_false_in = true;
6072 }
6073 // Other long conditional moves would generate 6+ instructions,
6074 // which is too many.
6075 } else {
6076 // movt out_reg_lo, true_reg_lo/ZERO, cc
6077 // movt out_reg_hi, true_reg_hi/ZERO, cc
6078 can_move_conditionally = true;
6079 use_const_for_true_in = is_true_value_zero_constant;
6080 }
6081 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006082 case DataType::Type::kFloat32:
6083 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006084 // Moving float/double on float/double condition.
6085 if (is_r6) {
6086 can_move_conditionally = true;
6087 if (is_true_value_zero_constant) {
6088 // seleqz.fmt out_reg, false_reg, temp_cond_reg
6089 use_const_for_true_in = true;
6090 } else if (is_false_value_zero_constant) {
6091 // selnez.fmt out_reg, true_reg, temp_cond_reg
6092 use_const_for_false_in = true;
6093 } else {
6094 // sel.fmt temp_cond_reg, false_reg, true_reg
6095 // mov.fmt out_reg, temp_cond_reg
6096 }
6097 } else {
6098 // movt.fmt out_reg, true_reg, cc
6099 can_move_conditionally = true;
6100 }
6101 break;
6102 }
6103 break;
6104 }
6105 }
6106
6107 if (can_move_conditionally) {
6108 DCHECK(!use_const_for_false_in || !use_const_for_true_in);
6109 } else {
6110 DCHECK(!use_const_for_false_in);
6111 DCHECK(!use_const_for_true_in);
6112 }
6113
6114 if (locations_to_set != nullptr) {
6115 if (use_const_for_false_in) {
6116 locations_to_set->SetInAt(0, Location::ConstantLocation(cst_false_value));
6117 } else {
6118 locations_to_set->SetInAt(0,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006119 DataType::IsFloatingPointType(dst_type)
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006120 ? Location::RequiresFpuRegister()
6121 : Location::RequiresRegister());
6122 }
6123 if (use_const_for_true_in) {
6124 locations_to_set->SetInAt(1, Location::ConstantLocation(cst_true_value));
6125 } else {
6126 locations_to_set->SetInAt(1,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006127 DataType::IsFloatingPointType(dst_type)
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006128 ? Location::RequiresFpuRegister()
6129 : Location::RequiresRegister());
6130 }
6131 if (materialized) {
6132 locations_to_set->SetInAt(2, Location::RequiresRegister());
6133 }
6134 // On R6 we don't require the output to be the same as the
6135 // first input for conditional moves unlike on R2.
6136 bool is_out_same_as_first_in = !can_move_conditionally || !is_r6;
6137 if (is_out_same_as_first_in) {
6138 locations_to_set->SetOut(Location::SameAsFirstInput());
6139 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006140 locations_to_set->SetOut(DataType::IsFloatingPointType(dst_type)
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006141 ? Location::RequiresFpuRegister()
6142 : Location::RequiresRegister());
6143 }
6144 }
6145
6146 return can_move_conditionally;
6147}
6148
6149void InstructionCodeGeneratorMIPS::GenConditionalMoveR2(HSelect* select) {
6150 LocationSummary* locations = select->GetLocations();
6151 Location dst = locations->Out();
6152 Location src = locations->InAt(1);
6153 Register src_reg = ZERO;
6154 Register src_reg_high = ZERO;
6155 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
6156 Register cond_reg = TMP;
6157 int cond_cc = 0;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006158 DataType::Type cond_type = DataType::Type::kInt32;
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006159 bool cond_inverted = false;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006160 DataType::Type dst_type = select->GetType();
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006161
6162 if (IsBooleanValueOrMaterializedCondition(cond)) {
6163 cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
6164 } else {
6165 HCondition* condition = cond->AsCondition();
6166 LocationSummary* cond_locations = cond->GetLocations();
6167 IfCondition if_cond = condition->GetCondition();
6168 cond_type = condition->InputAt(0)->GetType();
6169 switch (cond_type) {
6170 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006171 DCHECK_NE(cond_type, DataType::Type::kInt64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006172 cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
6173 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006174 case DataType::Type::kFloat32:
6175 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006176 cond_inverted = MaterializeFpCompareR2(if_cond,
6177 condition->IsGtBias(),
6178 cond_type,
6179 cond_locations,
6180 cond_cc);
6181 break;
6182 }
6183 }
6184
6185 DCHECK(dst.Equals(locations->InAt(0)));
6186 if (src.IsRegister()) {
6187 src_reg = src.AsRegister<Register>();
6188 } else if (src.IsRegisterPair()) {
6189 src_reg = src.AsRegisterPairLow<Register>();
6190 src_reg_high = src.AsRegisterPairHigh<Register>();
6191 } else if (src.IsConstant()) {
6192 DCHECK(src.GetConstant()->IsZeroBitPattern());
6193 }
6194
6195 switch (cond_type) {
6196 default:
6197 switch (dst_type) {
6198 default:
6199 if (cond_inverted) {
6200 __ Movz(dst.AsRegister<Register>(), src_reg, cond_reg);
6201 } else {
6202 __ Movn(dst.AsRegister<Register>(), src_reg, cond_reg);
6203 }
6204 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006205 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006206 if (cond_inverted) {
6207 __ Movz(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
6208 __ Movz(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
6209 } else {
6210 __ Movn(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
6211 __ Movn(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
6212 }
6213 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006214 case DataType::Type::kFloat32:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006215 if (cond_inverted) {
6216 __ MovzS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
6217 } else {
6218 __ MovnS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
6219 }
6220 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006221 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006222 if (cond_inverted) {
6223 __ MovzD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
6224 } else {
6225 __ MovnD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
6226 }
6227 break;
6228 }
6229 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006230 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006231 LOG(FATAL) << "Unreachable";
6232 UNREACHABLE();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006233 case DataType::Type::kFloat32:
6234 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006235 switch (dst_type) {
6236 default:
6237 if (cond_inverted) {
6238 __ Movf(dst.AsRegister<Register>(), src_reg, cond_cc);
6239 } else {
6240 __ Movt(dst.AsRegister<Register>(), src_reg, cond_cc);
6241 }
6242 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006243 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006244 if (cond_inverted) {
6245 __ Movf(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
6246 __ Movf(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
6247 } else {
6248 __ Movt(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
6249 __ Movt(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
6250 }
6251 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006252 case DataType::Type::kFloat32:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006253 if (cond_inverted) {
6254 __ MovfS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
6255 } else {
6256 __ MovtS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
6257 }
6258 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006259 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006260 if (cond_inverted) {
6261 __ MovfD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
6262 } else {
6263 __ MovtD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
6264 }
6265 break;
6266 }
6267 break;
6268 }
6269}
6270
6271void InstructionCodeGeneratorMIPS::GenConditionalMoveR6(HSelect* select) {
6272 LocationSummary* locations = select->GetLocations();
6273 Location dst = locations->Out();
6274 Location false_src = locations->InAt(0);
6275 Location true_src = locations->InAt(1);
6276 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
6277 Register cond_reg = TMP;
6278 FRegister fcond_reg = FTMP;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006279 DataType::Type cond_type = DataType::Type::kInt32;
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006280 bool cond_inverted = false;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006281 DataType::Type dst_type = select->GetType();
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006282
6283 if (IsBooleanValueOrMaterializedCondition(cond)) {
6284 cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
6285 } else {
6286 HCondition* condition = cond->AsCondition();
6287 LocationSummary* cond_locations = cond->GetLocations();
6288 IfCondition if_cond = condition->GetCondition();
6289 cond_type = condition->InputAt(0)->GetType();
6290 switch (cond_type) {
6291 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006292 DCHECK_NE(cond_type, DataType::Type::kInt64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006293 cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
6294 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006295 case DataType::Type::kFloat32:
6296 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006297 cond_inverted = MaterializeFpCompareR6(if_cond,
6298 condition->IsGtBias(),
6299 cond_type,
6300 cond_locations,
6301 fcond_reg);
6302 break;
6303 }
6304 }
6305
6306 if (true_src.IsConstant()) {
6307 DCHECK(true_src.GetConstant()->IsZeroBitPattern());
6308 }
6309 if (false_src.IsConstant()) {
6310 DCHECK(false_src.GetConstant()->IsZeroBitPattern());
6311 }
6312
6313 switch (dst_type) {
6314 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006315 if (DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006316 __ Mfc1(cond_reg, fcond_reg);
6317 }
6318 if (true_src.IsConstant()) {
6319 if (cond_inverted) {
6320 __ Selnez(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
6321 } else {
6322 __ Seleqz(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
6323 }
6324 } else if (false_src.IsConstant()) {
6325 if (cond_inverted) {
6326 __ Seleqz(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
6327 } else {
6328 __ Selnez(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
6329 }
6330 } else {
6331 DCHECK_NE(cond_reg, AT);
6332 if (cond_inverted) {
6333 __ Seleqz(AT, true_src.AsRegister<Register>(), cond_reg);
6334 __ Selnez(TMP, false_src.AsRegister<Register>(), cond_reg);
6335 } else {
6336 __ Selnez(AT, true_src.AsRegister<Register>(), cond_reg);
6337 __ Seleqz(TMP, false_src.AsRegister<Register>(), cond_reg);
6338 }
6339 __ Or(dst.AsRegister<Register>(), AT, TMP);
6340 }
6341 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006342 case DataType::Type::kInt64: {
6343 if (DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006344 __ Mfc1(cond_reg, fcond_reg);
6345 }
6346 Register dst_lo = dst.AsRegisterPairLow<Register>();
6347 Register dst_hi = dst.AsRegisterPairHigh<Register>();
6348 if (true_src.IsConstant()) {
6349 Register src_lo = false_src.AsRegisterPairLow<Register>();
6350 Register src_hi = false_src.AsRegisterPairHigh<Register>();
6351 if (cond_inverted) {
6352 __ Selnez(dst_lo, src_lo, cond_reg);
6353 __ Selnez(dst_hi, src_hi, cond_reg);
6354 } else {
6355 __ Seleqz(dst_lo, src_lo, cond_reg);
6356 __ Seleqz(dst_hi, src_hi, cond_reg);
6357 }
6358 } else {
6359 DCHECK(false_src.IsConstant());
6360 Register src_lo = true_src.AsRegisterPairLow<Register>();
6361 Register src_hi = true_src.AsRegisterPairHigh<Register>();
6362 if (cond_inverted) {
6363 __ Seleqz(dst_lo, src_lo, cond_reg);
6364 __ Seleqz(dst_hi, src_hi, cond_reg);
6365 } else {
6366 __ Selnez(dst_lo, src_lo, cond_reg);
6367 __ Selnez(dst_hi, src_hi, cond_reg);
6368 }
6369 }
6370 break;
6371 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006372 case DataType::Type::kFloat32: {
6373 if (!DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006374 // sel*.fmt tests bit 0 of the condition register, account for that.
6375 __ Sltu(TMP, ZERO, cond_reg);
6376 __ Mtc1(TMP, fcond_reg);
6377 }
6378 FRegister dst_reg = dst.AsFpuRegister<FRegister>();
6379 if (true_src.IsConstant()) {
6380 FRegister src_reg = false_src.AsFpuRegister<FRegister>();
6381 if (cond_inverted) {
6382 __ SelnezS(dst_reg, src_reg, fcond_reg);
6383 } else {
6384 __ SeleqzS(dst_reg, src_reg, fcond_reg);
6385 }
6386 } else if (false_src.IsConstant()) {
6387 FRegister src_reg = true_src.AsFpuRegister<FRegister>();
6388 if (cond_inverted) {
6389 __ SeleqzS(dst_reg, src_reg, fcond_reg);
6390 } else {
6391 __ SelnezS(dst_reg, src_reg, fcond_reg);
6392 }
6393 } else {
6394 if (cond_inverted) {
6395 __ SelS(fcond_reg,
6396 true_src.AsFpuRegister<FRegister>(),
6397 false_src.AsFpuRegister<FRegister>());
6398 } else {
6399 __ SelS(fcond_reg,
6400 false_src.AsFpuRegister<FRegister>(),
6401 true_src.AsFpuRegister<FRegister>());
6402 }
6403 __ MovS(dst_reg, fcond_reg);
6404 }
6405 break;
6406 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006407 case DataType::Type::kFloat64: {
6408 if (!DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006409 // sel*.fmt tests bit 0 of the condition register, account for that.
6410 __ Sltu(TMP, ZERO, cond_reg);
6411 __ Mtc1(TMP, fcond_reg);
6412 }
6413 FRegister dst_reg = dst.AsFpuRegister<FRegister>();
6414 if (true_src.IsConstant()) {
6415 FRegister src_reg = false_src.AsFpuRegister<FRegister>();
6416 if (cond_inverted) {
6417 __ SelnezD(dst_reg, src_reg, fcond_reg);
6418 } else {
6419 __ SeleqzD(dst_reg, src_reg, fcond_reg);
6420 }
6421 } else if (false_src.IsConstant()) {
6422 FRegister src_reg = true_src.AsFpuRegister<FRegister>();
6423 if (cond_inverted) {
6424 __ SeleqzD(dst_reg, src_reg, fcond_reg);
6425 } else {
6426 __ SelnezD(dst_reg, src_reg, fcond_reg);
6427 }
6428 } else {
6429 if (cond_inverted) {
6430 __ SelD(fcond_reg,
6431 true_src.AsFpuRegister<FRegister>(),
6432 false_src.AsFpuRegister<FRegister>());
6433 } else {
6434 __ SelD(fcond_reg,
6435 false_src.AsFpuRegister<FRegister>(),
6436 true_src.AsFpuRegister<FRegister>());
6437 }
6438 __ MovD(dst_reg, fcond_reg);
6439 }
6440 break;
6441 }
6442 }
6443}
6444
Goran Jakovljevicc6418422016-12-05 16:31:55 +01006445void LocationsBuilderMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006446 LocationSummary* locations = new (GetGraph()->GetAllocator())
Goran Jakovljevicc6418422016-12-05 16:31:55 +01006447 LocationSummary(flag, LocationSummary::kNoCall);
6448 locations->SetOut(Location::RequiresRegister());
Mingyao Yang063fc772016-08-02 11:02:54 -07006449}
6450
Goran Jakovljevicc6418422016-12-05 16:31:55 +01006451void InstructionCodeGeneratorMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
6452 __ LoadFromOffset(kLoadWord,
6453 flag->GetLocations()->Out().AsRegister<Register>(),
6454 SP,
6455 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
Mingyao Yang063fc772016-08-02 11:02:54 -07006456}
6457
David Brazdil74eb1b22015-12-14 11:44:01 +00006458void LocationsBuilderMIPS::VisitSelect(HSelect* select) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006459 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(select);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006460 CanMoveConditionally(select, codegen_->GetInstructionSetFeatures().IsR6(), locations);
David Brazdil74eb1b22015-12-14 11:44:01 +00006461}
6462
6463void InstructionCodeGeneratorMIPS::VisitSelect(HSelect* select) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006464 bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
6465 if (CanMoveConditionally(select, is_r6, /* locations_to_set */ nullptr)) {
6466 if (is_r6) {
6467 GenConditionalMoveR6(select);
6468 } else {
6469 GenConditionalMoveR2(select);
6470 }
6471 } else {
6472 LocationSummary* locations = select->GetLocations();
6473 MipsLabel false_target;
6474 GenerateTestAndBranch(select,
6475 /* condition_input_index */ 2,
6476 /* true_target */ nullptr,
6477 &false_target);
6478 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
6479 __ Bind(&false_target);
6480 }
David Brazdil74eb1b22015-12-14 11:44:01 +00006481}
6482
David Srbecky0cf44932015-12-09 14:09:59 +00006483void LocationsBuilderMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006484 new (GetGraph()->GetAllocator()) LocationSummary(info);
David Srbecky0cf44932015-12-09 14:09:59 +00006485}
6486
David Srbeckyd28f4a02016-03-14 17:14:24 +00006487void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo*) {
6488 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00006489}
6490
6491void CodeGeneratorMIPS::GenerateNop() {
6492 __ Nop();
David Srbecky0cf44932015-12-09 14:09:59 +00006493}
6494
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006495void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006496 DataType::Type field_type = field_info.GetFieldType();
6497 bool is_wide = (field_type == DataType::Type::kInt64) || (field_type == DataType::Type::kFloat64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006498 bool generate_volatile = field_info.IsVolatile() && is_wide;
Alexey Frunze15958152017-02-09 19:08:30 -08006499 bool object_field_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006500 kEmitCompilerReadBarrier && (field_type == DataType::Type::kReference);
Vladimir Markoca6fff82017-10-03 14:49:14 +01006501 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Alexey Frunze15958152017-02-09 19:08:30 -08006502 instruction,
6503 generate_volatile
6504 ? LocationSummary::kCallOnMainOnly
6505 : (object_field_get_with_read_barrier
6506 ? LocationSummary::kCallOnSlowPath
6507 : LocationSummary::kNoCall));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006508
Alexey Frunzec61c0762017-04-10 13:54:23 -07006509 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
6510 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
6511 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006512 locations->SetInAt(0, Location::RequiresRegister());
6513 if (generate_volatile) {
6514 InvokeRuntimeCallingConvention calling_convention;
6515 // need A0 to hold base + offset
6516 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006517 if (field_type == DataType::Type::kInt64) {
6518 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt64));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006519 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006520 // Use Location::Any() to prevent situations when running out of available fp registers.
6521 locations->SetOut(Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006522 // Need some temp core regs since FP results are returned in core registers
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006523 Location reg = calling_convention.GetReturnLocation(DataType::Type::kInt64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006524 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairLow<Register>()));
6525 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairHigh<Register>()));
6526 }
6527 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006528 if (DataType::IsFloatingPointType(instruction->GetType())) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006529 locations->SetOut(Location::RequiresFpuRegister());
6530 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006531 // The output overlaps in the case of an object field get with
6532 // read barriers enabled: we do not want the move to overwrite the
6533 // object's location, as we need it to emit the read barrier.
6534 locations->SetOut(Location::RequiresRegister(),
6535 object_field_get_with_read_barrier
6536 ? Location::kOutputOverlap
6537 : Location::kNoOutputOverlap);
6538 }
6539 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
6540 // We need a temporary register for the read barrier marking slow
6541 // path in CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier.
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006542 if (!kBakerReadBarrierThunksEnableForFields) {
6543 locations->AddTemp(Location::RequiresRegister());
6544 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006545 }
6546 }
6547}
6548
6549void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
6550 const FieldInfo& field_info,
6551 uint32_t dex_pc) {
Vladimir Marko61b92282017-10-11 13:23:17 +01006552 DCHECK_EQ(DataType::Size(field_info.GetFieldType()), DataType::Size(instruction->GetType()));
6553 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006554 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08006555 Location obj_loc = locations->InAt(0);
6556 Register obj = obj_loc.AsRegister<Register>();
6557 Location dst_loc = locations->Out();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006558 LoadOperandType load_type = kLoadUnsignedByte;
6559 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006560 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Tijana Jakovljevic57433862017-01-17 16:59:03 +01006561 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006562
6563 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006564 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006565 case DataType::Type::kUint8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006566 load_type = kLoadUnsignedByte;
6567 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006568 case DataType::Type::kInt8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006569 load_type = kLoadSignedByte;
6570 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006571 case DataType::Type::kUint16:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006572 load_type = kLoadUnsignedHalfword;
6573 break;
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006574 case DataType::Type::kInt16:
6575 load_type = kLoadSignedHalfword;
6576 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006577 case DataType::Type::kInt32:
6578 case DataType::Type::kFloat32:
6579 case DataType::Type::kReference:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006580 load_type = kLoadWord;
6581 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006582 case DataType::Type::kInt64:
6583 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006584 load_type = kLoadDoubleword;
6585 break;
Aart Bik66c158e2018-01-31 12:55:04 -08006586 case DataType::Type::kUint32:
6587 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006588 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006589 LOG(FATAL) << "Unreachable type " << type;
6590 UNREACHABLE();
6591 }
6592
6593 if (is_volatile && load_type == kLoadDoubleword) {
6594 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006595 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006596 // Do implicit Null check
Goran Jakovljevic2e61a572017-10-23 08:58:15 +02006597 __ LoadFromOffset(kLoadWord,
6598 ZERO,
6599 locations->GetTemp(0).AsRegister<Register>(),
6600 0,
6601 null_checker);
Serban Constantinescufca16662016-07-14 09:21:59 +01006602 codegen_->InvokeRuntime(kQuickA64Load, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006603 CheckEntrypointTypes<kQuickA64Load, int64_t, volatile const int64_t*>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006604 if (type == DataType::Type::kFloat64) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006605 // FP results are returned in core registers. Need to move them.
Alexey Frunze15958152017-02-09 19:08:30 -08006606 if (dst_loc.IsFpuRegister()) {
6607 __ Mtc1(locations->GetTemp(1).AsRegister<Register>(), dst_loc.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006608 __ MoveToFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
Alexey Frunze15958152017-02-09 19:08:30 -08006609 dst_loc.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006610 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006611 DCHECK(dst_loc.IsDoubleStackSlot());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006612 __ StoreToOffset(kStoreWord,
6613 locations->GetTemp(1).AsRegister<Register>(),
6614 SP,
Alexey Frunze15958152017-02-09 19:08:30 -08006615 dst_loc.GetStackIndex());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006616 __ StoreToOffset(kStoreWord,
6617 locations->GetTemp(2).AsRegister<Register>(),
6618 SP,
Alexey Frunze15958152017-02-09 19:08:30 -08006619 dst_loc.GetStackIndex() + 4);
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006620 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006621 }
6622 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006623 if (type == DataType::Type::kReference) {
Alexey Frunze15958152017-02-09 19:08:30 -08006624 // /* HeapReference<Object> */ dst = *(obj + offset)
6625 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006626 Location temp_loc =
6627 kBakerReadBarrierThunksEnableForFields ? Location::NoLocation() : locations->GetTemp(0);
Alexey Frunze15958152017-02-09 19:08:30 -08006628 // Note that a potential implicit null check is handled in this
6629 // CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier call.
6630 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6631 dst_loc,
6632 obj,
6633 offset,
6634 temp_loc,
6635 /* needs_null_check */ true);
6636 if (is_volatile) {
6637 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6638 }
6639 } else {
6640 __ LoadFromOffset(kLoadWord, dst_loc.AsRegister<Register>(), obj, offset, null_checker);
6641 if (is_volatile) {
6642 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6643 }
6644 // If read barriers are enabled, emit read barriers other than
6645 // Baker's using a slow path (and also unpoison the loaded
6646 // reference, if heap poisoning is enabled).
6647 codegen_->MaybeGenerateReadBarrierSlow(instruction, dst_loc, dst_loc, obj_loc, offset);
6648 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006649 } else if (!DataType::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006650 Register dst;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006651 if (type == DataType::Type::kInt64) {
Alexey Frunze15958152017-02-09 19:08:30 -08006652 DCHECK(dst_loc.IsRegisterPair());
6653 dst = dst_loc.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006654 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006655 DCHECK(dst_loc.IsRegister());
6656 dst = dst_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006657 }
Alexey Frunze2923db72016-08-20 01:55:47 -07006658 __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006659 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006660 DCHECK(dst_loc.IsFpuRegister());
6661 FRegister dst = dst_loc.AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006662 if (type == DataType::Type::kFloat32) {
Alexey Frunze2923db72016-08-20 01:55:47 -07006663 __ LoadSFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006664 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07006665 __ LoadDFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006666 }
6667 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006668 }
6669
Alexey Frunze15958152017-02-09 19:08:30 -08006670 // Memory barriers, in the case of references, are handled in the
6671 // previous switch statement.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006672 if (is_volatile && (type != DataType::Type::kReference)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006673 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6674 }
6675}
6676
6677void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006678 DataType::Type field_type = field_info.GetFieldType();
6679 bool is_wide = (field_type == DataType::Type::kInt64) || (field_type == DataType::Type::kFloat64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006680 bool generate_volatile = field_info.IsVolatile() && is_wide;
Vladimir Markoca6fff82017-10-03 14:49:14 +01006681 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006682 instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006683
6684 locations->SetInAt(0, Location::RequiresRegister());
6685 if (generate_volatile) {
6686 InvokeRuntimeCallingConvention calling_convention;
6687 // need A0 to hold base + offset
6688 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006689 if (field_type == DataType::Type::kInt64) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006690 locations->SetInAt(1, Location::RegisterPairLocation(
6691 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
6692 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006693 // Use Location::Any() to prevent situations when running out of available fp registers.
6694 locations->SetInAt(1, Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006695 // Pass FP parameters in core registers.
6696 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
6697 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
6698 }
6699 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006700 if (DataType::IsFloatingPointType(field_type)) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006701 locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006702 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006703 locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006704 }
6705 }
6706}
6707
6708void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction,
6709 const FieldInfo& field_info,
Goran Jakovljevice114da22016-12-26 14:21:43 +01006710 uint32_t dex_pc,
6711 bool value_can_be_null) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006712 DataType::Type type = field_info.GetFieldType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006713 LocationSummary* locations = instruction->GetLocations();
6714 Register obj = locations->InAt(0).AsRegister<Register>();
Alexey Frunzef58b2482016-09-02 22:14:06 -07006715 Location value_location = locations->InAt(1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006716 StoreOperandType store_type = kStoreByte;
6717 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006718 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Alexey Frunzec061de12017-02-14 13:27:23 -08006719 bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1));
Tijana Jakovljevic57433862017-01-17 16:59:03 +01006720 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006721
6722 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006723 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006724 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006725 case DataType::Type::kInt8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006726 store_type = kStoreByte;
6727 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006728 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006729 case DataType::Type::kInt16:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006730 store_type = kStoreHalfword;
6731 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006732 case DataType::Type::kInt32:
6733 case DataType::Type::kFloat32:
6734 case DataType::Type::kReference:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006735 store_type = kStoreWord;
6736 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006737 case DataType::Type::kInt64:
6738 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006739 store_type = kStoreDoubleword;
6740 break;
Aart Bik66c158e2018-01-31 12:55:04 -08006741 case DataType::Type::kUint32:
6742 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006743 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006744 LOG(FATAL) << "Unreachable type " << type;
6745 UNREACHABLE();
6746 }
6747
6748 if (is_volatile) {
6749 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
6750 }
6751
6752 if (is_volatile && store_type == kStoreDoubleword) {
6753 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006754 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006755 // Do implicit Null check.
Goran Jakovljevic2e61a572017-10-23 08:58:15 +02006756 __ LoadFromOffset(kLoadWord,
6757 ZERO,
6758 locations->GetTemp(0).AsRegister<Register>(),
6759 0,
6760 null_checker);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006761 if (type == DataType::Type::kFloat64) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006762 // Pass FP parameters in core registers.
Alexey Frunzef58b2482016-09-02 22:14:06 -07006763 if (value_location.IsFpuRegister()) {
6764 __ Mfc1(locations->GetTemp(1).AsRegister<Register>(),
6765 value_location.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006766 __ MoveFromFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
Alexey Frunzef58b2482016-09-02 22:14:06 -07006767 value_location.AsFpuRegister<FRegister>());
6768 } else if (value_location.IsDoubleStackSlot()) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006769 __ LoadFromOffset(kLoadWord,
6770 locations->GetTemp(1).AsRegister<Register>(),
6771 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07006772 value_location.GetStackIndex());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006773 __ LoadFromOffset(kLoadWord,
6774 locations->GetTemp(2).AsRegister<Register>(),
6775 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07006776 value_location.GetStackIndex() + 4);
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006777 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006778 DCHECK(value_location.IsConstant());
6779 DCHECK(value_location.GetConstant()->IsDoubleConstant());
6780 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006781 __ LoadConst64(locations->GetTemp(2).AsRegister<Register>(),
6782 locations->GetTemp(1).AsRegister<Register>(),
6783 value);
6784 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006785 }
Serban Constantinescufca16662016-07-14 09:21:59 +01006786 codegen_->InvokeRuntime(kQuickA64Store, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006787 CheckEntrypointTypes<kQuickA64Store, void, volatile int64_t *, int64_t>();
6788 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006789 if (value_location.IsConstant()) {
6790 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
6791 __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006792 } else if (!DataType::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006793 Register src;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006794 if (type == DataType::Type::kInt64) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006795 src = value_location.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006796 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006797 src = value_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006798 }
Alexey Frunzec061de12017-02-14 13:27:23 -08006799 if (kPoisonHeapReferences && needs_write_barrier) {
6800 // Note that in the case where `value` is a null reference,
6801 // we do not enter this block, as a null reference does not
6802 // need poisoning.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006803 DCHECK_EQ(type, DataType::Type::kReference);
Alexey Frunzec061de12017-02-14 13:27:23 -08006804 __ PoisonHeapReference(TMP, src);
6805 __ StoreToOffset(store_type, TMP, obj, offset, null_checker);
6806 } else {
6807 __ StoreToOffset(store_type, src, obj, offset, null_checker);
6808 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006809 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006810 FRegister src = value_location.AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006811 if (type == DataType::Type::kFloat32) {
Alexey Frunze2923db72016-08-20 01:55:47 -07006812 __ StoreSToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006813 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07006814 __ StoreDToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006815 }
6816 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006817 }
6818
Alexey Frunzec061de12017-02-14 13:27:23 -08006819 if (needs_write_barrier) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006820 Register src = value_location.AsRegister<Register>();
Goran Jakovljevice114da22016-12-26 14:21:43 +01006821 codegen_->MarkGCCard(obj, src, value_can_be_null);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006822 }
6823
6824 if (is_volatile) {
6825 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
6826 }
6827}
6828
6829void LocationsBuilderMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6830 HandleFieldGet(instruction, instruction->GetFieldInfo());
6831}
6832
6833void InstructionCodeGeneratorMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6834 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
6835}
6836
6837void LocationsBuilderMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
6838 HandleFieldSet(instruction, instruction->GetFieldInfo());
6839}
6840
6841void InstructionCodeGeneratorMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01006842 HandleFieldSet(instruction,
6843 instruction->GetFieldInfo(),
6844 instruction->GetDexPc(),
6845 instruction->GetValueCanBeNull());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006846}
6847
Alexey Frunze15958152017-02-09 19:08:30 -08006848void InstructionCodeGeneratorMIPS::GenerateReferenceLoadOneRegister(
6849 HInstruction* instruction,
6850 Location out,
6851 uint32_t offset,
6852 Location maybe_temp,
6853 ReadBarrierOption read_barrier_option) {
6854 Register out_reg = out.AsRegister<Register>();
6855 if (read_barrier_option == kWithReadBarrier) {
6856 CHECK(kEmitCompilerReadBarrier);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006857 if (!kUseBakerReadBarrier || !kBakerReadBarrierThunksEnableForFields) {
6858 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6859 }
Alexey Frunze15958152017-02-09 19:08:30 -08006860 if (kUseBakerReadBarrier) {
6861 // Load with fast path based Baker's read barrier.
6862 // /* HeapReference<Object> */ out = *(out + offset)
6863 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6864 out,
6865 out_reg,
6866 offset,
6867 maybe_temp,
6868 /* needs_null_check */ false);
6869 } else {
6870 // Load with slow path based read barrier.
6871 // Save the value of `out` into `maybe_temp` before overwriting it
6872 // in the following move operation, as we will need it for the
6873 // read barrier below.
6874 __ Move(maybe_temp.AsRegister<Register>(), out_reg);
6875 // /* HeapReference<Object> */ out = *(out + offset)
6876 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6877 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
6878 }
6879 } else {
6880 // Plain load with no read barrier.
6881 // /* HeapReference<Object> */ out = *(out + offset)
6882 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6883 __ MaybeUnpoisonHeapReference(out_reg);
6884 }
6885}
6886
6887void InstructionCodeGeneratorMIPS::GenerateReferenceLoadTwoRegisters(
6888 HInstruction* instruction,
6889 Location out,
6890 Location obj,
6891 uint32_t offset,
6892 Location maybe_temp,
6893 ReadBarrierOption read_barrier_option) {
6894 Register out_reg = out.AsRegister<Register>();
6895 Register obj_reg = obj.AsRegister<Register>();
6896 if (read_barrier_option == kWithReadBarrier) {
6897 CHECK(kEmitCompilerReadBarrier);
6898 if (kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006899 if (!kBakerReadBarrierThunksEnableForFields) {
6900 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6901 }
Alexey Frunze15958152017-02-09 19:08:30 -08006902 // Load with fast path based Baker's read barrier.
6903 // /* HeapReference<Object> */ out = *(obj + offset)
6904 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6905 out,
6906 obj_reg,
6907 offset,
6908 maybe_temp,
6909 /* needs_null_check */ false);
6910 } else {
6911 // Load with slow path based read barrier.
6912 // /* HeapReference<Object> */ out = *(obj + offset)
6913 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6914 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6915 }
6916 } else {
6917 // Plain load with no read barrier.
6918 // /* HeapReference<Object> */ out = *(obj + offset)
6919 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6920 __ MaybeUnpoisonHeapReference(out_reg);
6921 }
6922}
6923
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006924static inline int GetBakerMarkThunkNumber(Register reg) {
6925 static_assert(BAKER_MARK_INTROSPECTION_REGISTER_COUNT == 21, "Expecting equal");
6926 if (reg >= V0 && reg <= T7) { // 14 consequtive regs.
6927 return reg - V0;
6928 } else if (reg >= S2 && reg <= S7) { // 6 consequtive regs.
6929 return 14 + (reg - S2);
6930 } else if (reg == FP) { // One more.
6931 return 20;
6932 }
6933 LOG(FATAL) << "Unexpected register " << reg;
6934 UNREACHABLE();
6935}
6936
6937static inline int GetBakerMarkFieldArrayThunkDisplacement(Register reg, bool short_offset) {
6938 int num = GetBakerMarkThunkNumber(reg) +
6939 (short_offset ? BAKER_MARK_INTROSPECTION_REGISTER_COUNT : 0);
6940 return num * BAKER_MARK_INTROSPECTION_FIELD_ARRAY_ENTRY_SIZE;
6941}
6942
6943static inline int GetBakerMarkGcRootThunkDisplacement(Register reg) {
6944 return GetBakerMarkThunkNumber(reg) * BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRY_SIZE +
6945 BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRIES_OFFSET;
6946}
6947
Alexey Frunze15958152017-02-09 19:08:30 -08006948void InstructionCodeGeneratorMIPS::GenerateGcRootFieldLoad(HInstruction* instruction,
6949 Location root,
6950 Register obj,
6951 uint32_t offset,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006952 ReadBarrierOption read_barrier_option,
6953 MipsLabel* label_low) {
6954 bool reordering;
6955 if (label_low != nullptr) {
6956 DCHECK_EQ(offset, 0x5678u);
6957 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07006958 Register root_reg = root.AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08006959 if (read_barrier_option == kWithReadBarrier) {
6960 DCHECK(kEmitCompilerReadBarrier);
6961 if (kUseBakerReadBarrier) {
6962 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6963 // Baker's read barrier are used:
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006964 if (kBakerReadBarrierThunksEnableForGcRoots) {
6965 // Note that we do not actually check the value of `GetIsGcMarking()`
6966 // to decide whether to mark the loaded GC root or not. Instead, we
6967 // load into `temp` (T9) the read barrier mark introspection entrypoint.
6968 // If `temp` is null, it means that `GetIsGcMarking()` is false, and
6969 // vice versa.
6970 //
6971 // We use thunks for the slow path. That thunk checks the reference
6972 // and jumps to the entrypoint if needed.
6973 //
6974 // temp = Thread::Current()->pReadBarrierMarkReg00
6975 // // AKA &art_quick_read_barrier_mark_introspection.
6976 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
6977 // if (temp != nullptr) {
6978 // temp = &gc_root_thunk<root_reg>
6979 // root = temp(root)
6980 // }
Alexey Frunze15958152017-02-09 19:08:30 -08006981
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006982 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
6983 const int32_t entry_point_offset =
6984 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(0);
6985 const int thunk_disp = GetBakerMarkGcRootThunkDisplacement(root_reg);
6986 int16_t offset_low = Low16Bits(offset);
6987 int16_t offset_high = High16Bits(offset - offset_low); // Accounts for sign
6988 // extension in lw.
6989 bool short_offset = IsInt<16>(static_cast<int32_t>(offset));
6990 Register base = short_offset ? obj : TMP;
6991 // Loading the entrypoint does not require a load acquire since it is only changed when
6992 // threads are suspended or running a checkpoint.
6993 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
6994 reordering = __ SetReorder(false);
6995 if (!short_offset) {
6996 DCHECK(!label_low);
6997 __ AddUpper(base, obj, offset_high);
6998 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07006999 MipsLabel skip_call;
7000 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007001 if (label_low != nullptr) {
7002 DCHECK(short_offset);
7003 __ Bind(label_low);
7004 }
7005 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7006 __ LoadFromOffset(kLoadWord, root_reg, base, offset_low); // Single instruction
7007 // in delay slot.
7008 if (isR6) {
7009 __ Jialc(T9, thunk_disp);
7010 } else {
7011 __ Addiu(T9, T9, thunk_disp);
7012 __ Jalr(T9);
7013 __ Nop();
7014 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07007015 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007016 __ SetReorder(reordering);
7017 } else {
7018 // Note that we do not actually check the value of `GetIsGcMarking()`
7019 // to decide whether to mark the loaded GC root or not. Instead, we
7020 // load into `temp` (T9) the read barrier mark entry point corresponding
7021 // to register `root`. If `temp` is null, it means that `GetIsGcMarking()`
7022 // is false, and vice versa.
7023 //
7024 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
7025 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
7026 // if (temp != null) {
7027 // root = temp(root)
7028 // }
Alexey Frunze15958152017-02-09 19:08:30 -08007029
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007030 if (label_low != nullptr) {
7031 reordering = __ SetReorder(false);
7032 __ Bind(label_low);
7033 }
7034 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7035 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
7036 if (label_low != nullptr) {
7037 __ SetReorder(reordering);
7038 }
7039 static_assert(
7040 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
7041 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
7042 "have different sizes.");
7043 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
7044 "art::mirror::CompressedReference<mirror::Object> and int32_t "
7045 "have different sizes.");
Alexey Frunze15958152017-02-09 19:08:30 -08007046
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007047 // Slow path marking the GC root `root`.
7048 Location temp = Location::RegisterLocation(T9);
7049 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01007050 new (codegen_->GetScopedAllocator()) ReadBarrierMarkSlowPathMIPS(
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007051 instruction,
7052 root,
7053 /*entrypoint*/ temp);
7054 codegen_->AddSlowPath(slow_path);
7055
7056 const int32_t entry_point_offset =
7057 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(root.reg() - 1);
7058 // Loading the entrypoint does not require a load acquire since it is only changed when
7059 // threads are suspended or running a checkpoint.
7060 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
7061 __ Bnez(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
7062 __ Bind(slow_path->GetExitLabel());
7063 }
Alexey Frunze15958152017-02-09 19:08:30 -08007064 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007065 if (label_low != nullptr) {
7066 reordering = __ SetReorder(false);
7067 __ Bind(label_low);
7068 }
Alexey Frunze15958152017-02-09 19:08:30 -08007069 // GC root loaded through a slow path for read barriers other
7070 // than Baker's.
7071 // /* GcRoot<mirror::Object>* */ root = obj + offset
7072 __ Addiu32(root_reg, obj, offset);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007073 if (label_low != nullptr) {
7074 __ SetReorder(reordering);
7075 }
Alexey Frunze15958152017-02-09 19:08:30 -08007076 // /* mirror::Object* */ root = root->Read()
7077 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
7078 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007079 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007080 if (label_low != nullptr) {
7081 reordering = __ SetReorder(false);
7082 __ Bind(label_low);
7083 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007084 // Plain GC root load with no read barrier.
7085 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
7086 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
7087 // Note that GC roots are not affected by heap poisoning, thus we
7088 // do not have to unpoison `root_reg` here.
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007089 if (label_low != nullptr) {
7090 __ SetReorder(reordering);
7091 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007092 }
7093}
7094
Alexey Frunze15958152017-02-09 19:08:30 -08007095void CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
7096 Location ref,
7097 Register obj,
7098 uint32_t offset,
7099 Location temp,
7100 bool needs_null_check) {
7101 DCHECK(kEmitCompilerReadBarrier);
7102 DCHECK(kUseBakerReadBarrier);
7103
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007104 if (kBakerReadBarrierThunksEnableForFields) {
7105 // Note that we do not actually check the value of `GetIsGcMarking()`
7106 // to decide whether to mark the loaded reference or not. Instead, we
7107 // load into `temp` (T9) the read barrier mark introspection entrypoint.
7108 // If `temp` is null, it means that `GetIsGcMarking()` is false, and
7109 // vice versa.
7110 //
7111 // We use thunks for the slow path. That thunk checks the reference
7112 // and jumps to the entrypoint if needed. If the holder is not gray,
7113 // it issues a load-load memory barrier and returns to the original
7114 // reference load.
7115 //
7116 // temp = Thread::Current()->pReadBarrierMarkReg00
7117 // // AKA &art_quick_read_barrier_mark_introspection.
7118 // if (temp != nullptr) {
7119 // temp = &field_array_thunk<holder_reg>
7120 // temp()
7121 // }
7122 // not_gray_return_address:
7123 // // If the offset is too large to fit into the lw instruction, we
7124 // // use an adjusted base register (TMP) here. This register
7125 // // receives bits 16 ... 31 of the offset before the thunk invocation
7126 // // and the thunk benefits from it.
7127 // HeapReference<mirror::Object> reference = *(obj+offset); // Original reference load.
7128 // gray_return_address:
7129
7130 DCHECK(temp.IsInvalid());
7131 bool isR6 = GetInstructionSetFeatures().IsR6();
7132 int16_t offset_low = Low16Bits(offset);
7133 int16_t offset_high = High16Bits(offset - offset_low); // Accounts for sign extension in lw.
7134 bool short_offset = IsInt<16>(static_cast<int32_t>(offset));
7135 bool reordering = __ SetReorder(false);
7136 const int32_t entry_point_offset =
7137 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(0);
7138 // There may have or may have not been a null check if the field offset is smaller than
7139 // the page size.
7140 // There must've been a null check in case it's actually a load from an array.
7141 // We will, however, perform an explicit null check in the thunk as it's easier to
7142 // do it than not.
7143 if (instruction->IsArrayGet()) {
7144 DCHECK(!needs_null_check);
7145 }
7146 const int thunk_disp = GetBakerMarkFieldArrayThunkDisplacement(obj, short_offset);
7147 // Loading the entrypoint does not require a load acquire since it is only changed when
7148 // threads are suspended or running a checkpoint.
7149 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
7150 Register ref_reg = ref.AsRegister<Register>();
7151 Register base = short_offset ? obj : TMP;
Alexey Frunze0cab6562017-07-25 15:19:36 -07007152 MipsLabel skip_call;
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007153 if (short_offset) {
7154 if (isR6) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07007155 __ Beqzc(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007156 __ Nop(); // In forbidden slot.
7157 __ Jialc(T9, thunk_disp);
7158 } else {
Alexey Frunze0cab6562017-07-25 15:19:36 -07007159 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007160 __ Addiu(T9, T9, thunk_disp); // In delay slot.
7161 __ Jalr(T9);
7162 __ Nop(); // In delay slot.
7163 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07007164 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007165 } else {
7166 if (isR6) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07007167 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007168 __ Aui(base, obj, offset_high); // In delay slot.
7169 __ Jialc(T9, thunk_disp);
Alexey Frunze0cab6562017-07-25 15:19:36 -07007170 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007171 } else {
7172 __ Lui(base, offset_high);
Alexey Frunze0cab6562017-07-25 15:19:36 -07007173 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007174 __ Addiu(T9, T9, thunk_disp); // In delay slot.
7175 __ Jalr(T9);
Alexey Frunze0cab6562017-07-25 15:19:36 -07007176 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007177 __ Addu(base, base, obj); // In delay slot.
7178 }
7179 }
7180 // /* HeapReference<Object> */ ref = *(obj + offset)
7181 __ LoadFromOffset(kLoadWord, ref_reg, base, offset_low); // Single instruction.
7182 if (needs_null_check) {
7183 MaybeRecordImplicitNullCheck(instruction);
7184 }
7185 __ MaybeUnpoisonHeapReference(ref_reg);
7186 __ SetReorder(reordering);
7187 return;
7188 }
7189
Alexey Frunze15958152017-02-09 19:08:30 -08007190 // /* HeapReference<Object> */ ref = *(obj + offset)
7191 Location no_index = Location::NoLocation();
7192 ScaleFactor no_scale_factor = TIMES_1;
7193 GenerateReferenceLoadWithBakerReadBarrier(instruction,
7194 ref,
7195 obj,
7196 offset,
7197 no_index,
7198 no_scale_factor,
7199 temp,
7200 needs_null_check);
7201}
7202
7203void CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
7204 Location ref,
7205 Register obj,
7206 uint32_t data_offset,
7207 Location index,
7208 Location temp,
7209 bool needs_null_check) {
7210 DCHECK(kEmitCompilerReadBarrier);
7211 DCHECK(kUseBakerReadBarrier);
7212
7213 static_assert(
7214 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
7215 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007216 ScaleFactor scale_factor = TIMES_4;
7217
7218 if (kBakerReadBarrierThunksEnableForArrays) {
7219 // Note that we do not actually check the value of `GetIsGcMarking()`
7220 // to decide whether to mark the loaded reference or not. Instead, we
7221 // load into `temp` (T9) the read barrier mark introspection entrypoint.
7222 // If `temp` is null, it means that `GetIsGcMarking()` is false, and
7223 // vice versa.
7224 //
7225 // We use thunks for the slow path. That thunk checks the reference
7226 // and jumps to the entrypoint if needed. If the holder is not gray,
7227 // it issues a load-load memory barrier and returns to the original
7228 // reference load.
7229 //
7230 // temp = Thread::Current()->pReadBarrierMarkReg00
7231 // // AKA &art_quick_read_barrier_mark_introspection.
7232 // if (temp != nullptr) {
7233 // temp = &field_array_thunk<holder_reg>
7234 // temp()
7235 // }
7236 // not_gray_return_address:
7237 // // The element address is pre-calculated in the TMP register before the
7238 // // thunk invocation and the thunk benefits from it.
7239 // HeapReference<mirror::Object> reference = data[index]; // Original reference load.
7240 // gray_return_address:
7241
7242 DCHECK(temp.IsInvalid());
7243 DCHECK(index.IsValid());
7244 bool reordering = __ SetReorder(false);
7245 const int32_t entry_point_offset =
7246 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(0);
7247 // We will not do the explicit null check in the thunk as some form of a null check
7248 // must've been done earlier.
7249 DCHECK(!needs_null_check);
7250 const int thunk_disp = GetBakerMarkFieldArrayThunkDisplacement(obj, /* short_offset */ false);
7251 // Loading the entrypoint does not require a load acquire since it is only changed when
7252 // threads are suspended or running a checkpoint.
7253 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
7254 Register ref_reg = ref.AsRegister<Register>();
7255 Register index_reg = index.IsRegisterPair()
7256 ? index.AsRegisterPairLow<Register>()
7257 : index.AsRegister<Register>();
Alexey Frunze0cab6562017-07-25 15:19:36 -07007258 MipsLabel skip_call;
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007259 if (GetInstructionSetFeatures().IsR6()) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07007260 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007261 __ Lsa(TMP, index_reg, obj, scale_factor); // In delay slot.
7262 __ Jialc(T9, thunk_disp);
Alexey Frunze0cab6562017-07-25 15:19:36 -07007263 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007264 } else {
7265 __ Sll(TMP, index_reg, scale_factor);
Alexey Frunze0cab6562017-07-25 15:19:36 -07007266 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007267 __ Addiu(T9, T9, thunk_disp); // In delay slot.
7268 __ Jalr(T9);
Alexey Frunze0cab6562017-07-25 15:19:36 -07007269 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007270 __ Addu(TMP, TMP, obj); // In delay slot.
7271 }
7272 // /* HeapReference<Object> */ ref = *(obj + data_offset + (index << scale_factor))
7273 DCHECK(IsInt<16>(static_cast<int32_t>(data_offset))) << data_offset;
7274 __ LoadFromOffset(kLoadWord, ref_reg, TMP, data_offset); // Single instruction.
7275 __ MaybeUnpoisonHeapReference(ref_reg);
7276 __ SetReorder(reordering);
7277 return;
7278 }
7279
Alexey Frunze15958152017-02-09 19:08:30 -08007280 // /* HeapReference<Object> */ ref =
7281 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Alexey Frunze15958152017-02-09 19:08:30 -08007282 GenerateReferenceLoadWithBakerReadBarrier(instruction,
7283 ref,
7284 obj,
7285 data_offset,
7286 index,
7287 scale_factor,
7288 temp,
7289 needs_null_check);
7290}
7291
7292void CodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
7293 Location ref,
7294 Register obj,
7295 uint32_t offset,
7296 Location index,
7297 ScaleFactor scale_factor,
7298 Location temp,
7299 bool needs_null_check,
7300 bool always_update_field) {
7301 DCHECK(kEmitCompilerReadBarrier);
7302 DCHECK(kUseBakerReadBarrier);
7303
7304 // In slow path based read barriers, the read barrier call is
7305 // inserted after the original load. However, in fast path based
7306 // Baker's read barriers, we need to perform the load of
7307 // mirror::Object::monitor_ *before* the original reference load.
7308 // This load-load ordering is required by the read barrier.
7309 // The fast path/slow path (for Baker's algorithm) should look like:
7310 //
7311 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
7312 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
7313 // HeapReference<Object> ref = *src; // Original reference load.
7314 // bool is_gray = (rb_state == ReadBarrier::GrayState());
7315 // if (is_gray) {
7316 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
7317 // }
7318 //
7319 // Note: the original implementation in ReadBarrier::Barrier is
7320 // slightly more complex as it performs additional checks that we do
7321 // not do here for performance reasons.
7322
7323 Register ref_reg = ref.AsRegister<Register>();
7324 Register temp_reg = temp.AsRegister<Register>();
7325 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
7326
7327 // /* int32_t */ monitor = obj->monitor_
7328 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
7329 if (needs_null_check) {
7330 MaybeRecordImplicitNullCheck(instruction);
7331 }
7332 // /* LockWord */ lock_word = LockWord(monitor)
7333 static_assert(sizeof(LockWord) == sizeof(int32_t),
7334 "art::LockWord and int32_t have different sizes.");
7335
7336 __ Sync(0); // Barrier to prevent load-load reordering.
7337
7338 // The actual reference load.
7339 if (index.IsValid()) {
7340 // Load types involving an "index": ArrayGet,
7341 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7342 // intrinsics.
7343 // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
7344 if (index.IsConstant()) {
7345 size_t computed_offset =
7346 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
7347 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
7348 } else {
7349 // Handle the special case of the
7350 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7351 // intrinsics, which use a register pair as index ("long
7352 // offset"), of which only the low part contains data.
7353 Register index_reg = index.IsRegisterPair()
7354 ? index.AsRegisterPairLow<Register>()
7355 : index.AsRegister<Register>();
Chris Larsencd0295d2017-03-31 15:26:54 -07007356 __ ShiftAndAdd(TMP, index_reg, obj, scale_factor, TMP);
Alexey Frunze15958152017-02-09 19:08:30 -08007357 __ LoadFromOffset(kLoadWord, ref_reg, TMP, offset);
7358 }
7359 } else {
7360 // /* HeapReference<Object> */ ref = *(obj + offset)
7361 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
7362 }
7363
7364 // Object* ref = ref_addr->AsMirrorPtr()
7365 __ MaybeUnpoisonHeapReference(ref_reg);
7366
7367 // Slow path marking the object `ref` when it is gray.
7368 SlowPathCodeMIPS* slow_path;
7369 if (always_update_field) {
7370 // ReadBarrierMarkAndUpdateFieldSlowPathMIPS only supports address
7371 // of the form `obj + field_offset`, where `obj` is a register and
7372 // `field_offset` is a register pair (of which only the lower half
7373 // is used). Thus `offset` and `scale_factor` above are expected
7374 // to be null in this code path.
7375 DCHECK_EQ(offset, 0u);
7376 DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
Vladimir Marko174b2e22017-10-12 13:34:49 +01007377 slow_path = new (GetScopedAllocator())
Alexey Frunze15958152017-02-09 19:08:30 -08007378 ReadBarrierMarkAndUpdateFieldSlowPathMIPS(instruction,
7379 ref,
7380 obj,
7381 /* field_offset */ index,
7382 temp_reg);
7383 } else {
Vladimir Marko174b2e22017-10-12 13:34:49 +01007384 slow_path = new (GetScopedAllocator()) ReadBarrierMarkSlowPathMIPS(instruction, ref);
Alexey Frunze15958152017-02-09 19:08:30 -08007385 }
7386 AddSlowPath(slow_path);
7387
7388 // if (rb_state == ReadBarrier::GrayState())
7389 // ref = ReadBarrier::Mark(ref);
7390 // Given the numeric representation, it's enough to check the low bit of the
7391 // rb_state. We do that by shifting the bit into the sign bit (31) and
7392 // performing a branch on less than zero.
7393 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
7394 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
7395 static_assert(LockWord::kReadBarrierStateSize == 1, "Expecting 1-bit read barrier state size");
7396 __ Sll(temp_reg, temp_reg, 31 - LockWord::kReadBarrierStateShift);
7397 __ Bltz(temp_reg, slow_path->GetEntryLabel());
7398 __ Bind(slow_path->GetExitLabel());
7399}
7400
7401void CodeGeneratorMIPS::GenerateReadBarrierSlow(HInstruction* instruction,
7402 Location out,
7403 Location ref,
7404 Location obj,
7405 uint32_t offset,
7406 Location index) {
7407 DCHECK(kEmitCompilerReadBarrier);
7408
7409 // Insert a slow path based read barrier *after* the reference load.
7410 //
7411 // If heap poisoning is enabled, the unpoisoning of the loaded
7412 // reference will be carried out by the runtime within the slow
7413 // path.
7414 //
7415 // Note that `ref` currently does not get unpoisoned (when heap
7416 // poisoning is enabled), which is alright as the `ref` argument is
7417 // not used by the artReadBarrierSlow entry point.
7418 //
7419 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Vladimir Marko174b2e22017-10-12 13:34:49 +01007420 SlowPathCodeMIPS* slow_path = new (GetScopedAllocator())
Alexey Frunze15958152017-02-09 19:08:30 -08007421 ReadBarrierForHeapReferenceSlowPathMIPS(instruction, out, ref, obj, offset, index);
7422 AddSlowPath(slow_path);
7423
7424 __ B(slow_path->GetEntryLabel());
7425 __ Bind(slow_path->GetExitLabel());
7426}
7427
7428void CodeGeneratorMIPS::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
7429 Location out,
7430 Location ref,
7431 Location obj,
7432 uint32_t offset,
7433 Location index) {
7434 if (kEmitCompilerReadBarrier) {
7435 // Baker's read barriers shall be handled by the fast path
7436 // (CodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier).
7437 DCHECK(!kUseBakerReadBarrier);
7438 // If heap poisoning is enabled, unpoisoning will be taken care of
7439 // by the runtime within the slow path.
7440 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
7441 } else if (kPoisonHeapReferences) {
7442 __ UnpoisonHeapReference(out.AsRegister<Register>());
7443 }
7444}
7445
7446void CodeGeneratorMIPS::GenerateReadBarrierForRootSlow(HInstruction* instruction,
7447 Location out,
7448 Location root) {
7449 DCHECK(kEmitCompilerReadBarrier);
7450
7451 // Insert a slow path based read barrier *after* the GC root load.
7452 //
7453 // Note that GC roots are not affected by heap poisoning, so we do
7454 // not need to do anything special for this here.
7455 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01007456 new (GetScopedAllocator()) ReadBarrierForRootSlowPathMIPS(instruction, out, root);
Alexey Frunze15958152017-02-09 19:08:30 -08007457 AddSlowPath(slow_path);
7458
7459 __ B(slow_path->GetEntryLabel());
7460 __ Bind(slow_path->GetExitLabel());
7461}
7462
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007463void LocationsBuilderMIPS::VisitInstanceOf(HInstanceOf* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007464 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7465 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Alexey Frunzec61c0762017-04-10 13:54:23 -07007466 bool baker_read_barrier_slow_path = false;
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007467 switch (type_check_kind) {
7468 case TypeCheckKind::kExactCheck:
7469 case TypeCheckKind::kAbstractClassCheck:
7470 case TypeCheckKind::kClassHierarchyCheck:
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007471 case TypeCheckKind::kArrayObjectCheck: {
7472 bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
7473 call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
7474 baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007475 break;
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007476 }
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007477 case TypeCheckKind::kArrayCheck:
7478 case TypeCheckKind::kUnresolvedCheck:
7479 case TypeCheckKind::kInterfaceCheck:
7480 call_kind = LocationSummary::kCallOnSlowPath;
7481 break;
Vladimir Marko175e7862018-03-27 09:03:13 +00007482 case TypeCheckKind::kBitstringCheck:
7483 break;
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007484 }
7485
Vladimir Markoca6fff82017-10-03 14:49:14 +01007486 LocationSummary* locations =
7487 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Alexey Frunzec61c0762017-04-10 13:54:23 -07007488 if (baker_read_barrier_slow_path) {
7489 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
7490 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007491 locations->SetInAt(0, Location::RequiresRegister());
Vladimir Marko175e7862018-03-27 09:03:13 +00007492 if (type_check_kind == TypeCheckKind::kBitstringCheck) {
7493 locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
7494 locations->SetInAt(2, Location::ConstantLocation(instruction->InputAt(2)->AsConstant()));
7495 locations->SetInAt(3, Location::ConstantLocation(instruction->InputAt(3)->AsConstant()));
7496 } else {
7497 locations->SetInAt(1, Location::RequiresRegister());
7498 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007499 // The output does overlap inputs.
7500 // Note that TypeCheckSlowPathMIPS uses this register too.
7501 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Alexey Frunze15958152017-02-09 19:08:30 -08007502 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007503}
7504
7505void InstructionCodeGeneratorMIPS::VisitInstanceOf(HInstanceOf* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007506 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007507 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08007508 Location obj_loc = locations->InAt(0);
7509 Register obj = obj_loc.AsRegister<Register>();
Vladimir Marko175e7862018-03-27 09:03:13 +00007510 Location cls = locations->InAt(1);
Alexey Frunze15958152017-02-09 19:08:30 -08007511 Location out_loc = locations->Out();
7512 Register out = out_loc.AsRegister<Register>();
7513 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7514 DCHECK_LE(num_temps, 1u);
7515 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007516 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7517 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7518 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7519 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007520 MipsLabel done;
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007521 SlowPathCodeMIPS* slow_path = nullptr;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007522
7523 // Return 0 if `obj` is null.
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007524 // Avoid this check if we know `obj` is not null.
7525 if (instruction->MustDoNullCheck()) {
7526 __ Move(out, ZERO);
7527 __ Beqz(obj, &done);
7528 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007529
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007530 switch (type_check_kind) {
7531 case TypeCheckKind::kExactCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007532 ReadBarrierOption read_barrier_option =
7533 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007534 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007535 GenerateReferenceLoadTwoRegisters(instruction,
7536 out_loc,
7537 obj_loc,
7538 class_offset,
7539 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007540 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007541 // Classes must be equal for the instanceof to succeed.
Vladimir Marko175e7862018-03-27 09:03:13 +00007542 __ Xor(out, out, cls.AsRegister<Register>());
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007543 __ Sltiu(out, out, 1);
7544 break;
7545 }
7546
7547 case TypeCheckKind::kAbstractClassCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007548 ReadBarrierOption read_barrier_option =
7549 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007550 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007551 GenerateReferenceLoadTwoRegisters(instruction,
7552 out_loc,
7553 obj_loc,
7554 class_offset,
7555 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007556 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007557 // If the class is abstract, we eagerly fetch the super class of the
7558 // object to avoid doing a comparison we know will fail.
7559 MipsLabel loop;
7560 __ Bind(&loop);
7561 // /* HeapReference<Class> */ out = out->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08007562 GenerateReferenceLoadOneRegister(instruction,
7563 out_loc,
7564 super_offset,
7565 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007566 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007567 // If `out` is null, we use it for the result, and jump to `done`.
7568 __ Beqz(out, &done);
Vladimir Marko175e7862018-03-27 09:03:13 +00007569 __ Bne(out, cls.AsRegister<Register>(), &loop);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007570 __ LoadConst32(out, 1);
7571 break;
7572 }
7573
7574 case TypeCheckKind::kClassHierarchyCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007575 ReadBarrierOption read_barrier_option =
7576 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007577 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007578 GenerateReferenceLoadTwoRegisters(instruction,
7579 out_loc,
7580 obj_loc,
7581 class_offset,
7582 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007583 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007584 // Walk over the class hierarchy to find a match.
7585 MipsLabel loop, success;
7586 __ Bind(&loop);
Vladimir Marko175e7862018-03-27 09:03:13 +00007587 __ Beq(out, cls.AsRegister<Register>(), &success);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007588 // /* HeapReference<Class> */ out = out->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08007589 GenerateReferenceLoadOneRegister(instruction,
7590 out_loc,
7591 super_offset,
7592 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007593 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007594 __ Bnez(out, &loop);
7595 // If `out` is null, we use it for the result, and jump to `done`.
7596 __ B(&done);
7597 __ Bind(&success);
7598 __ LoadConst32(out, 1);
7599 break;
7600 }
7601
7602 case TypeCheckKind::kArrayObjectCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007603 ReadBarrierOption read_barrier_option =
7604 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007605 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007606 GenerateReferenceLoadTwoRegisters(instruction,
7607 out_loc,
7608 obj_loc,
7609 class_offset,
7610 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007611 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007612 // Do an exact check.
7613 MipsLabel success;
Vladimir Marko175e7862018-03-27 09:03:13 +00007614 __ Beq(out, cls.AsRegister<Register>(), &success);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007615 // Otherwise, we need to check that the object's class is a non-primitive array.
7616 // /* HeapReference<Class> */ out = out->component_type_
Alexey Frunze15958152017-02-09 19:08:30 -08007617 GenerateReferenceLoadOneRegister(instruction,
7618 out_loc,
7619 component_offset,
7620 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007621 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007622 // If `out` is null, we use it for the result, and jump to `done`.
7623 __ Beqz(out, &done);
7624 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
7625 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
7626 __ Sltiu(out, out, 1);
7627 __ B(&done);
7628 __ Bind(&success);
7629 __ LoadConst32(out, 1);
7630 break;
7631 }
7632
7633 case TypeCheckKind::kArrayCheck: {
7634 // No read barrier since the slow path will retry upon failure.
7635 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007636 GenerateReferenceLoadTwoRegisters(instruction,
7637 out_loc,
7638 obj_loc,
7639 class_offset,
7640 maybe_temp_loc,
7641 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007642 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01007643 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathMIPS(
7644 instruction, /* is_fatal */ false);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007645 codegen_->AddSlowPath(slow_path);
Vladimir Marko175e7862018-03-27 09:03:13 +00007646 __ Bne(out, cls.AsRegister<Register>(), slow_path->GetEntryLabel());
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007647 __ LoadConst32(out, 1);
7648 break;
7649 }
7650
7651 case TypeCheckKind::kUnresolvedCheck:
7652 case TypeCheckKind::kInterfaceCheck: {
7653 // Note that we indeed only call on slow path, but we always go
7654 // into the slow path for the unresolved and interface check
7655 // cases.
7656 //
7657 // We cannot directly call the InstanceofNonTrivial runtime
7658 // entry point without resorting to a type checking slow path
7659 // here (i.e. by calling InvokeRuntime directly), as it would
7660 // require to assign fixed registers for the inputs of this
7661 // HInstanceOf instruction (following the runtime calling
7662 // convention), which might be cluttered by the potential first
7663 // read barrier emission at the beginning of this method.
7664 //
7665 // TODO: Introduce a new runtime entry point taking the object
7666 // to test (instead of its class) as argument, and let it deal
7667 // with the read barrier issues. This will let us refactor this
7668 // case of the `switch` code as it was previously (with a direct
7669 // call to the runtime not using a type checking slow path).
7670 // This should also be beneficial for the other cases above.
7671 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01007672 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathMIPS(
7673 instruction, /* is_fatal */ false);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007674 codegen_->AddSlowPath(slow_path);
7675 __ B(slow_path->GetEntryLabel());
7676 break;
7677 }
Vladimir Marko175e7862018-03-27 09:03:13 +00007678
7679 case TypeCheckKind::kBitstringCheck: {
7680 // /* HeapReference<Class> */ temp = obj->klass_
7681 GenerateReferenceLoadTwoRegisters(instruction,
7682 out_loc,
7683 obj_loc,
7684 class_offset,
7685 maybe_temp_loc,
7686 kWithoutReadBarrier);
7687
7688 GenerateBitstringTypeCheckCompare(instruction, out);
7689 __ Sltiu(out, out, 1);
7690 break;
7691 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007692 }
7693
7694 __ Bind(&done);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007695
7696 if (slow_path != nullptr) {
7697 __ Bind(slow_path->GetExitLabel());
7698 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007699}
7700
7701void LocationsBuilderMIPS::VisitIntConstant(HIntConstant* constant) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007702 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007703 locations->SetOut(Location::ConstantLocation(constant));
7704}
7705
7706void InstructionCodeGeneratorMIPS::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
7707 // Will be generated at use site.
7708}
7709
7710void LocationsBuilderMIPS::VisitNullConstant(HNullConstant* constant) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007711 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007712 locations->SetOut(Location::ConstantLocation(constant));
7713}
7714
7715void InstructionCodeGeneratorMIPS::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
7716 // Will be generated at use site.
7717}
7718
7719void LocationsBuilderMIPS::HandleInvoke(HInvoke* invoke) {
7720 InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
7721 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
7722}
7723
7724void LocationsBuilderMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
7725 HandleInvoke(invoke);
Alexey Frunze1b8464d2016-11-12 17:22:05 -08007726 // The register T7 is required to be used for the hidden argument in
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007727 // art_quick_imt_conflict_trampoline, so add the hidden argument.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08007728 invoke->GetLocations()->AddTemp(Location::RegisterLocation(T7));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007729}
7730
7731void InstructionCodeGeneratorMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
7732 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
7733 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007734 Location receiver = invoke->GetLocations()->InAt(0);
7735 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07007736 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007737
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007738 // temp = object->GetClass();
7739 if (receiver.IsStackSlot()) {
7740 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
7741 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
7742 } else {
7743 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
7744 }
7745 codegen_->MaybeRecordImplicitNullCheck(invoke);
Alexey Frunzec061de12017-02-14 13:27:23 -08007746 // Instead of simply (possibly) unpoisoning `temp` here, we should
7747 // emit a read barrier for the previous class reference load.
7748 // However this is not required in practice, as this is an
7749 // intermediate/temporary reference and because the current
7750 // concurrent copying collector keeps the from-space memory
7751 // intact/accessible until the end of the marking phase (the
7752 // concurrent copying collector may not in the future).
7753 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00007754 __ LoadFromOffset(kLoadWord, temp, temp,
7755 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
7756 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00007757 invoke->GetImtIndex(), kMipsPointerSize));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007758 // temp = temp->GetImtEntryAt(method_offset);
7759 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
7760 // T9 = temp->GetEntryPoint();
7761 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
Lena Djokic3177e102018-02-28 11:32:40 +01007762 // Set the hidden argument.
7763 __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
7764 invoke->GetDexMethodIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007765 // T9();
7766 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07007767 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007768 DCHECK(!codegen_->IsLeafMethod());
7769 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
7770}
7771
7772void LocationsBuilderMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Chris Larsen701566a2015-10-27 15:29:13 -07007773 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
7774 if (intrinsic.TryDispatch(invoke)) {
7775 return;
7776 }
7777
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007778 HandleInvoke(invoke);
7779}
7780
7781void LocationsBuilderMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00007782 // Explicit clinit checks triggered by static invokes must have been pruned by
7783 // art::PrepareForRegisterAllocation.
7784 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007785
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007786 bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007787 bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
7788 bool has_extra_input = invoke->HasPcRelativeMethodLoadKind() && !is_r6 && !has_irreducible_loops;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007789
Chris Larsen701566a2015-10-27 15:29:13 -07007790 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
7791 if (intrinsic.TryDispatch(invoke)) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007792 if (invoke->GetLocations()->CanCall() && has_extra_input) {
7793 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
7794 }
Chris Larsen701566a2015-10-27 15:29:13 -07007795 return;
7796 }
7797
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007798 HandleInvoke(invoke);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007799
7800 // Add the extra input register if either the dex cache array base register
7801 // or the PC-relative base register for accessing literals is needed.
7802 if (has_extra_input) {
7803 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
7804 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007805}
7806
Orion Hodsonac141392017-01-13 11:53:47 +00007807void LocationsBuilderMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
7808 HandleInvoke(invoke);
7809}
7810
7811void InstructionCodeGeneratorMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
7812 codegen_->GenerateInvokePolymorphicCall(invoke);
7813}
7814
Orion Hodson4c8e12e2018-05-18 08:33:20 +01007815void LocationsBuilderMIPS::VisitInvokeCustom(HInvokeCustom* invoke) {
7816 HandleInvoke(invoke);
7817}
7818
7819void InstructionCodeGeneratorMIPS::VisitInvokeCustom(HInvokeCustom* invoke) {
7820 codegen_->GenerateInvokeCustomCall(invoke);
7821}
7822
Chris Larsen701566a2015-10-27 15:29:13 -07007823static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007824 if (invoke->GetLocations()->Intrinsified()) {
Chris Larsen701566a2015-10-27 15:29:13 -07007825 IntrinsicCodeGeneratorMIPS intrinsic(codegen);
7826 intrinsic.Dispatch(invoke);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007827 return true;
7828 }
7829 return false;
7830}
7831
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007832HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
Alexey Frunze06a46c42016-07-19 15:00:40 -07007833 HLoadString::LoadKind desired_string_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007834 switch (desired_string_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007835 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007836 case HLoadString::LoadKind::kBootImageRelRo:
Vladimir Markoaad75c62016-10-03 08:46:48 +00007837 case HLoadString::LoadKind::kBssEntry:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007838 DCHECK(!Runtime::Current()->UseJitCompilation());
Alexey Frunze06a46c42016-07-19 15:00:40 -07007839 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007840 case HLoadString::LoadKind::kJitTableAddress:
7841 DCHECK(Runtime::Current()->UseJitCompilation());
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007842 break;
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007843 case HLoadString::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007844 case HLoadString::LoadKind::kRuntimeCall:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007845 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07007846 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007847 return desired_string_load_kind;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007848}
7849
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007850HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind(
7851 HLoadClass::LoadKind desired_class_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007852 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007853 case HLoadClass::LoadKind::kInvalid:
7854 LOG(FATAL) << "UNREACHABLE";
7855 UNREACHABLE();
Alexey Frunze06a46c42016-07-19 15:00:40 -07007856 case HLoadClass::LoadKind::kReferrersClass:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007857 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07007858 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007859 case HLoadClass::LoadKind::kBootImageRelRo:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007860 case HLoadClass::LoadKind::kBssEntry:
7861 DCHECK(!Runtime::Current()->UseJitCompilation());
7862 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007863 case HLoadClass::LoadKind::kJitTableAddress:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007864 DCHECK(Runtime::Current()->UseJitCompilation());
Alexey Frunze06a46c42016-07-19 15:00:40 -07007865 break;
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007866 case HLoadClass::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007867 case HLoadClass::LoadKind::kRuntimeCall:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007868 break;
7869 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007870 return desired_class_load_kind;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007871}
7872
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007873Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
7874 Register temp) {
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007875 CHECK(!GetInstructionSetFeatures().IsR6());
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007876 CHECK(!GetGraph()->HasIrreducibleLoops());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007877 CHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
7878 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
7879 if (!invoke->GetLocations()->Intrinsified()) {
7880 return location.AsRegister<Register>();
7881 }
7882 // For intrinsics we allow any location, so it may be on the stack.
7883 if (!location.IsRegister()) {
7884 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
7885 return temp;
7886 }
7887 // For register locations, check if the register was saved. If so, get it from the stack.
7888 // Note: There is a chance that the register was saved but not overwritten, so we could
7889 // save one load. However, since this is just an intrinsic slow path we prefer this
7890 // simple and more robust approach rather that trying to determine if that's the case.
7891 SlowPathCode* slow_path = GetCurrentSlowPath();
7892 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
7893 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
7894 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
7895 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
7896 return temp;
7897 }
7898 return location.AsRegister<Register>();
7899}
7900
Vladimir Markodc151b22015-10-15 18:02:30 +01007901HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
7902 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +01007903 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007904 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01007905}
7906
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007907void CodeGeneratorMIPS::GenerateStaticOrDirectCall(
7908 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007909 // All registers are assumed to be correctly set up per the calling convention.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007910 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007911 HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
7912 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007913 bool is_r6 = GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007914 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
7915 Register base_reg = (invoke->HasPcRelativeMethodLoadKind() && !is_r6 && !has_irreducible_loops)
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007916 ? GetInvokeStaticOrDirectExtraParameter(invoke, temp.AsRegister<Register>())
7917 : ZERO;
7918
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007919 switch (method_load_kind) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007920 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007921 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007922 uint32_t offset =
7923 GetThreadOffset<kMipsPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007924 __ LoadFromOffset(kLoadWord,
7925 temp.AsRegister<Register>(),
7926 TR,
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007927 offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007928 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007929 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007930 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00007931 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007932 break;
Vladimir Marko65979462017-05-19 17:25:12 +01007933 case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
7934 DCHECK(GetCompilerOptions().IsBootImage());
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007935 PcRelativePatchInfo* info_high = NewBootImageMethodPatch(invoke->GetTargetMethod());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007936 PcRelativePatchInfo* info_low =
Vladimir Marko59eb30f2018-02-20 11:52:34 +00007937 NewBootImageMethodPatch(invoke->GetTargetMethod(), info_high);
Vladimir Marko65979462017-05-19 17:25:12 +01007938 Register temp_reg = temp.AsRegister<Register>();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07007939 EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg);
7940 __ Addiu(temp_reg, TMP, /* placeholder */ 0x5678, &info_low->label);
Vladimir Marko65979462017-05-19 17:25:12 +01007941 break;
7942 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007943 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
7944 __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
7945 break;
Vladimir Markob066d432018-01-03 13:14:37 +00007946 case HInvokeStaticOrDirect::MethodLoadKind::kBootImageRelRo: {
Vladimir Markoe47f60c2018-02-21 13:43:28 +00007947 uint32_t boot_image_offset = GetBootImageOffset(invoke);
Vladimir Markob066d432018-01-03 13:14:37 +00007948 PcRelativePatchInfo* info_high = NewBootImageRelRoPatch(boot_image_offset);
7949 PcRelativePatchInfo* info_low = NewBootImageRelRoPatch(boot_image_offset, info_high);
7950 Register temp_reg = temp.AsRegister<Register>();
7951 EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg);
7952 __ Lw(temp_reg, TMP, /* placeholder */ 0x5678, &info_low->label);
7953 break;
7954 }
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007955 case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007956 PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007957 MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007958 PcRelativePatchInfo* info_low = NewMethodBssEntryPatch(
7959 MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()), info_high);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007960 Register temp_reg = temp.AsRegister<Register>();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07007961 EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg);
7962 __ Lw(temp_reg, TMP, /* placeholder */ 0x5678, &info_low->label);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007963 break;
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007964 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007965 case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
7966 GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
7967 return; // No code pointer retrieval; the runtime performs the call directly.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007968 }
7969 }
7970
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007971 switch (code_ptr_location) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007972 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007973 __ Bal(&frame_entry_label_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007974 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007975 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
7976 // T9 = callee_method->entry_point_from_quick_compiled_code_;
Goran Jakovljevic1a878372015-10-26 14:28:52 +01007977 __ LoadFromOffset(kLoadWord,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007978 T9,
7979 callee_method.AsRegister<Register>(),
7980 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07007981 kMipsPointerSize).Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007982 // T9()
7983 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07007984 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007985 break;
7986 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007987 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
7988
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007989 DCHECK(!IsLeafMethod());
7990}
7991
7992void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00007993 // Explicit clinit checks triggered by static invokes must have been pruned by
7994 // art::PrepareForRegisterAllocation.
7995 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007996
7997 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
7998 return;
7999 }
8000
8001 LocationSummary* locations = invoke->GetLocations();
8002 codegen_->GenerateStaticOrDirectCall(invoke,
8003 locations->HasTemps()
8004 ? locations->GetTemp(0)
8005 : Location::NoLocation());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008006}
8007
Vladimir Markoe7197bf2017-06-02 17:00:23 +01008008void CodeGeneratorMIPS::GenerateVirtualCall(
8009 HInvokeVirtual* invoke, Location temp_location, SlowPathCode* slow_path) {
Goran Jakovljevice919b072016-10-04 10:17:34 +02008010 // Use the calling convention instead of the location of the receiver, as
8011 // intrinsics may have put the receiver in a different register. In the intrinsics
8012 // slow path, the arguments have been moved to the right place, so here we are
8013 // guaranteed that the receiver is the first register of the calling convention.
8014 InvokeDexCallingConvention calling_convention;
8015 Register receiver = calling_convention.GetRegisterAt(0);
8016
Chris Larsen3acee732015-11-18 13:31:08 -08008017 Register temp = temp_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008018 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
8019 invoke->GetVTableIndex(), kMipsPointerSize).SizeValue();
8020 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07008021 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008022
8023 // temp = object->GetClass();
Goran Jakovljevice919b072016-10-04 10:17:34 +02008024 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Chris Larsen3acee732015-11-18 13:31:08 -08008025 MaybeRecordImplicitNullCheck(invoke);
Alexey Frunzec061de12017-02-14 13:27:23 -08008026 // Instead of simply (possibly) unpoisoning `temp` here, we should
8027 // emit a read barrier for the previous class reference load.
8028 // However this is not required in practice, as this is an
8029 // intermediate/temporary reference and because the current
8030 // concurrent copying collector keeps the from-space memory
8031 // intact/accessible until the end of the marking phase (the
8032 // concurrent copying collector may not in the future).
8033 __ MaybeUnpoisonHeapReference(temp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008034 // temp = temp->GetMethodAt(method_offset);
8035 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
8036 // T9 = temp->GetEntryPoint();
8037 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
8038 // T9();
8039 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07008040 __ NopIfNoReordering();
Vladimir Markoe7197bf2017-06-02 17:00:23 +01008041 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Chris Larsen3acee732015-11-18 13:31:08 -08008042}
8043
8044void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
8045 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
8046 return;
8047 }
8048
8049 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008050 DCHECK(!codegen_->IsLeafMethod());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008051}
8052
8053void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00008054 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008055 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07008056 InvokeRuntimeCallingConvention calling_convention;
Alexey Frunzec61c0762017-04-10 13:54:23 -07008057 Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
8058 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(cls, loc, loc);
Alexey Frunze06a46c42016-07-19 15:00:40 -07008059 return;
8060 }
Vladimir Marko41559982017-01-06 14:04:23 +00008061 DCHECK(!cls->NeedsAccessCheck());
Alexey Frunzec61c0762017-04-10 13:54:23 -07008062 const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008063 const bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
Alexey Frunze15958152017-02-09 19:08:30 -08008064 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
8065 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Alexey Frunze06a46c42016-07-19 15:00:40 -07008066 ? LocationSummary::kCallOnSlowPath
8067 : LocationSummary::kNoCall;
Vladimir Markoca6fff82017-10-03 14:49:14 +01008068 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(cls, call_kind);
Alexey Frunzec61c0762017-04-10 13:54:23 -07008069 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
8070 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
8071 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07008072 switch (load_kind) {
8073 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07008074 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008075 case HLoadClass::LoadKind::kBootImageAddress:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008076 case HLoadClass::LoadKind::kBootImageRelRo:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008077 case HLoadClass::LoadKind::kBssEntry:
Alexey Frunzec61c0762017-04-10 13:54:23 -07008078 if (isR6) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07008079 break;
8080 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008081 if (has_irreducible_loops) {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07008082 if (load_kind != HLoadClass::LoadKind::kBootImageAddress) {
8083 codegen_->ClobberRA();
8084 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008085 break;
8086 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07008087 FALLTHROUGH_INTENDED;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008088 case HLoadClass::LoadKind::kReferrersClass:
Alexey Frunze06a46c42016-07-19 15:00:40 -07008089 locations->SetInAt(0, Location::RequiresRegister());
8090 break;
8091 default:
8092 break;
8093 }
8094 locations->SetOut(Location::RequiresRegister());
Alexey Frunzec61c0762017-04-10 13:54:23 -07008095 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
8096 if (!kUseReadBarrier || kUseBakerReadBarrier) {
8097 // Rely on the type resolution or initialization and marking to save everything we need.
Alexey Frunzec61c0762017-04-10 13:54:23 -07008098 RegisterSet caller_saves = RegisterSet::Empty();
8099 InvokeRuntimeCallingConvention calling_convention;
8100 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8101 locations->SetCustomSlowPathCallerSaves(caller_saves);
8102 } else {
8103 // For non-Baker read barriers we have a temp-clobbering call.
8104 }
8105 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008106}
8107
Nicolas Geoffray5247c082017-01-13 14:17:29 +00008108// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
8109// move.
8110void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00008111 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008112 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Marko41559982017-01-06 14:04:23 +00008113 codegen_->GenerateLoadClassRuntimeCall(cls);
Pavle Batutae87a7182015-10-28 13:10:42 +01008114 return;
8115 }
Vladimir Marko41559982017-01-06 14:04:23 +00008116 DCHECK(!cls->NeedsAccessCheck());
Pavle Batutae87a7182015-10-28 13:10:42 +01008117
Vladimir Marko41559982017-01-06 14:04:23 +00008118 LocationSummary* locations = cls->GetLocations();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008119 Location out_loc = locations->Out();
8120 Register out = out_loc.AsRegister<Register>();
8121 Register base_or_current_method_reg;
8122 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008123 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008124 switch (load_kind) {
8125 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07008126 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008127 case HLoadClass::LoadKind::kBootImageAddress:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008128 case HLoadClass::LoadKind::kBootImageRelRo:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008129 case HLoadClass::LoadKind::kBssEntry:
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008130 base_or_current_method_reg =
8131 (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008132 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008133 case HLoadClass::LoadKind::kReferrersClass:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008134 case HLoadClass::LoadKind::kRuntimeCall:
Alexey Frunze06a46c42016-07-19 15:00:40 -07008135 base_or_current_method_reg = locations->InAt(0).AsRegister<Register>();
8136 break;
8137 default:
8138 base_or_current_method_reg = ZERO;
8139 break;
8140 }
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00008141
Alexey Frunze15958152017-02-09 19:08:30 -08008142 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
8143 ? kWithoutReadBarrier
8144 : kCompilerReadBarrierOption;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008145 bool generate_null_check = false;
8146 switch (load_kind) {
8147 case HLoadClass::LoadKind::kReferrersClass: {
8148 DCHECK(!cls->CanCallRuntime());
8149 DCHECK(!cls->MustGenerateClinitCheck());
8150 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
8151 GenerateGcRootFieldLoad(cls,
8152 out_loc,
8153 base_or_current_method_reg,
Alexey Frunze15958152017-02-09 19:08:30 -08008154 ArtMethod::DeclaringClassOffset().Int32Value(),
8155 read_barrier_option);
Alexey Frunze06a46c42016-07-19 15:00:40 -07008156 break;
8157 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07008158 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008159 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze15958152017-02-09 19:08:30 -08008160 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008161 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
Vladimir Marko59eb30f2018-02-20 11:52:34 +00008162 codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008163 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
Vladimir Marko59eb30f2018-02-20 11:52:34 +00008164 codegen_->NewBootImageTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008165 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
8166 out,
Alexey Frunzea663d9d2017-07-31 18:43:18 -07008167 base_or_current_method_reg);
8168 __ Addiu(out, out, /* placeholder */ 0x5678, &info_low->label);
Alexey Frunze06a46c42016-07-19 15:00:40 -07008169 break;
8170 }
8171 case HLoadClass::LoadKind::kBootImageAddress: {
Alexey Frunze15958152017-02-09 19:08:30 -08008172 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00008173 uint32_t address = dchecked_integral_cast<uint32_t>(
8174 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
8175 DCHECK_NE(address, 0u);
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008176 if (isR6 || !has_irreducible_loops) {
8177 __ LoadLiteral(out,
8178 base_or_current_method_reg,
8179 codegen_->DeduplicateBootImageAddressLiteral(address));
8180 } else {
8181 __ LoadConst32(out, address);
8182 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07008183 break;
8184 }
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008185 case HLoadClass::LoadKind::kBootImageRelRo: {
Vladimir Marko94ec2db2017-09-06 17:21:03 +01008186 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008187 uint32_t boot_image_offset = codegen_->GetBootImageOffset(cls);
Vladimir Marko94ec2db2017-09-06 17:21:03 +01008188 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008189 codegen_->NewBootImageRelRoPatch(boot_image_offset);
Vladimir Marko94ec2db2017-09-06 17:21:03 +01008190 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008191 codegen_->NewBootImageRelRoPatch(boot_image_offset, info_high);
Vladimir Marko94ec2db2017-09-06 17:21:03 +01008192 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
8193 out,
8194 base_or_current_method_reg);
8195 __ Lw(out, out, /* placeholder */ 0x5678, &info_low->label);
Vladimir Marko94ec2db2017-09-06 17:21:03 +01008196 break;
8197 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008198 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Markof3c52b42017-11-17 17:32:12 +00008199 CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high =
8200 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008201 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
8202 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex(), bss_info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008203 codegen_->EmitPcRelativeAddressPlaceholderHigh(bss_info_high,
Vladimir Markof3c52b42017-11-17 17:32:12 +00008204 out,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008205 base_or_current_method_reg);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008206 GenerateGcRootFieldLoad(cls,
8207 out_loc,
Vladimir Markof3c52b42017-11-17 17:32:12 +00008208 out,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008209 /* placeholder */ 0x5678,
8210 read_barrier_option,
8211 &info_low->label);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008212 generate_null_check = true;
8213 break;
8214 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00008215 case HLoadClass::LoadKind::kJitTableAddress: {
Alexey Frunze627c1a02017-01-30 19:28:14 -08008216 CodeGeneratorMIPS::JitPatchInfo* info = codegen_->NewJitRootClassPatch(cls->GetDexFile(),
8217 cls->GetTypeIndex(),
8218 cls->GetClass());
8219 bool reordering = __ SetReorder(false);
8220 __ Bind(&info->high_label);
8221 __ Lui(out, /* placeholder */ 0x1234);
Alexey Frunze627c1a02017-01-30 19:28:14 -08008222 __ SetReorder(reordering);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008223 GenerateGcRootFieldLoad(cls,
8224 out_loc,
8225 out,
8226 /* placeholder */ 0x5678,
8227 read_barrier_option,
8228 &info->low_label);
Alexey Frunze06a46c42016-07-19 15:00:40 -07008229 break;
8230 }
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008231 case HLoadClass::LoadKind::kRuntimeCall:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00008232 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00008233 LOG(FATAL) << "UNREACHABLE";
8234 UNREACHABLE();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008235 }
8236
8237 if (generate_null_check || cls->MustGenerateClinitCheck()) {
8238 DCHECK(cls->CanCallRuntime());
Vladimir Marko174b2e22017-10-12 13:34:49 +01008239 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathMIPS(
Vladimir Markof3c52b42017-11-17 17:32:12 +00008240 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
Alexey Frunze06a46c42016-07-19 15:00:40 -07008241 codegen_->AddSlowPath(slow_path);
8242 if (generate_null_check) {
8243 __ Beqz(out, slow_path->GetEntryLabel());
8244 }
8245 if (cls->MustGenerateClinitCheck()) {
8246 GenerateClassInitializationCheck(slow_path, out);
8247 } else {
8248 __ Bind(slow_path->GetExitLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008249 }
8250 }
8251}
8252
Orion Hodsondbaa5c72018-05-10 08:22:46 +01008253void LocationsBuilderMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
8254 InvokeRuntimeCallingConvention calling_convention;
8255 Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
8256 CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc);
8257}
8258
8259void InstructionCodeGeneratorMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
8260 codegen_->GenerateLoadMethodHandleRuntimeCall(load);
8261}
8262
Orion Hodson18259d72018-04-12 11:18:23 +01008263void LocationsBuilderMIPS::VisitLoadMethodType(HLoadMethodType* load) {
8264 InvokeRuntimeCallingConvention calling_convention;
8265 Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
8266 CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc);
8267}
8268
8269void InstructionCodeGeneratorMIPS::VisitLoadMethodType(HLoadMethodType* load) {
8270 codegen_->GenerateLoadMethodTypeRuntimeCall(load);
8271}
8272
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008273static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07008274 return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008275}
8276
8277void LocationsBuilderMIPS::VisitLoadException(HLoadException* load) {
8278 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008279 new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008280 locations->SetOut(Location::RequiresRegister());
8281}
8282
8283void InstructionCodeGeneratorMIPS::VisitLoadException(HLoadException* load) {
8284 Register out = load->GetLocations()->Out().AsRegister<Register>();
8285 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
8286}
8287
8288void LocationsBuilderMIPS::VisitClearException(HClearException* clear) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008289 new (GetGraph()->GetAllocator()) LocationSummary(clear, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008290}
8291
8292void InstructionCodeGeneratorMIPS::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
8293 __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
8294}
8295
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008296void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
Alexey Frunzef63f5692016-12-13 17:43:11 -08008297 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Vladimir Markoca6fff82017-10-03 14:49:14 +01008298 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(load, call_kind);
Alexey Frunze06a46c42016-07-19 15:00:40 -07008299 HLoadString::LoadKind load_kind = load->GetLoadKind();
Alexey Frunzec61c0762017-04-10 13:54:23 -07008300 const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008301 const bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008302 switch (load_kind) {
8303 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07008304 case HLoadString::LoadKind::kBootImageAddress:
8305 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008306 case HLoadString::LoadKind::kBootImageRelRo:
Vladimir Markoaad75c62016-10-03 08:46:48 +00008307 case HLoadString::LoadKind::kBssEntry:
Alexey Frunzec61c0762017-04-10 13:54:23 -07008308 if (isR6) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07008309 break;
8310 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008311 if (has_irreducible_loops) {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07008312 if (load_kind != HLoadString::LoadKind::kBootImageAddress) {
8313 codegen_->ClobberRA();
8314 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008315 break;
8316 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07008317 FALLTHROUGH_INTENDED;
8318 // We need an extra register for PC-relative dex cache accesses.
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008319 case HLoadString::LoadKind::kRuntimeCall:
Alexey Frunze06a46c42016-07-19 15:00:40 -07008320 locations->SetInAt(0, Location::RequiresRegister());
8321 break;
8322 default:
8323 break;
8324 }
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008325 if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
Alexey Frunzebb51df82016-11-01 16:07:32 -07008326 InvokeRuntimeCallingConvention calling_convention;
Alexey Frunzec61c0762017-04-10 13:54:23 -07008327 locations->SetOut(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Alexey Frunzebb51df82016-11-01 16:07:32 -07008328 } else {
8329 locations->SetOut(Location::RequiresRegister());
Alexey Frunzec61c0762017-04-10 13:54:23 -07008330 if (load_kind == HLoadString::LoadKind::kBssEntry) {
8331 if (!kUseReadBarrier || kUseBakerReadBarrier) {
8332 // Rely on the pResolveString and marking to save everything we need.
Alexey Frunzec61c0762017-04-10 13:54:23 -07008333 RegisterSet caller_saves = RegisterSet::Empty();
8334 InvokeRuntimeCallingConvention calling_convention;
8335 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8336 locations->SetCustomSlowPathCallerSaves(caller_saves);
8337 } else {
8338 // For non-Baker read barriers we have a temp-clobbering call.
8339 }
8340 }
Alexey Frunzebb51df82016-11-01 16:07:32 -07008341 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008342}
8343
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00008344// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
8345// move.
8346void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Alexey Frunze06a46c42016-07-19 15:00:40 -07008347 HLoadString::LoadKind load_kind = load->GetLoadKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008348 LocationSummary* locations = load->GetLocations();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008349 Location out_loc = locations->Out();
8350 Register out = out_loc.AsRegister<Register>();
8351 Register base_or_current_method_reg;
8352 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008353 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008354 switch (load_kind) {
8355 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07008356 case HLoadString::LoadKind::kBootImageAddress:
8357 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008358 case HLoadString::LoadKind::kBootImageRelRo:
Vladimir Markoaad75c62016-10-03 08:46:48 +00008359 case HLoadString::LoadKind::kBssEntry:
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008360 base_or_current_method_reg =
8361 (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008362 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008363 default:
8364 base_or_current_method_reg = ZERO;
8365 break;
8366 }
8367
8368 switch (load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07008369 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00008370 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008371 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
Vladimir Marko59eb30f2018-02-20 11:52:34 +00008372 codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008373 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
Vladimir Marko59eb30f2018-02-20 11:52:34 +00008374 codegen_->NewBootImageStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008375 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
8376 out,
Alexey Frunzea663d9d2017-07-31 18:43:18 -07008377 base_or_current_method_reg);
8378 __ Addiu(out, out, /* placeholder */ 0x5678, &info_low->label);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008379 return;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008380 }
8381 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00008382 uint32_t address = dchecked_integral_cast<uint32_t>(
8383 reinterpret_cast<uintptr_t>(load->GetString().Get()));
8384 DCHECK_NE(address, 0u);
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008385 if (isR6 || !has_irreducible_loops) {
8386 __ LoadLiteral(out,
8387 base_or_current_method_reg,
8388 codegen_->DeduplicateBootImageAddressLiteral(address));
8389 } else {
8390 __ LoadConst32(out, address);
8391 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008392 return;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008393 }
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008394 case HLoadString::LoadKind::kBootImageRelRo: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00008395 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008396 uint32_t boot_image_offset = codegen_->GetBootImageOffset(load);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008397 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008398 codegen_->NewBootImageRelRoPatch(boot_image_offset);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008399 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
Vladimir Markoe47f60c2018-02-21 13:43:28 +00008400 codegen_->NewBootImageRelRoPatch(boot_image_offset, info_high);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008401 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
8402 out,
8403 base_or_current_method_reg);
8404 __ Lw(out, out, /* placeholder */ 0x5678, &info_low->label);
8405 return;
8406 }
8407 case HLoadString::LoadKind::kBssEntry: {
8408 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
8409 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
8410 codegen_->NewStringBssEntryPatch(load->GetDexFile(), load->GetStringIndex());
8411 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
8412 codegen_->NewStringBssEntryPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008413 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
Vladimir Markof3c52b42017-11-17 17:32:12 +00008414 out,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008415 base_or_current_method_reg);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008416 GenerateGcRootFieldLoad(load,
8417 out_loc,
Vladimir Markof3c52b42017-11-17 17:32:12 +00008418 out,
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008419 /* placeholder */ 0x5678,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008420 kCompilerReadBarrierOption,
8421 &info_low->label);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008422 SlowPathCodeMIPS* slow_path =
Vladimir Markof3c52b42017-11-17 17:32:12 +00008423 new (codegen_->GetScopedAllocator()) LoadStringSlowPathMIPS(load);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008424 codegen_->AddSlowPath(slow_path);
8425 __ Beqz(out, slow_path->GetEntryLabel());
8426 __ Bind(slow_path->GetExitLabel());
8427 return;
8428 }
Alexey Frunze627c1a02017-01-30 19:28:14 -08008429 case HLoadString::LoadKind::kJitTableAddress: {
8430 CodeGeneratorMIPS::JitPatchInfo* info =
8431 codegen_->NewJitRootStringPatch(load->GetDexFile(),
8432 load->GetStringIndex(),
8433 load->GetString());
8434 bool reordering = __ SetReorder(false);
8435 __ Bind(&info->high_label);
8436 __ Lui(out, /* placeholder */ 0x1234);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008437 __ SetReorder(reordering);
Alexey Frunze15958152017-02-09 19:08:30 -08008438 GenerateGcRootFieldLoad(load,
8439 out_loc,
8440 out,
8441 /* placeholder */ 0x5678,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008442 kCompilerReadBarrierOption,
8443 &info->low_label);
Alexey Frunze627c1a02017-01-30 19:28:14 -08008444 return;
8445 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07008446 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07008447 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008448 }
Nicolas Geoffray917d0162015-11-24 18:25:35 +00008449
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07008450 // TODO: Re-add the compiler code to do string dex cache lookup again.
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008451 DCHECK(load_kind == HLoadString::LoadKind::kRuntimeCall);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008452 InvokeRuntimeCallingConvention calling_convention;
Alexey Frunzec61c0762017-04-10 13:54:23 -07008453 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008454 __ LoadConst32(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008455 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
8456 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008457}
8458
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008459void LocationsBuilderMIPS::VisitLongConstant(HLongConstant* constant) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008460 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008461 locations->SetOut(Location::ConstantLocation(constant));
8462}
8463
8464void InstructionCodeGeneratorMIPS::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
8465 // Will be generated at use site.
8466}
8467
8468void LocationsBuilderMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008469 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8470 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008471 InvokeRuntimeCallingConvention calling_convention;
8472 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8473}
8474
8475void InstructionCodeGeneratorMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
8476 if (instruction->IsEnter()) {
Serban Constantinescufca16662016-07-14 09:21:59 +01008477 codegen_->InvokeRuntime(kQuickLockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008478 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
8479 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01008480 codegen_->InvokeRuntime(kQuickUnlockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008481 }
8482 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
8483}
8484
8485void LocationsBuilderMIPS::VisitMul(HMul* mul) {
8486 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008487 new (GetGraph()->GetAllocator()) LocationSummary(mul, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008488 switch (mul->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008489 case DataType::Type::kInt32:
8490 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008491 locations->SetInAt(0, Location::RequiresRegister());
8492 locations->SetInAt(1, Location::RequiresRegister());
8493 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8494 break;
8495
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008496 case DataType::Type::kFloat32:
8497 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008498 locations->SetInAt(0, Location::RequiresFpuRegister());
8499 locations->SetInAt(1, Location::RequiresFpuRegister());
8500 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
8501 break;
8502
8503 default:
8504 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
8505 }
8506}
8507
8508void InstructionCodeGeneratorMIPS::VisitMul(HMul* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008509 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008510 LocationSummary* locations = instruction->GetLocations();
8511 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
8512
8513 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008514 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008515 Register dst = locations->Out().AsRegister<Register>();
8516 Register lhs = locations->InAt(0).AsRegister<Register>();
8517 Register rhs = locations->InAt(1).AsRegister<Register>();
8518
8519 if (isR6) {
8520 __ MulR6(dst, lhs, rhs);
8521 } else {
8522 __ MulR2(dst, lhs, rhs);
8523 }
8524 break;
8525 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008526 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008527 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8528 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8529 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8530 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
8531 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
8532 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
8533
8534 // Extra checks to protect caused by the existance of A1_A2.
8535 // The algorithm is wrong if dst_high is either lhs_lo or rhs_lo:
8536 // (e.g. lhs=a0_a1, rhs=a2_a3 and dst=a1_a2).
8537 DCHECK_NE(dst_high, lhs_low);
8538 DCHECK_NE(dst_high, rhs_low);
8539
8540 // A_B * C_D
8541 // dst_hi: [ low(A*D) + low(B*C) + hi(B*D) ]
8542 // dst_lo: [ low(B*D) ]
8543 // Note: R2 and R6 MUL produce the low 32 bit of the multiplication result.
8544
8545 if (isR6) {
8546 __ MulR6(TMP, lhs_high, rhs_low);
8547 __ MulR6(dst_high, lhs_low, rhs_high);
8548 __ Addu(dst_high, dst_high, TMP);
8549 __ MuhuR6(TMP, lhs_low, rhs_low);
8550 __ Addu(dst_high, dst_high, TMP);
8551 __ MulR6(dst_low, lhs_low, rhs_low);
8552 } else {
8553 __ MulR2(TMP, lhs_high, rhs_low);
8554 __ MulR2(dst_high, lhs_low, rhs_high);
8555 __ Addu(dst_high, dst_high, TMP);
8556 __ MultuR2(lhs_low, rhs_low);
8557 __ Mfhi(TMP);
8558 __ Addu(dst_high, dst_high, TMP);
8559 __ Mflo(dst_low);
8560 }
8561 break;
8562 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008563 case DataType::Type::kFloat32:
8564 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008565 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8566 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
8567 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008568 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008569 __ MulS(dst, lhs, rhs);
8570 } else {
8571 __ MulD(dst, lhs, rhs);
8572 }
8573 break;
8574 }
8575 default:
8576 LOG(FATAL) << "Unexpected mul type " << type;
8577 }
8578}
8579
8580void LocationsBuilderMIPS::VisitNeg(HNeg* neg) {
8581 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008582 new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008583 switch (neg->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008584 case DataType::Type::kInt32:
8585 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008586 locations->SetInAt(0, Location::RequiresRegister());
8587 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8588 break;
8589
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008590 case DataType::Type::kFloat32:
8591 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008592 locations->SetInAt(0, Location::RequiresFpuRegister());
8593 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
8594 break;
8595
8596 default:
8597 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
8598 }
8599}
8600
8601void InstructionCodeGeneratorMIPS::VisitNeg(HNeg* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008602 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008603 LocationSummary* locations = instruction->GetLocations();
8604
8605 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008606 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008607 Register dst = locations->Out().AsRegister<Register>();
8608 Register src = locations->InAt(0).AsRegister<Register>();
8609 __ Subu(dst, ZERO, src);
8610 break;
8611 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008612 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008613 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8614 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8615 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8616 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
8617 __ Subu(dst_low, ZERO, src_low);
8618 __ Sltu(TMP, ZERO, dst_low);
8619 __ Subu(dst_high, ZERO, src_high);
8620 __ Subu(dst_high, dst_high, TMP);
8621 break;
8622 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008623 case DataType::Type::kFloat32:
8624 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008625 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8626 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008627 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008628 __ NegS(dst, src);
8629 } else {
8630 __ NegD(dst, src);
8631 }
8632 break;
8633 }
8634 default:
8635 LOG(FATAL) << "Unexpected neg type " << type;
8636 }
8637}
8638
8639void LocationsBuilderMIPS::VisitNewArray(HNewArray* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008640 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8641 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008642 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008643 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00008644 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8645 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008646}
8647
8648void InstructionCodeGeneratorMIPS::VisitNewArray(HNewArray* instruction) {
Alexey Frunzec061de12017-02-14 13:27:23 -08008649 // Note: if heap poisoning is enabled, the entry point takes care
8650 // of poisoning the reference.
Goran Jakovljevic854df412017-06-27 14:41:39 +02008651 QuickEntrypointEnum entrypoint =
8652 CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
8653 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00008654 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Goran Jakovljevic854df412017-06-27 14:41:39 +02008655 DCHECK(!codegen_->IsLeafMethod());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008656}
8657
8658void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008659 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8660 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008661 InvokeRuntimeCallingConvention calling_convention;
David Brazdil6de19382016-01-08 17:37:10 +00008662 if (instruction->IsStringAlloc()) {
8663 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
8664 } else {
8665 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00008666 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008667 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008668}
8669
8670void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) {
Alexey Frunzec061de12017-02-14 13:27:23 -08008671 // Note: if heap poisoning is enabled, the entry point takes care
8672 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00008673 if (instruction->IsStringAlloc()) {
8674 // String is allocated through StringFactory. Call NewEmptyString entry point.
8675 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07008676 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00008677 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
8678 __ LoadFromOffset(kLoadWord, T9, temp, code_offset.Int32Value());
8679 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07008680 __ NopIfNoReordering();
David Brazdil6de19382016-01-08 17:37:10 +00008681 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
8682 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01008683 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00008684 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00008685 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008686}
8687
8688void LocationsBuilderMIPS::VisitNot(HNot* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008689 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008690 locations->SetInAt(0, Location::RequiresRegister());
8691 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8692}
8693
8694void InstructionCodeGeneratorMIPS::VisitNot(HNot* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008695 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008696 LocationSummary* locations = instruction->GetLocations();
8697
8698 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008699 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008700 Register dst = locations->Out().AsRegister<Register>();
8701 Register src = locations->InAt(0).AsRegister<Register>();
8702 __ Nor(dst, src, ZERO);
8703 break;
8704 }
8705
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008706 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008707 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8708 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8709 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8710 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
8711 __ Nor(dst_high, src_high, ZERO);
8712 __ Nor(dst_low, src_low, ZERO);
8713 break;
8714 }
8715
8716 default:
8717 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
8718 }
8719}
8720
8721void LocationsBuilderMIPS::VisitBooleanNot(HBooleanNot* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008722 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008723 locations->SetInAt(0, Location::RequiresRegister());
8724 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8725}
8726
8727void InstructionCodeGeneratorMIPS::VisitBooleanNot(HBooleanNot* instruction) {
8728 LocationSummary* locations = instruction->GetLocations();
8729 __ Xori(locations->Out().AsRegister<Register>(),
8730 locations->InAt(0).AsRegister<Register>(),
8731 1);
8732}
8733
8734void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01008735 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
8736 locations->SetInAt(0, Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008737}
8738
Calin Juravle2ae48182016-03-16 14:05:09 +00008739void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
8740 if (CanMoveNullCheckToUser(instruction)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008741 return;
8742 }
8743 Location obj = instruction->GetLocations()->InAt(0);
8744
8745 __ Lw(ZERO, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00008746 RecordPcInfo(instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008747}
8748
Calin Juravle2ae48182016-03-16 14:05:09 +00008749void CodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01008750 SlowPathCodeMIPS* slow_path = new (GetScopedAllocator()) NullCheckSlowPathMIPS(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00008751 AddSlowPath(slow_path);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008752
8753 Location obj = instruction->GetLocations()->InAt(0);
8754
8755 __ Beqz(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
8756}
8757
8758void InstructionCodeGeneratorMIPS::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00008759 codegen_->GenerateNullCheck(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008760}
8761
8762void LocationsBuilderMIPS::VisitOr(HOr* instruction) {
8763 HandleBinaryOp(instruction);
8764}
8765
8766void InstructionCodeGeneratorMIPS::VisitOr(HOr* instruction) {
8767 HandleBinaryOp(instruction);
8768}
8769
8770void LocationsBuilderMIPS::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
8771 LOG(FATAL) << "Unreachable";
8772}
8773
8774void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) {
Vladimir Markobea75ff2017-10-11 20:39:54 +01008775 if (instruction->GetNext()->IsSuspendCheck() &&
8776 instruction->GetBlock()->GetLoopInformation() != nullptr) {
8777 HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
8778 // The back edge will generate the suspend check.
8779 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
8780 }
8781
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008782 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
8783}
8784
8785void LocationsBuilderMIPS::VisitParameterValue(HParameterValue* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008786 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008787 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
8788 if (location.IsStackSlot()) {
8789 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
8790 } else if (location.IsDoubleStackSlot()) {
8791 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
8792 }
8793 locations->SetOut(location);
8794}
8795
8796void InstructionCodeGeneratorMIPS::VisitParameterValue(HParameterValue* instruction
8797 ATTRIBUTE_UNUSED) {
8798 // Nothing to do, the parameter is already at its location.
8799}
8800
8801void LocationsBuilderMIPS::VisitCurrentMethod(HCurrentMethod* instruction) {
8802 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008803 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008804 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
8805}
8806
8807void InstructionCodeGeneratorMIPS::VisitCurrentMethod(HCurrentMethod* instruction
8808 ATTRIBUTE_UNUSED) {
8809 // Nothing to do, the method is already at its location.
8810}
8811
8812void LocationsBuilderMIPS::VisitPhi(HPhi* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008813 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Vladimir Marko372f10e2016-05-17 16:30:10 +01008814 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008815 locations->SetInAt(i, Location::Any());
8816 }
8817 locations->SetOut(Location::Any());
8818}
8819
8820void InstructionCodeGeneratorMIPS::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
8821 LOG(FATAL) << "Unreachable";
8822}
8823
8824void LocationsBuilderMIPS::VisitRem(HRem* rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008825 DataType::Type type = rem->GetResultType();
Lena Djokic4b8025c2017-12-21 16:15:50 +01008826 bool call_rem;
8827 if ((type == DataType::Type::kInt64) && rem->InputAt(1)->IsConstant()) {
8828 int64_t imm = CodeGenerator::GetInt64ValueOf(rem->InputAt(1)->AsConstant());
8829 call_rem = (imm != 0) && !IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm)));
8830 } else {
8831 call_rem = (type != DataType::Type::kInt32);
8832 }
8833 LocationSummary::CallKind call_kind = call_rem
8834 ? LocationSummary::kCallOnMainOnly
8835 : LocationSummary::kNoCall;
Vladimir Markoca6fff82017-10-03 14:49:14 +01008836 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(rem, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008837
8838 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008839 case DataType::Type::kInt32:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008840 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08008841 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008842 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8843 break;
8844
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008845 case DataType::Type::kInt64: {
Lena Djokic4b8025c2017-12-21 16:15:50 +01008846 if (call_rem) {
8847 InvokeRuntimeCallingConvention calling_convention;
8848 locations->SetInAt(0, Location::RegisterPairLocation(
8849 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
8850 locations->SetInAt(1, Location::RegisterPairLocation(
8851 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
8852 locations->SetOut(calling_convention.GetReturnLocation(type));
8853 } else {
8854 locations->SetInAt(0, Location::RequiresRegister());
8855 locations->SetInAt(1, Location::ConstantLocation(rem->InputAt(1)->AsConstant()));
8856 locations->SetOut(Location::RequiresRegister());
8857 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008858 break;
8859 }
8860
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008861 case DataType::Type::kFloat32:
8862 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008863 InvokeRuntimeCallingConvention calling_convention;
8864 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
8865 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
8866 locations->SetOut(calling_convention.GetReturnLocation(type));
8867 break;
8868 }
8869
8870 default:
8871 LOG(FATAL) << "Unexpected rem type " << type;
8872 }
8873}
8874
8875void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008876 DataType::Type type = instruction->GetType();
Lena Djokic4b8025c2017-12-21 16:15:50 +01008877 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008878
8879 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008880 case DataType::Type::kInt32:
Alexey Frunze7e99e052015-11-24 19:28:01 -08008881 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008882 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008883 case DataType::Type::kInt64: {
Lena Djokic4b8025c2017-12-21 16:15:50 +01008884 if (locations->InAt(1).IsConstant()) {
8885 int64_t imm = locations->InAt(1).GetConstant()->AsLongConstant()->GetValue();
8886 if (imm == 0) {
8887 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
8888 } else if (imm == 1 || imm == -1) {
8889 DivRemOneOrMinusOne(instruction);
8890 } else {
8891 DCHECK(IsPowerOfTwo(static_cast<uint64_t>(AbsOrMin(imm))));
8892 DivRemByPowerOfTwo(instruction);
8893 }
8894 } else {
8895 codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
8896 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
8897 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008898 break;
8899 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008900 case DataType::Type::kFloat32: {
Serban Constantinescufca16662016-07-14 09:21:59 +01008901 codegen_->InvokeRuntime(kQuickFmodf, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00008902 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008903 break;
8904 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008905 case DataType::Type::kFloat64: {
Serban Constantinescufca16662016-07-14 09:21:59 +01008906 codegen_->InvokeRuntime(kQuickFmod, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00008907 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008908 break;
8909 }
8910 default:
8911 LOG(FATAL) << "Unexpected rem type " << type;
8912 }
8913}
8914
Aart Bik1f8d51b2018-02-15 10:42:37 -08008915static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) {
8916 LocationSummary* locations = new (allocator) LocationSummary(minmax);
8917 switch (minmax->GetResultType()) {
8918 case DataType::Type::kInt32:
8919 case DataType::Type::kInt64:
8920 locations->SetInAt(0, Location::RequiresRegister());
8921 locations->SetInAt(1, Location::RequiresRegister());
8922 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8923 break;
8924 case DataType::Type::kFloat32:
8925 case DataType::Type::kFloat64:
8926 locations->SetInAt(0, Location::RequiresFpuRegister());
8927 locations->SetInAt(1, Location::RequiresFpuRegister());
8928 locations->SetOut(Location::RequiresFpuRegister(), Location::kOutputOverlap);
8929 break;
8930 default:
8931 LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType();
8932 }
8933}
8934
Aart Bik351df3e2018-03-07 11:54:57 -08008935void InstructionCodeGeneratorMIPS::GenerateMinMaxInt(LocationSummary* locations,
8936 bool is_min,
8937 bool isR6,
8938 DataType::Type type) {
Aart Bik1f8d51b2018-02-15 10:42:37 -08008939 if (isR6) {
8940 // Some architectures, such as ARM and MIPS (prior to r6), have a
8941 // conditional move instruction which only changes the target
8942 // (output) register if the condition is true (MIPS prior to r6 had
8943 // MOVF, MOVT, MOVN, and MOVZ). The SELEQZ and SELNEZ instructions
8944 // always change the target (output) register. If the condition is
8945 // true the output register gets the contents of the "rs" register;
8946 // otherwise, the output register is set to zero. One consequence
8947 // of this is that to implement something like "rd = c==0 ? rs : rt"
8948 // MIPS64r6 needs to use a pair of SELEQZ/SELNEZ instructions.
8949 // After executing this pair of instructions one of the output
8950 // registers from the pair will necessarily contain zero. Then the
8951 // code ORs the output registers from the SELEQZ/SELNEZ instructions
8952 // to get the final result.
8953 //
8954 // The initial test to see if the output register is same as the
8955 // first input register is needed to make sure that value in the
8956 // first input register isn't clobbered before we've finished
8957 // computing the output value. The logic in the corresponding else
8958 // clause performs the same task but makes sure the second input
8959 // register isn't clobbered in the event that it's the same register
8960 // as the output register; the else clause also handles the case
8961 // where the output register is distinct from both the first, and the
8962 // second input registers.
8963 if (type == DataType::Type::kInt64) {
8964 Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
8965 Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
8966 Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
8967 Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
8968 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
8969 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
8970
8971 MipsLabel compare_done;
8972
8973 if (a_lo == b_lo) {
8974 if (out_lo != a_lo) {
8975 __ Move(out_lo, a_lo);
8976 __ Move(out_hi, a_hi);
8977 }
8978 } else {
8979 __ Slt(TMP, b_hi, a_hi);
8980 __ Bne(b_hi, a_hi, &compare_done);
8981
8982 __ Sltu(TMP, b_lo, a_lo);
8983
8984 __ Bind(&compare_done);
8985
8986 if (is_min) {
8987 __ Seleqz(AT, a_lo, TMP);
8988 __ Selnez(out_lo, b_lo, TMP); // Safe even if out_lo == a_lo/b_lo
8989 // because at this point we're
8990 // done using a_lo/b_lo.
8991 } else {
8992 __ Selnez(AT, a_lo, TMP);
8993 __ Seleqz(out_lo, b_lo, TMP); // ditto
8994 }
8995 __ Or(out_lo, out_lo, AT);
8996 if (is_min) {
8997 __ Seleqz(AT, a_hi, TMP);
8998 __ Selnez(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi
8999 } else {
9000 __ Selnez(AT, a_hi, TMP);
9001 __ Seleqz(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi
9002 }
9003 __ Or(out_hi, out_hi, AT);
9004 }
9005 } else {
9006 DCHECK_EQ(type, DataType::Type::kInt32);
9007 Register a = locations->InAt(0).AsRegister<Register>();
9008 Register b = locations->InAt(1).AsRegister<Register>();
9009 Register out = locations->Out().AsRegister<Register>();
9010
9011 if (a == b) {
9012 if (out != a) {
9013 __ Move(out, a);
9014 }
9015 } else {
9016 __ Slt(AT, b, a);
9017 if (is_min) {
9018 __ Seleqz(TMP, a, AT);
9019 __ Selnez(AT, b, AT);
9020 } else {
9021 __ Selnez(TMP, a, AT);
9022 __ Seleqz(AT, b, AT);
9023 }
9024 __ Or(out, TMP, AT);
9025 }
9026 }
9027 } else { // !isR6
9028 if (type == DataType::Type::kInt64) {
9029 Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
9030 Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
9031 Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
9032 Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
9033 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
9034 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
9035
9036 MipsLabel compare_done;
9037
9038 if (a_lo == b_lo) {
9039 if (out_lo != a_lo) {
9040 __ Move(out_lo, a_lo);
9041 __ Move(out_hi, a_hi);
9042 }
9043 } else {
9044 __ Slt(TMP, a_hi, b_hi);
9045 __ Bne(a_hi, b_hi, &compare_done);
9046
9047 __ Sltu(TMP, a_lo, b_lo);
9048
9049 __ Bind(&compare_done);
9050
9051 if (is_min) {
9052 if (out_lo != a_lo) {
9053 __ Movn(out_hi, a_hi, TMP);
9054 __ Movn(out_lo, a_lo, TMP);
9055 }
9056 if (out_lo != b_lo) {
9057 __ Movz(out_hi, b_hi, TMP);
9058 __ Movz(out_lo, b_lo, TMP);
9059 }
9060 } else {
9061 if (out_lo != a_lo) {
9062 __ Movz(out_hi, a_hi, TMP);
9063 __ Movz(out_lo, a_lo, TMP);
9064 }
9065 if (out_lo != b_lo) {
9066 __ Movn(out_hi, b_hi, TMP);
9067 __ Movn(out_lo, b_lo, TMP);
9068 }
9069 }
9070 }
9071 } else {
9072 DCHECK_EQ(type, DataType::Type::kInt32);
9073 Register a = locations->InAt(0).AsRegister<Register>();
9074 Register b = locations->InAt(1).AsRegister<Register>();
9075 Register out = locations->Out().AsRegister<Register>();
9076
9077 if (a == b) {
9078 if (out != a) {
9079 __ Move(out, a);
9080 }
9081 } else {
9082 __ Slt(AT, a, b);
9083 if (is_min) {
9084 if (out != a) {
9085 __ Movn(out, a, AT);
9086 }
9087 if (out != b) {
9088 __ Movz(out, b, AT);
9089 }
9090 } else {
9091 if (out != a) {
9092 __ Movz(out, a, AT);
9093 }
9094 if (out != b) {
9095 __ Movn(out, b, AT);
9096 }
9097 }
9098 }
9099 }
9100 }
9101}
9102
9103void InstructionCodeGeneratorMIPS::GenerateMinMaxFP(LocationSummary* locations,
9104 bool is_min,
9105 bool isR6,
9106 DataType::Type type) {
9107 FRegister out = locations->Out().AsFpuRegister<FRegister>();
9108 FRegister a = locations->InAt(0).AsFpuRegister<FRegister>();
9109 FRegister b = locations->InAt(1).AsFpuRegister<FRegister>();
9110
9111 if (isR6) {
9112 MipsLabel noNaNs;
9113 MipsLabel done;
9114 FRegister ftmp = ((out != a) && (out != b)) ? out : FTMP;
9115
9116 // When Java computes min/max it prefers a NaN to a number; the
9117 // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of
9118 // the inputs is a NaN and the other is a valid number, the MIPS
9119 // instruction will return the number; Java wants the NaN value
9120 // returned. This is why there is extra logic preceding the use of
9121 // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
9122 // NaN, return the NaN, otherwise return the min/max.
9123 if (type == DataType::Type::kFloat64) {
9124 __ CmpUnD(FTMP, a, b);
9125 __ Bc1eqz(FTMP, &noNaNs);
9126
9127 // One of the inputs is a NaN
9128 __ CmpEqD(ftmp, a, a);
9129 // If a == a then b is the NaN, otherwise a is the NaN.
9130 __ SelD(ftmp, a, b);
9131
9132 if (ftmp != out) {
9133 __ MovD(out, ftmp);
9134 }
9135
9136 __ B(&done);
9137
9138 __ Bind(&noNaNs);
9139
9140 if (is_min) {
9141 __ MinD(out, a, b);
9142 } else {
9143 __ MaxD(out, a, b);
9144 }
9145 } else {
9146 DCHECK_EQ(type, DataType::Type::kFloat32);
9147 __ CmpUnS(FTMP, a, b);
9148 __ Bc1eqz(FTMP, &noNaNs);
9149
9150 // One of the inputs is a NaN
9151 __ CmpEqS(ftmp, a, a);
9152 // If a == a then b is the NaN, otherwise a is the NaN.
9153 __ SelS(ftmp, a, b);
9154
9155 if (ftmp != out) {
9156 __ MovS(out, ftmp);
9157 }
9158
9159 __ B(&done);
9160
9161 __ Bind(&noNaNs);
9162
9163 if (is_min) {
9164 __ MinS(out, a, b);
9165 } else {
9166 __ MaxS(out, a, b);
9167 }
9168 }
9169
9170 __ Bind(&done);
9171
9172 } else { // !isR6
9173 MipsLabel ordered;
9174 MipsLabel compare;
9175 MipsLabel select;
9176 MipsLabel done;
9177
9178 if (type == DataType::Type::kFloat64) {
9179 __ CunD(a, b);
9180 } else {
9181 DCHECK_EQ(type, DataType::Type::kFloat32);
9182 __ CunS(a, b);
9183 }
9184 __ Bc1f(&ordered);
9185
9186 // a or b (or both) is a NaN. Return one, which is a NaN.
9187 if (type == DataType::Type::kFloat64) {
9188 __ CeqD(b, b);
9189 } else {
9190 __ CeqS(b, b);
9191 }
9192 __ B(&select);
9193
9194 __ Bind(&ordered);
9195
9196 // Neither is a NaN.
9197 // a == b? (-0.0 compares equal with +0.0)
9198 // If equal, handle zeroes, else compare further.
9199 if (type == DataType::Type::kFloat64) {
9200 __ CeqD(a, b);
9201 } else {
9202 __ CeqS(a, b);
9203 }
9204 __ Bc1f(&compare);
9205
9206 // a == b either bit for bit or one is -0.0 and the other is +0.0.
9207 if (type == DataType::Type::kFloat64) {
9208 __ MoveFromFpuHigh(TMP, a);
9209 __ MoveFromFpuHigh(AT, b);
9210 } else {
9211 __ Mfc1(TMP, a);
9212 __ Mfc1(AT, b);
9213 }
9214
9215 if (is_min) {
9216 // -0.0 prevails over +0.0.
9217 __ Or(TMP, TMP, AT);
9218 } else {
9219 // +0.0 prevails over -0.0.
9220 __ And(TMP, TMP, AT);
9221 }
9222
9223 if (type == DataType::Type::kFloat64) {
9224 __ Mfc1(AT, a);
9225 __ Mtc1(AT, out);
9226 __ MoveToFpuHigh(TMP, out);
9227 } else {
9228 __ Mtc1(TMP, out);
9229 }
9230 __ B(&done);
9231
9232 __ Bind(&compare);
9233
9234 if (type == DataType::Type::kFloat64) {
9235 if (is_min) {
9236 // return (a <= b) ? a : b;
9237 __ ColeD(a, b);
9238 } else {
9239 // return (a >= b) ? a : b;
9240 __ ColeD(b, a); // b <= a
9241 }
9242 } else {
9243 if (is_min) {
9244 // return (a <= b) ? a : b;
9245 __ ColeS(a, b);
9246 } else {
9247 // return (a >= b) ? a : b;
9248 __ ColeS(b, a); // b <= a
9249 }
9250 }
9251
9252 __ Bind(&select);
9253
9254 if (type == DataType::Type::kFloat64) {
9255 __ MovtD(out, a);
9256 __ MovfD(out, b);
9257 } else {
9258 __ MovtS(out, a);
9259 __ MovfS(out, b);
9260 }
9261
9262 __ Bind(&done);
9263 }
9264}
9265
Aart Bik351df3e2018-03-07 11:54:57 -08009266void InstructionCodeGeneratorMIPS::GenerateMinMax(HBinaryOperation* minmax, bool is_min) {
9267 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
9268 DataType::Type type = minmax->GetResultType();
9269 switch (type) {
9270 case DataType::Type::kInt32:
9271 case DataType::Type::kInt64:
9272 GenerateMinMaxInt(minmax->GetLocations(), is_min, isR6, type);
9273 break;
9274 case DataType::Type::kFloat32:
9275 case DataType::Type::kFloat64:
9276 GenerateMinMaxFP(minmax->GetLocations(), is_min, isR6, type);
9277 break;
9278 default:
9279 LOG(FATAL) << "Unexpected type for HMinMax " << type;
9280 }
9281}
9282
Aart Bik1f8d51b2018-02-15 10:42:37 -08009283void LocationsBuilderMIPS::VisitMin(HMin* min) {
9284 CreateMinMaxLocations(GetGraph()->GetAllocator(), min);
9285}
9286
9287void InstructionCodeGeneratorMIPS::VisitMin(HMin* min) {
Aart Bik351df3e2018-03-07 11:54:57 -08009288 GenerateMinMax(min, /*is_min*/ true);
Aart Bik1f8d51b2018-02-15 10:42:37 -08009289}
9290
9291void LocationsBuilderMIPS::VisitMax(HMax* max) {
9292 CreateMinMaxLocations(GetGraph()->GetAllocator(), max);
9293}
9294
9295void InstructionCodeGeneratorMIPS::VisitMax(HMax* max) {
Aart Bik351df3e2018-03-07 11:54:57 -08009296 GenerateMinMax(max, /*is_min*/ false);
Aart Bik1f8d51b2018-02-15 10:42:37 -08009297}
9298
Aart Bik3dad3412018-02-28 12:01:46 -08009299void LocationsBuilderMIPS::VisitAbs(HAbs* abs) {
9300 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs);
9301 switch (abs->GetResultType()) {
9302 case DataType::Type::kInt32:
9303 case DataType::Type::kInt64:
9304 locations->SetInAt(0, Location::RequiresRegister());
9305 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
9306 break;
9307 case DataType::Type::kFloat32:
9308 case DataType::Type::kFloat64:
9309 locations->SetInAt(0, Location::RequiresFpuRegister());
9310 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
9311 break;
9312 default:
9313 LOG(FATAL) << "Unexpected abs type " << abs->GetResultType();
9314 }
9315}
9316
9317void InstructionCodeGeneratorMIPS::GenerateAbsFP(LocationSummary* locations,
9318 DataType::Type type,
9319 bool isR2OrNewer,
9320 bool isR6) {
9321 FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
9322 FRegister out = locations->Out().AsFpuRegister<FRegister>();
9323
9324 // Note, as a "quality of implementation", rather than pure "spec compliance", we require that
9325 // Math.abs() clears the sign bit (but changes nothing else) for all numbers, including NaN
9326 // (signaling NaN may become quiet though).
9327 //
9328 // The ABS.fmt instructions (abs.s and abs.d) do exactly that when NAN2008=1 (R6). For this case,
9329 // both regular floating point numbers and NAN values are treated alike, only the sign bit is
9330 // affected by this instruction.
9331 // But when NAN2008=0 (R2 and before), the ABS.fmt instructions can't be used. For this case, any
9332 // NaN operand signals invalid operation. This means that other bits (not just sign bit) might be
9333 // changed when doing abs(NaN). Because of that, we clear sign bit in a different way.
9334 if (isR6) {
9335 if (type == DataType::Type::kFloat64) {
9336 __ AbsD(out, in);
9337 } else {
9338 DCHECK_EQ(type, DataType::Type::kFloat32);
9339 __ AbsS(out, in);
9340 }
9341 } else {
9342 if (type == DataType::Type::kFloat64) {
9343 if (in != out) {
9344 __ MovD(out, in);
9345 }
9346 __ MoveFromFpuHigh(TMP, in);
9347 // ins instruction is not available for R1.
9348 if (isR2OrNewer) {
9349 __ Ins(TMP, ZERO, 31, 1);
9350 } else {
9351 __ Sll(TMP, TMP, 1);
9352 __ Srl(TMP, TMP, 1);
9353 }
9354 __ MoveToFpuHigh(TMP, out);
9355 } else {
9356 DCHECK_EQ(type, DataType::Type::kFloat32);
9357 __ Mfc1(TMP, in);
9358 // ins instruction is not available for R1.
9359 if (isR2OrNewer) {
9360 __ Ins(TMP, ZERO, 31, 1);
9361 } else {
9362 __ Sll(TMP, TMP, 1);
9363 __ Srl(TMP, TMP, 1);
9364 }
9365 __ Mtc1(TMP, out);
9366 }
9367 }
9368}
9369
9370void InstructionCodeGeneratorMIPS::VisitAbs(HAbs* abs) {
9371 LocationSummary* locations = abs->GetLocations();
9372 bool isR2OrNewer = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
9373 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
9374 switch (abs->GetResultType()) {
9375 case DataType::Type::kInt32: {
9376 Register in = locations->InAt(0).AsRegister<Register>();
9377 Register out = locations->Out().AsRegister<Register>();
9378 __ Sra(AT, in, 31);
9379 __ Xor(out, in, AT);
9380 __ Subu(out, out, AT);
9381 break;
9382 }
9383 case DataType::Type::kInt64: {
9384 Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
9385 Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
9386 Register out_lo = locations->Out().AsRegisterPairLow<Register>();
9387 Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
9388 // The comments in this section show the analogous operations which would
9389 // be performed if we had 64-bit registers "in", and "out".
9390 // __ Dsra32(AT, in, 31);
9391 __ Sra(AT, in_hi, 31);
9392 // __ Xor(out, in, AT);
9393 __ Xor(TMP, in_lo, AT);
9394 __ Xor(out_hi, in_hi, AT);
9395 // __ Dsubu(out, out, AT);
9396 __ Subu(out_lo, TMP, AT);
9397 __ Sltu(TMP, out_lo, TMP);
9398 __ Addu(out_hi, out_hi, TMP);
9399 break;
9400 }
9401 case DataType::Type::kFloat32:
9402 case DataType::Type::kFloat64:
9403 GenerateAbsFP(locations, abs->GetResultType(), isR2OrNewer, isR6);
9404 break;
9405 default:
9406 LOG(FATAL) << "Unexpected abs type " << abs->GetResultType();
9407 }
9408}
9409
Igor Murashkind01745e2017-04-05 16:40:31 -07009410void LocationsBuilderMIPS::VisitConstructorFence(HConstructorFence* constructor_fence) {
9411 constructor_fence->SetLocations(nullptr);
9412}
9413
9414void InstructionCodeGeneratorMIPS::VisitConstructorFence(
9415 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
9416 GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
9417}
9418
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009419void LocationsBuilderMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
9420 memory_barrier->SetLocations(nullptr);
9421}
9422
9423void InstructionCodeGeneratorMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
9424 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
9425}
9426
9427void LocationsBuilderMIPS::VisitReturn(HReturn* ret) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01009428 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(ret);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009429 DataType::Type return_type = ret->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009430 locations->SetInAt(0, MipsReturnLocation(return_type));
9431}
9432
9433void InstructionCodeGeneratorMIPS::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
9434 codegen_->GenerateFrameExit();
9435}
9436
9437void LocationsBuilderMIPS::VisitReturnVoid(HReturnVoid* ret) {
9438 ret->SetLocations(nullptr);
9439}
9440
9441void InstructionCodeGeneratorMIPS::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
9442 codegen_->GenerateFrameExit();
9443}
9444
Alexey Frunze92d90602015-12-18 18:16:36 -08009445void LocationsBuilderMIPS::VisitRor(HRor* ror) {
9446 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00009447}
9448
Alexey Frunze92d90602015-12-18 18:16:36 -08009449void InstructionCodeGeneratorMIPS::VisitRor(HRor* ror) {
9450 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00009451}
9452
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009453void LocationsBuilderMIPS::VisitShl(HShl* shl) {
9454 HandleShift(shl);
9455}
9456
9457void InstructionCodeGeneratorMIPS::VisitShl(HShl* shl) {
9458 HandleShift(shl);
9459}
9460
9461void LocationsBuilderMIPS::VisitShr(HShr* shr) {
9462 HandleShift(shr);
9463}
9464
9465void InstructionCodeGeneratorMIPS::VisitShr(HShr* shr) {
9466 HandleShift(shr);
9467}
9468
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009469void LocationsBuilderMIPS::VisitSub(HSub* instruction) {
9470 HandleBinaryOp(instruction);
9471}
9472
9473void InstructionCodeGeneratorMIPS::VisitSub(HSub* instruction) {
9474 HandleBinaryOp(instruction);
9475}
9476
9477void LocationsBuilderMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
9478 HandleFieldGet(instruction, instruction->GetFieldInfo());
9479}
9480
9481void InstructionCodeGeneratorMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
9482 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
9483}
9484
9485void LocationsBuilderMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
9486 HandleFieldSet(instruction, instruction->GetFieldInfo());
9487}
9488
9489void InstructionCodeGeneratorMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01009490 HandleFieldSet(instruction,
9491 instruction->GetFieldInfo(),
9492 instruction->GetDexPc(),
9493 instruction->GetValueCanBeNull());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009494}
9495
9496void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldGet(
9497 HUnresolvedInstanceFieldGet* instruction) {
9498 FieldAccessCallingConventionMIPS calling_convention;
9499 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
9500 instruction->GetFieldType(),
9501 calling_convention);
9502}
9503
9504void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldGet(
9505 HUnresolvedInstanceFieldGet* instruction) {
9506 FieldAccessCallingConventionMIPS calling_convention;
9507 codegen_->GenerateUnresolvedFieldAccess(instruction,
9508 instruction->GetFieldType(),
9509 instruction->GetFieldIndex(),
9510 instruction->GetDexPc(),
9511 calling_convention);
9512}
9513
9514void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldSet(
9515 HUnresolvedInstanceFieldSet* instruction) {
9516 FieldAccessCallingConventionMIPS calling_convention;
9517 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
9518 instruction->GetFieldType(),
9519 calling_convention);
9520}
9521
9522void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldSet(
9523 HUnresolvedInstanceFieldSet* instruction) {
9524 FieldAccessCallingConventionMIPS calling_convention;
9525 codegen_->GenerateUnresolvedFieldAccess(instruction,
9526 instruction->GetFieldType(),
9527 instruction->GetFieldIndex(),
9528 instruction->GetDexPc(),
9529 calling_convention);
9530}
9531
9532void LocationsBuilderMIPS::VisitUnresolvedStaticFieldGet(
9533 HUnresolvedStaticFieldGet* instruction) {
9534 FieldAccessCallingConventionMIPS calling_convention;
9535 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
9536 instruction->GetFieldType(),
9537 calling_convention);
9538}
9539
9540void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldGet(
9541 HUnresolvedStaticFieldGet* instruction) {
9542 FieldAccessCallingConventionMIPS calling_convention;
9543 codegen_->GenerateUnresolvedFieldAccess(instruction,
9544 instruction->GetFieldType(),
9545 instruction->GetFieldIndex(),
9546 instruction->GetDexPc(),
9547 calling_convention);
9548}
9549
9550void LocationsBuilderMIPS::VisitUnresolvedStaticFieldSet(
9551 HUnresolvedStaticFieldSet* instruction) {
9552 FieldAccessCallingConventionMIPS calling_convention;
9553 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
9554 instruction->GetFieldType(),
9555 calling_convention);
9556}
9557
9558void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldSet(
9559 HUnresolvedStaticFieldSet* instruction) {
9560 FieldAccessCallingConventionMIPS calling_convention;
9561 codegen_->GenerateUnresolvedFieldAccess(instruction,
9562 instruction->GetFieldType(),
9563 instruction->GetFieldIndex(),
9564 instruction->GetDexPc(),
9565 calling_convention);
9566}
9567
9568void LocationsBuilderMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01009569 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
9570 instruction, LocationSummary::kCallOnSlowPath);
Lena Djokicca8c2952017-05-29 11:31:46 +02009571 // In suspend check slow path, usually there are no caller-save registers at all.
9572 // If SIMD instructions are present, however, we force spilling all live SIMD
9573 // registers in full width (since the runtime only saves/restores lower part).
9574 locations->SetCustomSlowPathCallerSaves(
9575 GetGraph()->HasSIMD() ? RegisterSet::AllFpu() : RegisterSet::Empty());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009576}
9577
9578void InstructionCodeGeneratorMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
9579 HBasicBlock* block = instruction->GetBlock();
9580 if (block->GetLoopInformation() != nullptr) {
9581 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
9582 // The back edge will generate the suspend check.
9583 return;
9584 }
9585 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
9586 // The goto will generate the suspend check.
9587 return;
9588 }
9589 GenerateSuspendCheck(instruction, nullptr);
9590}
9591
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009592void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01009593 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
9594 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009595 InvokeRuntimeCallingConvention calling_convention;
9596 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
9597}
9598
9599void InstructionCodeGeneratorMIPS::VisitThrow(HThrow* instruction) {
Serban Constantinescufca16662016-07-14 09:21:59 +01009600 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009601 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
9602}
9603
9604void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009605 DataType::Type input_type = conversion->GetInputType();
9606 DataType::Type result_type = conversion->GetResultType();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01009607 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
9608 << input_type << " -> " << result_type;
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009609 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009610
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009611 if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
9612 (result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009613 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
9614 }
9615
9616 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009617 if (!isR6 &&
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009618 ((DataType::IsFloatingPointType(result_type) && input_type == DataType::Type::kInt64) ||
9619 (result_type == DataType::Type::kInt64 && DataType::IsFloatingPointType(input_type)))) {
Serban Constantinescu54ff4822016-07-07 18:03:19 +01009620 call_kind = LocationSummary::kCallOnMainOnly;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009621 }
9622
Vladimir Markoca6fff82017-10-03 14:49:14 +01009623 LocationSummary* locations =
9624 new (GetGraph()->GetAllocator()) LocationSummary(conversion, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009625
9626 if (call_kind == LocationSummary::kNoCall) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009627 if (DataType::IsFloatingPointType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009628 locations->SetInAt(0, Location::RequiresFpuRegister());
9629 } else {
9630 locations->SetInAt(0, Location::RequiresRegister());
9631 }
9632
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009633 if (DataType::IsFloatingPointType(result_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009634 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
9635 } else {
9636 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
9637 }
9638 } else {
9639 InvokeRuntimeCallingConvention calling_convention;
9640
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009641 if (DataType::IsFloatingPointType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009642 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
9643 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009644 DCHECK_EQ(input_type, DataType::Type::kInt64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009645 locations->SetInAt(0, Location::RegisterPairLocation(
9646 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
9647 }
9648
9649 locations->SetOut(calling_convention.GetReturnLocation(result_type));
9650 }
9651}
9652
9653void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversion) {
9654 LocationSummary* locations = conversion->GetLocations();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009655 DataType::Type result_type = conversion->GetResultType();
9656 DataType::Type input_type = conversion->GetInputType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009657 bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009658 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009659
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01009660 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
9661 << input_type << " -> " << result_type;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009662
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009663 if (result_type == DataType::Type::kInt64 && DataType::IsIntegralType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009664 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
9665 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
9666 Register src = locations->InAt(0).AsRegister<Register>();
9667
Alexey Frunzea871ef12016-06-27 15:20:11 -07009668 if (dst_low != src) {
9669 __ Move(dst_low, src);
9670 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009671 __ Sra(dst_high, src, 31);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009672 } else if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009673 Register dst = locations->Out().AsRegister<Register>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009674 Register src = (input_type == DataType::Type::kInt64)
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009675 ? locations->InAt(0).AsRegisterPairLow<Register>()
9676 : locations->InAt(0).AsRegister<Register>();
9677
9678 switch (result_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01009679 case DataType::Type::kUint8:
9680 __ Andi(dst, src, 0xFF);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009681 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009682 case DataType::Type::kInt8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009683 if (has_sign_extension) {
9684 __ Seb(dst, src);
9685 } else {
9686 __ Sll(dst, src, 24);
9687 __ Sra(dst, dst, 24);
9688 }
9689 break;
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01009690 case DataType::Type::kUint16:
9691 __ Andi(dst, src, 0xFFFF);
9692 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009693 case DataType::Type::kInt16:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009694 if (has_sign_extension) {
9695 __ Seh(dst, src);
9696 } else {
9697 __ Sll(dst, src, 16);
9698 __ Sra(dst, dst, 16);
9699 }
9700 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009701 case DataType::Type::kInt32:
Alexey Frunzea871ef12016-06-27 15:20:11 -07009702 if (dst != src) {
9703 __ Move(dst, src);
9704 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009705 break;
9706
9707 default:
9708 LOG(FATAL) << "Unexpected type conversion from " << input_type
9709 << " to " << result_type;
9710 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009711 } else if (DataType::IsFloatingPointType(result_type) && DataType::IsIntegralType(input_type)) {
9712 if (input_type == DataType::Type::kInt64) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009713 if (isR6) {
9714 // cvt.s.l/cvt.d.l requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
9715 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
9716 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
9717 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
9718 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
9719 __ Mtc1(src_low, FTMP);
9720 __ Mthc1(src_high, FTMP);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009721 if (result_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009722 __ Cvtsl(dst, FTMP);
9723 } else {
9724 __ Cvtdl(dst, FTMP);
9725 }
9726 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009727 QuickEntrypointEnum entrypoint =
9728 (result_type == DataType::Type::kFloat32) ? kQuickL2f : kQuickL2d;
Serban Constantinescufca16662016-07-14 09:21:59 +01009729 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009730 if (result_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009731 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
9732 } else {
9733 CheckEntrypointTypes<kQuickL2d, double, int64_t>();
9734 }
9735 }
9736 } else {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009737 Register src = locations->InAt(0).AsRegister<Register>();
9738 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
9739 __ Mtc1(src, FTMP);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009740 if (result_type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009741 __ Cvtsw(dst, FTMP);
9742 } else {
9743 __ Cvtdw(dst, FTMP);
9744 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009745 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009746 } else if (DataType::IsIntegralType(result_type) && DataType::IsFloatingPointType(input_type)) {
9747 CHECK(result_type == DataType::Type::kInt32 || result_type == DataType::Type::kInt64);
Lena Djokicf4e23a82017-05-09 15:43:45 +02009748
9749 // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
9750 // value of the output type if the input is outside of the range after the truncation or
9751 // produces 0 when the input is a NaN. IOW, the three special cases produce three distinct
9752 // results. This matches the desired float/double-to-int/long conversion exactly.
9753 //
9754 // When NAN2008=0 (R2 and before), the truncate instruction produces the maximum positive
9755 // value when the input is either a NaN or is outside of the range of the output type
9756 // after the truncation. IOW, the three special cases (NaN, too small, too big) produce
9757 // the same result.
9758 //
9759 // The code takes care of the different behaviors by first comparing the input to the
9760 // minimum output value (-2**-63 for truncating to long, -2**-31 for truncating to int).
9761 // If the input is greater than or equal to the minimum, it procedes to the truncate
9762 // instruction, which will handle such an input the same way irrespective of NAN2008.
9763 // Otherwise the input is compared to itself to determine whether it is a NaN or not
9764 // in order to return either zero or the minimum value.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009765 if (result_type == DataType::Type::kInt64) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009766 if (isR6) {
9767 // trunc.l.s/trunc.l.d requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
9768 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
9769 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
9770 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
9771 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009772
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009773 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009774 __ TruncLS(FTMP, src);
9775 } else {
9776 __ TruncLD(FTMP, src);
9777 }
9778 __ Mfc1(dst_low, FTMP);
9779 __ Mfhc1(dst_high, FTMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009780 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009781 QuickEntrypointEnum entrypoint =
9782 (input_type == DataType::Type::kFloat32) ? kQuickF2l : kQuickD2l;
Serban Constantinescufca16662016-07-14 09:21:59 +01009783 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009784 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009785 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
9786 } else {
9787 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
9788 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009789 }
9790 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009791 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
9792 Register dst = locations->Out().AsRegister<Register>();
9793 MipsLabel truncate;
9794 MipsLabel done;
9795
Lena Djokicf4e23a82017-05-09 15:43:45 +02009796 if (!isR6) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009797 if (input_type == DataType::Type::kFloat32) {
Lena Djokicf4e23a82017-05-09 15:43:45 +02009798 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
9799 __ LoadConst32(TMP, min_val);
9800 __ Mtc1(TMP, FTMP);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009801 } else {
Lena Djokicf4e23a82017-05-09 15:43:45 +02009802 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int32_t>::min());
9803 __ LoadConst32(TMP, High32Bits(min_val));
9804 __ Mtc1(ZERO, FTMP);
9805 __ MoveToFpuHigh(TMP, FTMP);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009806 }
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009807
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009808 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009809 __ ColeS(0, FTMP, src);
9810 } else {
9811 __ ColeD(0, FTMP, src);
9812 }
9813 __ Bc1t(0, &truncate);
9814
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009815 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009816 __ CeqS(0, src, src);
9817 } else {
9818 __ CeqD(0, src, src);
9819 }
9820 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
9821 __ Movf(dst, ZERO, 0);
Lena Djokicf4e23a82017-05-09 15:43:45 +02009822
9823 __ B(&done);
9824
9825 __ Bind(&truncate);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009826 }
9827
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009828 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08009829 __ TruncWS(FTMP, src);
9830 } else {
9831 __ TruncWD(FTMP, src);
9832 }
9833 __ Mfc1(dst, FTMP);
9834
Lena Djokicf4e23a82017-05-09 15:43:45 +02009835 if (!isR6) {
9836 __ Bind(&done);
9837 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009838 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009839 } else if (DataType::IsFloatingPointType(result_type) &&
9840 DataType::IsFloatingPointType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009841 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
9842 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01009843 if (result_type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009844 __ Cvtsd(dst, src);
9845 } else {
9846 __ Cvtds(dst, src);
9847 }
9848 } else {
9849 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
9850 << " to " << result_type;
9851 }
9852}
9853
9854void LocationsBuilderMIPS::VisitUShr(HUShr* ushr) {
9855 HandleShift(ushr);
9856}
9857
9858void InstructionCodeGeneratorMIPS::VisitUShr(HUShr* ushr) {
9859 HandleShift(ushr);
9860}
9861
9862void LocationsBuilderMIPS::VisitXor(HXor* instruction) {
9863 HandleBinaryOp(instruction);
9864}
9865
9866void InstructionCodeGeneratorMIPS::VisitXor(HXor* instruction) {
9867 HandleBinaryOp(instruction);
9868}
9869
9870void LocationsBuilderMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
9871 // Nothing to do, this should be removed during prepare for register allocator.
9872 LOG(FATAL) << "Unreachable";
9873}
9874
9875void InstructionCodeGeneratorMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
9876 // Nothing to do, this should be removed during prepare for register allocator.
9877 LOG(FATAL) << "Unreachable";
9878}
9879
9880void LocationsBuilderMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009881 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009882}
9883
9884void InstructionCodeGeneratorMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009885 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009886}
9887
9888void LocationsBuilderMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009889 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009890}
9891
9892void InstructionCodeGeneratorMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009893 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009894}
9895
9896void LocationsBuilderMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009897 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009898}
9899
9900void InstructionCodeGeneratorMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009901 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009902}
9903
9904void LocationsBuilderMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009905 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009906}
9907
9908void InstructionCodeGeneratorMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009909 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009910}
9911
9912void LocationsBuilderMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009913 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009914}
9915
9916void InstructionCodeGeneratorMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009917 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009918}
9919
9920void LocationsBuilderMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009921 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009922}
9923
9924void InstructionCodeGeneratorMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009925 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009926}
9927
9928void LocationsBuilderMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009929 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009930}
9931
9932void InstructionCodeGeneratorMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009933 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009934}
9935
9936void LocationsBuilderMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009937 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009938}
9939
9940void InstructionCodeGeneratorMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009941 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009942}
9943
9944void LocationsBuilderMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009945 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009946}
9947
9948void InstructionCodeGeneratorMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009949 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009950}
9951
9952void LocationsBuilderMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009953 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009954}
9955
9956void InstructionCodeGeneratorMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009957 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009958}
9959
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009960void LocationsBuilderMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
9961 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01009962 new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009963 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07009964 if (!codegen_->GetInstructionSetFeatures().IsR6()) {
9965 uint32_t num_entries = switch_instr->GetNumEntries();
9966 if (num_entries > InstructionCodeGeneratorMIPS::kPackedSwitchJumpTableThreshold) {
9967 // When there's no HMipsComputeBaseMethodAddress input, R2 uses the NAL
9968 // instruction to simulate PC-relative addressing when accessing the jump table.
9969 // NAL clobbers RA. Make sure RA is preserved.
9970 codegen_->ClobberRA();
9971 }
9972 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009973}
9974
Alexey Frunze96b66822016-09-10 02:32:44 -07009975void InstructionCodeGeneratorMIPS::GenPackedSwitchWithCompares(Register value_reg,
9976 int32_t lower_bound,
9977 uint32_t num_entries,
9978 HBasicBlock* switch_block,
9979 HBasicBlock* default_block) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009980 // Create a set of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009981 Register temp_reg = TMP;
9982 __ Addiu32(temp_reg, value_reg, -lower_bound);
9983 // Jump to default if index is negative
9984 // Note: We don't check the case that index is positive while value < lower_bound, because in
9985 // this case, index >= num_entries must be true. So that we can save one branch instruction.
9986 __ Bltz(temp_reg, codegen_->GetLabelOf(default_block));
9987
Alexey Frunze96b66822016-09-10 02:32:44 -07009988 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009989 // Jump to successors[0] if value == lower_bound.
9990 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[0]));
9991 int32_t last_index = 0;
9992 for (; num_entries - last_index > 2; last_index += 2) {
9993 __ Addiu(temp_reg, temp_reg, -2);
9994 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
9995 __ Bltz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
9996 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
9997 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 2]));
9998 }
9999 if (num_entries - last_index == 2) {
10000 // The last missing case_value.
10001 __ Addiu(temp_reg, temp_reg, -1);
10002 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020010003 }
10004
Vladimir Markof3e0ee22015-12-17 15:23:13 +000010005 // And the default for any other value.
Alexey Frunze96b66822016-09-10 02:32:44 -070010006 if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020010007 __ B(codegen_->GetLabelOf(default_block));
10008 }
10009}
10010
Alexey Frunze96b66822016-09-10 02:32:44 -070010011void InstructionCodeGeneratorMIPS::GenTableBasedPackedSwitch(Register value_reg,
10012 Register constant_area,
10013 int32_t lower_bound,
10014 uint32_t num_entries,
10015 HBasicBlock* switch_block,
10016 HBasicBlock* default_block) {
10017 // Create a jump table.
10018 std::vector<MipsLabel*> labels(num_entries);
10019 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
10020 for (uint32_t i = 0; i < num_entries; i++) {
10021 labels[i] = codegen_->GetLabelOf(successors[i]);
10022 }
10023 JumpTable* table = __ CreateJumpTable(std::move(labels));
10024
10025 // Is the value in range?
10026 __ Addiu32(TMP, value_reg, -lower_bound);
10027 if (IsInt<16>(static_cast<int32_t>(num_entries))) {
10028 __ Sltiu(AT, TMP, num_entries);
10029 __ Beqz(AT, codegen_->GetLabelOf(default_block));
10030 } else {
10031 __ LoadConst32(AT, num_entries);
10032 __ Bgeu(TMP, AT, codegen_->GetLabelOf(default_block));
10033 }
10034
10035 // We are in the range of the table.
10036 // Load the target address from the jump table, indexing by the value.
10037 __ LoadLabelAddress(AT, constant_area, table->GetLabel());
Chris Larsencd0295d2017-03-31 15:26:54 -070010038 __ ShiftAndAdd(TMP, TMP, AT, 2, TMP);
Alexey Frunze96b66822016-09-10 02:32:44 -070010039 __ Lw(TMP, TMP, 0);
10040 // Compute the absolute target address by adding the table start address
10041 // (the table contains offsets to targets relative to its start).
10042 __ Addu(TMP, TMP, AT);
10043 // And jump.
10044 __ Jr(TMP);
10045 __ NopIfNoReordering();
10046}
10047
10048void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
10049 int32_t lower_bound = switch_instr->GetStartValue();
10050 uint32_t num_entries = switch_instr->GetNumEntries();
10051 LocationSummary* locations = switch_instr->GetLocations();
10052 Register value_reg = locations->InAt(0).AsRegister<Register>();
10053 HBasicBlock* switch_block = switch_instr->GetBlock();
10054 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
10055
Alexey Frunze3b8c82f2017-10-10 23:01:34 -070010056 if (num_entries > kPackedSwitchJumpTableThreshold) {
Alexey Frunze96b66822016-09-10 02:32:44 -070010057 // R6 uses PC-relative addressing to access the jump table.
Alexey Frunze3b8c82f2017-10-10 23:01:34 -070010058 //
10059 // R2, OTOH, uses an HMipsComputeBaseMethodAddress input (when available)
10060 // to access the jump table and it is implemented by changing HPackedSwitch to
10061 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress (see
10062 // VisitMipsPackedSwitch()).
10063 //
10064 // When there's no HMipsComputeBaseMethodAddress input (e.g. in presence of
10065 // irreducible loops), R2 uses the NAL instruction to simulate PC-relative
10066 // addressing.
Alexey Frunze96b66822016-09-10 02:32:44 -070010067 GenTableBasedPackedSwitch(value_reg,
10068 ZERO,
10069 lower_bound,
10070 num_entries,
10071 switch_block,
10072 default_block);
10073 } else {
10074 GenPackedSwitchWithCompares(value_reg,
10075 lower_bound,
10076 num_entries,
10077 switch_block,
10078 default_block);
10079 }
10080}
10081
10082void LocationsBuilderMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
10083 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +010010084 new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
Alexey Frunze96b66822016-09-10 02:32:44 -070010085 locations->SetInAt(0, Location::RequiresRegister());
10086 // Constant area pointer (HMipsComputeBaseMethodAddress).
10087 locations->SetInAt(1, Location::RequiresRegister());
10088}
10089
10090void InstructionCodeGeneratorMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
10091 int32_t lower_bound = switch_instr->GetStartValue();
10092 uint32_t num_entries = switch_instr->GetNumEntries();
10093 LocationSummary* locations = switch_instr->GetLocations();
10094 Register value_reg = locations->InAt(0).AsRegister<Register>();
10095 Register constant_area = locations->InAt(1).AsRegister<Register>();
10096 HBasicBlock* switch_block = switch_instr->GetBlock();
10097 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
10098
10099 // This is an R2-only path. HPackedSwitch has been changed to
10100 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress
10101 // required to address the jump table relative to PC.
10102 GenTableBasedPackedSwitch(value_reg,
10103 constant_area,
10104 lower_bound,
10105 num_entries,
10106 switch_block,
10107 default_block);
10108}
10109
Alexey Frunzee3fb2452016-05-10 16:08:05 -070010110void LocationsBuilderMIPS::VisitMipsComputeBaseMethodAddress(
10111 HMipsComputeBaseMethodAddress* insn) {
10112 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +010010113 new (GetGraph()->GetAllocator()) LocationSummary(insn, LocationSummary::kNoCall);
Alexey Frunzee3fb2452016-05-10 16:08:05 -070010114 locations->SetOut(Location::RequiresRegister());
10115}
10116
10117void InstructionCodeGeneratorMIPS::VisitMipsComputeBaseMethodAddress(
10118 HMipsComputeBaseMethodAddress* insn) {
10119 LocationSummary* locations = insn->GetLocations();
10120 Register reg = locations->Out().AsRegister<Register>();
10121
10122 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
10123
10124 // Generate a dummy PC-relative call to obtain PC.
10125 __ Nal();
10126 // Grab the return address off RA.
10127 __ Move(reg, RA);
10128
10129 // Remember this offset (the obtained PC value) for later use with constant area.
10130 __ BindPcRelBaseLabel();
10131}
10132
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020010133void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
10134 // The trampoline uses the same calling convention as dex calling conventions,
10135 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
10136 // the method_idx.
10137 HandleInvoke(invoke);
10138}
10139
10140void InstructionCodeGeneratorMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
10141 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
10142}
10143
Roland Levillain2aba7cd2016-02-03 12:27:20 +000010144void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet* instruction) {
10145 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +010010146 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain2aba7cd2016-02-03 12:27:20 +000010147 locations->SetInAt(0, Location::RequiresRegister());
10148 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraya42363f2015-12-17 14:57:09 +000010149}
10150
Roland Levillain2aba7cd2016-02-03 12:27:20 +000010151void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
10152 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +000010153 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +010010154 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Roland Levillain2aba7cd2016-02-03 12:27:20 +000010155 instruction->GetIndex(), kMipsPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +010010156 __ LoadFromOffset(kLoadWord,
10157 locations->Out().AsRegister<Register>(),
10158 locations->InAt(0).AsRegister<Register>(),
10159 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +000010160 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +010010161 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +000010162 instruction->GetIndex(), kMipsPointerSize));
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +000010163 __ LoadFromOffset(kLoadWord,
10164 locations->Out().AsRegister<Register>(),
10165 locations->InAt(0).AsRegister<Register>(),
10166 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
Nicolas Geoffrayff484b92016-07-13 14:13:48 +010010167 __ LoadFromOffset(kLoadWord,
10168 locations->Out().AsRegister<Register>(),
10169 locations->Out().AsRegister<Register>(),
10170 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +000010171 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +000010172}
10173
xueliang.zhonge0eb4832017-10-30 13:43:14 +000010174void LocationsBuilderMIPS::VisitIntermediateAddress(HIntermediateAddress* instruction
10175 ATTRIBUTE_UNUSED) {
10176 LOG(FATAL) << "Unreachable";
10177}
10178
10179void InstructionCodeGeneratorMIPS::VisitIntermediateAddress(HIntermediateAddress* instruction
10180 ATTRIBUTE_UNUSED) {
10181 LOG(FATAL) << "Unreachable";
10182}
10183
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020010184#undef __
10185#undef QUICK_ENTRY_POINT
10186
10187} // namespace mips
10188} // namespace art