blob: 855da2b18f4c161a3b06115b8eba586bd4e207a0 [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"
Andreas Gampe09659c22017-09-18 18:23:32 -070029#include "heap_poisoning.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020030#include "intrinsics.h"
Chris Larsen701566a2015-10-27 15:29:13 -070031#include "intrinsics_mips.h"
Vladimir Markod8dbc8d2017-09-20 13:37:47 +010032#include "linker/linker_patch.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020033#include "mirror/array-inl.h"
34#include "mirror/class-inl.h"
35#include "offsets.h"
Vladimir Marko174b2e22017-10-12 13:34:49 +010036#include "stack_map_stream.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020037#include "thread.h"
38#include "utils/assembler.h"
39#include "utils/mips/assembler_mips.h"
40#include "utils/stack_checks.h"
41
42namespace art {
43namespace mips {
44
45static constexpr int kCurrentMethodStackOffset = 0;
46static constexpr Register kMethodRegisterArgument = A0;
47
Alexey Frunze4147fcc2017-06-17 19:57:27 -070048// Flags controlling the use of thunks for Baker read barriers.
49constexpr bool kBakerReadBarrierThunksEnableForFields = true;
50constexpr bool kBakerReadBarrierThunksEnableForArrays = true;
51constexpr bool kBakerReadBarrierThunksEnableForGcRoots = true;
52
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010053Location MipsReturnLocation(DataType::Type return_type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020054 switch (return_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010055 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010056 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010057 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010058 case DataType::Type::kInt8:
59 case DataType::Type::kUint16:
60 case DataType::Type::kInt16:
Aart Bik66c158e2018-01-31 12:55:04 -080061 case DataType::Type::kUint32:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010062 case DataType::Type::kInt32:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020063 return Location::RegisterLocation(V0);
64
Aart Bik66c158e2018-01-31 12:55:04 -080065 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010066 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020067 return Location::RegisterPairLocation(V0, V1);
68
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010069 case DataType::Type::kFloat32:
70 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020071 return Location::FpuRegisterLocation(F0);
72
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010073 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020074 return Location();
75 }
76 UNREACHABLE();
77}
78
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010079Location InvokeDexCallingConventionVisitorMIPS::GetReturnLocation(DataType::Type type) const {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020080 return MipsReturnLocation(type);
81}
82
83Location InvokeDexCallingConventionVisitorMIPS::GetMethodLocation() const {
84 return Location::RegisterLocation(kMethodRegisterArgument);
85}
86
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010087Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(DataType::Type type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020088 Location next_location;
89
90 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010091 case DataType::Type::kReference:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010092 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010093 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +010094 case DataType::Type::kInt8:
95 case DataType::Type::kUint16:
96 case DataType::Type::kInt16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +010097 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020098 uint32_t gp_index = gp_index_++;
99 if (gp_index < calling_convention.GetNumberOfRegisters()) {
100 next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index));
101 } else {
102 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
103 next_location = Location::StackSlot(stack_offset);
104 }
105 break;
106 }
107
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100108 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200109 uint32_t gp_index = gp_index_;
110 gp_index_ += 2;
111 if (gp_index + 1 < calling_convention.GetNumberOfRegisters()) {
Alexey Frunze1b8464d2016-11-12 17:22:05 -0800112 Register reg = calling_convention.GetRegisterAt(gp_index);
113 if (reg == A1 || reg == A3) {
114 gp_index_++; // Skip A1(A3), and use A2_A3(T0_T1) instead.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200115 gp_index++;
116 }
117 Register low_even = calling_convention.GetRegisterAt(gp_index);
118 Register high_odd = calling_convention.GetRegisterAt(gp_index + 1);
119 DCHECK_EQ(low_even + 1, high_odd);
120 next_location = Location::RegisterPairLocation(low_even, high_odd);
121 } else {
122 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
123 next_location = Location::DoubleStackSlot(stack_offset);
124 }
125 break;
126 }
127
128 // Note: both float and double types are stored in even FPU registers. On 32 bit FPU, double
129 // will take up the even/odd pair, while floats are stored in even regs only.
130 // On 64 bit FPU, both double and float are stored in even registers only.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100131 case DataType::Type::kFloat32:
132 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200133 uint32_t float_index = float_index_++;
134 if (float_index < calling_convention.GetNumberOfFpuRegisters()) {
135 next_location = Location::FpuRegisterLocation(
136 calling_convention.GetFpuRegisterAt(float_index));
137 } else {
138 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100139 next_location = DataType::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
140 : Location::StackSlot(stack_offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200141 }
142 break;
143 }
144
Aart Bik66c158e2018-01-31 12:55:04 -0800145 case DataType::Type::kUint32:
146 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100147 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200148 LOG(FATAL) << "Unexpected parameter type " << type;
149 break;
150 }
151
152 // Space on the stack is reserved for all arguments.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100153 stack_index_ += DataType::Is64BitType(type) ? 2 : 1;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200154
155 return next_location;
156}
157
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100158Location InvokeRuntimeCallingConvention::GetReturnLocation(DataType::Type type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200159 return MipsReturnLocation(type);
160}
161
Roland Levillain7cbd27f2016-08-11 23:53:33 +0100162// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
163#define __ down_cast<CodeGeneratorMIPS*>(codegen)->GetAssembler()-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -0700164#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200165
166class BoundsCheckSlowPathMIPS : public SlowPathCodeMIPS {
167 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000168 explicit BoundsCheckSlowPathMIPS(HBoundsCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200169
170 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
171 LocationSummary* locations = instruction_->GetLocations();
172 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
173 __ Bind(GetEntryLabel());
174 if (instruction_->CanThrowIntoCatchBlock()) {
175 // Live registers will be restored in the catch block if caught.
176 SaveLiveRegisters(codegen, instruction_->GetLocations());
177 }
178 // We're moving two locations to locations that could overlap, so we need a parallel
179 // move resolver.
180 InvokeRuntimeCallingConvention calling_convention;
181 codegen->EmitParallelMoves(locations->InAt(0),
182 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100183 DataType::Type::kInt32,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200184 locations->InAt(1),
185 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100186 DataType::Type::kInt32);
Serban Constantinescufca16662016-07-14 09:21:59 +0100187 QuickEntrypointEnum entrypoint = instruction_->AsBoundsCheck()->IsStringCharAt()
188 ? kQuickThrowStringBounds
189 : kQuickThrowArrayBounds;
190 mips_codegen->InvokeRuntime(entrypoint, instruction_, instruction_->GetDexPc(), this);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +0100191 CheckEntrypointTypes<kQuickThrowStringBounds, void, int32_t, int32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200192 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
193 }
194
195 bool IsFatal() const OVERRIDE { return true; }
196
197 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS"; }
198
199 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200200 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathMIPS);
201};
202
203class DivZeroCheckSlowPathMIPS : public SlowPathCodeMIPS {
204 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000205 explicit DivZeroCheckSlowPathMIPS(HDivZeroCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200206
207 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
208 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
209 __ Bind(GetEntryLabel());
Serban Constantinescufca16662016-07-14 09:21:59 +0100210 mips_codegen->InvokeRuntime(kQuickThrowDivZero, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200211 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
212 }
213
214 bool IsFatal() const OVERRIDE { return true; }
215
216 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS"; }
217
218 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200219 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS);
220};
221
222class LoadClassSlowPathMIPS : public SlowPathCodeMIPS {
223 public:
224 LoadClassSlowPathMIPS(HLoadClass* cls,
225 HInstruction* at,
226 uint32_t dex_pc,
Vladimir Markof3c52b42017-11-17 17:32:12 +0000227 bool do_clinit)
Alexey Frunze5fa5c042017-06-01 21:07:52 -0700228 : SlowPathCodeMIPS(at),
229 cls_(cls),
230 dex_pc_(dex_pc),
Vladimir Markof3c52b42017-11-17 17:32:12 +0000231 do_clinit_(do_clinit) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200232 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
233 }
234
235 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000236 LocationSummary* locations = instruction_->GetLocations();
Alexey Frunzec61c0762017-04-10 13:54:23 -0700237 Location out = locations->Out();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200238 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Alexey Frunzec61c0762017-04-10 13:54:23 -0700239 InvokeRuntimeCallingConvention calling_convention;
240 DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200241 __ Bind(GetEntryLabel());
242 SaveLiveRegisters(codegen, locations);
243
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000244 dex::TypeIndex type_index = cls_->GetTypeIndex();
245 __ LoadConst32(calling_convention.GetRegisterAt(0), type_index.index_);
Serban Constantinescufca16662016-07-14 09:21:59 +0100246 QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
247 : kQuickInitializeType;
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000248 mips_codegen->InvokeRuntime(entrypoint, instruction_, dex_pc_, this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200249 if (do_clinit_) {
250 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
251 } else {
252 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
253 }
254
255 // Move the class to the desired location.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200256 if (out.IsValid()) {
257 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100258 DataType::Type type = instruction_->GetType();
Alexey Frunzec61c0762017-04-10 13:54:23 -0700259 mips_codegen->MoveLocation(out,
260 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
261 type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200262 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200263 RestoreLiveRegisters(codegen, locations);
Alexey Frunzec61c0762017-04-10 13:54:23 -0700264
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200265 __ B(GetExitLabel());
266 }
267
268 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathMIPS"; }
269
270 private:
271 // The class this slow path will load.
272 HLoadClass* const cls_;
273
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200274 // The dex PC of `at_`.
275 const uint32_t dex_pc_;
276
277 // Whether to initialize the class.
278 const bool do_clinit_;
279
280 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS);
281};
282
283class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
284 public:
Vladimir Markof3c52b42017-11-17 17:32:12 +0000285 explicit LoadStringSlowPathMIPS(HLoadString* instruction)
286 : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200287
288 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Alexey Frunzec61c0762017-04-10 13:54:23 -0700289 DCHECK(instruction_->IsLoadString());
290 DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200291 LocationSummary* locations = instruction_->GetLocations();
292 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Vladimir Markof3c52b42017-11-17 17:32:12 +0000293 const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200294 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Alexey Frunzec61c0762017-04-10 13:54:23 -0700295 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200296 __ Bind(GetEntryLabel());
297 SaveLiveRegisters(codegen, locations);
298
Vladimir Marko6bec91c2017-01-09 15:03:12 +0000299 __ LoadConst32(calling_convention.GetRegisterAt(0), string_index.index_);
Serban Constantinescufca16662016-07-14 09:21:59 +0100300 mips_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200301 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Alexey Frunzec61c0762017-04-10 13:54:23 -0700302
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100303 DataType::Type type = instruction_->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200304 mips_codegen->MoveLocation(locations->Out(),
Alexey Frunzec61c0762017-04-10 13:54:23 -0700305 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200306 type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200307 RestoreLiveRegisters(codegen, locations);
Vladimir Markoaad75c62016-10-03 08:46:48 +0000308
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200309 __ B(GetExitLabel());
310 }
311
312 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
313
314 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200315 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
316};
317
318class NullCheckSlowPathMIPS : public SlowPathCodeMIPS {
319 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000320 explicit NullCheckSlowPathMIPS(HNullCheck* instr) : SlowPathCodeMIPS(instr) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200321
322 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
323 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
324 __ Bind(GetEntryLabel());
325 if (instruction_->CanThrowIntoCatchBlock()) {
326 // Live registers will be restored in the catch block if caught.
327 SaveLiveRegisters(codegen, instruction_->GetLocations());
328 }
Serban Constantinescufca16662016-07-14 09:21:59 +0100329 mips_codegen->InvokeRuntime(kQuickThrowNullPointer,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200330 instruction_,
331 instruction_->GetDexPc(),
Serban Constantinescufca16662016-07-14 09:21:59 +0100332 this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200333 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
334 }
335
336 bool IsFatal() const OVERRIDE { return true; }
337
338 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS"; }
339
340 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200341 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathMIPS);
342};
343
344class SuspendCheckSlowPathMIPS : public SlowPathCodeMIPS {
345 public:
346 SuspendCheckSlowPathMIPS(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000347 : SlowPathCodeMIPS(instruction), successor_(successor) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200348
349 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Lena Djokicca8c2952017-05-29 11:31:46 +0200350 LocationSummary* locations = instruction_->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200351 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
352 __ Bind(GetEntryLabel());
Lena Djokicca8c2952017-05-29 11:31:46 +0200353 SaveLiveRegisters(codegen, locations); // Only saves live vector registers for SIMD.
Serban Constantinescufca16662016-07-14 09:21:59 +0100354 mips_codegen->InvokeRuntime(kQuickTestSuspend, instruction_, instruction_->GetDexPc(), this);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200355 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
Lena Djokicca8c2952017-05-29 11:31:46 +0200356 RestoreLiveRegisters(codegen, locations); // Only restores live vector registers for SIMD.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200357 if (successor_ == nullptr) {
358 __ B(GetReturnLabel());
359 } else {
360 __ B(mips_codegen->GetLabelOf(successor_));
361 }
362 }
363
364 MipsLabel* GetReturnLabel() {
365 DCHECK(successor_ == nullptr);
366 return &return_label_;
367 }
368
369 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS"; }
370
Chris Larsena2045912017-11-02 12:39:54 -0700371 HBasicBlock* GetSuccessor() const {
372 return successor_;
373 }
374
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200375 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200376 // If not null, the block to branch to after the suspend check.
377 HBasicBlock* const successor_;
378
379 // If `successor_` is null, the label to branch to after the suspend check.
380 MipsLabel return_label_;
381
382 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathMIPS);
383};
384
385class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS {
386 public:
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800387 explicit TypeCheckSlowPathMIPS(HInstruction* instruction, bool is_fatal)
388 : SlowPathCodeMIPS(instruction), is_fatal_(is_fatal) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200389
390 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
391 LocationSummary* locations = instruction_->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200392 uint32_t dex_pc = instruction_->GetDexPc();
393 DCHECK(instruction_->IsCheckCast()
394 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
395 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
396
397 __ Bind(GetEntryLabel());
Alexey Frunzedfc30af2018-01-24 16:25:10 -0800398 if (!is_fatal_ || instruction_->CanThrowIntoCatchBlock()) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800399 SaveLiveRegisters(codegen, locations);
400 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200401
402 // We're moving two locations to locations that could overlap, so we need a parallel
403 // move resolver.
404 InvokeRuntimeCallingConvention calling_convention;
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800405 codegen->EmitParallelMoves(locations->InAt(0),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200406 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100407 DataType::Type::kReference,
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800408 locations->InAt(1),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200409 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100410 DataType::Type::kReference);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200411 if (instruction_->IsInstanceOf()) {
Serban Constantinescufca16662016-07-14 09:21:59 +0100412 mips_codegen->InvokeRuntime(kQuickInstanceofNonTrivial, instruction_, dex_pc, this);
Mathieu Chartier9fd8c602016-11-14 14:38:53 -0800413 CheckEntrypointTypes<kQuickInstanceofNonTrivial, size_t, mirror::Object*, mirror::Class*>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100414 DataType::Type ret_type = instruction_->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200415 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
416 mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200417 } else {
418 DCHECK(instruction_->IsCheckCast());
Mathieu Chartierb99f4d62016-11-07 16:17:26 -0800419 mips_codegen->InvokeRuntime(kQuickCheckInstanceOf, instruction_, dex_pc, this);
420 CheckEntrypointTypes<kQuickCheckInstanceOf, void, mirror::Object*, mirror::Class*>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200421 }
422
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800423 if (!is_fatal_) {
424 RestoreLiveRegisters(codegen, locations);
425 __ B(GetExitLabel());
426 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200427 }
428
429 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS"; }
430
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800431 bool IsFatal() const OVERRIDE { return is_fatal_; }
432
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200433 private:
Alexey Frunze66b69ad2017-02-24 00:51:44 -0800434 const bool is_fatal_;
435
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200436 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathMIPS);
437};
438
439class DeoptimizationSlowPathMIPS : public SlowPathCodeMIPS {
440 public:
Aart Bik42249c32016-01-07 15:33:50 -0800441 explicit DeoptimizationSlowPathMIPS(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000442 : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200443
444 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800445 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200446 __ Bind(GetEntryLabel());
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100447 LocationSummary* locations = instruction_->GetLocations();
448 SaveLiveRegisters(codegen, locations);
449 InvokeRuntimeCallingConvention calling_convention;
450 __ LoadConst32(calling_convention.GetRegisterAt(0),
451 static_cast<uint32_t>(instruction_->AsDeoptimize()->GetDeoptimizationKind()));
Serban Constantinescufca16662016-07-14 09:21:59 +0100452 mips_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +0100453 CheckEntrypointTypes<kQuickDeoptimize, void, DeoptimizationKind>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200454 }
455
456 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS"; }
457
458 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200459 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS);
460};
461
Alexey Frunze15958152017-02-09 19:08:30 -0800462class ArraySetSlowPathMIPS : public SlowPathCodeMIPS {
463 public:
464 explicit ArraySetSlowPathMIPS(HInstruction* instruction) : SlowPathCodeMIPS(instruction) {}
465
466 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
467 LocationSummary* locations = instruction_->GetLocations();
468 __ Bind(GetEntryLabel());
469 SaveLiveRegisters(codegen, locations);
470
471 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100472 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Alexey Frunze15958152017-02-09 19:08:30 -0800473 parallel_move.AddMove(
474 locations->InAt(0),
475 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100476 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800477 nullptr);
478 parallel_move.AddMove(
479 locations->InAt(1),
480 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100481 DataType::Type::kInt32,
Alexey Frunze15958152017-02-09 19:08:30 -0800482 nullptr);
483 parallel_move.AddMove(
484 locations->InAt(2),
485 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100486 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800487 nullptr);
488 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
489
490 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
491 mips_codegen->InvokeRuntime(kQuickAputObject, instruction_, instruction_->GetDexPc(), this);
492 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
493 RestoreLiveRegisters(codegen, locations);
494 __ B(GetExitLabel());
495 }
496
497 const char* GetDescription() const OVERRIDE { return "ArraySetSlowPathMIPS"; }
498
499 private:
500 DISALLOW_COPY_AND_ASSIGN(ArraySetSlowPathMIPS);
501};
502
503// Slow path marking an object reference `ref` during a read
504// barrier. The field `obj.field` in the object `obj` holding this
505// reference does not get updated by this slow path after marking (see
506// ReadBarrierMarkAndUpdateFieldSlowPathMIPS below for that).
507//
508// This means that after the execution of this slow path, `ref` will
509// always be up-to-date, but `obj.field` may not; i.e., after the
510// flip, `ref` will be a to-space reference, but `obj.field` will
511// probably still be a from-space reference (unless it gets updated by
512// another thread, or if another thread installed another object
513// reference (different from `ref`) in `obj.field`).
514//
515// If `entrypoint` is a valid location it is assumed to already be
516// holding the entrypoint. The case where the entrypoint is passed in
517// is for the GcRoot read barrier.
518class ReadBarrierMarkSlowPathMIPS : public SlowPathCodeMIPS {
519 public:
520 ReadBarrierMarkSlowPathMIPS(HInstruction* instruction,
521 Location ref,
522 Location entrypoint = Location::NoLocation())
523 : SlowPathCodeMIPS(instruction), ref_(ref), entrypoint_(entrypoint) {
524 DCHECK(kEmitCompilerReadBarrier);
525 }
526
527 const char* GetDescription() const OVERRIDE { return "ReadBarrierMarkSlowPathMIPS"; }
528
529 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
530 LocationSummary* locations = instruction_->GetLocations();
531 Register ref_reg = ref_.AsRegister<Register>();
532 DCHECK(locations->CanCall());
533 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
534 DCHECK(instruction_->IsInstanceFieldGet() ||
535 instruction_->IsStaticFieldGet() ||
536 instruction_->IsArrayGet() ||
537 instruction_->IsArraySet() ||
538 instruction_->IsLoadClass() ||
539 instruction_->IsLoadString() ||
540 instruction_->IsInstanceOf() ||
541 instruction_->IsCheckCast() ||
542 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()) ||
543 (instruction_->IsInvokeStaticOrDirect() && instruction_->GetLocations()->Intrinsified()))
544 << "Unexpected instruction in read barrier marking slow path: "
545 << instruction_->DebugName();
546
547 __ Bind(GetEntryLabel());
548 // No need to save live registers; it's taken care of by the
549 // entrypoint. Also, there is no need to update the stack mask,
550 // as this runtime call will not trigger a garbage collection.
551 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
552 DCHECK((V0 <= ref_reg && ref_reg <= T7) ||
553 (S2 <= ref_reg && ref_reg <= S7) ||
554 (ref_reg == FP)) << ref_reg;
555 // "Compact" slow path, saving two moves.
556 //
557 // Instead of using the standard runtime calling convention (input
558 // and output in A0 and V0 respectively):
559 //
560 // A0 <- ref
561 // V0 <- ReadBarrierMark(A0)
562 // ref <- V0
563 //
564 // we just use rX (the register containing `ref`) as input and output
565 // of a dedicated entrypoint:
566 //
567 // rX <- ReadBarrierMarkRegX(rX)
568 //
569 if (entrypoint_.IsValid()) {
570 mips_codegen->ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction_, this);
571 DCHECK_EQ(entrypoint_.AsRegister<Register>(), T9);
572 __ Jalr(entrypoint_.AsRegister<Register>());
573 __ NopIfNoReordering();
574 } else {
575 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100576 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(ref_reg - 1);
Alexey Frunze15958152017-02-09 19:08:30 -0800577 // This runtime call does not require a stack map.
578 mips_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
579 instruction_,
580 this,
581 /* direct */ false);
582 }
583 __ B(GetExitLabel());
584 }
585
586 private:
587 // The location (register) of the marked object reference.
588 const Location ref_;
589
590 // The location of the entrypoint if already loaded.
591 const Location entrypoint_;
592
593 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkSlowPathMIPS);
594};
595
596// Slow path marking an object reference `ref` during a read barrier,
597// and if needed, atomically updating the field `obj.field` in the
598// object `obj` holding this reference after marking (contrary to
599// ReadBarrierMarkSlowPathMIPS above, which never tries to update
600// `obj.field`).
601//
602// This means that after the execution of this slow path, both `ref`
603// and `obj.field` will be up-to-date; i.e., after the flip, both will
604// hold the same to-space reference (unless another thread installed
605// another object reference (different from `ref`) in `obj.field`).
606class ReadBarrierMarkAndUpdateFieldSlowPathMIPS : public SlowPathCodeMIPS {
607 public:
608 ReadBarrierMarkAndUpdateFieldSlowPathMIPS(HInstruction* instruction,
609 Location ref,
610 Register obj,
611 Location field_offset,
612 Register temp1)
613 : SlowPathCodeMIPS(instruction),
614 ref_(ref),
615 obj_(obj),
616 field_offset_(field_offset),
617 temp1_(temp1) {
618 DCHECK(kEmitCompilerReadBarrier);
619 }
620
621 const char* GetDescription() const OVERRIDE {
622 return "ReadBarrierMarkAndUpdateFieldSlowPathMIPS";
623 }
624
625 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
626 LocationSummary* locations = instruction_->GetLocations();
627 Register ref_reg = ref_.AsRegister<Register>();
628 DCHECK(locations->CanCall());
629 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(ref_reg)) << ref_reg;
630 // This slow path is only used by the UnsafeCASObject intrinsic.
631 DCHECK((instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
632 << "Unexpected instruction in read barrier marking and field updating slow path: "
633 << instruction_->DebugName();
634 DCHECK(instruction_->GetLocations()->Intrinsified());
635 DCHECK_EQ(instruction_->AsInvoke()->GetIntrinsic(), Intrinsics::kUnsafeCASObject);
636 DCHECK(field_offset_.IsRegisterPair()) << field_offset_;
637
638 __ Bind(GetEntryLabel());
639
640 // Save the old reference.
641 // Note that we cannot use AT or TMP to save the old reference, as those
642 // are used by the code that follows, but we need the old reference after
643 // the call to the ReadBarrierMarkRegX entry point.
644 DCHECK_NE(temp1_, AT);
645 DCHECK_NE(temp1_, TMP);
646 __ Move(temp1_, ref_reg);
647
648 // No need to save live registers; it's taken care of by the
649 // entrypoint. Also, there is no need to update the stack mask,
650 // as this runtime call will not trigger a garbage collection.
651 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
652 DCHECK((V0 <= ref_reg && ref_reg <= T7) ||
653 (S2 <= ref_reg && ref_reg <= S7) ||
654 (ref_reg == FP)) << ref_reg;
655 // "Compact" slow path, saving two moves.
656 //
657 // Instead of using the standard runtime calling convention (input
658 // and output in A0 and V0 respectively):
659 //
660 // A0 <- ref
661 // V0 <- ReadBarrierMark(A0)
662 // ref <- V0
663 //
664 // we just use rX (the register containing `ref`) as input and output
665 // of a dedicated entrypoint:
666 //
667 // rX <- ReadBarrierMarkRegX(rX)
668 //
669 int32_t entry_point_offset =
Roland Levillain97c46462017-05-11 14:04:03 +0100670 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(ref_reg - 1);
Alexey Frunze15958152017-02-09 19:08:30 -0800671 // This runtime call does not require a stack map.
672 mips_codegen->InvokeRuntimeWithoutRecordingPcInfo(entry_point_offset,
673 instruction_,
674 this,
675 /* direct */ false);
676
677 // If the new reference is different from the old reference,
678 // update the field in the holder (`*(obj_ + field_offset_)`).
679 //
680 // Note that this field could also hold a different object, if
681 // another thread had concurrently changed it. In that case, the
682 // the compare-and-set (CAS) loop below would abort, leaving the
683 // field as-is.
684 MipsLabel done;
685 __ Beq(temp1_, ref_reg, &done);
686
687 // Update the the holder's field atomically. This may fail if
688 // mutator updates before us, but it's OK. This is achieved
689 // using a strong compare-and-set (CAS) operation with relaxed
690 // memory synchronization ordering, where the expected value is
691 // the old reference and the desired value is the new reference.
692
693 // Convenience aliases.
694 Register base = obj_;
695 // The UnsafeCASObject intrinsic uses a register pair as field
696 // offset ("long offset"), of which only the low part contains
697 // data.
698 Register offset = field_offset_.AsRegisterPairLow<Register>();
699 Register expected = temp1_;
700 Register value = ref_reg;
701 Register tmp_ptr = TMP; // Pointer to actual memory.
702 Register tmp = AT; // Value in memory.
703
704 __ Addu(tmp_ptr, base, offset);
705
706 if (kPoisonHeapReferences) {
707 __ PoisonHeapReference(expected);
708 // Do not poison `value` if it is the same register as
709 // `expected`, which has just been poisoned.
710 if (value != expected) {
711 __ PoisonHeapReference(value);
712 }
713 }
714
715 // do {
716 // tmp = [r_ptr] - expected;
717 // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
718
719 bool is_r6 = mips_codegen->GetInstructionSetFeatures().IsR6();
720 MipsLabel loop_head, exit_loop;
721 __ Bind(&loop_head);
722 if (is_r6) {
723 __ LlR6(tmp, tmp_ptr);
724 } else {
725 __ LlR2(tmp, tmp_ptr);
726 }
727 __ Bne(tmp, expected, &exit_loop);
728 __ Move(tmp, value);
729 if (is_r6) {
730 __ ScR6(tmp, tmp_ptr);
731 } else {
732 __ ScR2(tmp, tmp_ptr);
733 }
734 __ Beqz(tmp, &loop_head);
735 __ Bind(&exit_loop);
736
737 if (kPoisonHeapReferences) {
738 __ UnpoisonHeapReference(expected);
739 // Do not unpoison `value` if it is the same register as
740 // `expected`, which has just been unpoisoned.
741 if (value != expected) {
742 __ UnpoisonHeapReference(value);
743 }
744 }
745
746 __ Bind(&done);
747 __ B(GetExitLabel());
748 }
749
750 private:
751 // The location (register) of the marked object reference.
752 const Location ref_;
753 // The register containing the object holding the marked object reference field.
754 const Register obj_;
755 // The location of the offset of the marked reference field within `obj_`.
756 Location field_offset_;
757
758 const Register temp1_;
759
760 DISALLOW_COPY_AND_ASSIGN(ReadBarrierMarkAndUpdateFieldSlowPathMIPS);
761};
762
763// Slow path generating a read barrier for a heap reference.
764class ReadBarrierForHeapReferenceSlowPathMIPS : public SlowPathCodeMIPS {
765 public:
766 ReadBarrierForHeapReferenceSlowPathMIPS(HInstruction* instruction,
767 Location out,
768 Location ref,
769 Location obj,
770 uint32_t offset,
771 Location index)
772 : SlowPathCodeMIPS(instruction),
773 out_(out),
774 ref_(ref),
775 obj_(obj),
776 offset_(offset),
777 index_(index) {
778 DCHECK(kEmitCompilerReadBarrier);
779 // If `obj` is equal to `out` or `ref`, it means the initial object
780 // has been overwritten by (or after) the heap object reference load
781 // to be instrumented, e.g.:
782 //
783 // __ LoadFromOffset(kLoadWord, out, out, offset);
784 // codegen_->GenerateReadBarrierSlow(instruction, out_loc, out_loc, out_loc, offset);
785 //
786 // In that case, we have lost the information about the original
787 // object, and the emitted read barrier cannot work properly.
788 DCHECK(!obj.Equals(out)) << "obj=" << obj << " out=" << out;
789 DCHECK(!obj.Equals(ref)) << "obj=" << obj << " ref=" << ref;
790 }
791
792 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
793 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
794 LocationSummary* locations = instruction_->GetLocations();
795 Register reg_out = out_.AsRegister<Register>();
796 DCHECK(locations->CanCall());
797 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
798 DCHECK(instruction_->IsInstanceFieldGet() ||
799 instruction_->IsStaticFieldGet() ||
800 instruction_->IsArrayGet() ||
801 instruction_->IsInstanceOf() ||
802 instruction_->IsCheckCast() ||
803 (instruction_->IsInvokeVirtual() && instruction_->GetLocations()->Intrinsified()))
804 << "Unexpected instruction in read barrier for heap reference slow path: "
805 << instruction_->DebugName();
806
807 __ Bind(GetEntryLabel());
808 SaveLiveRegisters(codegen, locations);
809
810 // We may have to change the index's value, but as `index_` is a
811 // constant member (like other "inputs" of this slow path),
812 // introduce a copy of it, `index`.
813 Location index = index_;
814 if (index_.IsValid()) {
815 // Handle `index_` for HArrayGet and UnsafeGetObject/UnsafeGetObjectVolatile intrinsics.
816 if (instruction_->IsArrayGet()) {
817 // Compute the actual memory offset and store it in `index`.
818 Register index_reg = index_.AsRegister<Register>();
819 DCHECK(locations->GetLiveRegisters()->ContainsCoreRegister(index_reg));
820 if (codegen->IsCoreCalleeSaveRegister(index_reg)) {
821 // We are about to change the value of `index_reg` (see the
822 // calls to art::mips::MipsAssembler::Sll and
823 // art::mips::MipsAssembler::Addiu32 below), but it has
824 // not been saved by the previous call to
825 // art::SlowPathCode::SaveLiveRegisters, as it is a
826 // callee-save register --
827 // art::SlowPathCode::SaveLiveRegisters does not consider
828 // callee-save registers, as it has been designed with the
829 // assumption that callee-save registers are supposed to be
830 // handled by the called function. So, as a callee-save
831 // register, `index_reg` _would_ eventually be saved onto
832 // the stack, but it would be too late: we would have
833 // changed its value earlier. Therefore, we manually save
834 // it here into another freely available register,
835 // `free_reg`, chosen of course among the caller-save
836 // registers (as a callee-save `free_reg` register would
837 // exhibit the same problem).
838 //
839 // Note we could have requested a temporary register from
840 // the register allocator instead; but we prefer not to, as
841 // this is a slow path, and we know we can find a
842 // caller-save register that is available.
843 Register free_reg = FindAvailableCallerSaveRegister(codegen);
844 __ Move(free_reg, index_reg);
845 index_reg = free_reg;
846 index = Location::RegisterLocation(index_reg);
847 } else {
848 // The initial register stored in `index_` has already been
849 // saved in the call to art::SlowPathCode::SaveLiveRegisters
850 // (as it is not a callee-save register), so we can freely
851 // use it.
852 }
853 // Shifting the index value contained in `index_reg` by the scale
854 // factor (2) cannot overflow in practice, as the runtime is
855 // unable to allocate object arrays with a size larger than
856 // 2^26 - 1 (that is, 2^28 - 4 bytes).
857 __ Sll(index_reg, index_reg, TIMES_4);
858 static_assert(
859 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
860 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
861 __ Addiu32(index_reg, index_reg, offset_);
862 } else {
863 // In the case of the UnsafeGetObject/UnsafeGetObjectVolatile
864 // intrinsics, `index_` is not shifted by a scale factor of 2
865 // (as in the case of ArrayGet), as it is actually an offset
866 // to an object field within an object.
867 DCHECK(instruction_->IsInvoke()) << instruction_->DebugName();
868 DCHECK(instruction_->GetLocations()->Intrinsified());
869 DCHECK((instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObject) ||
870 (instruction_->AsInvoke()->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile))
871 << instruction_->AsInvoke()->GetIntrinsic();
872 DCHECK_EQ(offset_, 0U);
873 DCHECK(index_.IsRegisterPair());
874 // UnsafeGet's offset location is a register pair, the low
875 // part contains the correct offset.
876 index = index_.ToLow();
877 }
878 }
879
880 // We're moving two or three locations to locations that could
881 // overlap, so we need a parallel move resolver.
882 InvokeRuntimeCallingConvention calling_convention;
Vladimir Markoca6fff82017-10-03 14:49:14 +0100883 HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
Alexey Frunze15958152017-02-09 19:08:30 -0800884 parallel_move.AddMove(ref_,
885 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100886 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800887 nullptr);
888 parallel_move.AddMove(obj_,
889 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100890 DataType::Type::kReference,
Alexey Frunze15958152017-02-09 19:08:30 -0800891 nullptr);
892 if (index.IsValid()) {
893 parallel_move.AddMove(index,
894 Location::RegisterLocation(calling_convention.GetRegisterAt(2)),
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100895 DataType::Type::kInt32,
Alexey Frunze15958152017-02-09 19:08:30 -0800896 nullptr);
897 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
898 } else {
899 codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
900 __ LoadConst32(calling_convention.GetRegisterAt(2), offset_);
901 }
902 mips_codegen->InvokeRuntime(kQuickReadBarrierSlow,
903 instruction_,
904 instruction_->GetDexPc(),
905 this);
906 CheckEntrypointTypes<
907 kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
Lena Djokic8098da92017-06-28 12:07:50 +0200908 mips_codegen->MoveLocation(out_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100909 calling_convention.GetReturnLocation(DataType::Type::kReference),
910 DataType::Type::kReference);
Alexey Frunze15958152017-02-09 19:08:30 -0800911
912 RestoreLiveRegisters(codegen, locations);
913 __ B(GetExitLabel());
914 }
915
916 const char* GetDescription() const OVERRIDE { return "ReadBarrierForHeapReferenceSlowPathMIPS"; }
917
918 private:
919 Register FindAvailableCallerSaveRegister(CodeGenerator* codegen) {
920 size_t ref = static_cast<int>(ref_.AsRegister<Register>());
921 size_t obj = static_cast<int>(obj_.AsRegister<Register>());
922 for (size_t i = 0, e = codegen->GetNumberOfCoreRegisters(); i < e; ++i) {
923 if (i != ref &&
924 i != obj &&
925 !codegen->IsCoreCalleeSaveRegister(i) &&
926 !codegen->IsBlockedCoreRegister(i)) {
927 return static_cast<Register>(i);
928 }
929 }
930 // We shall never fail to find a free caller-save register, as
931 // there are more than two core caller-save registers on MIPS
932 // (meaning it is possible to find one which is different from
933 // `ref` and `obj`).
934 DCHECK_GT(codegen->GetNumberOfCoreCallerSaveRegisters(), 2u);
935 LOG(FATAL) << "Could not find a free caller-save register";
936 UNREACHABLE();
937 }
938
939 const Location out_;
940 const Location ref_;
941 const Location obj_;
942 const uint32_t offset_;
943 // An additional location containing an index to an array.
944 // Only used for HArrayGet and the UnsafeGetObject &
945 // UnsafeGetObjectVolatile intrinsics.
946 const Location index_;
947
948 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForHeapReferenceSlowPathMIPS);
949};
950
951// Slow path generating a read barrier for a GC root.
952class ReadBarrierForRootSlowPathMIPS : public SlowPathCodeMIPS {
953 public:
954 ReadBarrierForRootSlowPathMIPS(HInstruction* instruction, Location out, Location root)
955 : SlowPathCodeMIPS(instruction), out_(out), root_(root) {
956 DCHECK(kEmitCompilerReadBarrier);
957 }
958
959 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
960 LocationSummary* locations = instruction_->GetLocations();
961 Register reg_out = out_.AsRegister<Register>();
962 DCHECK(locations->CanCall());
963 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg_out));
964 DCHECK(instruction_->IsLoadClass() || instruction_->IsLoadString())
965 << "Unexpected instruction in read barrier for GC root slow path: "
966 << instruction_->DebugName();
967
968 __ Bind(GetEntryLabel());
969 SaveLiveRegisters(codegen, locations);
970
971 InvokeRuntimeCallingConvention calling_convention;
972 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Lena Djokic8098da92017-06-28 12:07:50 +0200973 mips_codegen->MoveLocation(Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
974 root_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100975 DataType::Type::kReference);
Alexey Frunze15958152017-02-09 19:08:30 -0800976 mips_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
977 instruction_,
978 instruction_->GetDexPc(),
979 this);
980 CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
Lena Djokic8098da92017-06-28 12:07:50 +0200981 mips_codegen->MoveLocation(out_,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +0100982 calling_convention.GetReturnLocation(DataType::Type::kReference),
983 DataType::Type::kReference);
Alexey Frunze15958152017-02-09 19:08:30 -0800984
985 RestoreLiveRegisters(codegen, locations);
986 __ B(GetExitLabel());
987 }
988
989 const char* GetDescription() const OVERRIDE { return "ReadBarrierForRootSlowPathMIPS"; }
990
991 private:
992 const Location out_;
993 const Location root_;
994
995 DISALLOW_COPY_AND_ASSIGN(ReadBarrierForRootSlowPathMIPS);
996};
997
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200998CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph,
999 const MipsInstructionSetFeatures& isa_features,
1000 const CompilerOptions& compiler_options,
1001 OptimizingCompilerStats* stats)
1002 : CodeGenerator(graph,
1003 kNumberOfCoreRegisters,
1004 kNumberOfFRegisters,
1005 kNumberOfRegisterPairs,
1006 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
1007 arraysize(kCoreCalleeSaves)),
1008 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
1009 arraysize(kFpuCalleeSaves)),
1010 compiler_options,
1011 stats),
1012 block_labels_(nullptr),
1013 location_builder_(graph, this),
1014 instruction_visitor_(graph, this),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001015 move_resolver_(graph->GetAllocator(), this),
1016 assembler_(graph->GetAllocator(), &isa_features),
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001017 isa_features_(isa_features),
Alexey Frunze06a46c42016-07-19 15:00:40 -07001018 uint32_literals_(std::less<uint32_t>(),
Vladimir Markoca6fff82017-10-03 14:49:14 +01001019 graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1020 pc_relative_method_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1021 method_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1022 pc_relative_type_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1023 type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1024 pc_relative_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1025 string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1026 jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
1027 jit_class_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
Alexey Frunze06a46c42016-07-19 15:00:40 -07001028 clobbered_ra_(false) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001029 // Save RA (containing the return address) to mimic Quick.
1030 AddAllocatedRegister(Location::RegisterLocation(RA));
1031}
1032
1033#undef __
Roland Levillain7cbd27f2016-08-11 23:53:33 +01001034// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
1035#define __ down_cast<MipsAssembler*>(GetAssembler())-> // NOLINT
Andreas Gampe542451c2016-07-26 09:02:02 -07001036#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsPointerSize, x).Int32Value()
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001037
1038void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) {
1039 // Ensure that we fix up branches.
1040 __ FinalizeCode();
1041
1042 // Adjust native pc offsets in stack maps.
Vladimir Marko174b2e22017-10-12 13:34:49 +01001043 StackMapStream* stack_map_stream = GetStackMapStream();
1044 for (size_t i = 0, num = stack_map_stream->GetNumberOfStackMaps(); i != num; ++i) {
Mathieu Chartiera2f526f2017-01-19 14:48:48 -08001045 uint32_t old_position =
Vladimir Marko33bff252017-11-01 14:35:42 +00001046 stack_map_stream->GetStackMap(i).native_pc_code_offset.Uint32Value(InstructionSet::kMips);
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()) {
1284 LOG(WARNING) << "Unimplemented hotness update in mips backend";
1285 }
1286
Vladimir Marko33bff252017-11-01 14:35:42 +00001287 bool do_overflow_check =
1288 FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kMips) || !IsLeafMethod();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001289
1290 if (do_overflow_check) {
1291 __ LoadFromOffset(kLoadWord,
1292 ZERO,
1293 SP,
Vladimir Marko33bff252017-11-01 14:35:42 +00001294 -static_cast<int32_t>(GetStackOverflowReservedBytes(InstructionSet::kMips)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001295 RecordPcInfo(nullptr, 0);
1296 }
1297
1298 if (HasEmptyFrame()) {
Alexey Frunze58320ce2016-08-30 21:40:46 -07001299 CHECK_EQ(fpu_spill_mask_, 0u);
1300 CHECK_EQ(core_spill_mask_, 1u << RA);
1301 CHECK(!clobbered_ra_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001302 return;
1303 }
1304
1305 // Make sure the frame size isn't unreasonably large.
Vladimir Marko33bff252017-11-01 14:35:42 +00001306 if (GetFrameSize() > GetStackOverflowReservedBytes(InstructionSet::kMips)) {
1307 LOG(FATAL) << "Stack frame larger than "
1308 << GetStackOverflowReservedBytes(InstructionSet::kMips) << " bytes";
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001309 }
1310
1311 // Spill callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001312
Alexey Frunze73296a72016-06-03 22:51:46 -07001313 uint32_t ofs = GetFrameSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001314 __ IncreaseFrameSize(ofs);
1315
Alexey Frunze73296a72016-06-03 22:51:46 -07001316 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
1317 Register reg = static_cast<Register>(MostSignificantBit(mask));
1318 mask ^= 1u << reg;
1319 ofs -= kMipsWordSize;
1320 // The ZERO register is only included for alignment.
1321 if (reg != ZERO) {
1322 __ StoreToOffset(kStoreWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001323 __ cfi().RelOffset(DWARFReg(reg), ofs);
1324 }
1325 }
1326
Alexey Frunze73296a72016-06-03 22:51:46 -07001327 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
1328 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
1329 mask ^= 1u << reg;
1330 ofs -= kMipsDoublewordSize;
1331 __ StoreDToOffset(reg, SP, ofs);
1332 // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001333 }
1334
Nicolas Geoffray96eeb4e2016-10-12 22:03:31 +01001335 // Save the current method if we need it. Note that we do not
1336 // do this in HCurrentMethod, as the instruction might have been removed
1337 // in the SSA graph.
1338 if (RequiresCurrentMethod()) {
1339 __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, kCurrentMethodStackOffset);
1340 }
Goran Jakovljevicc6418422016-12-05 16:31:55 +01001341
1342 if (GetGraph()->HasShouldDeoptimizeFlag()) {
1343 // Initialize should deoptimize flag to 0.
1344 __ StoreToOffset(kStoreWord, ZERO, SP, GetStackOffsetOfShouldDeoptimizeFlag());
1345 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001346}
1347
1348void CodeGeneratorMIPS::GenerateFrameExit() {
1349 __ cfi().RememberState();
1350
1351 if (!HasEmptyFrame()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001352 // Restore callee-saved registers.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001353
Alexey Frunze73296a72016-06-03 22:51:46 -07001354 // For better instruction scheduling restore RA before other registers.
1355 uint32_t ofs = GetFrameSize();
1356 for (uint32_t mask = core_spill_mask_; mask != 0; ) {
1357 Register reg = static_cast<Register>(MostSignificantBit(mask));
1358 mask ^= 1u << reg;
1359 ofs -= kMipsWordSize;
1360 // The ZERO register is only included for alignment.
1361 if (reg != ZERO) {
1362 __ LoadFromOffset(kLoadWord, reg, SP, ofs);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001363 __ cfi().Restore(DWARFReg(reg));
1364 }
1365 }
1366
Alexey Frunze73296a72016-06-03 22:51:46 -07001367 for (uint32_t mask = fpu_spill_mask_; mask != 0; ) {
1368 FRegister reg = static_cast<FRegister>(MostSignificantBit(mask));
1369 mask ^= 1u << reg;
1370 ofs -= kMipsDoublewordSize;
1371 __ LoadDFromOffset(reg, SP, ofs);
1372 // TODO: __ cfi().Restore(DWARFReg(reg));
1373 }
1374
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001375 size_t frame_size = GetFrameSize();
1376 // Adjust the stack pointer in the delay slot if doing so doesn't break CFI.
1377 bool exchange = IsInt<16>(static_cast<int32_t>(frame_size));
1378 bool reordering = __ SetReorder(false);
1379 if (exchange) {
1380 __ Jr(RA);
1381 __ DecreaseFrameSize(frame_size); // Single instruction in delay slot.
1382 } else {
1383 __ DecreaseFrameSize(frame_size);
1384 __ Jr(RA);
1385 __ Nop(); // In delay slot.
1386 }
1387 __ SetReorder(reordering);
1388 } else {
1389 __ Jr(RA);
1390 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001391 }
1392
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001393 __ cfi().RestoreState();
1394 __ cfi().DefCFAOffset(GetFrameSize());
1395}
1396
1397void CodeGeneratorMIPS::Bind(HBasicBlock* block) {
1398 __ Bind(GetLabelOf(block));
1399}
1400
Lena Djokicca8c2952017-05-29 11:31:46 +02001401VectorRegister VectorRegisterFrom(Location location) {
1402 DCHECK(location.IsFpuRegister());
1403 return static_cast<VectorRegister>(location.AsFpuRegister<FRegister>());
1404}
1405
Lena Djokic8098da92017-06-28 12:07:50 +02001406void CodeGeneratorMIPS::MoveLocation(Location destination,
1407 Location source,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001408 DataType::Type dst_type) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001409 if (source.Equals(destination)) {
1410 return;
1411 }
1412
Lena Djokic8098da92017-06-28 12:07:50 +02001413 if (source.IsConstant()) {
1414 MoveConstant(destination, source.GetConstant());
1415 } else {
1416 if (destination.IsRegister()) {
1417 if (source.IsRegister()) {
1418 __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
1419 } else if (source.IsFpuRegister()) {
1420 __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
1421 } else {
1422 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001423 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
Lena Djokic8098da92017-06-28 12:07:50 +02001424 }
1425 } else if (destination.IsRegisterPair()) {
1426 if (source.IsRegisterPair()) {
1427 __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
1428 __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
1429 } else if (source.IsFpuRegister()) {
1430 Register dst_high = destination.AsRegisterPairHigh<Register>();
1431 Register dst_low = destination.AsRegisterPairLow<Register>();
1432 FRegister src = source.AsFpuRegister<FRegister>();
1433 __ Mfc1(dst_low, src);
1434 __ MoveFromFpuHigh(dst_high, src);
1435 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001436 DCHECK(source.IsDoubleStackSlot())
1437 << "Cannot move from " << source << " to " << destination;
Lena Djokic8098da92017-06-28 12:07:50 +02001438 int32_t off = source.GetStackIndex();
1439 Register r = destination.AsRegisterPairLow<Register>();
1440 __ LoadFromOffset(kLoadDoubleword, r, SP, off);
1441 }
1442 } else if (destination.IsFpuRegister()) {
1443 if (source.IsRegister()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001444 DCHECK(!DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001445 __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
1446 } else if (source.IsRegisterPair()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001447 DCHECK(DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001448 FRegister dst = destination.AsFpuRegister<FRegister>();
1449 Register src_high = source.AsRegisterPairHigh<Register>();
1450 Register src_low = source.AsRegisterPairLow<Register>();
1451 __ Mtc1(src_low, dst);
1452 __ MoveToFpuHigh(src_high, dst);
1453 } else if (source.IsFpuRegister()) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001454 if (GetGraph()->HasSIMD()) {
1455 __ MoveV(VectorRegisterFrom(destination),
1456 VectorRegisterFrom(source));
Lena Djokic8098da92017-06-28 12:07:50 +02001457 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001458 if (DataType::Is64BitType(dst_type)) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001459 __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
1460 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001461 DCHECK_EQ(dst_type, DataType::Type::kFloat32);
Lena Djokicca8c2952017-05-29 11:31:46 +02001462 __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
1463 }
Lena Djokic8098da92017-06-28 12:07:50 +02001464 }
Lena Djokicca8c2952017-05-29 11:31:46 +02001465 } else if (source.IsSIMDStackSlot()) {
1466 __ LoadQFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
Lena Djokic8098da92017-06-28 12:07:50 +02001467 } else if (source.IsDoubleStackSlot()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001468 DCHECK(DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001469 __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
1470 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001471 DCHECK(!DataType::Is64BitType(dst_type));
Lena Djokic8098da92017-06-28 12:07:50 +02001472 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
1473 __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
1474 }
Lena Djokicca8c2952017-05-29 11:31:46 +02001475 } else if (destination.IsSIMDStackSlot()) {
1476 if (source.IsFpuRegister()) {
1477 __ StoreQToOffset(source.AsFpuRegister<FRegister>(), SP, destination.GetStackIndex());
1478 } else {
1479 DCHECK(source.IsSIMDStackSlot());
1480 __ LoadQFromOffset(FTMP, SP, source.GetStackIndex());
1481 __ StoreQToOffset(FTMP, SP, destination.GetStackIndex());
1482 }
Lena Djokic8098da92017-06-28 12:07:50 +02001483 } else if (destination.IsDoubleStackSlot()) {
1484 int32_t dst_offset = destination.GetStackIndex();
1485 if (source.IsRegisterPair()) {
1486 __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, dst_offset);
1487 } else if (source.IsFpuRegister()) {
1488 __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, dst_offset);
1489 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001490 DCHECK(source.IsDoubleStackSlot())
1491 << "Cannot move from " << source << " to " << destination;
Lena Djokic8098da92017-06-28 12:07:50 +02001492 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
1493 __ StoreToOffset(kStoreWord, TMP, SP, dst_offset);
1494 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
1495 __ StoreToOffset(kStoreWord, TMP, SP, dst_offset + 4);
1496 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001497 } else {
Lena Djokic8098da92017-06-28 12:07:50 +02001498 DCHECK(destination.IsStackSlot()) << destination;
1499 int32_t dst_offset = destination.GetStackIndex();
1500 if (source.IsRegister()) {
1501 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, dst_offset);
1502 } else if (source.IsFpuRegister()) {
1503 __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, dst_offset);
1504 } else {
1505 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
1506 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
1507 __ StoreToOffset(kStoreWord, TMP, SP, dst_offset);
1508 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001509 }
1510 }
1511}
1512
1513void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) {
1514 if (c->IsIntConstant() || c->IsNullConstant()) {
1515 // Move 32 bit constant.
1516 int32_t value = GetInt32ValueOf(c);
1517 if (destination.IsRegister()) {
1518 Register dst = destination.AsRegister<Register>();
1519 __ LoadConst32(dst, value);
1520 } else {
1521 DCHECK(destination.IsStackSlot())
1522 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001523 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001524 }
1525 } else if (c->IsLongConstant()) {
1526 // Move 64 bit constant.
1527 int64_t value = GetInt64ValueOf(c);
1528 if (destination.IsRegisterPair()) {
1529 Register r_h = destination.AsRegisterPairHigh<Register>();
1530 Register r_l = destination.AsRegisterPairLow<Register>();
1531 __ LoadConst64(r_h, r_l, value);
1532 } else {
1533 DCHECK(destination.IsDoubleStackSlot())
1534 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001535 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001536 }
1537 } else if (c->IsFloatConstant()) {
1538 // Move 32 bit float constant.
1539 int32_t value = GetInt32ValueOf(c);
1540 if (destination.IsFpuRegister()) {
1541 __ LoadSConst32(destination.AsFpuRegister<FRegister>(), value, TMP);
1542 } else {
1543 DCHECK(destination.IsStackSlot())
1544 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001545 __ StoreConstToOffset(kStoreWord, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001546 }
1547 } else {
1548 // Move 64 bit double constant.
1549 DCHECK(c->IsDoubleConstant()) << c->DebugName();
1550 int64_t value = GetInt64ValueOf(c);
1551 if (destination.IsFpuRegister()) {
1552 FRegister fd = destination.AsFpuRegister<FRegister>();
1553 __ LoadDConst64(fd, value, TMP);
1554 } else {
1555 DCHECK(destination.IsDoubleStackSlot())
1556 << "Cannot move " << c->DebugName() << " to " << destination;
Alexey Frunzef58b2482016-09-02 22:14:06 -07001557 __ StoreConstToOffset(kStoreDoubleword, value, SP, destination.GetStackIndex(), TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001558 }
1559 }
1560}
1561
1562void CodeGeneratorMIPS::MoveConstant(Location destination, int32_t value) {
1563 DCHECK(destination.IsRegister());
1564 Register dst = destination.AsRegister<Register>();
1565 __ LoadConst32(dst, value);
1566}
1567
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001568void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
1569 if (location.IsRegister()) {
1570 locations->AddTemp(location);
Alexey Frunzec9e94f32015-10-26 16:11:39 -07001571 } else if (location.IsRegisterPair()) {
1572 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
1573 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001574 } else {
1575 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
1576 }
1577}
1578
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001579template <linker::LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
Vladimir Markoaad75c62016-10-03 08:46:48 +00001580inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches(
1581 const ArenaDeque<PcRelativePatchInfo>& infos,
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001582 ArenaVector<linker::LinkerPatch>* linker_patches) {
Vladimir Markoaad75c62016-10-03 08:46:48 +00001583 for (const PcRelativePatchInfo& info : infos) {
1584 const DexFile& dex_file = info.target_dex_file;
1585 size_t offset_or_index = info.offset_or_index;
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001586 DCHECK(info.label.IsBound());
1587 uint32_t literal_offset = __ GetLabelLocation(&info.label);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001588 // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
1589 // the assembler's base label used for PC-relative addressing.
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001590 const PcRelativePatchInfo& info_high = info.patch_info_high ? *info.patch_info_high : info;
1591 uint32_t pc_rel_offset = info_high.pc_rel_label.IsBound()
1592 ? __ GetLabelLocation(&info_high.pc_rel_label)
Vladimir Markoaad75c62016-10-03 08:46:48 +00001593 : __ GetPcRelBaseLabelLocation();
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001594 linker_patches->push_back(Factory(literal_offset, &dex_file, pc_rel_offset, offset_or_index));
Vladimir Markoaad75c62016-10-03 08:46:48 +00001595 }
1596}
1597
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001598void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* linker_patches) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001599 DCHECK(linker_patches->empty());
1600 size_t size =
Vladimir Marko65979462017-05-19 17:25:12 +01001601 pc_relative_method_patches_.size() +
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001602 method_bss_entry_patches_.size() +
Alexey Frunze06a46c42016-07-19 15:00:40 -07001603 pc_relative_type_patches_.size() +
Vladimir Marko65979462017-05-19 17:25:12 +01001604 type_bss_entry_patches_.size() +
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001605 pc_relative_string_patches_.size() +
1606 string_bss_entry_patches_.size();
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001607 linker_patches->reserve(size);
Vladimir Marko65979462017-05-19 17:25:12 +01001608 if (GetCompilerOptions().IsBootImage()) {
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001609 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeMethodPatch>(
1610 pc_relative_method_patches_, linker_patches);
1611 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeTypePatch>(
1612 pc_relative_type_patches_, linker_patches);
1613 EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeStringPatch>(
1614 pc_relative_string_patches_, linker_patches);
Vladimir Marko65979462017-05-19 17:25:12 +01001615 } else {
1616 DCHECK(pc_relative_method_patches_.empty());
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001617 EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeClassTablePatch>(
1618 pc_relative_type_patches_, linker_patches);
1619 EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringInternTablePatch>(
1620 pc_relative_string_patches_, linker_patches);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001621 }
Vladimir Markod8dbc8d2017-09-20 13:37:47 +01001622 EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodBssEntryPatch>(
1623 method_bss_entry_patches_, linker_patches);
1624 EmitPcRelativeLinkerPatches<linker::LinkerPatch::TypeBssEntryPatch>(
1625 type_bss_entry_patches_, linker_patches);
1626 EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
1627 string_bss_entry_patches_, linker_patches);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001628 DCHECK_EQ(size, linker_patches->size());
Alexey Frunze06a46c42016-07-19 15:00:40 -07001629}
1630
Vladimir Marko65979462017-05-19 17:25:12 +01001631CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeMethodPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001632 MethodReference target_method,
1633 const PcRelativePatchInfo* info_high) {
Vladimir Marko65979462017-05-19 17:25:12 +01001634 return NewPcRelativePatch(*target_method.dex_file,
Mathieu Chartierfc8b4222017-09-17 13:44:24 -07001635 target_method.index,
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001636 info_high,
Vladimir Marko65979462017-05-19 17:25:12 +01001637 &pc_relative_method_patches_);
Alexey Frunze06a46c42016-07-19 15:00:40 -07001638}
1639
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001640CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewMethodBssEntryPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001641 MethodReference target_method,
1642 const PcRelativePatchInfo* info_high) {
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001643 return NewPcRelativePatch(*target_method.dex_file,
Mathieu Chartierfc8b4222017-09-17 13:44:24 -07001644 target_method.index,
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001645 info_high,
Vladimir Marko0eb882b2017-05-15 13:39:18 +01001646 &method_bss_entry_patches_);
1647}
1648
Alexey Frunze06a46c42016-07-19 15:00:40 -07001649CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001650 const DexFile& dex_file,
1651 dex::TypeIndex type_index,
1652 const PcRelativePatchInfo* info_high) {
1653 return NewPcRelativePatch(dex_file, type_index.index_, info_high, &pc_relative_type_patches_);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001654}
1655
Vladimir Marko1998cd02017-01-13 13:02:58 +00001656CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewTypeBssEntryPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001657 const DexFile& dex_file,
1658 dex::TypeIndex type_index,
1659 const PcRelativePatchInfo* info_high) {
1660 return NewPcRelativePatch(dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
Vladimir Marko1998cd02017-01-13 13:02:58 +00001661}
1662
Vladimir Marko65979462017-05-19 17:25:12 +01001663CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001664 const DexFile& dex_file,
1665 dex::StringIndex string_index,
1666 const PcRelativePatchInfo* info_high) {
1667 return NewPcRelativePatch(dex_file, string_index.index_, info_high, &pc_relative_string_patches_);
Vladimir Marko65979462017-05-19 17:25:12 +01001668}
1669
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01001670CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewStringBssEntryPatch(
1671 const DexFile& dex_file,
1672 dex::StringIndex string_index,
1673 const PcRelativePatchInfo* info_high) {
1674 return NewPcRelativePatch(dex_file, string_index.index_, info_high, &string_bss_entry_patches_);
1675}
1676
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001677CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001678 const DexFile& dex_file,
1679 uint32_t offset_or_index,
1680 const PcRelativePatchInfo* info_high,
1681 ArenaDeque<PcRelativePatchInfo>* patches) {
1682 patches->emplace_back(dex_file, offset_or_index, info_high);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07001683 return &patches->back();
1684}
1685
Alexey Frunze06a46c42016-07-19 15:00:40 -07001686Literal* CodeGeneratorMIPS::DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map) {
1687 return map->GetOrCreate(
1688 value,
1689 [this, value]() { return __ NewLiteral<uint32_t>(value); });
1690}
1691
Alexey Frunze06a46c42016-07-19 15:00:40 -07001692Literal* CodeGeneratorMIPS::DeduplicateBootImageAddressLiteral(uint32_t address) {
Richard Uhlerc52f3032017-03-02 13:45:45 +00001693 return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
Alexey Frunze06a46c42016-07-19 15:00:40 -07001694}
1695
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001696void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001697 Register out,
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001698 Register base) {
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001699 DCHECK(!info_high->patch_info_high);
Alexey Frunze6079dca2017-05-28 19:10:28 -07001700 DCHECK_NE(out, base);
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001701 bool reordering = __ SetReorder(false);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001702 if (GetInstructionSetFeatures().IsR6()) {
1703 DCHECK_EQ(base, ZERO);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001704 __ Bind(&info_high->label);
1705 __ Bind(&info_high->pc_rel_label);
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001706 // Add the high half of a 32-bit offset to PC.
Vladimir Markoaad75c62016-10-03 08:46:48 +00001707 __ Auipc(out, /* placeholder */ 0x1234);
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001708 __ SetReorder(reordering);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001709 } else {
1710 // If base is ZERO, emit NAL to obtain the actual base.
1711 if (base == ZERO) {
1712 // Generate a dummy PC-relative call to obtain PC.
1713 __ Nal();
1714 }
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001715 __ Bind(&info_high->label);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001716 __ Lui(out, /* placeholder */ 0x1234);
1717 // If we emitted the NAL, bind the pc_rel_label, otherwise base is a register holding
1718 // the HMipsComputeBaseMethodAddress which has its own label stored in MipsAssembler.
1719 if (base == ZERO) {
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001720 __ Bind(&info_high->pc_rel_label);
Vladimir Markoaad75c62016-10-03 08:46:48 +00001721 }
Alexey Frunzea663d9d2017-07-31 18:43:18 -07001722 __ SetReorder(reordering);
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001723 // Add the high half of a 32-bit offset to PC.
Vladimir Markoaad75c62016-10-03 08:46:48 +00001724 __ Addu(out, out, (base == ZERO) ? RA : base);
1725 }
Alexey Frunze5fa5c042017-06-01 21:07:52 -07001726 // A following instruction will add the sign-extended low half of the 32-bit
Alexey Frunze6b892cd2017-01-03 17:11:38 -08001727 // offset to `out` (e.g. lw, jialc, addiu).
Vladimir Markoaad75c62016-10-03 08:46:48 +00001728}
1729
Alexey Frunze627c1a02017-01-30 19:28:14 -08001730CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootStringPatch(
1731 const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01001732 dex::StringIndex string_index,
Alexey Frunze627c1a02017-01-30 19:28:14 -08001733 Handle<mirror::String> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001734 ReserveJitStringRoot(StringReference(&dex_file, string_index), handle);
1735 jit_string_patches_.emplace_back(dex_file, string_index.index_);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001736 return &jit_string_patches_.back();
1737}
1738
1739CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootClassPatch(
1740 const DexFile& dex_file,
Vladimir Marko174b2e22017-10-12 13:34:49 +01001741 dex::TypeIndex type_index,
Alexey Frunze627c1a02017-01-30 19:28:14 -08001742 Handle<mirror::Class> handle) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001743 ReserveJitClassRoot(TypeReference(&dex_file, type_index), handle);
1744 jit_class_patches_.emplace_back(dex_file, type_index.index_);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001745 return &jit_class_patches_.back();
1746}
1747
1748void CodeGeneratorMIPS::PatchJitRootUse(uint8_t* code,
1749 const uint8_t* roots_data,
1750 const CodeGeneratorMIPS::JitPatchInfo& info,
1751 uint64_t index_in_table) const {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001752 uint32_t high_literal_offset = GetAssembler().GetLabelLocation(&info.high_label);
1753 uint32_t low_literal_offset = GetAssembler().GetLabelLocation(&info.low_label);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001754 uintptr_t address =
1755 reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
1756 uint32_t addr32 = dchecked_integral_cast<uint32_t>(address);
1757 // lui reg, addr32_high
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001758 DCHECK_EQ(code[high_literal_offset + 0], 0x34);
1759 DCHECK_EQ(code[high_literal_offset + 1], 0x12);
1760 DCHECK_EQ((code[high_literal_offset + 2] & 0xE0), 0x00);
1761 DCHECK_EQ(code[high_literal_offset + 3], 0x3C);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001762 // instr reg, reg, addr32_low
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001763 DCHECK_EQ(code[low_literal_offset + 0], 0x78);
1764 DCHECK_EQ(code[low_literal_offset + 1], 0x56);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001765 addr32 += (addr32 & 0x8000) << 1; // Account for sign extension in "instr reg, reg, addr32_low".
Alexey Frunze627c1a02017-01-30 19:28:14 -08001766 // lui reg, addr32_high
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001767 code[high_literal_offset + 0] = static_cast<uint8_t>(addr32 >> 16);
1768 code[high_literal_offset + 1] = static_cast<uint8_t>(addr32 >> 24);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001769 // instr reg, reg, addr32_low
Alexey Frunze4147fcc2017-06-17 19:57:27 -07001770 code[low_literal_offset + 0] = static_cast<uint8_t>(addr32 >> 0);
1771 code[low_literal_offset + 1] = static_cast<uint8_t>(addr32 >> 8);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001772}
1773
1774void CodeGeneratorMIPS::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
1775 for (const JitPatchInfo& info : jit_string_patches_) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001776 StringReference string_reference(&info.target_dex_file, dex::StringIndex(info.index));
1777 uint64_t index_in_table = GetJitStringRootIndex(string_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01001778 PatchJitRootUse(code, roots_data, info, index_in_table);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001779 }
1780 for (const JitPatchInfo& info : jit_class_patches_) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01001781 TypeReference type_reference(&info.target_dex_file, dex::TypeIndex(info.index));
1782 uint64_t index_in_table = GetJitClassRootIndex(type_reference);
Vladimir Marko7d157fc2017-05-10 16:29:23 +01001783 PatchJitRootUse(code, roots_data, info, index_in_table);
Alexey Frunze627c1a02017-01-30 19:28:14 -08001784 }
1785}
1786
Goran Jakovljevice114da22016-12-26 14:21:43 +01001787void CodeGeneratorMIPS::MarkGCCard(Register object,
1788 Register value,
1789 bool value_can_be_null) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001790 MipsLabel done;
1791 Register card = AT;
1792 Register temp = TMP;
Goran Jakovljevice114da22016-12-26 14:21:43 +01001793 if (value_can_be_null) {
1794 __ Beqz(value, &done);
1795 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001796 __ LoadFromOffset(kLoadWord,
1797 card,
1798 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07001799 Thread::CardTableOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001800 __ Srl(temp, object, gc::accounting::CardTable::kCardShift);
1801 __ Addu(temp, card, temp);
1802 __ Sb(card, temp, 0);
Goran Jakovljevice114da22016-12-26 14:21:43 +01001803 if (value_can_be_null) {
1804 __ Bind(&done);
1805 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001806}
1807
David Brazdil58282f42016-01-14 12:45:10 +00001808void CodeGeneratorMIPS::SetupBlockedRegisters() const {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001809 // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated.
1810 blocked_core_registers_[ZERO] = true;
1811 blocked_core_registers_[K0] = true;
1812 blocked_core_registers_[K1] = true;
1813 blocked_core_registers_[GP] = true;
1814 blocked_core_registers_[SP] = true;
1815 blocked_core_registers_[RA] = true;
1816
1817 // AT and TMP(T8) are used as temporary/scratch registers
1818 // (similar to how AT is used by MIPS assemblers).
1819 blocked_core_registers_[AT] = true;
1820 blocked_core_registers_[TMP] = true;
1821 blocked_fpu_registers_[FTMP] = true;
1822
Goran Jakovljevice7de5ec2017-12-14 10:25:20 +01001823 if (GetInstructionSetFeatures().HasMsa()) {
1824 // To be used just for MSA instructions.
1825 blocked_fpu_registers_[FTMP2] = true;
1826 }
1827
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001828 // Reserve suspend and thread registers.
1829 blocked_core_registers_[S0] = true;
1830 blocked_core_registers_[TR] = true;
1831
1832 // Reserve T9 for function calls
1833 blocked_core_registers_[T9] = true;
1834
1835 // Reserve odd-numbered FPU registers.
1836 for (size_t i = 1; i < kNumberOfFRegisters; i += 2) {
1837 blocked_fpu_registers_[i] = true;
1838 }
1839
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02001840 if (GetGraph()->IsDebuggable()) {
1841 // Stubs do not save callee-save floating point registers. If the graph
1842 // is debuggable, we need to deal with these registers differently. For
1843 // now, just block them.
1844 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
1845 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true;
1846 }
1847 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001848}
1849
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001850size_t CodeGeneratorMIPS::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1851 __ StoreToOffset(kStoreWord, Register(reg_id), SP, stack_index);
1852 return kMipsWordSize;
1853}
1854
1855size_t CodeGeneratorMIPS::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1856 __ LoadFromOffset(kLoadWord, Register(reg_id), SP, stack_index);
1857 return kMipsWordSize;
1858}
1859
1860size_t CodeGeneratorMIPS::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001861 if (GetGraph()->HasSIMD()) {
1862 __ StoreQToOffset(FRegister(reg_id), SP, stack_index);
1863 } else {
1864 __ StoreDToOffset(FRegister(reg_id), SP, stack_index);
1865 }
1866 return GetFloatingPointSpillSlotSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001867}
1868
1869size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
Lena Djokicca8c2952017-05-29 11:31:46 +02001870 if (GetGraph()->HasSIMD()) {
1871 __ LoadQFromOffset(FRegister(reg_id), SP, stack_index);
1872 } else {
1873 __ LoadDFromOffset(FRegister(reg_id), SP, stack_index);
1874 }
1875 return GetFloatingPointSpillSlotSize();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001876}
1877
1878void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001879 stream << Register(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001880}
1881
1882void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001883 stream << FRegister(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001884}
1885
Serban Constantinescufca16662016-07-14 09:21:59 +01001886constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16;
1887
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001888void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
1889 HInstruction* instruction,
1890 uint32_t dex_pc,
1891 SlowPathCode* slow_path) {
Alexandre Rames91a65162016-09-19 13:54:30 +01001892 ValidateInvokeRuntime(entrypoint, instruction, slow_path);
Alexey Frunze15958152017-02-09 19:08:30 -08001893 GenerateInvokeRuntime(GetThreadOffset<kMipsPointerSize>(entrypoint).Int32Value(),
1894 IsDirectEntrypoint(entrypoint));
1895 if (EntrypointRequiresStackMap(entrypoint)) {
1896 RecordPcInfo(instruction, dex_pc, slow_path);
1897 }
1898}
1899
1900void CodeGeneratorMIPS::InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
1901 HInstruction* instruction,
1902 SlowPathCode* slow_path,
1903 bool direct) {
1904 ValidateInvokeRuntimeWithoutRecordingPcInfo(instruction, slow_path);
1905 GenerateInvokeRuntime(entry_point_offset, direct);
1906}
1907
1908void CodeGeneratorMIPS::GenerateInvokeRuntime(int32_t entry_point_offset, bool direct) {
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001909 bool reordering = __ SetReorder(false);
Alexey Frunze15958152017-02-09 19:08:30 -08001910 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001911 __ Jalr(T9);
Alexey Frunze15958152017-02-09 19:08:30 -08001912 if (direct) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001913 // Reserve argument space on stack (for $a0-$a3) for
1914 // entrypoints that directly reference native implementations.
1915 // Called function may use this space to store $a0-$a3 regs.
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001916 __ IncreaseFrameSize(kMipsDirectEntrypointRuntimeOffset); // Single instruction in delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001917 __ DecreaseFrameSize(kMipsDirectEntrypointRuntimeOffset);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001918 } else {
1919 __ Nop(); // In delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001920 }
Alexey Frunze57eb0f52016-07-29 22:04:46 -07001921 __ SetReorder(reordering);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001922}
1923
1924void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
1925 Register class_reg) {
Vladimir Markodc682aa2018-01-04 18:42:57 +00001926 constexpr size_t status_lsb_position = SubtypeCheckBits::BitStructSizeOf();
1927 const size_t status_byte_offset =
1928 mirror::Class::StatusOffset().SizeValue() + (status_lsb_position / kBitsPerByte);
1929 constexpr uint32_t shifted_initialized_value =
1930 enum_cast<uint32_t>(ClassStatus::kInitialized) << (status_lsb_position % kBitsPerByte);
1931
1932 __ LoadFromOffset(kLoadUnsignedByte, TMP, class_reg, status_byte_offset);
1933 __ LoadConst32(AT, shifted_initialized_value);
Vladimir Marko2c64a832018-01-04 11:31:56 +00001934 __ Bltu(TMP, AT, slow_path->GetEntryLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001935 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1936 __ Sync(0);
1937 __ Bind(slow_path->GetExitLabel());
1938}
1939
1940void InstructionCodeGeneratorMIPS::GenerateMemoryBarrier(MemBarrierKind kind ATTRIBUTE_UNUSED) {
1941 __ Sync(0); // Only stype 0 is supported.
1942}
1943
1944void InstructionCodeGeneratorMIPS::GenerateSuspendCheck(HSuspendCheck* instruction,
1945 HBasicBlock* successor) {
1946 SuspendCheckSlowPathMIPS* slow_path =
Chris Larsena2045912017-11-02 12:39:54 -07001947 down_cast<SuspendCheckSlowPathMIPS*>(instruction->GetSlowPath());
1948
1949 if (slow_path == nullptr) {
1950 slow_path =
1951 new (codegen_->GetScopedAllocator()) SuspendCheckSlowPathMIPS(instruction, successor);
1952 instruction->SetSlowPath(slow_path);
1953 codegen_->AddSlowPath(slow_path);
1954 if (successor != nullptr) {
1955 DCHECK(successor->IsLoopHeader());
1956 }
1957 } else {
1958 DCHECK_EQ(slow_path->GetSuccessor(), successor);
1959 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001960
1961 __ LoadFromOffset(kLoadUnsignedHalfword,
1962 TMP,
1963 TR,
Andreas Gampe542451c2016-07-26 09:02:02 -07001964 Thread::ThreadFlagsOffset<kMipsPointerSize>().Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001965 if (successor == nullptr) {
1966 __ Bnez(TMP, slow_path->GetEntryLabel());
1967 __ Bind(slow_path->GetReturnLabel());
1968 } else {
1969 __ Beqz(TMP, codegen_->GetLabelOf(successor));
1970 __ B(slow_path->GetEntryLabel());
1971 // slow_path will return to GetLabelOf(successor).
1972 }
1973}
1974
1975InstructionCodeGeneratorMIPS::InstructionCodeGeneratorMIPS(HGraph* graph,
1976 CodeGeneratorMIPS* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001977 : InstructionCodeGenerator(graph, codegen),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001978 assembler_(codegen->GetAssembler()),
1979 codegen_(codegen) {}
1980
1981void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1982 DCHECK_EQ(instruction->InputCount(), 2U);
Vladimir Markoca6fff82017-10-03 14:49:14 +01001983 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001984 DataType::Type type = instruction->GetResultType();
Lena Djokic38530172017-11-16 11:11:50 +01001985 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001986 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01001987 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001988 locations->SetInAt(0, Location::RequiresRegister());
1989 HInstruction* right = instruction->InputAt(1);
1990 bool can_use_imm = false;
1991 if (right->IsConstant()) {
1992 int32_t imm = CodeGenerator::GetInt32ValueOf(right->AsConstant());
1993 if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
1994 can_use_imm = IsUint<16>(imm);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001995 } else {
Lena Djokic38530172017-11-16 11:11:50 +01001996 DCHECK(instruction->IsSub() || instruction->IsAdd());
1997 if (instruction->IsSub()) {
1998 imm = -imm;
1999 }
2000 if (isR6) {
2001 bool single_use = right->GetUses().HasExactlyOneElement();
2002 int16_t imm_high = High16Bits(imm);
2003 int16_t imm_low = Low16Bits(imm);
2004 if (imm_low < 0) {
2005 imm_high += 1;
2006 }
2007 can_use_imm = !((imm_high != 0) && (imm_low != 0)) || single_use;
2008 } else {
2009 can_use_imm = IsInt<16>(imm);
2010 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002011 }
2012 }
2013 if (can_use_imm)
2014 locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
2015 else
2016 locations->SetInAt(1, Location::RequiresRegister());
2017 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2018 break;
2019 }
2020
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002021 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002022 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002023 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2024 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002025 break;
2026 }
2027
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002028 case DataType::Type::kFloat32:
2029 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002030 DCHECK(instruction->IsAdd() || instruction->IsSub());
2031 locations->SetInAt(0, Location::RequiresFpuRegister());
2032 locations->SetInAt(1, Location::RequiresFpuRegister());
2033 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2034 break;
2035
2036 default:
2037 LOG(FATAL) << "Unexpected " << instruction->DebugName() << " type " << type;
2038 }
2039}
2040
2041void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002042 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002043 LocationSummary* locations = instruction->GetLocations();
Lena Djokic38530172017-11-16 11:11:50 +01002044 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002045
2046 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002047 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002048 Register dst = locations->Out().AsRegister<Register>();
2049 Register lhs = locations->InAt(0).AsRegister<Register>();
2050 Location rhs_location = locations->InAt(1);
2051
2052 Register rhs_reg = ZERO;
2053 int32_t rhs_imm = 0;
2054 bool use_imm = rhs_location.IsConstant();
2055 if (use_imm) {
2056 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
2057 } else {
2058 rhs_reg = rhs_location.AsRegister<Register>();
2059 }
2060
2061 if (instruction->IsAnd()) {
2062 if (use_imm)
2063 __ Andi(dst, lhs, rhs_imm);
2064 else
2065 __ And(dst, lhs, rhs_reg);
2066 } else if (instruction->IsOr()) {
2067 if (use_imm)
2068 __ Ori(dst, lhs, rhs_imm);
2069 else
2070 __ Or(dst, lhs, rhs_reg);
2071 } else if (instruction->IsXor()) {
2072 if (use_imm)
2073 __ Xori(dst, lhs, rhs_imm);
2074 else
2075 __ Xor(dst, lhs, rhs_reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002076 } else {
Lena Djokic38530172017-11-16 11:11:50 +01002077 DCHECK(instruction->IsAdd() || instruction->IsSub());
2078 if (use_imm) {
2079 if (instruction->IsSub()) {
2080 rhs_imm = -rhs_imm;
2081 }
2082 if (IsInt<16>(rhs_imm)) {
2083 __ Addiu(dst, lhs, rhs_imm);
2084 } else {
2085 DCHECK(isR6);
2086 int16_t rhs_imm_high = High16Bits(rhs_imm);
2087 int16_t rhs_imm_low = Low16Bits(rhs_imm);
2088 if (rhs_imm_low < 0) {
2089 rhs_imm_high += 1;
2090 }
2091 __ Aui(dst, lhs, rhs_imm_high);
2092 if (rhs_imm_low != 0) {
2093 __ Addiu(dst, dst, rhs_imm_low);
2094 }
2095 }
2096 } else if (instruction->IsAdd()) {
2097 __ Addu(dst, lhs, rhs_reg);
2098 } else {
2099 DCHECK(instruction->IsSub());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002100 __ Subu(dst, lhs, rhs_reg);
Lena Djokic38530172017-11-16 11:11:50 +01002101 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002102 }
2103 break;
2104 }
2105
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002106 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002107 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
2108 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
2109 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2110 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002111 Location rhs_location = locations->InAt(1);
2112 bool use_imm = rhs_location.IsConstant();
2113 if (!use_imm) {
2114 Register rhs_high = rhs_location.AsRegisterPairHigh<Register>();
2115 Register rhs_low = rhs_location.AsRegisterPairLow<Register>();
2116 if (instruction->IsAnd()) {
2117 __ And(dst_low, lhs_low, rhs_low);
2118 __ And(dst_high, lhs_high, rhs_high);
2119 } else if (instruction->IsOr()) {
2120 __ Or(dst_low, lhs_low, rhs_low);
2121 __ Or(dst_high, lhs_high, rhs_high);
2122 } else if (instruction->IsXor()) {
2123 __ Xor(dst_low, lhs_low, rhs_low);
2124 __ Xor(dst_high, lhs_high, rhs_high);
2125 } else if (instruction->IsAdd()) {
2126 if (lhs_low == rhs_low) {
2127 // Special case for lhs = rhs and the sum potentially overwriting both lhs and rhs.
2128 __ Slt(TMP, lhs_low, ZERO);
2129 __ Addu(dst_low, lhs_low, rhs_low);
2130 } else {
2131 __ Addu(dst_low, lhs_low, rhs_low);
2132 // If the sum overwrites rhs, lhs remains unchanged, otherwise rhs remains unchanged.
2133 __ Sltu(TMP, dst_low, (dst_low == rhs_low) ? lhs_low : rhs_low);
2134 }
2135 __ Addu(dst_high, lhs_high, rhs_high);
2136 __ Addu(dst_high, dst_high, TMP);
2137 } else {
2138 DCHECK(instruction->IsSub());
2139 __ Sltu(TMP, lhs_low, rhs_low);
2140 __ Subu(dst_low, lhs_low, rhs_low);
2141 __ Subu(dst_high, lhs_high, rhs_high);
2142 __ Subu(dst_high, dst_high, TMP);
2143 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002144 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002145 int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
2146 if (instruction->IsOr()) {
2147 uint32_t low = Low32Bits(value);
2148 uint32_t high = High32Bits(value);
2149 if (IsUint<16>(low)) {
2150 if (dst_low != lhs_low || low != 0) {
2151 __ Ori(dst_low, lhs_low, low);
2152 }
2153 } else {
2154 __ LoadConst32(TMP, low);
2155 __ Or(dst_low, lhs_low, TMP);
2156 }
2157 if (IsUint<16>(high)) {
2158 if (dst_high != lhs_high || high != 0) {
2159 __ Ori(dst_high, lhs_high, high);
2160 }
2161 } else {
2162 if (high != low) {
2163 __ LoadConst32(TMP, high);
2164 }
2165 __ Or(dst_high, lhs_high, TMP);
2166 }
2167 } else if (instruction->IsXor()) {
2168 uint32_t low = Low32Bits(value);
2169 uint32_t high = High32Bits(value);
2170 if (IsUint<16>(low)) {
2171 if (dst_low != lhs_low || low != 0) {
2172 __ Xori(dst_low, lhs_low, low);
2173 }
2174 } else {
2175 __ LoadConst32(TMP, low);
2176 __ Xor(dst_low, lhs_low, TMP);
2177 }
2178 if (IsUint<16>(high)) {
2179 if (dst_high != lhs_high || high != 0) {
2180 __ Xori(dst_high, lhs_high, high);
2181 }
2182 } else {
2183 if (high != low) {
2184 __ LoadConst32(TMP, high);
2185 }
2186 __ Xor(dst_high, lhs_high, TMP);
2187 }
2188 } else if (instruction->IsAnd()) {
2189 uint32_t low = Low32Bits(value);
2190 uint32_t high = High32Bits(value);
2191 if (IsUint<16>(low)) {
2192 __ Andi(dst_low, lhs_low, low);
2193 } else if (low != 0xFFFFFFFF) {
2194 __ LoadConst32(TMP, low);
2195 __ And(dst_low, lhs_low, TMP);
2196 } else if (dst_low != lhs_low) {
2197 __ Move(dst_low, lhs_low);
2198 }
2199 if (IsUint<16>(high)) {
2200 __ Andi(dst_high, lhs_high, high);
2201 } else if (high != 0xFFFFFFFF) {
2202 if (high != low) {
2203 __ LoadConst32(TMP, high);
2204 }
2205 __ And(dst_high, lhs_high, TMP);
2206 } else if (dst_high != lhs_high) {
2207 __ Move(dst_high, lhs_high);
2208 }
2209 } else {
2210 if (instruction->IsSub()) {
2211 value = -value;
2212 } else {
2213 DCHECK(instruction->IsAdd());
2214 }
2215 int32_t low = Low32Bits(value);
2216 int32_t high = High32Bits(value);
2217 if (IsInt<16>(low)) {
2218 if (dst_low != lhs_low || low != 0) {
2219 __ Addiu(dst_low, lhs_low, low);
2220 }
2221 if (low != 0) {
2222 __ Sltiu(AT, dst_low, low);
2223 }
2224 } else {
2225 __ LoadConst32(TMP, low);
2226 __ Addu(dst_low, lhs_low, TMP);
2227 __ Sltu(AT, dst_low, TMP);
2228 }
2229 if (IsInt<16>(high)) {
2230 if (dst_high != lhs_high || high != 0) {
2231 __ Addiu(dst_high, lhs_high, high);
2232 }
2233 } else {
2234 if (high != low) {
2235 __ LoadConst32(TMP, high);
2236 }
2237 __ Addu(dst_high, lhs_high, TMP);
2238 }
2239 if (low != 0) {
2240 __ Addu(dst_high, dst_high, AT);
2241 }
2242 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002243 }
2244 break;
2245 }
2246
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002247 case DataType::Type::kFloat32:
2248 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002249 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
2250 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2251 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2252 if (instruction->IsAdd()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002253 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002254 __ AddS(dst, lhs, rhs);
2255 } else {
2256 __ AddD(dst, lhs, rhs);
2257 }
2258 } else {
2259 DCHECK(instruction->IsSub());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002260 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002261 __ SubS(dst, lhs, rhs);
2262 } else {
2263 __ SubD(dst, lhs, rhs);
2264 }
2265 }
2266 break;
2267 }
2268
2269 default:
2270 LOG(FATAL) << "Unexpected binary operation type " << type;
2271 }
2272}
2273
2274void LocationsBuilderMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002275 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002276
Vladimir Markoca6fff82017-10-03 14:49:14 +01002277 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instr);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002278 DataType::Type type = instr->GetResultType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002279 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002280 case DataType::Type::kInt32:
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002281 locations->SetInAt(0, Location::RequiresRegister());
2282 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
2283 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2284 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002285 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002286 locations->SetInAt(0, Location::RequiresRegister());
2287 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
2288 locations->SetOut(Location::RequiresRegister());
2289 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002290 default:
2291 LOG(FATAL) << "Unexpected shift type " << type;
2292 }
2293}
2294
2295static constexpr size_t kMipsBitsPerWord = kMipsWordSize * kBitsPerByte;
2296
2297void InstructionCodeGeneratorMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002298 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002299 LocationSummary* locations = instr->GetLocations();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002300 DataType::Type type = instr->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002301
2302 Location rhs_location = locations->InAt(1);
2303 bool use_imm = rhs_location.IsConstant();
2304 Register rhs_reg = use_imm ? ZERO : rhs_location.AsRegister<Register>();
2305 int64_t rhs_imm = use_imm ? CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()) : 0;
Roland Levillain5b5b9312016-03-22 14:57:31 +00002306 const uint32_t shift_mask =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002307 (type == DataType::Type::kInt32) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002308 const uint32_t shift_value = rhs_imm & shift_mask;
Alexey Frunze92d90602015-12-18 18:16:36 -08002309 // Are the INS (Insert Bit Field) and ROTR instructions supported?
2310 bool has_ins_rotr = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002311
2312 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002313 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002314 Register dst = locations->Out().AsRegister<Register>();
2315 Register lhs = locations->InAt(0).AsRegister<Register>();
2316 if (use_imm) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002317 if (shift_value == 0) {
2318 if (dst != lhs) {
2319 __ Move(dst, lhs);
2320 }
2321 } else if (instr->IsShl()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002322 __ Sll(dst, lhs, shift_value);
2323 } else if (instr->IsShr()) {
2324 __ Sra(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002325 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002326 __ Srl(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002327 } else {
2328 if (has_ins_rotr) {
2329 __ Rotr(dst, lhs, shift_value);
2330 } else {
2331 __ Sll(TMP, lhs, (kMipsBitsPerWord - shift_value) & shift_mask);
2332 __ Srl(dst, lhs, shift_value);
2333 __ Or(dst, dst, TMP);
2334 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002335 }
2336 } else {
2337 if (instr->IsShl()) {
2338 __ Sllv(dst, lhs, rhs_reg);
2339 } else if (instr->IsShr()) {
2340 __ Srav(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08002341 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002342 __ Srlv(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08002343 } else {
2344 if (has_ins_rotr) {
2345 __ Rotrv(dst, lhs, rhs_reg);
2346 } else {
2347 __ Subu(TMP, ZERO, rhs_reg);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002348 // 32-bit shift instructions use the 5 least significant bits of the shift count, so
2349 // shifting by `-rhs_reg` is equivalent to shifting by `(32 - rhs_reg) & 31`. The case
2350 // when `rhs_reg & 31 == 0` is OK even though we don't shift `lhs` left all the way out
2351 // by 32, because the result in this case is computed as `(lhs >> 0) | (lhs << 0)`,
2352 // IOW, the OR'd values are equal.
Alexey Frunze92d90602015-12-18 18:16:36 -08002353 __ Sllv(TMP, lhs, TMP);
2354 __ Srlv(dst, lhs, rhs_reg);
2355 __ Or(dst, dst, TMP);
2356 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002357 }
2358 }
2359 break;
2360 }
2361
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002362 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002363 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
2364 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
2365 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2366 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2367 if (use_imm) {
2368 if (shift_value == 0) {
Lena Djokic8098da92017-06-28 12:07:50 +02002369 codegen_->MoveLocation(locations->Out(), locations->InAt(0), type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002370 } else if (shift_value < kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002371 if (has_ins_rotr) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002372 if (instr->IsShl()) {
2373 __ Srl(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
2374 __ Ins(dst_high, lhs_high, shift_value, kMipsBitsPerWord - shift_value);
2375 __ Sll(dst_low, lhs_low, shift_value);
2376 } else if (instr->IsShr()) {
2377 __ Srl(dst_low, lhs_low, shift_value);
2378 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2379 __ Sra(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002380 } else if (instr->IsUShr()) {
2381 __ Srl(dst_low, lhs_low, shift_value);
2382 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2383 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002384 } else {
2385 __ Srl(dst_low, lhs_low, shift_value);
2386 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
2387 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08002388 __ Ins(dst_high, lhs_low, kMipsBitsPerWord - shift_value, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002389 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002390 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002391 if (instr->IsShl()) {
2392 __ Sll(dst_low, lhs_low, shift_value);
2393 __ Srl(TMP, lhs_low, kMipsBitsPerWord - shift_value);
2394 __ Sll(dst_high, lhs_high, shift_value);
2395 __ Or(dst_high, dst_high, TMP);
2396 } else if (instr->IsShr()) {
2397 __ Sra(dst_high, lhs_high, shift_value);
2398 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
2399 __ Srl(dst_low, lhs_low, shift_value);
2400 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08002401 } else if (instr->IsUShr()) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002402 __ Srl(dst_high, lhs_high, shift_value);
2403 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
2404 __ Srl(dst_low, lhs_low, shift_value);
2405 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08002406 } else {
2407 __ Srl(TMP, lhs_low, shift_value);
2408 __ Sll(dst_low, lhs_high, kMipsBitsPerWord - shift_value);
2409 __ Or(dst_low, dst_low, TMP);
2410 __ Srl(TMP, lhs_high, shift_value);
2411 __ Sll(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
2412 __ Or(dst_high, dst_high, TMP);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08002413 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002414 }
2415 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002416 const uint32_t shift_value_high = shift_value - kMipsBitsPerWord;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002417 if (instr->IsShl()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002418 __ Sll(dst_high, lhs_low, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002419 __ Move(dst_low, ZERO);
2420 } else if (instr->IsShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002421 __ Sra(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002422 __ Sra(dst_high, dst_low, kMipsBitsPerWord - 1);
Alexey Frunze92d90602015-12-18 18:16:36 -08002423 } else if (instr->IsUShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002424 __ Srl(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002425 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08002426 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002427 if (shift_value == kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08002428 // 64-bit rotation by 32 is just a swap.
2429 __ Move(dst_low, lhs_high);
2430 __ Move(dst_high, lhs_low);
2431 } else {
2432 if (has_ins_rotr) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002433 __ Srl(dst_low, lhs_high, shift_value_high);
2434 __ Ins(dst_low, lhs_low, kMipsBitsPerWord - shift_value_high, shift_value_high);
2435 __ Srl(dst_high, lhs_low, shift_value_high);
2436 __ Ins(dst_high, lhs_high, kMipsBitsPerWord - shift_value_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08002437 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002438 __ Sll(TMP, lhs_low, kMipsBitsPerWord - shift_value_high);
2439 __ Srl(dst_low, lhs_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08002440 __ Or(dst_low, dst_low, TMP);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08002441 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value_high);
2442 __ Srl(dst_high, lhs_low, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08002443 __ Or(dst_high, dst_high, TMP);
2444 }
2445 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002446 }
2447 }
2448 } else {
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002449 const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002450 MipsLabel done;
2451 if (instr->IsShl()) {
2452 __ Sllv(dst_low, lhs_low, rhs_reg);
2453 __ Nor(AT, ZERO, rhs_reg);
2454 __ Srl(TMP, lhs_low, 1);
2455 __ Srlv(TMP, TMP, AT);
2456 __ Sllv(dst_high, lhs_high, rhs_reg);
2457 __ Or(dst_high, dst_high, TMP);
2458 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002459 if (isR6) {
2460 __ Beqzc(TMP, &done, /* is_bare */ true);
2461 __ Move(dst_high, dst_low);
2462 __ Move(dst_low, ZERO);
2463 } else {
2464 __ Movn(dst_high, dst_low, TMP);
2465 __ Movn(dst_low, ZERO, TMP);
2466 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002467 } else if (instr->IsShr()) {
2468 __ Srav(dst_high, lhs_high, rhs_reg);
2469 __ Nor(AT, ZERO, rhs_reg);
2470 __ Sll(TMP, lhs_high, 1);
2471 __ Sllv(TMP, TMP, AT);
2472 __ Srlv(dst_low, lhs_low, rhs_reg);
2473 __ Or(dst_low, dst_low, TMP);
2474 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002475 if (isR6) {
2476 __ Beqzc(TMP, &done, /* is_bare */ true);
2477 __ Move(dst_low, dst_high);
2478 __ Sra(dst_high, dst_high, 31);
2479 } else {
2480 __ Sra(AT, dst_high, 31);
2481 __ Movn(dst_low, dst_high, TMP);
2482 __ Movn(dst_high, AT, TMP);
2483 }
Alexey Frunze92d90602015-12-18 18:16:36 -08002484 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002485 __ Srlv(dst_high, lhs_high, rhs_reg);
2486 __ Nor(AT, ZERO, rhs_reg);
2487 __ Sll(TMP, lhs_high, 1);
2488 __ Sllv(TMP, TMP, AT);
2489 __ Srlv(dst_low, lhs_low, rhs_reg);
2490 __ Or(dst_low, dst_low, TMP);
2491 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002492 if (isR6) {
2493 __ Beqzc(TMP, &done, /* is_bare */ true);
2494 __ Move(dst_low, dst_high);
2495 __ Move(dst_high, ZERO);
2496 } else {
2497 __ Movn(dst_low, dst_high, TMP);
2498 __ Movn(dst_high, ZERO, TMP);
2499 }
2500 } else { // Rotate.
Alexey Frunze92d90602015-12-18 18:16:36 -08002501 __ Nor(AT, ZERO, rhs_reg);
2502 __ Srlv(TMP, lhs_low, rhs_reg);
2503 __ Sll(dst_low, lhs_high, 1);
2504 __ Sllv(dst_low, dst_low, AT);
2505 __ Or(dst_low, dst_low, TMP);
2506 __ Srlv(TMP, lhs_high, rhs_reg);
2507 __ Sll(dst_high, lhs_low, 1);
2508 __ Sllv(dst_high, dst_high, AT);
2509 __ Or(dst_high, dst_high, TMP);
2510 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
Chris Larsen3e5fecd2017-11-09 14:21:28 -08002511 if (isR6) {
2512 __ Beqzc(TMP, &done, /* is_bare */ true);
2513 __ Move(TMP, dst_high);
2514 __ Move(dst_high, dst_low);
2515 __ Move(dst_low, TMP);
2516 } else {
2517 __ Movn(AT, dst_high, TMP);
2518 __ Movn(dst_high, dst_low, TMP);
2519 __ Movn(dst_low, AT, TMP);
2520 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002521 }
2522 __ Bind(&done);
2523 }
2524 break;
2525 }
2526
2527 default:
2528 LOG(FATAL) << "Unexpected shift operation type " << type;
2529 }
2530}
2531
2532void LocationsBuilderMIPS::VisitAdd(HAdd* instruction) {
2533 HandleBinaryOp(instruction);
2534}
2535
2536void InstructionCodeGeneratorMIPS::VisitAdd(HAdd* instruction) {
2537 HandleBinaryOp(instruction);
2538}
2539
2540void LocationsBuilderMIPS::VisitAnd(HAnd* instruction) {
2541 HandleBinaryOp(instruction);
2542}
2543
2544void InstructionCodeGeneratorMIPS::VisitAnd(HAnd* instruction) {
2545 HandleBinaryOp(instruction);
2546}
2547
2548void LocationsBuilderMIPS::VisitArrayGet(HArrayGet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002549 DataType::Type type = instruction->GetType();
Alexey Frunze15958152017-02-09 19:08:30 -08002550 bool object_array_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002551 kEmitCompilerReadBarrier && (type == DataType::Type::kReference);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002552 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01002553 new (GetGraph()->GetAllocator()) LocationSummary(instruction,
2554 object_array_get_with_read_barrier
2555 ? LocationSummary::kCallOnSlowPath
2556 : LocationSummary::kNoCall);
Alexey Frunzec61c0762017-04-10 13:54:23 -07002557 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
2558 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
2559 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002560 locations->SetInAt(0, Location::RequiresRegister());
2561 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002562 if (DataType::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002563 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2564 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08002565 // The output overlaps in the case of an object array get with
2566 // read barriers enabled: we do not want the move to overwrite the
2567 // array's location, as we need it to emit the read barrier.
2568 locations->SetOut(Location::RequiresRegister(),
2569 object_array_get_with_read_barrier
2570 ? Location::kOutputOverlap
2571 : Location::kNoOutputOverlap);
2572 }
2573 // We need a temporary register for the read barrier marking slow
2574 // path in CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier.
2575 if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002576 bool temp_needed = instruction->GetIndex()->IsConstant()
2577 ? !kBakerReadBarrierThunksEnableForFields
2578 : !kBakerReadBarrierThunksEnableForArrays;
2579 if (temp_needed) {
2580 locations->AddTemp(Location::RequiresRegister());
2581 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002582 }
2583}
2584
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002585static auto GetImplicitNullChecker(HInstruction* instruction, CodeGeneratorMIPS* codegen) {
2586 auto null_checker = [codegen, instruction]() {
2587 codegen->MaybeRecordImplicitNullCheck(instruction);
Alexey Frunze2923db72016-08-20 01:55:47 -07002588 };
2589 return null_checker;
2590}
2591
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002592void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
2593 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08002594 Location obj_loc = locations->InAt(0);
2595 Register obj = obj_loc.AsRegister<Register>();
2596 Location out_loc = locations->Out();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002597 Location index = locations->InAt(1);
Vladimir Marko87f3fcb2016-04-28 15:52:11 +01002598 uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002599 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002600
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002601 DataType::Type type = instruction->GetType();
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002602 const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
2603 instruction->IsStringCharAt();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002604 switch (type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002605 case DataType::Type::kBool:
2606 case DataType::Type::kUint8: {
Alexey Frunze15958152017-02-09 19:08:30 -08002607 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002608 if (index.IsConstant()) {
2609 size_t offset =
2610 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002611 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002612 } else {
2613 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07002614 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002615 }
2616 break;
2617 }
2618
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002619 case DataType::Type::kInt8: {
Alexey Frunze15958152017-02-09 19:08:30 -08002620 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002621 if (index.IsConstant()) {
2622 size_t offset =
2623 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002624 __ LoadFromOffset(kLoadSignedByte, out, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002625 } else {
2626 __ Addu(TMP, obj, index.AsRegister<Register>());
Alexey Frunze2923db72016-08-20 01:55:47 -07002627 __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002628 }
2629 break;
2630 }
2631
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002632 case DataType::Type::kUint16: {
Alexey Frunze15958152017-02-09 19:08:30 -08002633 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002634 if (maybe_compressed_char_at) {
2635 uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2636 __ LoadFromOffset(kLoadWord, TMP, obj, count_offset, null_checker);
2637 __ Sll(TMP, TMP, 31); // Extract compression flag into the most significant bit of TMP.
2638 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2639 "Expecting 0=compressed, 1=uncompressed");
2640 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002641 if (index.IsConstant()) {
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002642 int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
2643 if (maybe_compressed_char_at) {
2644 MipsLabel uncompressed_load, done;
2645 __ Bnez(TMP, &uncompressed_load);
2646 __ LoadFromOffset(kLoadUnsignedByte,
2647 out,
2648 obj,
2649 data_offset + (const_index << TIMES_1));
2650 __ B(&done);
2651 __ Bind(&uncompressed_load);
2652 __ LoadFromOffset(kLoadUnsignedHalfword,
2653 out,
2654 obj,
2655 data_offset + (const_index << TIMES_2));
2656 __ Bind(&done);
2657 } else {
2658 __ LoadFromOffset(kLoadUnsignedHalfword,
2659 out,
2660 obj,
2661 data_offset + (const_index << TIMES_2),
2662 null_checker);
2663 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002664 } else {
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002665 Register index_reg = index.AsRegister<Register>();
2666 if (maybe_compressed_char_at) {
2667 MipsLabel uncompressed_load, done;
2668 __ Bnez(TMP, &uncompressed_load);
2669 __ Addu(TMP, obj, index_reg);
2670 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
2671 __ B(&done);
2672 __ Bind(&uncompressed_load);
Chris Larsencd0295d2017-03-31 15:26:54 -07002673 __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002674 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
2675 __ Bind(&done);
Lena Djokica2901602017-09-21 13:50:52 +02002676 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2677 __ Addu(TMP, index_reg, obj);
2678 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002679 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002680 __ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002681 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
2682 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002683 }
2684 break;
2685 }
2686
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002687 case DataType::Type::kInt16: {
2688 Register out = out_loc.AsRegister<Register>();
2689 if (index.IsConstant()) {
2690 size_t offset =
2691 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
2692 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002693 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2694 __ Addu(TMP, index.AsRegister<Register>(), obj);
2695 __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002696 } else {
2697 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_2, TMP);
2698 __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
2699 }
2700 break;
2701 }
2702
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002703 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002704 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
Alexey Frunze15958152017-02-09 19:08:30 -08002705 Register out = out_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002706 if (index.IsConstant()) {
2707 size_t offset =
2708 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002709 __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002710 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2711 __ Addu(TMP, index.AsRegister<Register>(), obj);
2712 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002713 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002714 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002715 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002716 }
2717 break;
2718 }
2719
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002720 case DataType::Type::kReference: {
Alexey Frunze15958152017-02-09 19:08:30 -08002721 static_assert(
2722 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
2723 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
2724 // /* HeapReference<Object> */ out =
2725 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
2726 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002727 bool temp_needed = index.IsConstant()
2728 ? !kBakerReadBarrierThunksEnableForFields
2729 : !kBakerReadBarrierThunksEnableForArrays;
2730 Location temp = temp_needed ? locations->GetTemp(0) : Location::NoLocation();
Alexey Frunze15958152017-02-09 19:08:30 -08002731 // Note that a potential implicit null check is handled in this
2732 // CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier call.
Alexey Frunze4147fcc2017-06-17 19:57:27 -07002733 DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
2734 if (index.IsConstant()) {
2735 // Array load with a constant index can be treated as a field load.
2736 size_t offset =
2737 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2738 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
2739 out_loc,
2740 obj,
2741 offset,
2742 temp,
2743 /* needs_null_check */ false);
2744 } else {
2745 codegen_->GenerateArrayLoadWithBakerReadBarrier(instruction,
2746 out_loc,
2747 obj,
2748 data_offset,
2749 index,
2750 temp,
2751 /* needs_null_check */ false);
2752 }
Alexey Frunze15958152017-02-09 19:08:30 -08002753 } else {
2754 Register out = out_loc.AsRegister<Register>();
2755 if (index.IsConstant()) {
2756 size_t offset =
2757 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
2758 __ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
2759 // If read barriers are enabled, emit read barriers other than
2760 // Baker's using a slow path (and also unpoison the loaded
2761 // reference, if heap poisoning is enabled).
2762 codegen_->MaybeGenerateReadBarrierSlow(instruction, out_loc, out_loc, obj_loc, offset);
2763 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002764 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
Alexey Frunze15958152017-02-09 19:08:30 -08002765 __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
2766 // If read barriers are enabled, emit read barriers other than
2767 // Baker's using a slow path (and also unpoison the loaded
2768 // reference, if heap poisoning is enabled).
2769 codegen_->MaybeGenerateReadBarrierSlow(instruction,
2770 out_loc,
2771 out_loc,
2772 obj_loc,
2773 data_offset,
2774 index);
2775 }
2776 }
2777 break;
2778 }
2779
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002780 case DataType::Type::kInt64: {
Alexey Frunze15958152017-02-09 19:08:30 -08002781 Register out = out_loc.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002782 if (index.IsConstant()) {
2783 size_t offset =
2784 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002785 __ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002786 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2787 __ Addu(TMP, index.AsRegister<Register>(), obj);
2788 __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002789 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002790 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002791 __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002792 }
2793 break;
2794 }
2795
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002796 case DataType::Type::kFloat32: {
Alexey Frunze15958152017-02-09 19:08:30 -08002797 FRegister out = out_loc.AsFpuRegister<FRegister>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002798 if (index.IsConstant()) {
2799 size_t offset =
2800 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002801 __ LoadSFromOffset(out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002802 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2803 __ Addu(TMP, index.AsRegister<Register>(), obj);
2804 __ LoadSFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002805 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002806 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002807 __ LoadSFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002808 }
2809 break;
2810 }
2811
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002812 case DataType::Type::kFloat64: {
Alexey Frunze15958152017-02-09 19:08:30 -08002813 FRegister out = out_loc.AsFpuRegister<FRegister>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002814 if (index.IsConstant()) {
2815 size_t offset =
2816 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Alexey Frunze2923db72016-08-20 01:55:47 -07002817 __ LoadDFromOffset(out, obj, offset, null_checker);
Lena Djokica2901602017-09-21 13:50:52 +02002818 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2819 __ Addu(TMP, index.AsRegister<Register>(), obj);
2820 __ LoadDFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002821 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002822 __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
Alexey Frunze2923db72016-08-20 01:55:47 -07002823 __ LoadDFromOffset(out, TMP, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002824 }
2825 break;
2826 }
2827
Aart Bik66c158e2018-01-31 12:55:04 -08002828 case DataType::Type::kUint32:
2829 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002830 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002831 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2832 UNREACHABLE();
2833 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002834}
2835
2836void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01002837 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002838 locations->SetInAt(0, Location::RequiresRegister());
2839 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2840}
2841
2842void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) {
2843 LocationSummary* locations = instruction->GetLocations();
Vladimir Markodce016e2016-04-28 13:10:02 +01002844 uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002845 Register obj = locations->InAt(0).AsRegister<Register>();
2846 Register out = locations->Out().AsRegister<Register>();
2847 __ LoadFromOffset(kLoadWord, out, obj, offset);
2848 codegen_->MaybeRecordImplicitNullCheck(instruction);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002849 // Mask out compression flag from String's array length.
2850 if (mirror::kUseStringCompression && instruction->IsStringLength()) {
2851 __ Srl(out, out, 1u);
2852 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002853}
2854
Alexey Frunzef58b2482016-09-02 22:14:06 -07002855Location LocationsBuilderMIPS::RegisterOrZeroConstant(HInstruction* instruction) {
2856 return (instruction->IsConstant() && instruction->AsConstant()->IsZeroBitPattern())
2857 ? Location::ConstantLocation(instruction->AsConstant())
2858 : Location::RequiresRegister();
2859}
2860
2861Location LocationsBuilderMIPS::FpuRegisterOrConstantForStore(HInstruction* instruction) {
2862 // We can store 0.0 directly (from the ZERO register) without loading it into an FPU register.
2863 // We can store a non-zero float or double constant without first loading it into the FPU,
2864 // but we should only prefer this if the constant has a single use.
2865 if (instruction->IsConstant() &&
2866 (instruction->AsConstant()->IsZeroBitPattern() ||
2867 instruction->GetUses().HasExactlyOneElement())) {
2868 return Location::ConstantLocation(instruction->AsConstant());
2869 // Otherwise fall through and require an FPU register for the constant.
2870 }
2871 return Location::RequiresFpuRegister();
2872}
2873
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002874void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002875 DataType::Type value_type = instruction->GetComponentType();
Alexey Frunze15958152017-02-09 19:08:30 -08002876
2877 bool needs_write_barrier =
2878 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
2879 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
2880
Vladimir Markoca6fff82017-10-03 14:49:14 +01002881 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002882 instruction,
Alexey Frunze15958152017-02-09 19:08:30 -08002883 may_need_runtime_call_for_type_check ?
2884 LocationSummary::kCallOnSlowPath :
2885 LocationSummary::kNoCall);
2886
2887 locations->SetInAt(0, Location::RequiresRegister());
2888 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002889 if (DataType::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
Alexey Frunze15958152017-02-09 19:08:30 -08002890 locations->SetInAt(2, FpuRegisterOrConstantForStore(instruction->InputAt(2)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002891 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08002892 locations->SetInAt(2, RegisterOrZeroConstant(instruction->InputAt(2)));
2893 }
2894 if (needs_write_barrier) {
2895 // Temporary register for the write barrier.
2896 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002897 }
2898}
2899
2900void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
2901 LocationSummary* locations = instruction->GetLocations();
2902 Register obj = locations->InAt(0).AsRegister<Register>();
2903 Location index = locations->InAt(1);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002904 Location value_location = locations->InAt(2);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002905 DataType::Type value_type = instruction->GetComponentType();
Alexey Frunze15958152017-02-09 19:08:30 -08002906 bool may_need_runtime_call_for_type_check = instruction->NeedsTypeCheck();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002907 bool needs_write_barrier =
2908 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Tijana Jakovljevic57433862017-01-17 16:59:03 +01002909 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002910 Register base_reg = index.IsConstant() ? obj : TMP;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002911
2912 switch (value_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002913 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002914 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002915 case DataType::Type::kInt8: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002916 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002917 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002918 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002919 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002920 __ Addu(base_reg, obj, index.AsRegister<Register>());
2921 }
2922 if (value_location.IsConstant()) {
2923 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2924 __ StoreConstToOffset(kStoreByte, value, base_reg, data_offset, TMP, null_checker);
2925 } else {
2926 Register value = value_location.AsRegister<Register>();
2927 __ StoreToOffset(kStoreByte, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002928 }
2929 break;
2930 }
2931
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01002932 case DataType::Type::kUint16:
2933 case DataType::Type::kInt16: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002934 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002935 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002936 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
Lena Djokica2901602017-09-21 13:50:52 +02002937 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2938 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002939 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002940 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_2, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07002941 }
2942 if (value_location.IsConstant()) {
2943 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2944 __ StoreConstToOffset(kStoreHalfword, value, base_reg, data_offset, TMP, null_checker);
2945 } else {
2946 Register value = value_location.AsRegister<Register>();
2947 __ StoreToOffset(kStoreHalfword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002948 }
2949 break;
2950 }
2951
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002952 case DataType::Type::kInt32: {
Alexey Frunze15958152017-02-09 19:08:30 -08002953 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
2954 if (index.IsConstant()) {
2955 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Lena Djokica2901602017-09-21 13:50:52 +02002956 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
2957 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Alexey Frunze15958152017-02-09 19:08:30 -08002958 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002959 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunze15958152017-02-09 19:08:30 -08002960 }
2961 if (value_location.IsConstant()) {
2962 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2963 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2964 } else {
2965 Register value = value_location.AsRegister<Register>();
2966 __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
2967 }
2968 break;
2969 }
2970
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01002971 case DataType::Type::kReference: {
Alexey Frunze15958152017-02-09 19:08:30 -08002972 if (value_location.IsConstant()) {
2973 // Just setting null.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002974 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002975 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07002976 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002977 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07002978 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002979 }
Alexey Frunze15958152017-02-09 19:08:30 -08002980 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
2981 DCHECK_EQ(value, 0);
2982 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
2983 DCHECK(!needs_write_barrier);
2984 DCHECK(!may_need_runtime_call_for_type_check);
2985 break;
2986 }
2987
2988 DCHECK(needs_write_barrier);
2989 Register value = value_location.AsRegister<Register>();
2990 Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2991 Register temp2 = TMP; // Doesn't need to survive slow path.
2992 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
2993 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
2994 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
2995 MipsLabel done;
2996 SlowPathCodeMIPS* slow_path = nullptr;
2997
2998 if (may_need_runtime_call_for_type_check) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01002999 slow_path = new (codegen_->GetScopedAllocator()) ArraySetSlowPathMIPS(instruction);
Alexey Frunze15958152017-02-09 19:08:30 -08003000 codegen_->AddSlowPath(slow_path);
3001 if (instruction->GetValueCanBeNull()) {
3002 MipsLabel non_zero;
3003 __ Bnez(value, &non_zero);
3004 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3005 if (index.IsConstant()) {
3006 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Lena Djokica2901602017-09-21 13:50:52 +02003007 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3008 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Alexey Frunzec061de12017-02-14 13:27:23 -08003009 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003010 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunzec061de12017-02-14 13:27:23 -08003011 }
Alexey Frunze15958152017-02-09 19:08:30 -08003012 __ StoreToOffset(kStoreWord, value, base_reg, data_offset, null_checker);
3013 __ B(&done);
3014 __ Bind(&non_zero);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003015 }
Alexey Frunze15958152017-02-09 19:08:30 -08003016
3017 // Note that when read barriers are enabled, the type checks
3018 // are performed without read barriers. This is fine, even in
3019 // the case where a class object is in the from-space after
3020 // the flip, as a comparison involving such a type would not
3021 // produce a false positive; it may of course produce a false
3022 // negative, in which case we would take the ArraySet slow
3023 // path.
3024
3025 // /* HeapReference<Class> */ temp1 = obj->klass_
3026 __ LoadFromOffset(kLoadWord, temp1, obj, class_offset, null_checker);
3027 __ MaybeUnpoisonHeapReference(temp1);
3028
3029 // /* HeapReference<Class> */ temp1 = temp1->component_type_
3030 __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
3031 // /* HeapReference<Class> */ temp2 = value->klass_
3032 __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
3033 // If heap poisoning is enabled, no need to unpoison `temp1`
3034 // nor `temp2`, as we are comparing two poisoned references.
3035
3036 if (instruction->StaticTypeOfArrayIsObjectArray()) {
3037 MipsLabel do_put;
3038 __ Beq(temp1, temp2, &do_put);
3039 // If heap poisoning is enabled, the `temp1` reference has
3040 // not been unpoisoned yet; unpoison it now.
3041 __ MaybeUnpoisonHeapReference(temp1);
3042
3043 // /* HeapReference<Class> */ temp1 = temp1->super_class_
3044 __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
3045 // If heap poisoning is enabled, no need to unpoison
3046 // `temp1`, as we are comparing against null below.
3047 __ Bnez(temp1, slow_path->GetEntryLabel());
3048 __ Bind(&do_put);
3049 } else {
3050 __ Bne(temp1, temp2, slow_path->GetEntryLabel());
3051 }
3052 }
3053
3054 Register source = value;
3055 if (kPoisonHeapReferences) {
3056 // Note that in the case where `value` is a null reference,
3057 // we do not enter this block, as a null reference does not
3058 // need poisoning.
3059 __ Move(temp1, value);
3060 __ PoisonHeapReference(temp1);
3061 source = temp1;
3062 }
3063
3064 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3065 if (index.IsConstant()) {
3066 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003067 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003068 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunze15958152017-02-09 19:08:30 -08003069 }
3070 __ StoreToOffset(kStoreWord, source, base_reg, data_offset);
3071
3072 if (!may_need_runtime_call_for_type_check) {
3073 codegen_->MaybeRecordImplicitNullCheck(instruction);
3074 }
3075
3076 codegen_->MarkGCCard(obj, value, instruction->GetValueCanBeNull());
3077
3078 if (done.IsLinked()) {
3079 __ Bind(&done);
3080 }
3081
3082 if (slow_path != nullptr) {
3083 __ Bind(slow_path->GetExitLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003084 }
3085 break;
3086 }
3087
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003088 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003089 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003090 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003091 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Lena Djokica2901602017-09-21 13:50:52 +02003092 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3093 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003094 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003095 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07003096 }
3097 if (value_location.IsConstant()) {
3098 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
3099 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
3100 } else {
3101 Register value = value_location.AsRegisterPairLow<Register>();
3102 __ StoreToOffset(kStoreDoubleword, value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003103 }
3104 break;
3105 }
3106
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003107 case DataType::Type::kFloat32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003108 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003109 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003110 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
Lena Djokica2901602017-09-21 13:50:52 +02003111 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3112 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003113 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003114 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07003115 }
3116 if (value_location.IsConstant()) {
3117 int32_t value = CodeGenerator::GetInt32ValueOf(value_location.GetConstant());
3118 __ StoreConstToOffset(kStoreWord, value, base_reg, data_offset, TMP, null_checker);
3119 } else {
3120 FRegister value = value_location.AsFpuRegister<FRegister>();
3121 __ StoreSToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003122 }
3123 break;
3124 }
3125
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003126 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003127 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003128 if (index.IsConstant()) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07003129 data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
Lena Djokica2901602017-09-21 13:50:52 +02003130 } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
3131 __ Addu(base_reg, index.AsRegister<Register>(), obj);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003132 } else {
Chris Larsencd0295d2017-03-31 15:26:54 -07003133 __ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
Alexey Frunzef58b2482016-09-02 22:14:06 -07003134 }
3135 if (value_location.IsConstant()) {
3136 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
3137 __ StoreConstToOffset(kStoreDoubleword, value, base_reg, data_offset, TMP, null_checker);
3138 } else {
3139 FRegister value = value_location.AsFpuRegister<FRegister>();
3140 __ StoreDToOffset(value, base_reg, data_offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003141 }
3142 break;
3143 }
3144
Aart Bik66c158e2018-01-31 12:55:04 -08003145 case DataType::Type::kUint32:
3146 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003147 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003148 LOG(FATAL) << "Unreachable type " << instruction->GetType();
3149 UNREACHABLE();
3150 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003151}
3152
Lena Djokica2901602017-09-21 13:50:52 +02003153void LocationsBuilderMIPS::VisitIntermediateArrayAddressIndex(
3154 HIntermediateArrayAddressIndex* instruction) {
3155 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003156 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Lena Djokica2901602017-09-21 13:50:52 +02003157
3158 HIntConstant* shift = instruction->GetShift()->AsIntConstant();
3159
3160 locations->SetInAt(0, Location::RequiresRegister());
3161 locations->SetInAt(1, Location::ConstantLocation(shift));
3162 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3163}
3164
3165void InstructionCodeGeneratorMIPS::VisitIntermediateArrayAddressIndex(
3166 HIntermediateArrayAddressIndex* instruction) {
3167 LocationSummary* locations = instruction->GetLocations();
3168 Register index_reg = locations->InAt(0).AsRegister<Register>();
3169 uint32_t shift = instruction->GetShift()->AsIntConstant()->GetValue();
3170 __ Sll(locations->Out().AsRegister<Register>(), index_reg, shift);
3171}
3172
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003173void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01003174 RegisterSet caller_saves = RegisterSet::Empty();
3175 InvokeRuntimeCallingConvention calling_convention;
3176 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3177 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3178 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction, caller_saves);
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003179
3180 HInstruction* index = instruction->InputAt(0);
3181 HInstruction* length = instruction->InputAt(1);
3182
3183 bool const_index = false;
3184 bool const_length = false;
3185
3186 if (index->IsConstant()) {
3187 if (length->IsConstant()) {
3188 const_index = true;
3189 const_length = true;
3190 } else {
3191 int32_t index_value = index->AsIntConstant()->GetValue();
3192 if (index_value < 0 || IsInt<16>(index_value + 1)) {
3193 const_index = true;
3194 }
3195 }
3196 } else if (length->IsConstant()) {
3197 int32_t length_value = length->AsIntConstant()->GetValue();
3198 if (IsUint<15>(length_value)) {
3199 const_length = true;
3200 }
3201 }
3202
3203 locations->SetInAt(0, const_index
3204 ? Location::ConstantLocation(index->AsConstant())
3205 : Location::RequiresRegister());
3206 locations->SetInAt(1, const_length
3207 ? Location::ConstantLocation(length->AsConstant())
3208 : Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003209}
3210
3211void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
3212 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003213 Location index_loc = locations->InAt(0);
3214 Location length_loc = locations->InAt(1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003215
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003216 if (length_loc.IsConstant()) {
3217 int32_t length = length_loc.GetConstant()->AsIntConstant()->GetValue();
3218 if (index_loc.IsConstant()) {
3219 int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
3220 if (index < 0 || index >= length) {
3221 BoundsCheckSlowPathMIPS* slow_path =
3222 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
3223 codegen_->AddSlowPath(slow_path);
3224 __ B(slow_path->GetEntryLabel());
3225 } else {
3226 // Nothing to be done.
3227 }
3228 return;
3229 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003230
Goran Jakovljevicdbd43032017-11-15 16:31:56 +01003231 BoundsCheckSlowPathMIPS* slow_path =
3232 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
3233 codegen_->AddSlowPath(slow_path);
3234 Register index = index_loc.AsRegister<Register>();
3235 if (length == 0) {
3236 __ B(slow_path->GetEntryLabel());
3237 } else if (length == 1) {
3238 __ Bnez(index, slow_path->GetEntryLabel());
3239 } else {
3240 DCHECK(IsUint<15>(length)) << length;
3241 __ Sltiu(TMP, index, length);
3242 __ Beqz(TMP, slow_path->GetEntryLabel());
3243 }
3244 } else {
3245 Register length = length_loc.AsRegister<Register>();
3246 BoundsCheckSlowPathMIPS* slow_path =
3247 new (codegen_->GetScopedAllocator()) BoundsCheckSlowPathMIPS(instruction);
3248 codegen_->AddSlowPath(slow_path);
3249 if (index_loc.IsConstant()) {
3250 int32_t index = index_loc.GetConstant()->AsIntConstant()->GetValue();
3251 if (index < 0) {
3252 __ B(slow_path->GetEntryLabel());
3253 } else if (index == 0) {
3254 __ Blez(length, slow_path->GetEntryLabel());
3255 } else {
3256 DCHECK(IsInt<16>(index + 1)) << index;
3257 __ Sltiu(TMP, length, index + 1);
3258 __ Bnez(TMP, slow_path->GetEntryLabel());
3259 }
3260 } else {
3261 Register index = index_loc.AsRegister<Register>();
3262 __ Bgeu(index, length, slow_path->GetEntryLabel());
3263 }
3264 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003265}
3266
Alexey Frunze15958152017-02-09 19:08:30 -08003267// Temp is used for read barrier.
3268static size_t NumberOfInstanceOfTemps(TypeCheckKind type_check_kind) {
3269 if (kEmitCompilerReadBarrier &&
Alexey Frunze4147fcc2017-06-17 19:57:27 -07003270 !(kUseBakerReadBarrier && kBakerReadBarrierThunksEnableForFields) &&
Alexey Frunze15958152017-02-09 19:08:30 -08003271 (kUseBakerReadBarrier ||
3272 type_check_kind == TypeCheckKind::kAbstractClassCheck ||
3273 type_check_kind == TypeCheckKind::kClassHierarchyCheck ||
3274 type_check_kind == TypeCheckKind::kArrayObjectCheck)) {
3275 return 1;
3276 }
3277 return 0;
3278}
3279
3280// Extra temp is used for read barrier.
3281static size_t NumberOfCheckCastTemps(TypeCheckKind type_check_kind) {
3282 return 1 + NumberOfInstanceOfTemps(type_check_kind);
3283}
3284
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003285void LocationsBuilderMIPS::VisitCheckCast(HCheckCast* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003286 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Alexey Frunzedfc30af2018-01-24 16:25:10 -08003287 LocationSummary::CallKind call_kind = CodeGenerator::GetCheckCastCallKind(instruction);
Vladimir Markoca6fff82017-10-03 14:49:14 +01003288 LocationSummary* locations =
3289 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003290 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00003291 locations->SetInAt(1, Location::RequiresRegister());
Alexey Frunze15958152017-02-09 19:08:30 -08003292 locations->AddRegisterTemps(NumberOfCheckCastTemps(type_check_kind));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003293}
3294
3295void InstructionCodeGeneratorMIPS::VisitCheckCast(HCheckCast* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003296 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003297 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08003298 Location obj_loc = locations->InAt(0);
3299 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00003300 Register cls = locations->InAt(1).AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08003301 Location temp_loc = locations->GetTemp(0);
3302 Register temp = temp_loc.AsRegister<Register>();
3303 const size_t num_temps = NumberOfCheckCastTemps(type_check_kind);
3304 DCHECK_LE(num_temps, 2u);
3305 Location maybe_temp2_loc = (num_temps >= 2) ? locations->GetTemp(1) : Location::NoLocation();
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003306 const uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3307 const uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
3308 const uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
3309 const uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
3310 const uint32_t iftable_offset = mirror::Class::IfTableOffset().Uint32Value();
3311 const uint32_t array_length_offset = mirror::Array::LengthOffset().Uint32Value();
3312 const uint32_t object_array_data_offset =
3313 mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
3314 MipsLabel done;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003315
Alexey Frunzedfc30af2018-01-24 16:25:10 -08003316 bool is_type_check_slow_path_fatal = CodeGenerator::IsTypeCheckSlowPathFatal(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003317 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01003318 new (codegen_->GetScopedAllocator()) TypeCheckSlowPathMIPS(
3319 instruction, is_type_check_slow_path_fatal);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003320 codegen_->AddSlowPath(slow_path);
3321
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003322 // Avoid this check if we know `obj` is not null.
3323 if (instruction->MustDoNullCheck()) {
3324 __ Beqz(obj, &done);
3325 }
3326
3327 switch (type_check_kind) {
3328 case TypeCheckKind::kExactCheck:
3329 case TypeCheckKind::kArrayCheck: {
3330 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003331 GenerateReferenceLoadTwoRegisters(instruction,
3332 temp_loc,
3333 obj_loc,
3334 class_offset,
3335 maybe_temp2_loc,
3336 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003337 // Jump to slow path for throwing the exception or doing a
3338 // more involved array check.
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00003339 __ Bne(temp, cls, slow_path->GetEntryLabel());
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003340 break;
3341 }
3342
3343 case TypeCheckKind::kAbstractClassCheck: {
3344 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003345 GenerateReferenceLoadTwoRegisters(instruction,
3346 temp_loc,
3347 obj_loc,
3348 class_offset,
3349 maybe_temp2_loc,
3350 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003351 // If the class is abstract, we eagerly fetch the super class of the
3352 // object to avoid doing a comparison we know will fail.
3353 MipsLabel loop;
3354 __ Bind(&loop);
3355 // /* HeapReference<Class> */ temp = temp->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08003356 GenerateReferenceLoadOneRegister(instruction,
3357 temp_loc,
3358 super_offset,
3359 maybe_temp2_loc,
3360 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003361 // If the class reference currently in `temp` is null, jump to the slow path to throw the
3362 // exception.
3363 __ Beqz(temp, slow_path->GetEntryLabel());
3364 // Otherwise, compare the classes.
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00003365 __ Bne(temp, cls, &loop);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003366 break;
3367 }
3368
3369 case TypeCheckKind::kClassHierarchyCheck: {
3370 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003371 GenerateReferenceLoadTwoRegisters(instruction,
3372 temp_loc,
3373 obj_loc,
3374 class_offset,
3375 maybe_temp2_loc,
3376 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003377 // Walk over the class hierarchy to find a match.
3378 MipsLabel loop;
3379 __ Bind(&loop);
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00003380 __ Beq(temp, cls, &done);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003381 // /* HeapReference<Class> */ temp = temp->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08003382 GenerateReferenceLoadOneRegister(instruction,
3383 temp_loc,
3384 super_offset,
3385 maybe_temp2_loc,
3386 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003387 // If the class reference currently in `temp` is null, jump to the slow path to throw the
3388 // exception. Otherwise, jump to the beginning of the loop.
3389 __ Bnez(temp, &loop);
3390 __ B(slow_path->GetEntryLabel());
3391 break;
3392 }
3393
3394 case TypeCheckKind::kArrayObjectCheck: {
3395 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003396 GenerateReferenceLoadTwoRegisters(instruction,
3397 temp_loc,
3398 obj_loc,
3399 class_offset,
3400 maybe_temp2_loc,
3401 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003402 // Do an exact check.
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00003403 __ Beq(temp, cls, &done);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003404 // Otherwise, we need to check that the object's class is a non-primitive array.
3405 // /* HeapReference<Class> */ temp = temp->component_type_
Alexey Frunze15958152017-02-09 19:08:30 -08003406 GenerateReferenceLoadOneRegister(instruction,
3407 temp_loc,
3408 component_offset,
3409 maybe_temp2_loc,
3410 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003411 // If the component type is null, jump to the slow path to throw the exception.
3412 __ Beqz(temp, slow_path->GetEntryLabel());
3413 // Otherwise, the object is indeed an array, further check that this component
3414 // type is not a primitive type.
3415 __ LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
3416 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
3417 __ Bnez(temp, slow_path->GetEntryLabel());
3418 break;
3419 }
3420
3421 case TypeCheckKind::kUnresolvedCheck:
3422 // We always go into the type check slow path for the unresolved check case.
3423 // We cannot directly call the CheckCast runtime entry point
3424 // without resorting to a type checking slow path here (i.e. by
3425 // calling InvokeRuntime directly), as it would require to
3426 // assign fixed registers for the inputs of this HInstanceOf
3427 // instruction (following the runtime calling convention), which
3428 // might be cluttered by the potential first read barrier
3429 // emission at the beginning of this method.
3430 __ B(slow_path->GetEntryLabel());
3431 break;
3432
3433 case TypeCheckKind::kInterfaceCheck: {
3434 // Avoid read barriers to improve performance of the fast path. We can not get false
3435 // positives by doing this.
3436 // /* HeapReference<Class> */ temp = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08003437 GenerateReferenceLoadTwoRegisters(instruction,
3438 temp_loc,
3439 obj_loc,
3440 class_offset,
3441 maybe_temp2_loc,
3442 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003443 // /* HeapReference<Class> */ temp = temp->iftable_
Alexey Frunze15958152017-02-09 19:08:30 -08003444 GenerateReferenceLoadTwoRegisters(instruction,
3445 temp_loc,
3446 temp_loc,
3447 iftable_offset,
3448 maybe_temp2_loc,
3449 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003450 // Iftable is never null.
3451 __ Lw(TMP, temp, array_length_offset);
3452 // Loop through the iftable and check if any class matches.
3453 MipsLabel loop;
3454 __ Bind(&loop);
3455 __ Addiu(temp, temp, 2 * kHeapReferenceSize); // Possibly in delay slot on R2.
3456 __ Beqz(TMP, slow_path->GetEntryLabel());
3457 __ Lw(AT, temp, object_array_data_offset - 2 * kHeapReferenceSize);
3458 __ MaybeUnpoisonHeapReference(AT);
3459 // Go to next interface.
3460 __ Addiu(TMP, TMP, -2);
3461 // Compare the classes and continue the loop if they do not match.
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00003462 __ Bne(AT, cls, &loop);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08003463 break;
3464 }
3465 }
3466
3467 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003468 __ Bind(slow_path->GetExitLabel());
3469}
3470
3471void LocationsBuilderMIPS::VisitClinitCheck(HClinitCheck* check) {
3472 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003473 new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003474 locations->SetInAt(0, Location::RequiresRegister());
3475 if (check->HasUses()) {
3476 locations->SetOut(Location::SameAsFirstInput());
3477 }
3478}
3479
3480void InstructionCodeGeneratorMIPS::VisitClinitCheck(HClinitCheck* check) {
3481 // We assume the class is not null.
Vladimir Marko174b2e22017-10-12 13:34:49 +01003482 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathMIPS(
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003483 check->GetLoadClass(),
3484 check,
3485 check->GetDexPc(),
3486 true);
3487 codegen_->AddSlowPath(slow_path);
3488 GenerateClassInitializationCheck(slow_path,
3489 check->GetLocations()->InAt(0).AsRegister<Register>());
3490}
3491
3492void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003493 DataType::Type in_type = compare->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003494
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003495 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003496 new (GetGraph()->GetAllocator()) LocationSummary(compare, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003497
3498 switch (in_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003499 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003500 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003501 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003502 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003503 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003504 case DataType::Type::kInt32:
Alexey Frunzee7697712016-09-15 21:37:49 -07003505 locations->SetInAt(0, Location::RequiresRegister());
3506 locations->SetInAt(1, Location::RequiresRegister());
3507 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3508 break;
3509
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003510 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003511 locations->SetInAt(0, Location::RequiresRegister());
3512 locations->SetInAt(1, Location::RequiresRegister());
3513 // Output overlaps because it is written before doing the low comparison.
3514 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3515 break;
3516
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003517 case DataType::Type::kFloat32:
3518 case DataType::Type::kFloat64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003519 locations->SetInAt(0, Location::RequiresFpuRegister());
3520 locations->SetInAt(1, Location::RequiresFpuRegister());
3521 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003522 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003523
3524 default:
3525 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
3526 }
3527}
3528
3529void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
3530 LocationSummary* locations = instruction->GetLocations();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003531 Register res = locations->Out().AsRegister<Register>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003532 DataType::Type in_type = instruction->InputAt(0)->GetType();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003533 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003534
3535 // 0 if: left == right
3536 // 1 if: left > right
3537 // -1 if: left < right
3538 switch (in_type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003539 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003540 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003541 case DataType::Type::kInt8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003542 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003543 case DataType::Type::kInt16:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003544 case DataType::Type::kInt32: {
Aart Bika19616e2016-02-01 18:57:58 -08003545 Register lhs = locations->InAt(0).AsRegister<Register>();
3546 Register rhs = locations->InAt(1).AsRegister<Register>();
3547 __ Slt(TMP, lhs, rhs);
3548 __ Slt(res, rhs, lhs);
3549 __ Subu(res, res, TMP);
3550 break;
3551 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003552 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003553 MipsLabel done;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003554 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
3555 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
3556 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
3557 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
3558 // TODO: more efficient (direct) comparison with a constant.
3559 __ Slt(TMP, lhs_high, rhs_high);
3560 __ Slt(AT, rhs_high, lhs_high); // Inverted: is actually gt.
3561 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
3562 __ Bnez(res, &done); // If we compared ==, check if lower bits are also equal.
3563 __ Sltu(TMP, lhs_low, rhs_low);
3564 __ Sltu(AT, rhs_low, lhs_low); // Inverted: is actually gt.
3565 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
3566 __ Bind(&done);
3567 break;
3568 }
3569
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003570 case DataType::Type::kFloat32: {
Roland Levillain32ca3752016-02-17 16:49:37 +00003571 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003572 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3573 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3574 MipsLabel done;
3575 if (isR6) {
3576 __ CmpEqS(FTMP, lhs, rhs);
3577 __ LoadConst32(res, 0);
3578 __ Bc1nez(FTMP, &done);
3579 if (gt_bias) {
3580 __ CmpLtS(FTMP, lhs, rhs);
3581 __ LoadConst32(res, -1);
3582 __ Bc1nez(FTMP, &done);
3583 __ LoadConst32(res, 1);
3584 } else {
3585 __ CmpLtS(FTMP, rhs, lhs);
3586 __ LoadConst32(res, 1);
3587 __ Bc1nez(FTMP, &done);
3588 __ LoadConst32(res, -1);
3589 }
3590 } else {
3591 if (gt_bias) {
3592 __ ColtS(0, lhs, rhs);
3593 __ LoadConst32(res, -1);
3594 __ Bc1t(0, &done);
3595 __ CeqS(0, lhs, rhs);
3596 __ LoadConst32(res, 1);
3597 __ Movt(res, ZERO, 0);
3598 } else {
3599 __ ColtS(0, rhs, lhs);
3600 __ LoadConst32(res, 1);
3601 __ Bc1t(0, &done);
3602 __ CeqS(0, lhs, rhs);
3603 __ LoadConst32(res, -1);
3604 __ Movt(res, ZERO, 0);
3605 }
3606 }
3607 __ Bind(&done);
3608 break;
3609 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003610 case DataType::Type::kFloat64: {
Roland Levillain32ca3752016-02-17 16:49:37 +00003611 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003612 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3613 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3614 MipsLabel done;
3615 if (isR6) {
3616 __ CmpEqD(FTMP, lhs, rhs);
3617 __ LoadConst32(res, 0);
3618 __ Bc1nez(FTMP, &done);
3619 if (gt_bias) {
3620 __ CmpLtD(FTMP, lhs, rhs);
3621 __ LoadConst32(res, -1);
3622 __ Bc1nez(FTMP, &done);
3623 __ LoadConst32(res, 1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003624 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003625 __ CmpLtD(FTMP, rhs, lhs);
3626 __ LoadConst32(res, 1);
3627 __ Bc1nez(FTMP, &done);
3628 __ LoadConst32(res, -1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003629 }
3630 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003631 if (gt_bias) {
3632 __ ColtD(0, lhs, rhs);
3633 __ LoadConst32(res, -1);
3634 __ Bc1t(0, &done);
3635 __ CeqD(0, lhs, rhs);
3636 __ LoadConst32(res, 1);
3637 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003638 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003639 __ ColtD(0, rhs, lhs);
3640 __ LoadConst32(res, 1);
3641 __ Bc1t(0, &done);
3642 __ CeqD(0, lhs, rhs);
3643 __ LoadConst32(res, -1);
3644 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003645 }
3646 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003647 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003648 break;
3649 }
3650
3651 default:
3652 LOG(FATAL) << "Unimplemented compare type " << in_type;
3653 }
3654}
3655
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003656void LocationsBuilderMIPS::HandleCondition(HCondition* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01003657 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003658 switch (instruction->InputAt(0)->GetType()) {
3659 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003660 case DataType::Type::kInt64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003661 locations->SetInAt(0, Location::RequiresRegister());
3662 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3663 break;
3664
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003665 case DataType::Type::kFloat32:
3666 case DataType::Type::kFloat64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003667 locations->SetInAt(0, Location::RequiresFpuRegister());
3668 locations->SetInAt(1, Location::RequiresFpuRegister());
3669 break;
3670 }
David Brazdilb3e773e2016-01-26 11:28:37 +00003671 if (!instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003672 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3673 }
3674}
3675
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00003676void InstructionCodeGeneratorMIPS::HandleCondition(HCondition* instruction) {
David Brazdilb3e773e2016-01-26 11:28:37 +00003677 if (instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003678 return;
3679 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003680
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003681 DataType::Type type = instruction->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003682 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003683
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003684 switch (type) {
3685 default:
3686 // Integer case.
3687 GenerateIntCompare(instruction->GetCondition(), locations);
3688 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003689
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003690 case DataType::Type::kInt64:
Tijana Jakovljevic6d482aa2017-02-03 13:24:08 +01003691 GenerateLongCompare(instruction->GetCondition(), locations);
3692 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003693
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003694 case DataType::Type::kFloat32:
3695 case DataType::Type::kFloat64:
Alexey Frunze2ddb7172016-09-06 17:04:55 -07003696 GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
3697 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003698 }
3699}
3700
Alexey Frunze7e99e052015-11-24 19:28:01 -08003701void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
3702 DCHECK(instruction->IsDiv() || instruction->IsRem());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003703 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
Alexey Frunze7e99e052015-11-24 19:28:01 -08003704
3705 LocationSummary* locations = instruction->GetLocations();
3706 Location second = locations->InAt(1);
3707 DCHECK(second.IsConstant());
3708
3709 Register out = locations->Out().AsRegister<Register>();
3710 Register dividend = locations->InAt(0).AsRegister<Register>();
3711 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3712 DCHECK(imm == 1 || imm == -1);
3713
3714 if (instruction->IsRem()) {
3715 __ Move(out, ZERO);
3716 } else {
3717 if (imm == -1) {
3718 __ Subu(out, ZERO, dividend);
3719 } else if (out != dividend) {
3720 __ Move(out, dividend);
3721 }
3722 }
3723}
3724
3725void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
3726 DCHECK(instruction->IsDiv() || instruction->IsRem());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003727 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
Alexey Frunze7e99e052015-11-24 19:28:01 -08003728
3729 LocationSummary* locations = instruction->GetLocations();
3730 Location second = locations->InAt(1);
3731 DCHECK(second.IsConstant());
3732
3733 Register out = locations->Out().AsRegister<Register>();
3734 Register dividend = locations->InAt(0).AsRegister<Register>();
3735 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003736 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Alexey Frunze7e99e052015-11-24 19:28:01 -08003737 int ctz_imm = CTZ(abs_imm);
3738
3739 if (instruction->IsDiv()) {
3740 if (ctz_imm == 1) {
3741 // Fast path for division by +/-2, which is very common.
3742 __ Srl(TMP, dividend, 31);
3743 } else {
3744 __ Sra(TMP, dividend, 31);
3745 __ Srl(TMP, TMP, 32 - ctz_imm);
3746 }
3747 __ Addu(out, dividend, TMP);
3748 __ Sra(out, out, ctz_imm);
3749 if (imm < 0) {
3750 __ Subu(out, ZERO, out);
3751 }
3752 } else {
3753 if (ctz_imm == 1) {
3754 // Fast path for modulo +/-2, which is very common.
3755 __ Sra(TMP, dividend, 31);
3756 __ Subu(out, dividend, TMP);
3757 __ Andi(out, out, 1);
3758 __ Addu(out, out, TMP);
3759 } else {
3760 __ Sra(TMP, dividend, 31);
3761 __ Srl(TMP, TMP, 32 - ctz_imm);
3762 __ Addu(out, dividend, TMP);
3763 if (IsUint<16>(abs_imm - 1)) {
3764 __ Andi(out, out, abs_imm - 1);
3765 } else {
Lena Djokica556e6b2017-12-13 12:09:42 +01003766 if (codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2()) {
3767 __ Ins(out, ZERO, ctz_imm, 32 - ctz_imm);
3768 } else {
3769 __ Sll(out, out, 32 - ctz_imm);
3770 __ Srl(out, out, 32 - ctz_imm);
3771 }
Alexey Frunze7e99e052015-11-24 19:28:01 -08003772 }
3773 __ Subu(out, out, TMP);
3774 }
3775 }
3776}
3777
3778void InstructionCodeGeneratorMIPS::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
3779 DCHECK(instruction->IsDiv() || instruction->IsRem());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003780 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
Alexey Frunze7e99e052015-11-24 19:28:01 -08003781
3782 LocationSummary* locations = instruction->GetLocations();
3783 Location second = locations->InAt(1);
3784 DCHECK(second.IsConstant());
3785
3786 Register out = locations->Out().AsRegister<Register>();
3787 Register dividend = locations->InAt(0).AsRegister<Register>();
3788 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3789
3790 int64_t magic;
3791 int shift;
3792 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
3793
3794 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3795
3796 __ LoadConst32(TMP, magic);
3797 if (isR6) {
3798 __ MuhR6(TMP, dividend, TMP);
3799 } else {
3800 __ MultR2(dividend, TMP);
3801 __ Mfhi(TMP);
3802 }
3803 if (imm > 0 && magic < 0) {
3804 __ Addu(TMP, TMP, dividend);
3805 } else if (imm < 0 && magic > 0) {
3806 __ Subu(TMP, TMP, dividend);
3807 }
3808
3809 if (shift != 0) {
3810 __ Sra(TMP, TMP, shift);
3811 }
3812
3813 if (instruction->IsDiv()) {
3814 __ Sra(out, TMP, 31);
3815 __ Subu(out, TMP, out);
3816 } else {
3817 __ Sra(AT, TMP, 31);
3818 __ Subu(AT, TMP, AT);
3819 __ LoadConst32(TMP, imm);
3820 if (isR6) {
3821 __ MulR6(TMP, AT, TMP);
3822 } else {
3823 __ MulR2(TMP, AT, TMP);
3824 }
3825 __ Subu(out, dividend, TMP);
3826 }
3827}
3828
3829void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* instruction) {
3830 DCHECK(instruction->IsDiv() || instruction->IsRem());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003831 DCHECK_EQ(instruction->GetResultType(), DataType::Type::kInt32);
Alexey Frunze7e99e052015-11-24 19:28:01 -08003832
3833 LocationSummary* locations = instruction->GetLocations();
3834 Register out = locations->Out().AsRegister<Register>();
3835 Location second = locations->InAt(1);
3836
3837 if (second.IsConstant()) {
3838 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
3839 if (imm == 0) {
3840 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
3841 } else if (imm == 1 || imm == -1) {
3842 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00003843 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08003844 DivRemByPowerOfTwo(instruction);
3845 } else {
3846 DCHECK(imm <= -2 || imm >= 2);
3847 GenerateDivRemWithAnyConstant(instruction);
3848 }
3849 } else {
3850 Register dividend = locations->InAt(0).AsRegister<Register>();
3851 Register divisor = second.AsRegister<Register>();
3852 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3853 if (instruction->IsDiv()) {
3854 if (isR6) {
3855 __ DivR6(out, dividend, divisor);
3856 } else {
3857 __ DivR2(out, dividend, divisor);
3858 }
3859 } else {
3860 if (isR6) {
3861 __ ModR6(out, dividend, divisor);
3862 } else {
3863 __ ModR2(out, dividend, divisor);
3864 }
3865 }
3866 }
3867}
3868
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003869void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003870 DataType::Type type = div->GetResultType();
3871 LocationSummary::CallKind call_kind = (type == DataType::Type::kInt64)
Serban Constantinescu54ff4822016-07-07 18:03:19 +01003872 ? LocationSummary::kCallOnMainOnly
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003873 : LocationSummary::kNoCall;
3874
Vladimir Markoca6fff82017-10-03 14:49:14 +01003875 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(div, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003876
3877 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003878 case DataType::Type::kInt32:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003879 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08003880 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003881 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3882 break;
3883
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003884 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003885 InvokeRuntimeCallingConvention calling_convention;
3886 locations->SetInAt(0, Location::RegisterPairLocation(
3887 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3888 locations->SetInAt(1, Location::RegisterPairLocation(
3889 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3890 locations->SetOut(calling_convention.GetReturnLocation(type));
3891 break;
3892 }
3893
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003894 case DataType::Type::kFloat32:
3895 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003896 locations->SetInAt(0, Location::RequiresFpuRegister());
3897 locations->SetInAt(1, Location::RequiresFpuRegister());
3898 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3899 break;
3900
3901 default:
3902 LOG(FATAL) << "Unexpected div type " << type;
3903 }
3904}
3905
3906void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003907 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003908 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003909
3910 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003911 case DataType::Type::kInt32:
Alexey Frunze7e99e052015-11-24 19:28:01 -08003912 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003913 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003914 case DataType::Type::kInt64: {
Serban Constantinescufca16662016-07-14 09:21:59 +01003915 codegen_->InvokeRuntime(kQuickLdiv, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003916 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
3917 break;
3918 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003919 case DataType::Type::kFloat32:
3920 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003921 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
3922 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3923 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003924 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003925 __ DivS(dst, lhs, rhs);
3926 } else {
3927 __ DivD(dst, lhs, rhs);
3928 }
3929 break;
3930 }
3931 default:
3932 LOG(FATAL) << "Unexpected div type " << type;
3933 }
3934}
3935
3936void LocationsBuilderMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01003937 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003938 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003939}
3940
3941void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01003942 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01003943 new (codegen_->GetScopedAllocator()) DivZeroCheckSlowPathMIPS(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003944 codegen_->AddSlowPath(slow_path);
3945 Location value = instruction->GetLocations()->InAt(0);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003946 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003947
3948 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003949 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01003950 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003951 case DataType::Type::kInt8:
3952 case DataType::Type::kUint16:
3953 case DataType::Type::kInt16:
3954 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003955 if (value.IsConstant()) {
3956 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3957 __ B(slow_path->GetEntryLabel());
3958 } else {
3959 // A division by a non-null constant is valid. We don't need to perform
3960 // any check, so simply fall through.
3961 }
3962 } else {
3963 DCHECK(value.IsRegister()) << value;
3964 __ Beqz(value.AsRegister<Register>(), slow_path->GetEntryLabel());
3965 }
3966 break;
3967 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01003968 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003969 if (value.IsConstant()) {
3970 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3971 __ B(slow_path->GetEntryLabel());
3972 } else {
3973 // A division by a non-null constant is valid. We don't need to perform
3974 // any check, so simply fall through.
3975 }
3976 } else {
3977 DCHECK(value.IsRegisterPair()) << value;
3978 __ Or(TMP, value.AsRegisterPairHigh<Register>(), value.AsRegisterPairLow<Register>());
3979 __ Beqz(TMP, slow_path->GetEntryLabel());
3980 }
3981 break;
3982 }
3983 default:
3984 LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
3985 }
3986}
3987
3988void LocationsBuilderMIPS::VisitDoubleConstant(HDoubleConstant* constant) {
3989 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01003990 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003991 locations->SetOut(Location::ConstantLocation(constant));
3992}
3993
3994void InstructionCodeGeneratorMIPS::VisitDoubleConstant(HDoubleConstant* cst ATTRIBUTE_UNUSED) {
3995 // Will be generated at use site.
3996}
3997
3998void LocationsBuilderMIPS::VisitExit(HExit* exit) {
3999 exit->SetLocations(nullptr);
4000}
4001
4002void InstructionCodeGeneratorMIPS::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
4003}
4004
4005void LocationsBuilderMIPS::VisitFloatConstant(HFloatConstant* constant) {
4006 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01004007 new (GetGraph()->GetAllocator()) LocationSummary(constant, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004008 locations->SetOut(Location::ConstantLocation(constant));
4009}
4010
4011void InstructionCodeGeneratorMIPS::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
4012 // Will be generated at use site.
4013}
4014
4015void LocationsBuilderMIPS::VisitGoto(HGoto* got) {
4016 got->SetLocations(nullptr);
4017}
4018
4019void InstructionCodeGeneratorMIPS::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Aart Bika8b8e9b2018-01-09 11:01:02 -08004020 if (successor->IsExitBlock()) {
4021 DCHECK(got->GetPrevious()->AlwaysThrows());
4022 return; // no code needed
4023 }
4024
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004025 HBasicBlock* block = got->GetBlock();
4026 HInstruction* previous = got->GetPrevious();
4027 HLoopInformation* info = block->GetLoopInformation();
4028
4029 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004030 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
4031 return;
4032 }
4033 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
4034 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
4035 }
4036 if (!codegen_->GoesToNextBlock(block, successor)) {
4037 __ B(codegen_->GetLabelOf(successor));
4038 }
4039}
4040
4041void InstructionCodeGeneratorMIPS::VisitGoto(HGoto* got) {
4042 HandleGoto(got, got->GetSuccessor());
4043}
4044
4045void LocationsBuilderMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
4046 try_boundary->SetLocations(nullptr);
4047}
4048
4049void InstructionCodeGeneratorMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
4050 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
4051 if (!successor->IsExitBlock()) {
4052 HandleGoto(try_boundary, successor);
4053 }
4054}
4055
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004056void InstructionCodeGeneratorMIPS::GenerateIntCompare(IfCondition cond,
4057 LocationSummary* locations) {
4058 Register dst = locations->Out().AsRegister<Register>();
4059 Register lhs = locations->InAt(0).AsRegister<Register>();
4060 Location rhs_location = locations->InAt(1);
4061 Register rhs_reg = ZERO;
4062 int64_t rhs_imm = 0;
4063 bool use_imm = rhs_location.IsConstant();
4064 if (use_imm) {
4065 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
4066 } else {
4067 rhs_reg = rhs_location.AsRegister<Register>();
4068 }
4069
4070 switch (cond) {
4071 case kCondEQ:
4072 case kCondNE:
Alexey Frunzee7697712016-09-15 21:37:49 -07004073 if (use_imm && IsInt<16>(-rhs_imm)) {
4074 if (rhs_imm == 0) {
4075 if (cond == kCondEQ) {
4076 __ Sltiu(dst, lhs, 1);
4077 } else {
4078 __ Sltu(dst, ZERO, lhs);
4079 }
4080 } else {
4081 __ Addiu(dst, lhs, -rhs_imm);
4082 if (cond == kCondEQ) {
4083 __ Sltiu(dst, dst, 1);
4084 } else {
4085 __ Sltu(dst, ZERO, dst);
4086 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004087 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004088 } else {
Alexey Frunzee7697712016-09-15 21:37:49 -07004089 if (use_imm && IsUint<16>(rhs_imm)) {
4090 __ Xori(dst, lhs, rhs_imm);
4091 } else {
4092 if (use_imm) {
4093 rhs_reg = TMP;
4094 __ LoadConst32(rhs_reg, rhs_imm);
4095 }
4096 __ Xor(dst, lhs, rhs_reg);
4097 }
4098 if (cond == kCondEQ) {
4099 __ Sltiu(dst, dst, 1);
4100 } else {
4101 __ Sltu(dst, ZERO, dst);
4102 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004103 }
4104 break;
4105
4106 case kCondLT:
4107 case kCondGE:
4108 if (use_imm && IsInt<16>(rhs_imm)) {
4109 __ Slti(dst, lhs, rhs_imm);
4110 } else {
4111 if (use_imm) {
4112 rhs_reg = TMP;
4113 __ LoadConst32(rhs_reg, rhs_imm);
4114 }
4115 __ Slt(dst, lhs, rhs_reg);
4116 }
4117 if (cond == kCondGE) {
4118 // Simulate lhs >= rhs via !(lhs < rhs) since there's
4119 // only the slt instruction but no sge.
4120 __ Xori(dst, dst, 1);
4121 }
4122 break;
4123
4124 case kCondLE:
4125 case kCondGT:
4126 if (use_imm && IsInt<16>(rhs_imm + 1)) {
4127 // Simulate lhs <= rhs via lhs < rhs + 1.
4128 __ Slti(dst, lhs, rhs_imm + 1);
4129 if (cond == kCondGT) {
4130 // Simulate lhs > rhs via !(lhs <= rhs) since there's
4131 // only the slti instruction but no sgti.
4132 __ Xori(dst, dst, 1);
4133 }
4134 } else {
4135 if (use_imm) {
4136 rhs_reg = TMP;
4137 __ LoadConst32(rhs_reg, rhs_imm);
4138 }
4139 __ Slt(dst, rhs_reg, lhs);
4140 if (cond == kCondLE) {
4141 // Simulate lhs <= rhs via !(rhs < lhs) since there's
4142 // only the slt instruction but no sle.
4143 __ Xori(dst, dst, 1);
4144 }
4145 }
4146 break;
4147
4148 case kCondB:
4149 case kCondAE:
4150 if (use_imm && IsInt<16>(rhs_imm)) {
4151 // Sltiu sign-extends its 16-bit immediate operand before
4152 // the comparison and thus lets us compare directly with
4153 // unsigned values in the ranges [0, 0x7fff] and
4154 // [0xffff8000, 0xffffffff].
4155 __ Sltiu(dst, lhs, rhs_imm);
4156 } else {
4157 if (use_imm) {
4158 rhs_reg = TMP;
4159 __ LoadConst32(rhs_reg, rhs_imm);
4160 }
4161 __ Sltu(dst, lhs, rhs_reg);
4162 }
4163 if (cond == kCondAE) {
4164 // Simulate lhs >= rhs via !(lhs < rhs) since there's
4165 // only the sltu instruction but no sgeu.
4166 __ Xori(dst, dst, 1);
4167 }
4168 break;
4169
4170 case kCondBE:
4171 case kCondA:
4172 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4173 // Simulate lhs <= rhs via lhs < rhs + 1.
4174 // Note that this only works if rhs + 1 does not overflow
4175 // to 0, hence the check above.
4176 // Sltiu sign-extends its 16-bit immediate operand before
4177 // the comparison and thus lets us compare directly with
4178 // unsigned values in the ranges [0, 0x7fff] and
4179 // [0xffff8000, 0xffffffff].
4180 __ Sltiu(dst, lhs, rhs_imm + 1);
4181 if (cond == kCondA) {
4182 // Simulate lhs > rhs via !(lhs <= rhs) since there's
4183 // only the sltiu instruction but no sgtiu.
4184 __ Xori(dst, dst, 1);
4185 }
4186 } else {
4187 if (use_imm) {
4188 rhs_reg = TMP;
4189 __ LoadConst32(rhs_reg, rhs_imm);
4190 }
4191 __ Sltu(dst, rhs_reg, lhs);
4192 if (cond == kCondBE) {
4193 // Simulate lhs <= rhs via !(rhs < lhs) since there's
4194 // only the sltu instruction but no sleu.
4195 __ Xori(dst, dst, 1);
4196 }
4197 }
4198 break;
4199 }
4200}
4201
Alexey Frunze674b9ee2016-09-20 14:54:15 -07004202bool InstructionCodeGeneratorMIPS::MaterializeIntCompare(IfCondition cond,
4203 LocationSummary* input_locations,
4204 Register dst) {
4205 Register lhs = input_locations->InAt(0).AsRegister<Register>();
4206 Location rhs_location = input_locations->InAt(1);
4207 Register rhs_reg = ZERO;
4208 int64_t rhs_imm = 0;
4209 bool use_imm = rhs_location.IsConstant();
4210 if (use_imm) {
4211 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
4212 } else {
4213 rhs_reg = rhs_location.AsRegister<Register>();
4214 }
4215
4216 switch (cond) {
4217 case kCondEQ:
4218 case kCondNE:
4219 if (use_imm && IsInt<16>(-rhs_imm)) {
4220 __ Addiu(dst, lhs, -rhs_imm);
4221 } else if (use_imm && IsUint<16>(rhs_imm)) {
4222 __ Xori(dst, lhs, rhs_imm);
4223 } else {
4224 if (use_imm) {
4225 rhs_reg = TMP;
4226 __ LoadConst32(rhs_reg, rhs_imm);
4227 }
4228 __ Xor(dst, lhs, rhs_reg);
4229 }
4230 return (cond == kCondEQ);
4231
4232 case kCondLT:
4233 case kCondGE:
4234 if (use_imm && IsInt<16>(rhs_imm)) {
4235 __ Slti(dst, lhs, rhs_imm);
4236 } else {
4237 if (use_imm) {
4238 rhs_reg = TMP;
4239 __ LoadConst32(rhs_reg, rhs_imm);
4240 }
4241 __ Slt(dst, lhs, rhs_reg);
4242 }
4243 return (cond == kCondGE);
4244
4245 case kCondLE:
4246 case kCondGT:
4247 if (use_imm && IsInt<16>(rhs_imm + 1)) {
4248 // Simulate lhs <= rhs via lhs < rhs + 1.
4249 __ Slti(dst, lhs, rhs_imm + 1);
4250 return (cond == kCondGT);
4251 } else {
4252 if (use_imm) {
4253 rhs_reg = TMP;
4254 __ LoadConst32(rhs_reg, rhs_imm);
4255 }
4256 __ Slt(dst, rhs_reg, lhs);
4257 return (cond == kCondLE);
4258 }
4259
4260 case kCondB:
4261 case kCondAE:
4262 if (use_imm && IsInt<16>(rhs_imm)) {
4263 // Sltiu sign-extends its 16-bit immediate operand before
4264 // the comparison and thus lets us compare directly with
4265 // unsigned values in the ranges [0, 0x7fff] and
4266 // [0xffff8000, 0xffffffff].
4267 __ Sltiu(dst, lhs, rhs_imm);
4268 } else {
4269 if (use_imm) {
4270 rhs_reg = TMP;
4271 __ LoadConst32(rhs_reg, rhs_imm);
4272 }
4273 __ Sltu(dst, lhs, rhs_reg);
4274 }
4275 return (cond == kCondAE);
4276
4277 case kCondBE:
4278 case kCondA:
4279 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4280 // Simulate lhs <= rhs via lhs < rhs + 1.
4281 // Note that this only works if rhs + 1 does not overflow
4282 // to 0, hence the check above.
4283 // Sltiu sign-extends its 16-bit immediate operand before
4284 // the comparison and thus lets us compare directly with
4285 // unsigned values in the ranges [0, 0x7fff] and
4286 // [0xffff8000, 0xffffffff].
4287 __ Sltiu(dst, lhs, rhs_imm + 1);
4288 return (cond == kCondA);
4289 } else {
4290 if (use_imm) {
4291 rhs_reg = TMP;
4292 __ LoadConst32(rhs_reg, rhs_imm);
4293 }
4294 __ Sltu(dst, rhs_reg, lhs);
4295 return (cond == kCondBE);
4296 }
4297 }
4298}
4299
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004300void InstructionCodeGeneratorMIPS::GenerateIntCompareAndBranch(IfCondition cond,
4301 LocationSummary* locations,
4302 MipsLabel* label) {
4303 Register lhs = locations->InAt(0).AsRegister<Register>();
4304 Location rhs_location = locations->InAt(1);
4305 Register rhs_reg = ZERO;
Alexey Frunzee7697712016-09-15 21:37:49 -07004306 int64_t rhs_imm = 0;
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004307 bool use_imm = rhs_location.IsConstant();
4308 if (use_imm) {
4309 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
4310 } else {
4311 rhs_reg = rhs_location.AsRegister<Register>();
4312 }
4313
4314 if (use_imm && rhs_imm == 0) {
4315 switch (cond) {
4316 case kCondEQ:
4317 case kCondBE: // <= 0 if zero
4318 __ Beqz(lhs, label);
4319 break;
4320 case kCondNE:
4321 case kCondA: // > 0 if non-zero
4322 __ Bnez(lhs, label);
4323 break;
4324 case kCondLT:
4325 __ Bltz(lhs, label);
4326 break;
4327 case kCondGE:
4328 __ Bgez(lhs, label);
4329 break;
4330 case kCondLE:
4331 __ Blez(lhs, label);
4332 break;
4333 case kCondGT:
4334 __ Bgtz(lhs, label);
4335 break;
4336 case kCondB: // always false
4337 break;
4338 case kCondAE: // always true
4339 __ B(label);
4340 break;
4341 }
4342 } else {
Alexey Frunzee7697712016-09-15 21:37:49 -07004343 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4344 if (isR6 || !use_imm) {
4345 if (use_imm) {
4346 rhs_reg = TMP;
4347 __ LoadConst32(rhs_reg, rhs_imm);
4348 }
4349 switch (cond) {
4350 case kCondEQ:
4351 __ Beq(lhs, rhs_reg, label);
4352 break;
4353 case kCondNE:
4354 __ Bne(lhs, rhs_reg, label);
4355 break;
4356 case kCondLT:
4357 __ Blt(lhs, rhs_reg, label);
4358 break;
4359 case kCondGE:
4360 __ Bge(lhs, rhs_reg, label);
4361 break;
4362 case kCondLE:
4363 __ Bge(rhs_reg, lhs, label);
4364 break;
4365 case kCondGT:
4366 __ Blt(rhs_reg, lhs, label);
4367 break;
4368 case kCondB:
4369 __ Bltu(lhs, rhs_reg, label);
4370 break;
4371 case kCondAE:
4372 __ Bgeu(lhs, rhs_reg, label);
4373 break;
4374 case kCondBE:
4375 __ Bgeu(rhs_reg, lhs, label);
4376 break;
4377 case kCondA:
4378 __ Bltu(rhs_reg, lhs, label);
4379 break;
4380 }
4381 } else {
4382 // Special cases for more efficient comparison with constants on R2.
4383 switch (cond) {
4384 case kCondEQ:
4385 __ LoadConst32(TMP, rhs_imm);
4386 __ Beq(lhs, TMP, label);
4387 break;
4388 case kCondNE:
4389 __ LoadConst32(TMP, rhs_imm);
4390 __ Bne(lhs, TMP, label);
4391 break;
4392 case kCondLT:
4393 if (IsInt<16>(rhs_imm)) {
4394 __ Slti(TMP, lhs, rhs_imm);
4395 __ Bnez(TMP, label);
4396 } else {
4397 __ LoadConst32(TMP, rhs_imm);
4398 __ Blt(lhs, TMP, label);
4399 }
4400 break;
4401 case kCondGE:
4402 if (IsInt<16>(rhs_imm)) {
4403 __ Slti(TMP, lhs, rhs_imm);
4404 __ Beqz(TMP, label);
4405 } else {
4406 __ LoadConst32(TMP, rhs_imm);
4407 __ Bge(lhs, TMP, label);
4408 }
4409 break;
4410 case kCondLE:
4411 if (IsInt<16>(rhs_imm + 1)) {
4412 // Simulate lhs <= rhs via lhs < rhs + 1.
4413 __ Slti(TMP, lhs, rhs_imm + 1);
4414 __ Bnez(TMP, label);
4415 } else {
4416 __ LoadConst32(TMP, rhs_imm);
4417 __ Bge(TMP, lhs, label);
4418 }
4419 break;
4420 case kCondGT:
4421 if (IsInt<16>(rhs_imm + 1)) {
4422 // Simulate lhs > rhs via !(lhs < rhs + 1).
4423 __ Slti(TMP, lhs, rhs_imm + 1);
4424 __ Beqz(TMP, label);
4425 } else {
4426 __ LoadConst32(TMP, rhs_imm);
4427 __ Blt(TMP, lhs, label);
4428 }
4429 break;
4430 case kCondB:
4431 if (IsInt<16>(rhs_imm)) {
4432 __ Sltiu(TMP, lhs, rhs_imm);
4433 __ Bnez(TMP, label);
4434 } else {
4435 __ LoadConst32(TMP, rhs_imm);
4436 __ Bltu(lhs, TMP, label);
4437 }
4438 break;
4439 case kCondAE:
4440 if (IsInt<16>(rhs_imm)) {
4441 __ Sltiu(TMP, lhs, rhs_imm);
4442 __ Beqz(TMP, label);
4443 } else {
4444 __ LoadConst32(TMP, rhs_imm);
4445 __ Bgeu(lhs, TMP, label);
4446 }
4447 break;
4448 case kCondBE:
4449 if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4450 // Simulate lhs <= rhs via lhs < rhs + 1.
4451 // Note that this only works if rhs + 1 does not overflow
4452 // to 0, hence the check above.
4453 __ Sltiu(TMP, lhs, rhs_imm + 1);
4454 __ Bnez(TMP, label);
4455 } else {
4456 __ LoadConst32(TMP, rhs_imm);
4457 __ Bgeu(TMP, lhs, label);
4458 }
4459 break;
4460 case kCondA:
4461 if ((rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
4462 // Simulate lhs > rhs via !(lhs < rhs + 1).
4463 // Note that this only works if rhs + 1 does not overflow
4464 // to 0, hence the check above.
4465 __ Sltiu(TMP, lhs, rhs_imm + 1);
4466 __ Beqz(TMP, label);
4467 } else {
4468 __ LoadConst32(TMP, rhs_imm);
4469 __ Bltu(TMP, lhs, label);
4470 }
4471 break;
4472 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004473 }
4474 }
4475}
4476
Tijana Jakovljevic6d482aa2017-02-03 13:24:08 +01004477void InstructionCodeGeneratorMIPS::GenerateLongCompare(IfCondition cond,
4478 LocationSummary* locations) {
4479 Register dst = locations->Out().AsRegister<Register>();
4480 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4481 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
4482 Location rhs_location = locations->InAt(1);
4483 Register rhs_high = ZERO;
4484 Register rhs_low = ZERO;
4485 int64_t imm = 0;
4486 uint32_t imm_high = 0;
4487 uint32_t imm_low = 0;
4488 bool use_imm = rhs_location.IsConstant();
4489 if (use_imm) {
4490 imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
4491 imm_high = High32Bits(imm);
4492 imm_low = Low32Bits(imm);
4493 } else {
4494 rhs_high = rhs_location.AsRegisterPairHigh<Register>();
4495 rhs_low = rhs_location.AsRegisterPairLow<Register>();
4496 }
4497 if (use_imm && imm == 0) {
4498 switch (cond) {
4499 case kCondEQ:
4500 case kCondBE: // <= 0 if zero
4501 __ Or(dst, lhs_high, lhs_low);
4502 __ Sltiu(dst, dst, 1);
4503 break;
4504 case kCondNE:
4505 case kCondA: // > 0 if non-zero
4506 __ Or(dst, lhs_high, lhs_low);
4507 __ Sltu(dst, ZERO, dst);
4508 break;
4509 case kCondLT:
4510 __ Slt(dst, lhs_high, ZERO);
4511 break;
4512 case kCondGE:
4513 __ Slt(dst, lhs_high, ZERO);
4514 __ Xori(dst, dst, 1);
4515 break;
4516 case kCondLE:
4517 __ Or(TMP, lhs_high, lhs_low);
4518 __ Sra(AT, lhs_high, 31);
4519 __ Sltu(dst, AT, TMP);
4520 __ Xori(dst, dst, 1);
4521 break;
4522 case kCondGT:
4523 __ Or(TMP, lhs_high, lhs_low);
4524 __ Sra(AT, lhs_high, 31);
4525 __ Sltu(dst, AT, TMP);
4526 break;
4527 case kCondB: // always false
4528 __ Andi(dst, dst, 0);
4529 break;
4530 case kCondAE: // always true
4531 __ Ori(dst, ZERO, 1);
4532 break;
4533 }
4534 } else if (use_imm) {
4535 // TODO: more efficient comparison with constants without loading them into TMP/AT.
4536 switch (cond) {
4537 case kCondEQ:
4538 __ LoadConst32(TMP, imm_high);
4539 __ Xor(TMP, TMP, lhs_high);
4540 __ LoadConst32(AT, imm_low);
4541 __ Xor(AT, AT, lhs_low);
4542 __ Or(dst, TMP, AT);
4543 __ Sltiu(dst, dst, 1);
4544 break;
4545 case kCondNE:
4546 __ LoadConst32(TMP, imm_high);
4547 __ Xor(TMP, TMP, lhs_high);
4548 __ LoadConst32(AT, imm_low);
4549 __ Xor(AT, AT, lhs_low);
4550 __ Or(dst, TMP, AT);
4551 __ Sltu(dst, ZERO, dst);
4552 break;
4553 case kCondLT:
4554 case kCondGE:
4555 if (dst == lhs_low) {
4556 __ LoadConst32(TMP, imm_low);
4557 __ Sltu(dst, lhs_low, TMP);
4558 }
4559 __ LoadConst32(TMP, imm_high);
4560 __ Slt(AT, lhs_high, TMP);
4561 __ Slt(TMP, TMP, lhs_high);
4562 if (dst != lhs_low) {
4563 __ LoadConst32(dst, imm_low);
4564 __ Sltu(dst, lhs_low, dst);
4565 }
4566 __ Slt(dst, TMP, dst);
4567 __ Or(dst, dst, AT);
4568 if (cond == kCondGE) {
4569 __ Xori(dst, dst, 1);
4570 }
4571 break;
4572 case kCondGT:
4573 case kCondLE:
4574 if (dst == lhs_low) {
4575 __ LoadConst32(TMP, imm_low);
4576 __ Sltu(dst, TMP, lhs_low);
4577 }
4578 __ LoadConst32(TMP, imm_high);
4579 __ Slt(AT, TMP, lhs_high);
4580 __ Slt(TMP, lhs_high, TMP);
4581 if (dst != lhs_low) {
4582 __ LoadConst32(dst, imm_low);
4583 __ Sltu(dst, dst, lhs_low);
4584 }
4585 __ Slt(dst, TMP, dst);
4586 __ Or(dst, dst, AT);
4587 if (cond == kCondLE) {
4588 __ Xori(dst, dst, 1);
4589 }
4590 break;
4591 case kCondB:
4592 case kCondAE:
4593 if (dst == lhs_low) {
4594 __ LoadConst32(TMP, imm_low);
4595 __ Sltu(dst, lhs_low, TMP);
4596 }
4597 __ LoadConst32(TMP, imm_high);
4598 __ Sltu(AT, lhs_high, TMP);
4599 __ Sltu(TMP, TMP, lhs_high);
4600 if (dst != lhs_low) {
4601 __ LoadConst32(dst, imm_low);
4602 __ Sltu(dst, lhs_low, dst);
4603 }
4604 __ Slt(dst, TMP, dst);
4605 __ Or(dst, dst, AT);
4606 if (cond == kCondAE) {
4607 __ Xori(dst, dst, 1);
4608 }
4609 break;
4610 case kCondA:
4611 case kCondBE:
4612 if (dst == lhs_low) {
4613 __ LoadConst32(TMP, imm_low);
4614 __ Sltu(dst, TMP, lhs_low);
4615 }
4616 __ LoadConst32(TMP, imm_high);
4617 __ Sltu(AT, TMP, lhs_high);
4618 __ Sltu(TMP, lhs_high, TMP);
4619 if (dst != lhs_low) {
4620 __ LoadConst32(dst, imm_low);
4621 __ Sltu(dst, dst, lhs_low);
4622 }
4623 __ Slt(dst, TMP, dst);
4624 __ Or(dst, dst, AT);
4625 if (cond == kCondBE) {
4626 __ Xori(dst, dst, 1);
4627 }
4628 break;
4629 }
4630 } else {
4631 switch (cond) {
4632 case kCondEQ:
4633 __ Xor(TMP, lhs_high, rhs_high);
4634 __ Xor(AT, lhs_low, rhs_low);
4635 __ Or(dst, TMP, AT);
4636 __ Sltiu(dst, dst, 1);
4637 break;
4638 case kCondNE:
4639 __ Xor(TMP, lhs_high, rhs_high);
4640 __ Xor(AT, lhs_low, rhs_low);
4641 __ Or(dst, TMP, AT);
4642 __ Sltu(dst, ZERO, dst);
4643 break;
4644 case kCondLT:
4645 case kCondGE:
4646 __ Slt(TMP, rhs_high, lhs_high);
4647 __ Sltu(AT, lhs_low, rhs_low);
4648 __ Slt(TMP, TMP, AT);
4649 __ Slt(AT, lhs_high, rhs_high);
4650 __ Or(dst, AT, TMP);
4651 if (cond == kCondGE) {
4652 __ Xori(dst, dst, 1);
4653 }
4654 break;
4655 case kCondGT:
4656 case kCondLE:
4657 __ Slt(TMP, lhs_high, rhs_high);
4658 __ Sltu(AT, rhs_low, lhs_low);
4659 __ Slt(TMP, TMP, AT);
4660 __ Slt(AT, rhs_high, lhs_high);
4661 __ Or(dst, AT, TMP);
4662 if (cond == kCondLE) {
4663 __ Xori(dst, dst, 1);
4664 }
4665 break;
4666 case kCondB:
4667 case kCondAE:
4668 __ Sltu(TMP, rhs_high, lhs_high);
4669 __ Sltu(AT, lhs_low, rhs_low);
4670 __ Slt(TMP, TMP, AT);
4671 __ Sltu(AT, lhs_high, rhs_high);
4672 __ Or(dst, AT, TMP);
4673 if (cond == kCondAE) {
4674 __ Xori(dst, dst, 1);
4675 }
4676 break;
4677 case kCondA:
4678 case kCondBE:
4679 __ Sltu(TMP, lhs_high, rhs_high);
4680 __ Sltu(AT, rhs_low, lhs_low);
4681 __ Slt(TMP, TMP, AT);
4682 __ Sltu(AT, rhs_high, lhs_high);
4683 __ Or(dst, AT, TMP);
4684 if (cond == kCondBE) {
4685 __ Xori(dst, dst, 1);
4686 }
4687 break;
4688 }
4689 }
4690}
4691
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08004692void InstructionCodeGeneratorMIPS::GenerateLongCompareAndBranch(IfCondition cond,
4693 LocationSummary* locations,
4694 MipsLabel* label) {
4695 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4696 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
4697 Location rhs_location = locations->InAt(1);
4698 Register rhs_high = ZERO;
4699 Register rhs_low = ZERO;
4700 int64_t imm = 0;
4701 uint32_t imm_high = 0;
4702 uint32_t imm_low = 0;
4703 bool use_imm = rhs_location.IsConstant();
4704 if (use_imm) {
4705 imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
4706 imm_high = High32Bits(imm);
4707 imm_low = Low32Bits(imm);
4708 } else {
4709 rhs_high = rhs_location.AsRegisterPairHigh<Register>();
4710 rhs_low = rhs_location.AsRegisterPairLow<Register>();
4711 }
4712
4713 if (use_imm && imm == 0) {
4714 switch (cond) {
4715 case kCondEQ:
4716 case kCondBE: // <= 0 if zero
4717 __ Or(TMP, lhs_high, lhs_low);
4718 __ Beqz(TMP, label);
4719 break;
4720 case kCondNE:
4721 case kCondA: // > 0 if non-zero
4722 __ Or(TMP, lhs_high, lhs_low);
4723 __ Bnez(TMP, label);
4724 break;
4725 case kCondLT:
4726 __ Bltz(lhs_high, label);
4727 break;
4728 case kCondGE:
4729 __ Bgez(lhs_high, label);
4730 break;
4731 case kCondLE:
4732 __ Or(TMP, lhs_high, lhs_low);
4733 __ Sra(AT, lhs_high, 31);
4734 __ Bgeu(AT, TMP, label);
4735 break;
4736 case kCondGT:
4737 __ Or(TMP, lhs_high, lhs_low);
4738 __ Sra(AT, lhs_high, 31);
4739 __ Bltu(AT, TMP, label);
4740 break;
4741 case kCondB: // always false
4742 break;
4743 case kCondAE: // always true
4744 __ B(label);
4745 break;
4746 }
4747 } else if (use_imm) {
4748 // TODO: more efficient comparison with constants without loading them into TMP/AT.
4749 switch (cond) {
4750 case kCondEQ:
4751 __ LoadConst32(TMP, imm_high);
4752 __ Xor(TMP, TMP, lhs_high);
4753 __ LoadConst32(AT, imm_low);
4754 __ Xor(AT, AT, lhs_low);
4755 __ Or(TMP, TMP, AT);
4756 __ Beqz(TMP, label);
4757 break;
4758 case kCondNE:
4759 __ LoadConst32(TMP, imm_high);
4760 __ Xor(TMP, TMP, lhs_high);
4761 __ LoadConst32(AT, imm_low);
4762 __ Xor(AT, AT, lhs_low);
4763 __ Or(TMP, TMP, AT);
4764 __ Bnez(TMP, label);
4765 break;
4766 case kCondLT:
4767 __ LoadConst32(TMP, imm_high);
4768 __ Blt(lhs_high, TMP, label);
4769 __ Slt(TMP, TMP, lhs_high);
4770 __ LoadConst32(AT, imm_low);
4771 __ Sltu(AT, lhs_low, AT);
4772 __ Blt(TMP, AT, label);
4773 break;
4774 case kCondGE:
4775 __ LoadConst32(TMP, imm_high);
4776 __ Blt(TMP, lhs_high, label);
4777 __ Slt(TMP, lhs_high, TMP);
4778 __ LoadConst32(AT, imm_low);
4779 __ Sltu(AT, lhs_low, AT);
4780 __ Or(TMP, TMP, AT);
4781 __ Beqz(TMP, label);
4782 break;
4783 case kCondLE:
4784 __ LoadConst32(TMP, imm_high);
4785 __ Blt(lhs_high, TMP, label);
4786 __ Slt(TMP, TMP, lhs_high);
4787 __ LoadConst32(AT, imm_low);
4788 __ Sltu(AT, AT, lhs_low);
4789 __ Or(TMP, TMP, AT);
4790 __ Beqz(TMP, label);
4791 break;
4792 case kCondGT:
4793 __ LoadConst32(TMP, imm_high);
4794 __ Blt(TMP, lhs_high, label);
4795 __ Slt(TMP, lhs_high, TMP);
4796 __ LoadConst32(AT, imm_low);
4797 __ Sltu(AT, AT, lhs_low);
4798 __ Blt(TMP, AT, label);
4799 break;
4800 case kCondB:
4801 __ LoadConst32(TMP, imm_high);
4802 __ Bltu(lhs_high, TMP, label);
4803 __ Sltu(TMP, TMP, lhs_high);
4804 __ LoadConst32(AT, imm_low);
4805 __ Sltu(AT, lhs_low, AT);
4806 __ Blt(TMP, AT, label);
4807 break;
4808 case kCondAE:
4809 __ LoadConst32(TMP, imm_high);
4810 __ Bltu(TMP, lhs_high, label);
4811 __ Sltu(TMP, lhs_high, TMP);
4812 __ LoadConst32(AT, imm_low);
4813 __ Sltu(AT, lhs_low, AT);
4814 __ Or(TMP, TMP, AT);
4815 __ Beqz(TMP, label);
4816 break;
4817 case kCondBE:
4818 __ LoadConst32(TMP, imm_high);
4819 __ Bltu(lhs_high, TMP, label);
4820 __ Sltu(TMP, TMP, lhs_high);
4821 __ LoadConst32(AT, imm_low);
4822 __ Sltu(AT, AT, lhs_low);
4823 __ Or(TMP, TMP, AT);
4824 __ Beqz(TMP, label);
4825 break;
4826 case kCondA:
4827 __ LoadConst32(TMP, imm_high);
4828 __ Bltu(TMP, lhs_high, label);
4829 __ Sltu(TMP, lhs_high, TMP);
4830 __ LoadConst32(AT, imm_low);
4831 __ Sltu(AT, AT, lhs_low);
4832 __ Blt(TMP, AT, label);
4833 break;
4834 }
4835 } else {
4836 switch (cond) {
4837 case kCondEQ:
4838 __ Xor(TMP, lhs_high, rhs_high);
4839 __ Xor(AT, lhs_low, rhs_low);
4840 __ Or(TMP, TMP, AT);
4841 __ Beqz(TMP, label);
4842 break;
4843 case kCondNE:
4844 __ Xor(TMP, lhs_high, rhs_high);
4845 __ Xor(AT, lhs_low, rhs_low);
4846 __ Or(TMP, TMP, AT);
4847 __ Bnez(TMP, label);
4848 break;
4849 case kCondLT:
4850 __ Blt(lhs_high, rhs_high, label);
4851 __ Slt(TMP, rhs_high, lhs_high);
4852 __ Sltu(AT, lhs_low, rhs_low);
4853 __ Blt(TMP, AT, label);
4854 break;
4855 case kCondGE:
4856 __ Blt(rhs_high, lhs_high, label);
4857 __ Slt(TMP, lhs_high, rhs_high);
4858 __ Sltu(AT, lhs_low, rhs_low);
4859 __ Or(TMP, TMP, AT);
4860 __ Beqz(TMP, label);
4861 break;
4862 case kCondLE:
4863 __ Blt(lhs_high, rhs_high, label);
4864 __ Slt(TMP, rhs_high, lhs_high);
4865 __ Sltu(AT, rhs_low, lhs_low);
4866 __ Or(TMP, TMP, AT);
4867 __ Beqz(TMP, label);
4868 break;
4869 case kCondGT:
4870 __ Blt(rhs_high, lhs_high, label);
4871 __ Slt(TMP, lhs_high, rhs_high);
4872 __ Sltu(AT, rhs_low, lhs_low);
4873 __ Blt(TMP, AT, label);
4874 break;
4875 case kCondB:
4876 __ Bltu(lhs_high, rhs_high, label);
4877 __ Sltu(TMP, rhs_high, lhs_high);
4878 __ Sltu(AT, lhs_low, rhs_low);
4879 __ Blt(TMP, AT, label);
4880 break;
4881 case kCondAE:
4882 __ Bltu(rhs_high, lhs_high, label);
4883 __ Sltu(TMP, lhs_high, rhs_high);
4884 __ Sltu(AT, lhs_low, rhs_low);
4885 __ Or(TMP, TMP, AT);
4886 __ Beqz(TMP, label);
4887 break;
4888 case kCondBE:
4889 __ Bltu(lhs_high, rhs_high, label);
4890 __ Sltu(TMP, rhs_high, lhs_high);
4891 __ Sltu(AT, rhs_low, lhs_low);
4892 __ Or(TMP, TMP, AT);
4893 __ Beqz(TMP, label);
4894 break;
4895 case kCondA:
4896 __ Bltu(rhs_high, lhs_high, label);
4897 __ Sltu(TMP, lhs_high, rhs_high);
4898 __ Sltu(AT, rhs_low, lhs_low);
4899 __ Blt(TMP, AT, label);
4900 break;
4901 }
4902 }
4903}
4904
Alexey Frunze2ddb7172016-09-06 17:04:55 -07004905void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
4906 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004907 DataType::Type type,
Alexey Frunze2ddb7172016-09-06 17:04:55 -07004908 LocationSummary* locations) {
4909 Register dst = locations->Out().AsRegister<Register>();
4910 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
4911 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
4912 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01004913 if (type == DataType::Type::kFloat32) {
Alexey Frunze2ddb7172016-09-06 17:04:55 -07004914 if (isR6) {
4915 switch (cond) {
4916 case kCondEQ:
4917 __ CmpEqS(FTMP, lhs, rhs);
4918 __ Mfc1(dst, FTMP);
4919 __ Andi(dst, dst, 1);
4920 break;
4921 case kCondNE:
4922 __ CmpEqS(FTMP, lhs, rhs);
4923 __ Mfc1(dst, FTMP);
4924 __ Addiu(dst, dst, 1);
4925 break;
4926 case kCondLT:
4927 if (gt_bias) {
4928 __ CmpLtS(FTMP, lhs, rhs);
4929 } else {
4930 __ CmpUltS(FTMP, lhs, rhs);
4931 }
4932 __ Mfc1(dst, FTMP);
4933 __ Andi(dst, dst, 1);
4934 break;
4935 case kCondLE:
4936 if (gt_bias) {
4937 __ CmpLeS(FTMP, lhs, rhs);
4938 } else {
4939 __ CmpUleS(FTMP, lhs, rhs);
4940 }
4941 __ Mfc1(dst, FTMP);
4942 __ Andi(dst, dst, 1);
4943 break;
4944 case kCondGT:
4945 if (gt_bias) {
4946 __ CmpUltS(FTMP, rhs, lhs);
4947 } else {
4948 __ CmpLtS(FTMP, rhs, lhs);
4949 }
4950 __ Mfc1(dst, FTMP);
4951 __ Andi(dst, dst, 1);
4952 break;
4953 case kCondGE:
4954 if (gt_bias) {
4955 __ CmpUleS(FTMP, rhs, lhs);
4956 } else {
4957 __ CmpLeS(FTMP, rhs, lhs);
4958 }
4959 __ Mfc1(dst, FTMP);
4960 __ Andi(dst, dst, 1);
4961 break;
4962 default:
4963 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
4964 UNREACHABLE();
4965 }
4966 } else {
4967 switch (cond) {
4968 case kCondEQ:
4969 __ CeqS(0, lhs, rhs);
4970 __ LoadConst32(dst, 1);
4971 __ Movf(dst, ZERO, 0);
4972 break;
4973 case kCondNE:
4974 __ CeqS(0, lhs, rhs);
4975 __ LoadConst32(dst, 1);
4976 __ Movt(dst, ZERO, 0);
4977 break;
4978 case kCondLT:
4979 if (gt_bias) {
4980 __ ColtS(0, lhs, rhs);
4981 } else {
4982 __ CultS(0, lhs, rhs);
4983 }
4984 __ LoadConst32(dst, 1);
4985 __ Movf(dst, ZERO, 0);
4986 break;
4987 case kCondLE:
4988 if (gt_bias) {
4989 __ ColeS(0, lhs, rhs);
4990 } else {
4991 __ CuleS(0, lhs, rhs);
4992 }
4993 __ LoadConst32(dst, 1);
4994 __ Movf(dst, ZERO, 0);
4995 break;
4996 case kCondGT:
4997 if (gt_bias) {
4998 __ CultS(0, rhs, lhs);
4999 } else {
5000 __ ColtS(0, rhs, lhs);
5001 }
5002 __ LoadConst32(dst, 1);
5003 __ Movf(dst, ZERO, 0);
5004 break;
5005 case kCondGE:
5006 if (gt_bias) {
5007 __ CuleS(0, rhs, lhs);
5008 } else {
5009 __ ColeS(0, rhs, lhs);
5010 }
5011 __ LoadConst32(dst, 1);
5012 __ Movf(dst, ZERO, 0);
5013 break;
5014 default:
5015 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
5016 UNREACHABLE();
5017 }
5018 }
5019 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005020 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunze2ddb7172016-09-06 17:04:55 -07005021 if (isR6) {
5022 switch (cond) {
5023 case kCondEQ:
5024 __ CmpEqD(FTMP, lhs, rhs);
5025 __ Mfc1(dst, FTMP);
5026 __ Andi(dst, dst, 1);
5027 break;
5028 case kCondNE:
5029 __ CmpEqD(FTMP, lhs, rhs);
5030 __ Mfc1(dst, FTMP);
5031 __ Addiu(dst, dst, 1);
5032 break;
5033 case kCondLT:
5034 if (gt_bias) {
5035 __ CmpLtD(FTMP, lhs, rhs);
5036 } else {
5037 __ CmpUltD(FTMP, lhs, rhs);
5038 }
5039 __ Mfc1(dst, FTMP);
5040 __ Andi(dst, dst, 1);
5041 break;
5042 case kCondLE:
5043 if (gt_bias) {
5044 __ CmpLeD(FTMP, lhs, rhs);
5045 } else {
5046 __ CmpUleD(FTMP, lhs, rhs);
5047 }
5048 __ Mfc1(dst, FTMP);
5049 __ Andi(dst, dst, 1);
5050 break;
5051 case kCondGT:
5052 if (gt_bias) {
5053 __ CmpUltD(FTMP, rhs, lhs);
5054 } else {
5055 __ CmpLtD(FTMP, rhs, lhs);
5056 }
5057 __ Mfc1(dst, FTMP);
5058 __ Andi(dst, dst, 1);
5059 break;
5060 case kCondGE:
5061 if (gt_bias) {
5062 __ CmpUleD(FTMP, rhs, lhs);
5063 } else {
5064 __ CmpLeD(FTMP, rhs, lhs);
5065 }
5066 __ Mfc1(dst, FTMP);
5067 __ Andi(dst, dst, 1);
5068 break;
5069 default:
5070 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
5071 UNREACHABLE();
5072 }
5073 } else {
5074 switch (cond) {
5075 case kCondEQ:
5076 __ CeqD(0, lhs, rhs);
5077 __ LoadConst32(dst, 1);
5078 __ Movf(dst, ZERO, 0);
5079 break;
5080 case kCondNE:
5081 __ CeqD(0, lhs, rhs);
5082 __ LoadConst32(dst, 1);
5083 __ Movt(dst, ZERO, 0);
5084 break;
5085 case kCondLT:
5086 if (gt_bias) {
5087 __ ColtD(0, lhs, rhs);
5088 } else {
5089 __ CultD(0, lhs, rhs);
5090 }
5091 __ LoadConst32(dst, 1);
5092 __ Movf(dst, ZERO, 0);
5093 break;
5094 case kCondLE:
5095 if (gt_bias) {
5096 __ ColeD(0, lhs, rhs);
5097 } else {
5098 __ CuleD(0, lhs, rhs);
5099 }
5100 __ LoadConst32(dst, 1);
5101 __ Movf(dst, ZERO, 0);
5102 break;
5103 case kCondGT:
5104 if (gt_bias) {
5105 __ CultD(0, rhs, lhs);
5106 } else {
5107 __ ColtD(0, rhs, lhs);
5108 }
5109 __ LoadConst32(dst, 1);
5110 __ Movf(dst, ZERO, 0);
5111 break;
5112 case kCondGE:
5113 if (gt_bias) {
5114 __ CuleD(0, rhs, lhs);
5115 } else {
5116 __ ColeD(0, rhs, lhs);
5117 }
5118 __ LoadConst32(dst, 1);
5119 __ Movf(dst, ZERO, 0);
5120 break;
5121 default:
5122 LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
5123 UNREACHABLE();
5124 }
5125 }
5126 }
5127}
5128
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005129bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR2(IfCondition cond,
5130 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005131 DataType::Type type,
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005132 LocationSummary* input_locations,
5133 int cc) {
5134 FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
5135 FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
5136 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005137 if (type == DataType::Type::kFloat32) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005138 switch (cond) {
5139 case kCondEQ:
5140 __ CeqS(cc, lhs, rhs);
5141 return false;
5142 case kCondNE:
5143 __ CeqS(cc, lhs, rhs);
5144 return true;
5145 case kCondLT:
5146 if (gt_bias) {
5147 __ ColtS(cc, lhs, rhs);
5148 } else {
5149 __ CultS(cc, lhs, rhs);
5150 }
5151 return false;
5152 case kCondLE:
5153 if (gt_bias) {
5154 __ ColeS(cc, lhs, rhs);
5155 } else {
5156 __ CuleS(cc, lhs, rhs);
5157 }
5158 return false;
5159 case kCondGT:
5160 if (gt_bias) {
5161 __ CultS(cc, rhs, lhs);
5162 } else {
5163 __ ColtS(cc, rhs, lhs);
5164 }
5165 return false;
5166 case kCondGE:
5167 if (gt_bias) {
5168 __ CuleS(cc, rhs, lhs);
5169 } else {
5170 __ ColeS(cc, rhs, lhs);
5171 }
5172 return false;
5173 default:
5174 LOG(FATAL) << "Unexpected non-floating-point condition";
5175 UNREACHABLE();
5176 }
5177 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005178 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005179 switch (cond) {
5180 case kCondEQ:
5181 __ CeqD(cc, lhs, rhs);
5182 return false;
5183 case kCondNE:
5184 __ CeqD(cc, lhs, rhs);
5185 return true;
5186 case kCondLT:
5187 if (gt_bias) {
5188 __ ColtD(cc, lhs, rhs);
5189 } else {
5190 __ CultD(cc, lhs, rhs);
5191 }
5192 return false;
5193 case kCondLE:
5194 if (gt_bias) {
5195 __ ColeD(cc, lhs, rhs);
5196 } else {
5197 __ CuleD(cc, lhs, rhs);
5198 }
5199 return false;
5200 case kCondGT:
5201 if (gt_bias) {
5202 __ CultD(cc, rhs, lhs);
5203 } else {
5204 __ ColtD(cc, rhs, lhs);
5205 }
5206 return false;
5207 case kCondGE:
5208 if (gt_bias) {
5209 __ CuleD(cc, rhs, lhs);
5210 } else {
5211 __ ColeD(cc, rhs, lhs);
5212 }
5213 return false;
5214 default:
5215 LOG(FATAL) << "Unexpected non-floating-point condition";
5216 UNREACHABLE();
5217 }
5218 }
5219}
5220
5221bool InstructionCodeGeneratorMIPS::MaterializeFpCompareR6(IfCondition cond,
5222 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005223 DataType::Type type,
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005224 LocationSummary* input_locations,
5225 FRegister dst) {
5226 FRegister lhs = input_locations->InAt(0).AsFpuRegister<FRegister>();
5227 FRegister rhs = input_locations->InAt(1).AsFpuRegister<FRegister>();
5228 CHECK(codegen_->GetInstructionSetFeatures().IsR6());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005229 if (type == DataType::Type::kFloat32) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005230 switch (cond) {
5231 case kCondEQ:
5232 __ CmpEqS(dst, lhs, rhs);
5233 return false;
5234 case kCondNE:
5235 __ CmpEqS(dst, lhs, rhs);
5236 return true;
5237 case kCondLT:
5238 if (gt_bias) {
5239 __ CmpLtS(dst, lhs, rhs);
5240 } else {
5241 __ CmpUltS(dst, lhs, rhs);
5242 }
5243 return false;
5244 case kCondLE:
5245 if (gt_bias) {
5246 __ CmpLeS(dst, lhs, rhs);
5247 } else {
5248 __ CmpUleS(dst, lhs, rhs);
5249 }
5250 return false;
5251 case kCondGT:
5252 if (gt_bias) {
5253 __ CmpUltS(dst, rhs, lhs);
5254 } else {
5255 __ CmpLtS(dst, rhs, lhs);
5256 }
5257 return false;
5258 case kCondGE:
5259 if (gt_bias) {
5260 __ CmpUleS(dst, rhs, lhs);
5261 } else {
5262 __ CmpLeS(dst, rhs, lhs);
5263 }
5264 return false;
5265 default:
5266 LOG(FATAL) << "Unexpected non-floating-point condition";
5267 UNREACHABLE();
5268 }
5269 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005270 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005271 switch (cond) {
5272 case kCondEQ:
5273 __ CmpEqD(dst, lhs, rhs);
5274 return false;
5275 case kCondNE:
5276 __ CmpEqD(dst, lhs, rhs);
5277 return true;
5278 case kCondLT:
5279 if (gt_bias) {
5280 __ CmpLtD(dst, lhs, rhs);
5281 } else {
5282 __ CmpUltD(dst, lhs, rhs);
5283 }
5284 return false;
5285 case kCondLE:
5286 if (gt_bias) {
5287 __ CmpLeD(dst, lhs, rhs);
5288 } else {
5289 __ CmpUleD(dst, lhs, rhs);
5290 }
5291 return false;
5292 case kCondGT:
5293 if (gt_bias) {
5294 __ CmpUltD(dst, rhs, lhs);
5295 } else {
5296 __ CmpLtD(dst, rhs, lhs);
5297 }
5298 return false;
5299 case kCondGE:
5300 if (gt_bias) {
5301 __ CmpUleD(dst, rhs, lhs);
5302 } else {
5303 __ CmpLeD(dst, rhs, lhs);
5304 }
5305 return false;
5306 default:
5307 LOG(FATAL) << "Unexpected non-floating-point condition";
5308 UNREACHABLE();
5309 }
5310 }
5311}
5312
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005313void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
5314 bool gt_bias,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005315 DataType::Type type,
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005316 LocationSummary* locations,
5317 MipsLabel* label) {
5318 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
5319 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
5320 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005321 if (type == DataType::Type::kFloat32) {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005322 if (isR6) {
5323 switch (cond) {
5324 case kCondEQ:
5325 __ CmpEqS(FTMP, lhs, rhs);
5326 __ Bc1nez(FTMP, label);
5327 break;
5328 case kCondNE:
5329 __ CmpEqS(FTMP, lhs, rhs);
5330 __ Bc1eqz(FTMP, label);
5331 break;
5332 case kCondLT:
5333 if (gt_bias) {
5334 __ CmpLtS(FTMP, lhs, rhs);
5335 } else {
5336 __ CmpUltS(FTMP, lhs, rhs);
5337 }
5338 __ Bc1nez(FTMP, label);
5339 break;
5340 case kCondLE:
5341 if (gt_bias) {
5342 __ CmpLeS(FTMP, lhs, rhs);
5343 } else {
5344 __ CmpUleS(FTMP, lhs, rhs);
5345 }
5346 __ Bc1nez(FTMP, label);
5347 break;
5348 case kCondGT:
5349 if (gt_bias) {
5350 __ CmpUltS(FTMP, rhs, lhs);
5351 } else {
5352 __ CmpLtS(FTMP, rhs, lhs);
5353 }
5354 __ Bc1nez(FTMP, label);
5355 break;
5356 case kCondGE:
5357 if (gt_bias) {
5358 __ CmpUleS(FTMP, rhs, lhs);
5359 } else {
5360 __ CmpLeS(FTMP, rhs, lhs);
5361 }
5362 __ Bc1nez(FTMP, label);
5363 break;
5364 default:
5365 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005366 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005367 }
5368 } else {
5369 switch (cond) {
5370 case kCondEQ:
5371 __ CeqS(0, lhs, rhs);
5372 __ Bc1t(0, label);
5373 break;
5374 case kCondNE:
5375 __ CeqS(0, lhs, rhs);
5376 __ Bc1f(0, label);
5377 break;
5378 case kCondLT:
5379 if (gt_bias) {
5380 __ ColtS(0, lhs, rhs);
5381 } else {
5382 __ CultS(0, lhs, rhs);
5383 }
5384 __ Bc1t(0, label);
5385 break;
5386 case kCondLE:
5387 if (gt_bias) {
5388 __ ColeS(0, lhs, rhs);
5389 } else {
5390 __ CuleS(0, lhs, rhs);
5391 }
5392 __ Bc1t(0, label);
5393 break;
5394 case kCondGT:
5395 if (gt_bias) {
5396 __ CultS(0, rhs, lhs);
5397 } else {
5398 __ ColtS(0, rhs, lhs);
5399 }
5400 __ Bc1t(0, label);
5401 break;
5402 case kCondGE:
5403 if (gt_bias) {
5404 __ CuleS(0, rhs, lhs);
5405 } else {
5406 __ ColeS(0, rhs, lhs);
5407 }
5408 __ Bc1t(0, label);
5409 break;
5410 default:
5411 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005412 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005413 }
5414 }
5415 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005416 DCHECK_EQ(type, DataType::Type::kFloat64);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005417 if (isR6) {
5418 switch (cond) {
5419 case kCondEQ:
5420 __ CmpEqD(FTMP, lhs, rhs);
5421 __ Bc1nez(FTMP, label);
5422 break;
5423 case kCondNE:
5424 __ CmpEqD(FTMP, lhs, rhs);
5425 __ Bc1eqz(FTMP, label);
5426 break;
5427 case kCondLT:
5428 if (gt_bias) {
5429 __ CmpLtD(FTMP, lhs, rhs);
5430 } else {
5431 __ CmpUltD(FTMP, lhs, rhs);
5432 }
5433 __ Bc1nez(FTMP, label);
5434 break;
5435 case kCondLE:
5436 if (gt_bias) {
5437 __ CmpLeD(FTMP, lhs, rhs);
5438 } else {
5439 __ CmpUleD(FTMP, lhs, rhs);
5440 }
5441 __ Bc1nez(FTMP, label);
5442 break;
5443 case kCondGT:
5444 if (gt_bias) {
5445 __ CmpUltD(FTMP, rhs, lhs);
5446 } else {
5447 __ CmpLtD(FTMP, rhs, lhs);
5448 }
5449 __ Bc1nez(FTMP, label);
5450 break;
5451 case kCondGE:
5452 if (gt_bias) {
5453 __ CmpUleD(FTMP, rhs, lhs);
5454 } else {
5455 __ CmpLeD(FTMP, rhs, lhs);
5456 }
5457 __ Bc1nez(FTMP, label);
5458 break;
5459 default:
5460 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005461 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005462 }
5463 } else {
5464 switch (cond) {
5465 case kCondEQ:
5466 __ CeqD(0, lhs, rhs);
5467 __ Bc1t(0, label);
5468 break;
5469 case kCondNE:
5470 __ CeqD(0, lhs, rhs);
5471 __ Bc1f(0, label);
5472 break;
5473 case kCondLT:
5474 if (gt_bias) {
5475 __ ColtD(0, lhs, rhs);
5476 } else {
5477 __ CultD(0, lhs, rhs);
5478 }
5479 __ Bc1t(0, label);
5480 break;
5481 case kCondLE:
5482 if (gt_bias) {
5483 __ ColeD(0, lhs, rhs);
5484 } else {
5485 __ CuleD(0, lhs, rhs);
5486 }
5487 __ Bc1t(0, label);
5488 break;
5489 case kCondGT:
5490 if (gt_bias) {
5491 __ CultD(0, rhs, lhs);
5492 } else {
5493 __ ColtD(0, rhs, lhs);
5494 }
5495 __ Bc1t(0, label);
5496 break;
5497 case kCondGE:
5498 if (gt_bias) {
5499 __ CuleD(0, rhs, lhs);
5500 } else {
5501 __ ColeD(0, rhs, lhs);
5502 }
5503 __ Bc1t(0, label);
5504 break;
5505 default:
5506 LOG(FATAL) << "Unexpected non-floating-point condition";
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005507 UNREACHABLE();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005508 }
5509 }
5510 }
5511}
5512
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005513void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00005514 size_t condition_input_index,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005515 MipsLabel* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00005516 MipsLabel* false_target) {
5517 HInstruction* cond = instruction->InputAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005518
David Brazdil0debae72015-11-12 18:37:00 +00005519 if (true_target == nullptr && false_target == nullptr) {
5520 // Nothing to do. The code always falls through.
5521 return;
5522 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00005523 // Constant condition, statically compared against "true" (integer value 1).
5524 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00005525 if (true_target != nullptr) {
5526 __ B(true_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005527 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005528 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00005529 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00005530 if (false_target != nullptr) {
5531 __ B(false_target);
5532 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005533 }
David Brazdil0debae72015-11-12 18:37:00 +00005534 return;
5535 }
5536
5537 // The following code generates these patterns:
5538 // (1) true_target == nullptr && false_target != nullptr
5539 // - opposite condition true => branch to false_target
5540 // (2) true_target != nullptr && false_target == nullptr
5541 // - condition true => branch to true_target
5542 // (3) true_target != nullptr && false_target != nullptr
5543 // - condition true => branch to true_target
5544 // - branch to false_target
5545 if (IsBooleanValueOrMaterializedCondition(cond)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005546 // The condition instruction has been materialized, compare the output to 0.
David Brazdil0debae72015-11-12 18:37:00 +00005547 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005548 DCHECK(cond_val.IsRegister());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005549 if (true_target == nullptr) {
David Brazdil0debae72015-11-12 18:37:00 +00005550 __ Beqz(cond_val.AsRegister<Register>(), false_target);
5551 } else {
5552 __ Bnez(cond_val.AsRegister<Register>(), true_target);
5553 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005554 } else {
5555 // The condition instruction has not been materialized, use its inputs as
5556 // the comparison and its condition as the branch condition.
David Brazdil0debae72015-11-12 18:37:00 +00005557 HCondition* condition = cond->AsCondition();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005558 DataType::Type type = condition->InputAt(0)->GetType();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005559 LocationSummary* locations = cond->GetLocations();
5560 IfCondition if_cond = condition->GetCondition();
5561 MipsLabel* branch_target = true_target;
David Brazdil0debae72015-11-12 18:37:00 +00005562
David Brazdil0debae72015-11-12 18:37:00 +00005563 if (true_target == nullptr) {
5564 if_cond = condition->GetOppositeCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005565 branch_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00005566 }
5567
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005568 switch (type) {
5569 default:
5570 GenerateIntCompareAndBranch(if_cond, locations, branch_target);
5571 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005572 case DataType::Type::kInt64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005573 GenerateLongCompareAndBranch(if_cond, locations, branch_target);
5574 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005575 case DataType::Type::kFloat32:
5576 case DataType::Type::kFloat64:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08005577 GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
5578 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005579 }
5580 }
David Brazdil0debae72015-11-12 18:37:00 +00005581
5582 // If neither branch falls through (case 3), the conditional branch to `true_target`
5583 // was already emitted (case 2) and we need to emit a jump to `false_target`.
5584 if (true_target != nullptr && false_target != nullptr) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005585 __ B(false_target);
5586 }
5587}
5588
5589void LocationsBuilderMIPS::VisitIf(HIf* if_instr) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01005590 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(if_instr);
David Brazdil0debae72015-11-12 18:37:00 +00005591 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005592 locations->SetInAt(0, Location::RequiresRegister());
5593 }
5594}
5595
5596void InstructionCodeGeneratorMIPS::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00005597 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
5598 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
5599 MipsLabel* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
5600 nullptr : codegen_->GetLabelOf(true_successor);
5601 MipsLabel* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
5602 nullptr : codegen_->GetLabelOf(false_successor);
5603 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005604}
5605
5606void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01005607 LocationSummary* locations = new (GetGraph()->GetAllocator())
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005608 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
Nicolas Geoffray4e92c3c2017-05-08 09:34:26 +01005609 InvokeRuntimeCallingConvention calling_convention;
5610 RegisterSet caller_saves = RegisterSet::Empty();
5611 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5612 locations->SetCustomSlowPathCallerSaves(caller_saves);
David Brazdil0debae72015-11-12 18:37:00 +00005613 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005614 locations->SetInAt(0, Location::RequiresRegister());
5615 }
5616}
5617
5618void InstructionCodeGeneratorMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08005619 SlowPathCodeMIPS* slow_path =
5620 deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathMIPS>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00005621 GenerateTestAndBranch(deoptimize,
5622 /* condition_input_index */ 0,
5623 slow_path->GetEntryLabel(),
5624 /* false_target */ nullptr);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005625}
5626
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005627// This function returns true if a conditional move can be generated for HSelect.
5628// Otherwise it returns false and HSelect must be implemented in terms of conditonal
5629// branches and regular moves.
5630//
5631// If `locations_to_set` isn't nullptr, its inputs and outputs are set for HSelect.
5632//
5633// While determining feasibility of a conditional move and setting inputs/outputs
5634// are two distinct tasks, this function does both because they share quite a bit
5635// of common logic.
5636static bool CanMoveConditionally(HSelect* select, bool is_r6, LocationSummary* locations_to_set) {
5637 bool materialized = IsBooleanValueOrMaterializedCondition(select->GetCondition());
5638 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
5639 HCondition* condition = cond->AsCondition();
5640
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005641 DataType::Type cond_type =
5642 materialized ? DataType::Type::kInt32 : condition->InputAt(0)->GetType();
5643 DataType::Type dst_type = select->GetType();
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005644
5645 HConstant* cst_true_value = select->GetTrueValue()->AsConstant();
5646 HConstant* cst_false_value = select->GetFalseValue()->AsConstant();
5647 bool is_true_value_zero_constant =
5648 (cst_true_value != nullptr && cst_true_value->IsZeroBitPattern());
5649 bool is_false_value_zero_constant =
5650 (cst_false_value != nullptr && cst_false_value->IsZeroBitPattern());
5651
5652 bool can_move_conditionally = false;
5653 bool use_const_for_false_in = false;
5654 bool use_const_for_true_in = false;
5655
5656 if (!cond->IsConstant()) {
5657 switch (cond_type) {
5658 default:
5659 switch (dst_type) {
5660 default:
5661 // Moving int on int condition.
5662 if (is_r6) {
5663 if (is_true_value_zero_constant) {
5664 // seleqz out_reg, false_reg, cond_reg
5665 can_move_conditionally = true;
5666 use_const_for_true_in = true;
5667 } else if (is_false_value_zero_constant) {
5668 // selnez out_reg, true_reg, cond_reg
5669 can_move_conditionally = true;
5670 use_const_for_false_in = true;
5671 } else if (materialized) {
5672 // Not materializing unmaterialized int conditions
5673 // to keep the instruction count low.
5674 // selnez AT, true_reg, cond_reg
5675 // seleqz TMP, false_reg, cond_reg
5676 // or out_reg, AT, TMP
5677 can_move_conditionally = true;
5678 }
5679 } else {
5680 // movn out_reg, true_reg/ZERO, cond_reg
5681 can_move_conditionally = true;
5682 use_const_for_true_in = is_true_value_zero_constant;
5683 }
5684 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005685 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005686 // Moving long on int condition.
5687 if (is_r6) {
5688 if (is_true_value_zero_constant) {
5689 // seleqz out_reg_lo, false_reg_lo, cond_reg
5690 // seleqz out_reg_hi, false_reg_hi, cond_reg
5691 can_move_conditionally = true;
5692 use_const_for_true_in = true;
5693 } else if (is_false_value_zero_constant) {
5694 // selnez out_reg_lo, true_reg_lo, cond_reg
5695 // selnez out_reg_hi, true_reg_hi, cond_reg
5696 can_move_conditionally = true;
5697 use_const_for_false_in = true;
5698 }
5699 // Other long conditional moves would generate 6+ instructions,
5700 // which is too many.
5701 } else {
5702 // movn out_reg_lo, true_reg_lo/ZERO, cond_reg
5703 // movn out_reg_hi, true_reg_hi/ZERO, cond_reg
5704 can_move_conditionally = true;
5705 use_const_for_true_in = is_true_value_zero_constant;
5706 }
5707 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005708 case DataType::Type::kFloat32:
5709 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005710 // Moving float/double on int condition.
5711 if (is_r6) {
5712 if (materialized) {
5713 // Not materializing unmaterialized int conditions
5714 // to keep the instruction count low.
5715 can_move_conditionally = true;
5716 if (is_true_value_zero_constant) {
5717 // sltu TMP, ZERO, cond_reg
5718 // mtc1 TMP, temp_cond_reg
5719 // seleqz.fmt out_reg, false_reg, temp_cond_reg
5720 use_const_for_true_in = true;
5721 } else if (is_false_value_zero_constant) {
5722 // sltu TMP, ZERO, cond_reg
5723 // mtc1 TMP, temp_cond_reg
5724 // selnez.fmt out_reg, true_reg, temp_cond_reg
5725 use_const_for_false_in = true;
5726 } else {
5727 // sltu TMP, ZERO, cond_reg
5728 // mtc1 TMP, temp_cond_reg
5729 // sel.fmt temp_cond_reg, false_reg, true_reg
5730 // mov.fmt out_reg, temp_cond_reg
5731 }
5732 }
5733 } else {
5734 // movn.fmt out_reg, true_reg, cond_reg
5735 can_move_conditionally = true;
5736 }
5737 break;
5738 }
5739 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005740 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005741 // We don't materialize long comparison now
5742 // and use conditional branches instead.
5743 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005744 case DataType::Type::kFloat32:
5745 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005746 switch (dst_type) {
5747 default:
5748 // Moving int on float/double condition.
5749 if (is_r6) {
5750 if (is_true_value_zero_constant) {
5751 // mfc1 TMP, temp_cond_reg
5752 // seleqz out_reg, false_reg, TMP
5753 can_move_conditionally = true;
5754 use_const_for_true_in = true;
5755 } else if (is_false_value_zero_constant) {
5756 // mfc1 TMP, temp_cond_reg
5757 // selnez out_reg, true_reg, TMP
5758 can_move_conditionally = true;
5759 use_const_for_false_in = true;
5760 } else {
5761 // mfc1 TMP, temp_cond_reg
5762 // selnez AT, true_reg, TMP
5763 // seleqz TMP, false_reg, TMP
5764 // or out_reg, AT, TMP
5765 can_move_conditionally = true;
5766 }
5767 } else {
5768 // movt out_reg, true_reg/ZERO, cc
5769 can_move_conditionally = true;
5770 use_const_for_true_in = is_true_value_zero_constant;
5771 }
5772 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005773 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005774 // Moving long on float/double condition.
5775 if (is_r6) {
5776 if (is_true_value_zero_constant) {
5777 // mfc1 TMP, temp_cond_reg
5778 // seleqz out_reg_lo, false_reg_lo, TMP
5779 // seleqz out_reg_hi, false_reg_hi, TMP
5780 can_move_conditionally = true;
5781 use_const_for_true_in = true;
5782 } else if (is_false_value_zero_constant) {
5783 // mfc1 TMP, temp_cond_reg
5784 // selnez out_reg_lo, true_reg_lo, TMP
5785 // selnez out_reg_hi, true_reg_hi, TMP
5786 can_move_conditionally = true;
5787 use_const_for_false_in = true;
5788 }
5789 // Other long conditional moves would generate 6+ instructions,
5790 // which is too many.
5791 } else {
5792 // movt out_reg_lo, true_reg_lo/ZERO, cc
5793 // movt out_reg_hi, true_reg_hi/ZERO, cc
5794 can_move_conditionally = true;
5795 use_const_for_true_in = is_true_value_zero_constant;
5796 }
5797 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005798 case DataType::Type::kFloat32:
5799 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005800 // Moving float/double on float/double condition.
5801 if (is_r6) {
5802 can_move_conditionally = true;
5803 if (is_true_value_zero_constant) {
5804 // seleqz.fmt out_reg, false_reg, temp_cond_reg
5805 use_const_for_true_in = true;
5806 } else if (is_false_value_zero_constant) {
5807 // selnez.fmt out_reg, true_reg, temp_cond_reg
5808 use_const_for_false_in = true;
5809 } else {
5810 // sel.fmt temp_cond_reg, false_reg, true_reg
5811 // mov.fmt out_reg, temp_cond_reg
5812 }
5813 } else {
5814 // movt.fmt out_reg, true_reg, cc
5815 can_move_conditionally = true;
5816 }
5817 break;
5818 }
5819 break;
5820 }
5821 }
5822
5823 if (can_move_conditionally) {
5824 DCHECK(!use_const_for_false_in || !use_const_for_true_in);
5825 } else {
5826 DCHECK(!use_const_for_false_in);
5827 DCHECK(!use_const_for_true_in);
5828 }
5829
5830 if (locations_to_set != nullptr) {
5831 if (use_const_for_false_in) {
5832 locations_to_set->SetInAt(0, Location::ConstantLocation(cst_false_value));
5833 } else {
5834 locations_to_set->SetInAt(0,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005835 DataType::IsFloatingPointType(dst_type)
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005836 ? Location::RequiresFpuRegister()
5837 : Location::RequiresRegister());
5838 }
5839 if (use_const_for_true_in) {
5840 locations_to_set->SetInAt(1, Location::ConstantLocation(cst_true_value));
5841 } else {
5842 locations_to_set->SetInAt(1,
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005843 DataType::IsFloatingPointType(dst_type)
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005844 ? Location::RequiresFpuRegister()
5845 : Location::RequiresRegister());
5846 }
5847 if (materialized) {
5848 locations_to_set->SetInAt(2, Location::RequiresRegister());
5849 }
5850 // On R6 we don't require the output to be the same as the
5851 // first input for conditional moves unlike on R2.
5852 bool is_out_same_as_first_in = !can_move_conditionally || !is_r6;
5853 if (is_out_same_as_first_in) {
5854 locations_to_set->SetOut(Location::SameAsFirstInput());
5855 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005856 locations_to_set->SetOut(DataType::IsFloatingPointType(dst_type)
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005857 ? Location::RequiresFpuRegister()
5858 : Location::RequiresRegister());
5859 }
5860 }
5861
5862 return can_move_conditionally;
5863}
5864
5865void InstructionCodeGeneratorMIPS::GenConditionalMoveR2(HSelect* select) {
5866 LocationSummary* locations = select->GetLocations();
5867 Location dst = locations->Out();
5868 Location src = locations->InAt(1);
5869 Register src_reg = ZERO;
5870 Register src_reg_high = ZERO;
5871 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
5872 Register cond_reg = TMP;
5873 int cond_cc = 0;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005874 DataType::Type cond_type = DataType::Type::kInt32;
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005875 bool cond_inverted = false;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005876 DataType::Type dst_type = select->GetType();
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005877
5878 if (IsBooleanValueOrMaterializedCondition(cond)) {
5879 cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
5880 } else {
5881 HCondition* condition = cond->AsCondition();
5882 LocationSummary* cond_locations = cond->GetLocations();
5883 IfCondition if_cond = condition->GetCondition();
5884 cond_type = condition->InputAt(0)->GetType();
5885 switch (cond_type) {
5886 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005887 DCHECK_NE(cond_type, DataType::Type::kInt64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005888 cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
5889 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005890 case DataType::Type::kFloat32:
5891 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005892 cond_inverted = MaterializeFpCompareR2(if_cond,
5893 condition->IsGtBias(),
5894 cond_type,
5895 cond_locations,
5896 cond_cc);
5897 break;
5898 }
5899 }
5900
5901 DCHECK(dst.Equals(locations->InAt(0)));
5902 if (src.IsRegister()) {
5903 src_reg = src.AsRegister<Register>();
5904 } else if (src.IsRegisterPair()) {
5905 src_reg = src.AsRegisterPairLow<Register>();
5906 src_reg_high = src.AsRegisterPairHigh<Register>();
5907 } else if (src.IsConstant()) {
5908 DCHECK(src.GetConstant()->IsZeroBitPattern());
5909 }
5910
5911 switch (cond_type) {
5912 default:
5913 switch (dst_type) {
5914 default:
5915 if (cond_inverted) {
5916 __ Movz(dst.AsRegister<Register>(), src_reg, cond_reg);
5917 } else {
5918 __ Movn(dst.AsRegister<Register>(), src_reg, cond_reg);
5919 }
5920 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005921 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005922 if (cond_inverted) {
5923 __ Movz(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
5924 __ Movz(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
5925 } else {
5926 __ Movn(dst.AsRegisterPairLow<Register>(), src_reg, cond_reg);
5927 __ Movn(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_reg);
5928 }
5929 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005930 case DataType::Type::kFloat32:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005931 if (cond_inverted) {
5932 __ MovzS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5933 } else {
5934 __ MovnS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5935 }
5936 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005937 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005938 if (cond_inverted) {
5939 __ MovzD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5940 } else {
5941 __ MovnD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_reg);
5942 }
5943 break;
5944 }
5945 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005946 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005947 LOG(FATAL) << "Unreachable";
5948 UNREACHABLE();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005949 case DataType::Type::kFloat32:
5950 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005951 switch (dst_type) {
5952 default:
5953 if (cond_inverted) {
5954 __ Movf(dst.AsRegister<Register>(), src_reg, cond_cc);
5955 } else {
5956 __ Movt(dst.AsRegister<Register>(), src_reg, cond_cc);
5957 }
5958 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005959 case DataType::Type::kInt64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005960 if (cond_inverted) {
5961 __ Movf(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
5962 __ Movf(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
5963 } else {
5964 __ Movt(dst.AsRegisterPairLow<Register>(), src_reg, cond_cc);
5965 __ Movt(dst.AsRegisterPairHigh<Register>(), src_reg_high, cond_cc);
5966 }
5967 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005968 case DataType::Type::kFloat32:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005969 if (cond_inverted) {
5970 __ MovfS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5971 } else {
5972 __ MovtS(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5973 }
5974 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005975 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005976 if (cond_inverted) {
5977 __ MovfD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5978 } else {
5979 __ MovtD(dst.AsFpuRegister<FRegister>(), src.AsFpuRegister<FRegister>(), cond_cc);
5980 }
5981 break;
5982 }
5983 break;
5984 }
5985}
5986
5987void InstructionCodeGeneratorMIPS::GenConditionalMoveR6(HSelect* select) {
5988 LocationSummary* locations = select->GetLocations();
5989 Location dst = locations->Out();
5990 Location false_src = locations->InAt(0);
5991 Location true_src = locations->InAt(1);
5992 HInstruction* cond = select->InputAt(/* condition_input_index */ 2);
5993 Register cond_reg = TMP;
5994 FRegister fcond_reg = FTMP;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005995 DataType::Type cond_type = DataType::Type::kInt32;
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005996 bool cond_inverted = false;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01005997 DataType::Type dst_type = select->GetType();
Alexey Frunze674b9ee2016-09-20 14:54:15 -07005998
5999 if (IsBooleanValueOrMaterializedCondition(cond)) {
6000 cond_reg = locations->InAt(/* condition_input_index */ 2).AsRegister<Register>();
6001 } else {
6002 HCondition* condition = cond->AsCondition();
6003 LocationSummary* cond_locations = cond->GetLocations();
6004 IfCondition if_cond = condition->GetCondition();
6005 cond_type = condition->InputAt(0)->GetType();
6006 switch (cond_type) {
6007 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006008 DCHECK_NE(cond_type, DataType::Type::kInt64);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006009 cond_inverted = MaterializeIntCompare(if_cond, cond_locations, cond_reg);
6010 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006011 case DataType::Type::kFloat32:
6012 case DataType::Type::kFloat64:
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006013 cond_inverted = MaterializeFpCompareR6(if_cond,
6014 condition->IsGtBias(),
6015 cond_type,
6016 cond_locations,
6017 fcond_reg);
6018 break;
6019 }
6020 }
6021
6022 if (true_src.IsConstant()) {
6023 DCHECK(true_src.GetConstant()->IsZeroBitPattern());
6024 }
6025 if (false_src.IsConstant()) {
6026 DCHECK(false_src.GetConstant()->IsZeroBitPattern());
6027 }
6028
6029 switch (dst_type) {
6030 default:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006031 if (DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006032 __ Mfc1(cond_reg, fcond_reg);
6033 }
6034 if (true_src.IsConstant()) {
6035 if (cond_inverted) {
6036 __ Selnez(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
6037 } else {
6038 __ Seleqz(dst.AsRegister<Register>(), false_src.AsRegister<Register>(), cond_reg);
6039 }
6040 } else if (false_src.IsConstant()) {
6041 if (cond_inverted) {
6042 __ Seleqz(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
6043 } else {
6044 __ Selnez(dst.AsRegister<Register>(), true_src.AsRegister<Register>(), cond_reg);
6045 }
6046 } else {
6047 DCHECK_NE(cond_reg, AT);
6048 if (cond_inverted) {
6049 __ Seleqz(AT, true_src.AsRegister<Register>(), cond_reg);
6050 __ Selnez(TMP, false_src.AsRegister<Register>(), cond_reg);
6051 } else {
6052 __ Selnez(AT, true_src.AsRegister<Register>(), cond_reg);
6053 __ Seleqz(TMP, false_src.AsRegister<Register>(), cond_reg);
6054 }
6055 __ Or(dst.AsRegister<Register>(), AT, TMP);
6056 }
6057 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006058 case DataType::Type::kInt64: {
6059 if (DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006060 __ Mfc1(cond_reg, fcond_reg);
6061 }
6062 Register dst_lo = dst.AsRegisterPairLow<Register>();
6063 Register dst_hi = dst.AsRegisterPairHigh<Register>();
6064 if (true_src.IsConstant()) {
6065 Register src_lo = false_src.AsRegisterPairLow<Register>();
6066 Register src_hi = false_src.AsRegisterPairHigh<Register>();
6067 if (cond_inverted) {
6068 __ Selnez(dst_lo, src_lo, cond_reg);
6069 __ Selnez(dst_hi, src_hi, cond_reg);
6070 } else {
6071 __ Seleqz(dst_lo, src_lo, cond_reg);
6072 __ Seleqz(dst_hi, src_hi, cond_reg);
6073 }
6074 } else {
6075 DCHECK(false_src.IsConstant());
6076 Register src_lo = true_src.AsRegisterPairLow<Register>();
6077 Register src_hi = true_src.AsRegisterPairHigh<Register>();
6078 if (cond_inverted) {
6079 __ Seleqz(dst_lo, src_lo, cond_reg);
6080 __ Seleqz(dst_hi, src_hi, cond_reg);
6081 } else {
6082 __ Selnez(dst_lo, src_lo, cond_reg);
6083 __ Selnez(dst_hi, src_hi, cond_reg);
6084 }
6085 }
6086 break;
6087 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006088 case DataType::Type::kFloat32: {
6089 if (!DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006090 // sel*.fmt tests bit 0 of the condition register, account for that.
6091 __ Sltu(TMP, ZERO, cond_reg);
6092 __ Mtc1(TMP, fcond_reg);
6093 }
6094 FRegister dst_reg = dst.AsFpuRegister<FRegister>();
6095 if (true_src.IsConstant()) {
6096 FRegister src_reg = false_src.AsFpuRegister<FRegister>();
6097 if (cond_inverted) {
6098 __ SelnezS(dst_reg, src_reg, fcond_reg);
6099 } else {
6100 __ SeleqzS(dst_reg, src_reg, fcond_reg);
6101 }
6102 } else if (false_src.IsConstant()) {
6103 FRegister src_reg = true_src.AsFpuRegister<FRegister>();
6104 if (cond_inverted) {
6105 __ SeleqzS(dst_reg, src_reg, fcond_reg);
6106 } else {
6107 __ SelnezS(dst_reg, src_reg, fcond_reg);
6108 }
6109 } else {
6110 if (cond_inverted) {
6111 __ SelS(fcond_reg,
6112 true_src.AsFpuRegister<FRegister>(),
6113 false_src.AsFpuRegister<FRegister>());
6114 } else {
6115 __ SelS(fcond_reg,
6116 false_src.AsFpuRegister<FRegister>(),
6117 true_src.AsFpuRegister<FRegister>());
6118 }
6119 __ MovS(dst_reg, fcond_reg);
6120 }
6121 break;
6122 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006123 case DataType::Type::kFloat64: {
6124 if (!DataType::IsFloatingPointType(cond_type)) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006125 // sel*.fmt tests bit 0 of the condition register, account for that.
6126 __ Sltu(TMP, ZERO, cond_reg);
6127 __ Mtc1(TMP, fcond_reg);
6128 }
6129 FRegister dst_reg = dst.AsFpuRegister<FRegister>();
6130 if (true_src.IsConstant()) {
6131 FRegister src_reg = false_src.AsFpuRegister<FRegister>();
6132 if (cond_inverted) {
6133 __ SelnezD(dst_reg, src_reg, fcond_reg);
6134 } else {
6135 __ SeleqzD(dst_reg, src_reg, fcond_reg);
6136 }
6137 } else if (false_src.IsConstant()) {
6138 FRegister src_reg = true_src.AsFpuRegister<FRegister>();
6139 if (cond_inverted) {
6140 __ SeleqzD(dst_reg, src_reg, fcond_reg);
6141 } else {
6142 __ SelnezD(dst_reg, src_reg, fcond_reg);
6143 }
6144 } else {
6145 if (cond_inverted) {
6146 __ SelD(fcond_reg,
6147 true_src.AsFpuRegister<FRegister>(),
6148 false_src.AsFpuRegister<FRegister>());
6149 } else {
6150 __ SelD(fcond_reg,
6151 false_src.AsFpuRegister<FRegister>(),
6152 true_src.AsFpuRegister<FRegister>());
6153 }
6154 __ MovD(dst_reg, fcond_reg);
6155 }
6156 break;
6157 }
6158 }
6159}
6160
Goran Jakovljevicc6418422016-12-05 16:31:55 +01006161void LocationsBuilderMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006162 LocationSummary* locations = new (GetGraph()->GetAllocator())
Goran Jakovljevicc6418422016-12-05 16:31:55 +01006163 LocationSummary(flag, LocationSummary::kNoCall);
6164 locations->SetOut(Location::RequiresRegister());
Mingyao Yang063fc772016-08-02 11:02:54 -07006165}
6166
Goran Jakovljevicc6418422016-12-05 16:31:55 +01006167void InstructionCodeGeneratorMIPS::VisitShouldDeoptimizeFlag(HShouldDeoptimizeFlag* flag) {
6168 __ LoadFromOffset(kLoadWord,
6169 flag->GetLocations()->Out().AsRegister<Register>(),
6170 SP,
6171 codegen_->GetStackOffsetOfShouldDeoptimizeFlag());
Mingyao Yang063fc772016-08-02 11:02:54 -07006172}
6173
David Brazdil74eb1b22015-12-14 11:44:01 +00006174void LocationsBuilderMIPS::VisitSelect(HSelect* select) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006175 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(select);
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006176 CanMoveConditionally(select, codegen_->GetInstructionSetFeatures().IsR6(), locations);
David Brazdil74eb1b22015-12-14 11:44:01 +00006177}
6178
6179void InstructionCodeGeneratorMIPS::VisitSelect(HSelect* select) {
Alexey Frunze674b9ee2016-09-20 14:54:15 -07006180 bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
6181 if (CanMoveConditionally(select, is_r6, /* locations_to_set */ nullptr)) {
6182 if (is_r6) {
6183 GenConditionalMoveR6(select);
6184 } else {
6185 GenConditionalMoveR2(select);
6186 }
6187 } else {
6188 LocationSummary* locations = select->GetLocations();
6189 MipsLabel false_target;
6190 GenerateTestAndBranch(select,
6191 /* condition_input_index */ 2,
6192 /* true_target */ nullptr,
6193 &false_target);
6194 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
6195 __ Bind(&false_target);
6196 }
David Brazdil74eb1b22015-12-14 11:44:01 +00006197}
6198
David Srbecky0cf44932015-12-09 14:09:59 +00006199void LocationsBuilderMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01006200 new (GetGraph()->GetAllocator()) LocationSummary(info);
David Srbecky0cf44932015-12-09 14:09:59 +00006201}
6202
David Srbeckyd28f4a02016-03-14 17:14:24 +00006203void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo*) {
6204 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00006205}
6206
6207void CodeGeneratorMIPS::GenerateNop() {
6208 __ Nop();
David Srbecky0cf44932015-12-09 14:09:59 +00006209}
6210
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006211void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006212 DataType::Type field_type = field_info.GetFieldType();
6213 bool is_wide = (field_type == DataType::Type::kInt64) || (field_type == DataType::Type::kFloat64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006214 bool generate_volatile = field_info.IsVolatile() && is_wide;
Alexey Frunze15958152017-02-09 19:08:30 -08006215 bool object_field_get_with_read_barrier =
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006216 kEmitCompilerReadBarrier && (field_type == DataType::Type::kReference);
Vladimir Markoca6fff82017-10-03 14:49:14 +01006217 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Alexey Frunze15958152017-02-09 19:08:30 -08006218 instruction,
6219 generate_volatile
6220 ? LocationSummary::kCallOnMainOnly
6221 : (object_field_get_with_read_barrier
6222 ? LocationSummary::kCallOnSlowPath
6223 : LocationSummary::kNoCall));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006224
Alexey Frunzec61c0762017-04-10 13:54:23 -07006225 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
6226 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
6227 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006228 locations->SetInAt(0, Location::RequiresRegister());
6229 if (generate_volatile) {
6230 InvokeRuntimeCallingConvention calling_convention;
6231 // need A0 to hold base + offset
6232 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006233 if (field_type == DataType::Type::kInt64) {
6234 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kInt64));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006235 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006236 // Use Location::Any() to prevent situations when running out of available fp registers.
6237 locations->SetOut(Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006238 // Need some temp core regs since FP results are returned in core registers
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006239 Location reg = calling_convention.GetReturnLocation(DataType::Type::kInt64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006240 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairLow<Register>()));
6241 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairHigh<Register>()));
6242 }
6243 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006244 if (DataType::IsFloatingPointType(instruction->GetType())) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006245 locations->SetOut(Location::RequiresFpuRegister());
6246 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006247 // The output overlaps in the case of an object field get with
6248 // read barriers enabled: we do not want the move to overwrite the
6249 // object's location, as we need it to emit the read barrier.
6250 locations->SetOut(Location::RequiresRegister(),
6251 object_field_get_with_read_barrier
6252 ? Location::kOutputOverlap
6253 : Location::kNoOutputOverlap);
6254 }
6255 if (object_field_get_with_read_barrier && kUseBakerReadBarrier) {
6256 // We need a temporary register for the read barrier marking slow
6257 // path in CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier.
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006258 if (!kBakerReadBarrierThunksEnableForFields) {
6259 locations->AddTemp(Location::RequiresRegister());
6260 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006261 }
6262 }
6263}
6264
6265void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
6266 const FieldInfo& field_info,
6267 uint32_t dex_pc) {
Vladimir Marko61b92282017-10-11 13:23:17 +01006268 DCHECK_EQ(DataType::Size(field_info.GetFieldType()), DataType::Size(instruction->GetType()));
6269 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006270 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08006271 Location obj_loc = locations->InAt(0);
6272 Register obj = obj_loc.AsRegister<Register>();
6273 Location dst_loc = locations->Out();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006274 LoadOperandType load_type = kLoadUnsignedByte;
6275 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006276 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Tijana Jakovljevic57433862017-01-17 16:59:03 +01006277 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006278
6279 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006280 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006281 case DataType::Type::kUint8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006282 load_type = kLoadUnsignedByte;
6283 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006284 case DataType::Type::kInt8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006285 load_type = kLoadSignedByte;
6286 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006287 case DataType::Type::kUint16:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006288 load_type = kLoadUnsignedHalfword;
6289 break;
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006290 case DataType::Type::kInt16:
6291 load_type = kLoadSignedHalfword;
6292 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006293 case DataType::Type::kInt32:
6294 case DataType::Type::kFloat32:
6295 case DataType::Type::kReference:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006296 load_type = kLoadWord;
6297 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006298 case DataType::Type::kInt64:
6299 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006300 load_type = kLoadDoubleword;
6301 break;
Aart Bik66c158e2018-01-31 12:55:04 -08006302 case DataType::Type::kUint32:
6303 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006304 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006305 LOG(FATAL) << "Unreachable type " << type;
6306 UNREACHABLE();
6307 }
6308
6309 if (is_volatile && load_type == kLoadDoubleword) {
6310 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006311 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006312 // Do implicit Null check
Goran Jakovljevic2e61a572017-10-23 08:58:15 +02006313 __ LoadFromOffset(kLoadWord,
6314 ZERO,
6315 locations->GetTemp(0).AsRegister<Register>(),
6316 0,
6317 null_checker);
Serban Constantinescufca16662016-07-14 09:21:59 +01006318 codegen_->InvokeRuntime(kQuickA64Load, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006319 CheckEntrypointTypes<kQuickA64Load, int64_t, volatile const int64_t*>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006320 if (type == DataType::Type::kFloat64) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006321 // FP results are returned in core registers. Need to move them.
Alexey Frunze15958152017-02-09 19:08:30 -08006322 if (dst_loc.IsFpuRegister()) {
6323 __ Mtc1(locations->GetTemp(1).AsRegister<Register>(), dst_loc.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006324 __ MoveToFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
Alexey Frunze15958152017-02-09 19:08:30 -08006325 dst_loc.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006326 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006327 DCHECK(dst_loc.IsDoubleStackSlot());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006328 __ StoreToOffset(kStoreWord,
6329 locations->GetTemp(1).AsRegister<Register>(),
6330 SP,
Alexey Frunze15958152017-02-09 19:08:30 -08006331 dst_loc.GetStackIndex());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006332 __ StoreToOffset(kStoreWord,
6333 locations->GetTemp(2).AsRegister<Register>(),
6334 SP,
Alexey Frunze15958152017-02-09 19:08:30 -08006335 dst_loc.GetStackIndex() + 4);
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006336 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006337 }
6338 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006339 if (type == DataType::Type::kReference) {
Alexey Frunze15958152017-02-09 19:08:30 -08006340 // /* HeapReference<Object> */ dst = *(obj + offset)
6341 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006342 Location temp_loc =
6343 kBakerReadBarrierThunksEnableForFields ? Location::NoLocation() : locations->GetTemp(0);
Alexey Frunze15958152017-02-09 19:08:30 -08006344 // Note that a potential implicit null check is handled in this
6345 // CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier call.
6346 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6347 dst_loc,
6348 obj,
6349 offset,
6350 temp_loc,
6351 /* needs_null_check */ true);
6352 if (is_volatile) {
6353 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6354 }
6355 } else {
6356 __ LoadFromOffset(kLoadWord, dst_loc.AsRegister<Register>(), obj, offset, null_checker);
6357 if (is_volatile) {
6358 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6359 }
6360 // If read barriers are enabled, emit read barriers other than
6361 // Baker's using a slow path (and also unpoison the loaded
6362 // reference, if heap poisoning is enabled).
6363 codegen_->MaybeGenerateReadBarrierSlow(instruction, dst_loc, dst_loc, obj_loc, offset);
6364 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006365 } else if (!DataType::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006366 Register dst;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006367 if (type == DataType::Type::kInt64) {
Alexey Frunze15958152017-02-09 19:08:30 -08006368 DCHECK(dst_loc.IsRegisterPair());
6369 dst = dst_loc.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006370 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006371 DCHECK(dst_loc.IsRegister());
6372 dst = dst_loc.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006373 }
Alexey Frunze2923db72016-08-20 01:55:47 -07006374 __ LoadFromOffset(load_type, dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006375 } else {
Alexey Frunze15958152017-02-09 19:08:30 -08006376 DCHECK(dst_loc.IsFpuRegister());
6377 FRegister dst = dst_loc.AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006378 if (type == DataType::Type::kFloat32) {
Alexey Frunze2923db72016-08-20 01:55:47 -07006379 __ LoadSFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006380 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07006381 __ LoadDFromOffset(dst, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006382 }
6383 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006384 }
6385
Alexey Frunze15958152017-02-09 19:08:30 -08006386 // Memory barriers, in the case of references, are handled in the
6387 // previous switch statement.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006388 if (is_volatile && (type != DataType::Type::kReference)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006389 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
6390 }
6391}
6392
6393void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006394 DataType::Type field_type = field_info.GetFieldType();
6395 bool is_wide = (field_type == DataType::Type::kInt64) || (field_type == DataType::Type::kFloat64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006396 bool generate_volatile = field_info.IsVolatile() && is_wide;
Vladimir Markoca6fff82017-10-03 14:49:14 +01006397 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
Serban Constantinescu54ff4822016-07-07 18:03:19 +01006398 instruction, generate_volatile ? LocationSummary::kCallOnMainOnly : LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006399
6400 locations->SetInAt(0, Location::RequiresRegister());
6401 if (generate_volatile) {
6402 InvokeRuntimeCallingConvention calling_convention;
6403 // need A0 to hold base + offset
6404 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006405 if (field_type == DataType::Type::kInt64) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006406 locations->SetInAt(1, Location::RegisterPairLocation(
6407 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
6408 } else {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006409 // Use Location::Any() to prevent situations when running out of available fp registers.
6410 locations->SetInAt(1, Location::Any());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006411 // Pass FP parameters in core registers.
6412 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
6413 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
6414 }
6415 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006416 if (DataType::IsFloatingPointType(field_type)) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006417 locations->SetInAt(1, FpuRegisterOrConstantForStore(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006418 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006419 locations->SetInAt(1, RegisterOrZeroConstant(instruction->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006420 }
6421 }
6422}
6423
6424void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction,
6425 const FieldInfo& field_info,
Goran Jakovljevice114da22016-12-26 14:21:43 +01006426 uint32_t dex_pc,
6427 bool value_can_be_null) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006428 DataType::Type type = field_info.GetFieldType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006429 LocationSummary* locations = instruction->GetLocations();
6430 Register obj = locations->InAt(0).AsRegister<Register>();
Alexey Frunzef58b2482016-09-02 22:14:06 -07006431 Location value_location = locations->InAt(1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006432 StoreOperandType store_type = kStoreByte;
6433 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006434 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Alexey Frunzec061de12017-02-14 13:27:23 -08006435 bool needs_write_barrier = CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1));
Tijana Jakovljevic57433862017-01-17 16:59:03 +01006436 auto null_checker = GetImplicitNullChecker(instruction, codegen_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006437
6438 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006439 case DataType::Type::kBool:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006440 case DataType::Type::kUint8:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006441 case DataType::Type::kInt8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006442 store_type = kStoreByte;
6443 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006444 case DataType::Type::kUint16:
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01006445 case DataType::Type::kInt16:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006446 store_type = kStoreHalfword;
6447 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006448 case DataType::Type::kInt32:
6449 case DataType::Type::kFloat32:
6450 case DataType::Type::kReference:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006451 store_type = kStoreWord;
6452 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006453 case DataType::Type::kInt64:
6454 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006455 store_type = kStoreDoubleword;
6456 break;
Aart Bik66c158e2018-01-31 12:55:04 -08006457 case DataType::Type::kUint32:
6458 case DataType::Type::kUint64:
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006459 case DataType::Type::kVoid:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006460 LOG(FATAL) << "Unreachable type " << type;
6461 UNREACHABLE();
6462 }
6463
6464 if (is_volatile) {
6465 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
6466 }
6467
6468 if (is_volatile && store_type == kStoreDoubleword) {
6469 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01006470 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006471 // Do implicit Null check.
Goran Jakovljevic2e61a572017-10-23 08:58:15 +02006472 __ LoadFromOffset(kLoadWord,
6473 ZERO,
6474 locations->GetTemp(0).AsRegister<Register>(),
6475 0,
6476 null_checker);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006477 if (type == DataType::Type::kFloat64) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006478 // Pass FP parameters in core registers.
Alexey Frunzef58b2482016-09-02 22:14:06 -07006479 if (value_location.IsFpuRegister()) {
6480 __ Mfc1(locations->GetTemp(1).AsRegister<Register>(),
6481 value_location.AsFpuRegister<FRegister>());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006482 __ MoveFromFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
Alexey Frunzef58b2482016-09-02 22:14:06 -07006483 value_location.AsFpuRegister<FRegister>());
6484 } else if (value_location.IsDoubleStackSlot()) {
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006485 __ LoadFromOffset(kLoadWord,
6486 locations->GetTemp(1).AsRegister<Register>(),
6487 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07006488 value_location.GetStackIndex());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006489 __ LoadFromOffset(kLoadWord,
6490 locations->GetTemp(2).AsRegister<Register>(),
6491 SP,
Alexey Frunzef58b2482016-09-02 22:14:06 -07006492 value_location.GetStackIndex() + 4);
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006493 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006494 DCHECK(value_location.IsConstant());
6495 DCHECK(value_location.GetConstant()->IsDoubleConstant());
6496 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
Goran Jakovljeviccdd822f2016-07-22 09:46:43 +02006497 __ LoadConst64(locations->GetTemp(2).AsRegister<Register>(),
6498 locations->GetTemp(1).AsRegister<Register>(),
6499 value);
6500 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006501 }
Serban Constantinescufca16662016-07-14 09:21:59 +01006502 codegen_->InvokeRuntime(kQuickA64Store, instruction, dex_pc);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006503 CheckEntrypointTypes<kQuickA64Store, void, volatile int64_t *, int64_t>();
6504 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006505 if (value_location.IsConstant()) {
6506 int64_t value = CodeGenerator::GetInt64ValueOf(value_location.GetConstant());
6507 __ StoreConstToOffset(store_type, value, obj, offset, TMP, null_checker);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006508 } else if (!DataType::IsFloatingPointType(type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006509 Register src;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006510 if (type == DataType::Type::kInt64) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006511 src = value_location.AsRegisterPairLow<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006512 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006513 src = value_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006514 }
Alexey Frunzec061de12017-02-14 13:27:23 -08006515 if (kPoisonHeapReferences && needs_write_barrier) {
6516 // Note that in the case where `value` is a null reference,
6517 // we do not enter this block, as a null reference does not
6518 // need poisoning.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006519 DCHECK_EQ(type, DataType::Type::kReference);
Alexey Frunzec061de12017-02-14 13:27:23 -08006520 __ PoisonHeapReference(TMP, src);
6521 __ StoreToOffset(store_type, TMP, obj, offset, null_checker);
6522 } else {
6523 __ StoreToOffset(store_type, src, obj, offset, null_checker);
6524 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006525 } else {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006526 FRegister src = value_location.AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01006527 if (type == DataType::Type::kFloat32) {
Alexey Frunze2923db72016-08-20 01:55:47 -07006528 __ StoreSToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006529 } else {
Alexey Frunze2923db72016-08-20 01:55:47 -07006530 __ StoreDToOffset(src, obj, offset, null_checker);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006531 }
6532 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006533 }
6534
Alexey Frunzec061de12017-02-14 13:27:23 -08006535 if (needs_write_barrier) {
Alexey Frunzef58b2482016-09-02 22:14:06 -07006536 Register src = value_location.AsRegister<Register>();
Goran Jakovljevice114da22016-12-26 14:21:43 +01006537 codegen_->MarkGCCard(obj, src, value_can_be_null);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006538 }
6539
6540 if (is_volatile) {
6541 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
6542 }
6543}
6544
6545void LocationsBuilderMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6546 HandleFieldGet(instruction, instruction->GetFieldInfo());
6547}
6548
6549void InstructionCodeGeneratorMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
6550 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
6551}
6552
6553void LocationsBuilderMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
6554 HandleFieldSet(instruction, instruction->GetFieldInfo());
6555}
6556
6557void InstructionCodeGeneratorMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01006558 HandleFieldSet(instruction,
6559 instruction->GetFieldInfo(),
6560 instruction->GetDexPc(),
6561 instruction->GetValueCanBeNull());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02006562}
6563
Alexey Frunze15958152017-02-09 19:08:30 -08006564void InstructionCodeGeneratorMIPS::GenerateReferenceLoadOneRegister(
6565 HInstruction* instruction,
6566 Location out,
6567 uint32_t offset,
6568 Location maybe_temp,
6569 ReadBarrierOption read_barrier_option) {
6570 Register out_reg = out.AsRegister<Register>();
6571 if (read_barrier_option == kWithReadBarrier) {
6572 CHECK(kEmitCompilerReadBarrier);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006573 if (!kUseBakerReadBarrier || !kBakerReadBarrierThunksEnableForFields) {
6574 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6575 }
Alexey Frunze15958152017-02-09 19:08:30 -08006576 if (kUseBakerReadBarrier) {
6577 // Load with fast path based Baker's read barrier.
6578 // /* HeapReference<Object> */ out = *(out + offset)
6579 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6580 out,
6581 out_reg,
6582 offset,
6583 maybe_temp,
6584 /* needs_null_check */ false);
6585 } else {
6586 // Load with slow path based read barrier.
6587 // Save the value of `out` into `maybe_temp` before overwriting it
6588 // in the following move operation, as we will need it for the
6589 // read barrier below.
6590 __ Move(maybe_temp.AsRegister<Register>(), out_reg);
6591 // /* HeapReference<Object> */ out = *(out + offset)
6592 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6593 codegen_->GenerateReadBarrierSlow(instruction, out, out, maybe_temp, offset);
6594 }
6595 } else {
6596 // Plain load with no read barrier.
6597 // /* HeapReference<Object> */ out = *(out + offset)
6598 __ LoadFromOffset(kLoadWord, out_reg, out_reg, offset);
6599 __ MaybeUnpoisonHeapReference(out_reg);
6600 }
6601}
6602
6603void InstructionCodeGeneratorMIPS::GenerateReferenceLoadTwoRegisters(
6604 HInstruction* instruction,
6605 Location out,
6606 Location obj,
6607 uint32_t offset,
6608 Location maybe_temp,
6609 ReadBarrierOption read_barrier_option) {
6610 Register out_reg = out.AsRegister<Register>();
6611 Register obj_reg = obj.AsRegister<Register>();
6612 if (read_barrier_option == kWithReadBarrier) {
6613 CHECK(kEmitCompilerReadBarrier);
6614 if (kUseBakerReadBarrier) {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006615 if (!kBakerReadBarrierThunksEnableForFields) {
6616 DCHECK(maybe_temp.IsRegister()) << maybe_temp;
6617 }
Alexey Frunze15958152017-02-09 19:08:30 -08006618 // Load with fast path based Baker's read barrier.
6619 // /* HeapReference<Object> */ out = *(obj + offset)
6620 codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
6621 out,
6622 obj_reg,
6623 offset,
6624 maybe_temp,
6625 /* needs_null_check */ false);
6626 } else {
6627 // Load with slow path based read barrier.
6628 // /* HeapReference<Object> */ out = *(obj + offset)
6629 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6630 codegen_->GenerateReadBarrierSlow(instruction, out, out, obj, offset);
6631 }
6632 } else {
6633 // Plain load with no read barrier.
6634 // /* HeapReference<Object> */ out = *(obj + offset)
6635 __ LoadFromOffset(kLoadWord, out_reg, obj_reg, offset);
6636 __ MaybeUnpoisonHeapReference(out_reg);
6637 }
6638}
6639
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006640static inline int GetBakerMarkThunkNumber(Register reg) {
6641 static_assert(BAKER_MARK_INTROSPECTION_REGISTER_COUNT == 21, "Expecting equal");
6642 if (reg >= V0 && reg <= T7) { // 14 consequtive regs.
6643 return reg - V0;
6644 } else if (reg >= S2 && reg <= S7) { // 6 consequtive regs.
6645 return 14 + (reg - S2);
6646 } else if (reg == FP) { // One more.
6647 return 20;
6648 }
6649 LOG(FATAL) << "Unexpected register " << reg;
6650 UNREACHABLE();
6651}
6652
6653static inline int GetBakerMarkFieldArrayThunkDisplacement(Register reg, bool short_offset) {
6654 int num = GetBakerMarkThunkNumber(reg) +
6655 (short_offset ? BAKER_MARK_INTROSPECTION_REGISTER_COUNT : 0);
6656 return num * BAKER_MARK_INTROSPECTION_FIELD_ARRAY_ENTRY_SIZE;
6657}
6658
6659static inline int GetBakerMarkGcRootThunkDisplacement(Register reg) {
6660 return GetBakerMarkThunkNumber(reg) * BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRY_SIZE +
6661 BAKER_MARK_INTROSPECTION_GC_ROOT_ENTRIES_OFFSET;
6662}
6663
Alexey Frunze15958152017-02-09 19:08:30 -08006664void InstructionCodeGeneratorMIPS::GenerateGcRootFieldLoad(HInstruction* instruction,
6665 Location root,
6666 Register obj,
6667 uint32_t offset,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006668 ReadBarrierOption read_barrier_option,
6669 MipsLabel* label_low) {
6670 bool reordering;
6671 if (label_low != nullptr) {
6672 DCHECK_EQ(offset, 0x5678u);
6673 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07006674 Register root_reg = root.AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08006675 if (read_barrier_option == kWithReadBarrier) {
6676 DCHECK(kEmitCompilerReadBarrier);
6677 if (kUseBakerReadBarrier) {
6678 // Fast path implementation of art::ReadBarrier::BarrierForRoot when
6679 // Baker's read barrier are used:
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006680 if (kBakerReadBarrierThunksEnableForGcRoots) {
6681 // Note that we do not actually check the value of `GetIsGcMarking()`
6682 // to decide whether to mark the loaded GC root or not. Instead, we
6683 // load into `temp` (T9) the read barrier mark introspection entrypoint.
6684 // If `temp` is null, it means that `GetIsGcMarking()` is false, and
6685 // vice versa.
6686 //
6687 // We use thunks for the slow path. That thunk checks the reference
6688 // and jumps to the entrypoint if needed.
6689 //
6690 // temp = Thread::Current()->pReadBarrierMarkReg00
6691 // // AKA &art_quick_read_barrier_mark_introspection.
6692 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
6693 // if (temp != nullptr) {
6694 // temp = &gc_root_thunk<root_reg>
6695 // root = temp(root)
6696 // }
Alexey Frunze15958152017-02-09 19:08:30 -08006697
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006698 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
6699 const int32_t entry_point_offset =
6700 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(0);
6701 const int thunk_disp = GetBakerMarkGcRootThunkDisplacement(root_reg);
6702 int16_t offset_low = Low16Bits(offset);
6703 int16_t offset_high = High16Bits(offset - offset_low); // Accounts for sign
6704 // extension in lw.
6705 bool short_offset = IsInt<16>(static_cast<int32_t>(offset));
6706 Register base = short_offset ? obj : TMP;
6707 // Loading the entrypoint does not require a load acquire since it is only changed when
6708 // threads are suspended or running a checkpoint.
6709 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
6710 reordering = __ SetReorder(false);
6711 if (!short_offset) {
6712 DCHECK(!label_low);
6713 __ AddUpper(base, obj, offset_high);
6714 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07006715 MipsLabel skip_call;
6716 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006717 if (label_low != nullptr) {
6718 DCHECK(short_offset);
6719 __ Bind(label_low);
6720 }
6721 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6722 __ LoadFromOffset(kLoadWord, root_reg, base, offset_low); // Single instruction
6723 // in delay slot.
6724 if (isR6) {
6725 __ Jialc(T9, thunk_disp);
6726 } else {
6727 __ Addiu(T9, T9, thunk_disp);
6728 __ Jalr(T9);
6729 __ Nop();
6730 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07006731 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006732 __ SetReorder(reordering);
6733 } else {
6734 // Note that we do not actually check the value of `GetIsGcMarking()`
6735 // to decide whether to mark the loaded GC root or not. Instead, we
6736 // load into `temp` (T9) the read barrier mark entry point corresponding
6737 // to register `root`. If `temp` is null, it means that `GetIsGcMarking()`
6738 // is false, and vice versa.
6739 //
6740 // GcRoot<mirror::Object> root = *(obj+offset); // Original reference load.
6741 // temp = Thread::Current()->pReadBarrierMarkReg ## root.reg()
6742 // if (temp != null) {
6743 // root = temp(root)
6744 // }
Alexey Frunze15958152017-02-09 19:08:30 -08006745
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006746 if (label_low != nullptr) {
6747 reordering = __ SetReorder(false);
6748 __ Bind(label_low);
6749 }
6750 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6751 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6752 if (label_low != nullptr) {
6753 __ SetReorder(reordering);
6754 }
6755 static_assert(
6756 sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
6757 "art::mirror::CompressedReference<mirror::Object> and art::GcRoot<mirror::Object> "
6758 "have different sizes.");
6759 static_assert(sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(int32_t),
6760 "art::mirror::CompressedReference<mirror::Object> and int32_t "
6761 "have different sizes.");
Alexey Frunze15958152017-02-09 19:08:30 -08006762
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006763 // Slow path marking the GC root `root`.
6764 Location temp = Location::RegisterLocation(T9);
6765 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01006766 new (codegen_->GetScopedAllocator()) ReadBarrierMarkSlowPathMIPS(
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006767 instruction,
6768 root,
6769 /*entrypoint*/ temp);
6770 codegen_->AddSlowPath(slow_path);
6771
6772 const int32_t entry_point_offset =
6773 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(root.reg() - 1);
6774 // Loading the entrypoint does not require a load acquire since it is only changed when
6775 // threads are suspended or running a checkpoint.
6776 __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, entry_point_offset);
6777 __ Bnez(temp.AsRegister<Register>(), slow_path->GetEntryLabel());
6778 __ Bind(slow_path->GetExitLabel());
6779 }
Alexey Frunze15958152017-02-09 19:08:30 -08006780 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006781 if (label_low != nullptr) {
6782 reordering = __ SetReorder(false);
6783 __ Bind(label_low);
6784 }
Alexey Frunze15958152017-02-09 19:08:30 -08006785 // GC root loaded through a slow path for read barriers other
6786 // than Baker's.
6787 // /* GcRoot<mirror::Object>* */ root = obj + offset
6788 __ Addiu32(root_reg, obj, offset);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006789 if (label_low != nullptr) {
6790 __ SetReorder(reordering);
6791 }
Alexey Frunze15958152017-02-09 19:08:30 -08006792 // /* mirror::Object* */ root = root->Read()
6793 codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
6794 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07006795 } else {
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006796 if (label_low != nullptr) {
6797 reordering = __ SetReorder(false);
6798 __ Bind(label_low);
6799 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07006800 // Plain GC root load with no read barrier.
6801 // /* GcRoot<mirror::Object> */ root = *(obj + offset)
6802 __ LoadFromOffset(kLoadWord, root_reg, obj, offset);
6803 // Note that GC roots are not affected by heap poisoning, thus we
6804 // do not have to unpoison `root_reg` here.
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006805 if (label_low != nullptr) {
6806 __ SetReorder(reordering);
6807 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07006808 }
6809}
6810
Alexey Frunze15958152017-02-09 19:08:30 -08006811void CodeGeneratorMIPS::GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
6812 Location ref,
6813 Register obj,
6814 uint32_t offset,
6815 Location temp,
6816 bool needs_null_check) {
6817 DCHECK(kEmitCompilerReadBarrier);
6818 DCHECK(kUseBakerReadBarrier);
6819
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006820 if (kBakerReadBarrierThunksEnableForFields) {
6821 // Note that we do not actually check the value of `GetIsGcMarking()`
6822 // to decide whether to mark the loaded reference or not. Instead, we
6823 // load into `temp` (T9) the read barrier mark introspection entrypoint.
6824 // If `temp` is null, it means that `GetIsGcMarking()` is false, and
6825 // vice versa.
6826 //
6827 // We use thunks for the slow path. That thunk checks the reference
6828 // and jumps to the entrypoint if needed. If the holder is not gray,
6829 // it issues a load-load memory barrier and returns to the original
6830 // reference load.
6831 //
6832 // temp = Thread::Current()->pReadBarrierMarkReg00
6833 // // AKA &art_quick_read_barrier_mark_introspection.
6834 // if (temp != nullptr) {
6835 // temp = &field_array_thunk<holder_reg>
6836 // temp()
6837 // }
6838 // not_gray_return_address:
6839 // // If the offset is too large to fit into the lw instruction, we
6840 // // use an adjusted base register (TMP) here. This register
6841 // // receives bits 16 ... 31 of the offset before the thunk invocation
6842 // // and the thunk benefits from it.
6843 // HeapReference<mirror::Object> reference = *(obj+offset); // Original reference load.
6844 // gray_return_address:
6845
6846 DCHECK(temp.IsInvalid());
6847 bool isR6 = GetInstructionSetFeatures().IsR6();
6848 int16_t offset_low = Low16Bits(offset);
6849 int16_t offset_high = High16Bits(offset - offset_low); // Accounts for sign extension in lw.
6850 bool short_offset = IsInt<16>(static_cast<int32_t>(offset));
6851 bool reordering = __ SetReorder(false);
6852 const int32_t entry_point_offset =
6853 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(0);
6854 // There may have or may have not been a null check if the field offset is smaller than
6855 // the page size.
6856 // There must've been a null check in case it's actually a load from an array.
6857 // We will, however, perform an explicit null check in the thunk as it's easier to
6858 // do it than not.
6859 if (instruction->IsArrayGet()) {
6860 DCHECK(!needs_null_check);
6861 }
6862 const int thunk_disp = GetBakerMarkFieldArrayThunkDisplacement(obj, short_offset);
6863 // Loading the entrypoint does not require a load acquire since it is only changed when
6864 // threads are suspended or running a checkpoint.
6865 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
6866 Register ref_reg = ref.AsRegister<Register>();
6867 Register base = short_offset ? obj : TMP;
Alexey Frunze0cab6562017-07-25 15:19:36 -07006868 MipsLabel skip_call;
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006869 if (short_offset) {
6870 if (isR6) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07006871 __ Beqzc(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006872 __ Nop(); // In forbidden slot.
6873 __ Jialc(T9, thunk_disp);
6874 } else {
Alexey Frunze0cab6562017-07-25 15:19:36 -07006875 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006876 __ Addiu(T9, T9, thunk_disp); // In delay slot.
6877 __ Jalr(T9);
6878 __ Nop(); // In delay slot.
6879 }
Alexey Frunze0cab6562017-07-25 15:19:36 -07006880 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006881 } else {
6882 if (isR6) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07006883 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006884 __ Aui(base, obj, offset_high); // In delay slot.
6885 __ Jialc(T9, thunk_disp);
Alexey Frunze0cab6562017-07-25 15:19:36 -07006886 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006887 } else {
6888 __ Lui(base, offset_high);
Alexey Frunze0cab6562017-07-25 15:19:36 -07006889 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006890 __ Addiu(T9, T9, thunk_disp); // In delay slot.
6891 __ Jalr(T9);
Alexey Frunze0cab6562017-07-25 15:19:36 -07006892 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006893 __ Addu(base, base, obj); // In delay slot.
6894 }
6895 }
6896 // /* HeapReference<Object> */ ref = *(obj + offset)
6897 __ LoadFromOffset(kLoadWord, ref_reg, base, offset_low); // Single instruction.
6898 if (needs_null_check) {
6899 MaybeRecordImplicitNullCheck(instruction);
6900 }
6901 __ MaybeUnpoisonHeapReference(ref_reg);
6902 __ SetReorder(reordering);
6903 return;
6904 }
6905
Alexey Frunze15958152017-02-09 19:08:30 -08006906 // /* HeapReference<Object> */ ref = *(obj + offset)
6907 Location no_index = Location::NoLocation();
6908 ScaleFactor no_scale_factor = TIMES_1;
6909 GenerateReferenceLoadWithBakerReadBarrier(instruction,
6910 ref,
6911 obj,
6912 offset,
6913 no_index,
6914 no_scale_factor,
6915 temp,
6916 needs_null_check);
6917}
6918
6919void CodeGeneratorMIPS::GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction,
6920 Location ref,
6921 Register obj,
6922 uint32_t data_offset,
6923 Location index,
6924 Location temp,
6925 bool needs_null_check) {
6926 DCHECK(kEmitCompilerReadBarrier);
6927 DCHECK(kUseBakerReadBarrier);
6928
6929 static_assert(
6930 sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
6931 "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006932 ScaleFactor scale_factor = TIMES_4;
6933
6934 if (kBakerReadBarrierThunksEnableForArrays) {
6935 // Note that we do not actually check the value of `GetIsGcMarking()`
6936 // to decide whether to mark the loaded reference or not. Instead, we
6937 // load into `temp` (T9) the read barrier mark introspection entrypoint.
6938 // If `temp` is null, it means that `GetIsGcMarking()` is false, and
6939 // vice versa.
6940 //
6941 // We use thunks for the slow path. That thunk checks the reference
6942 // and jumps to the entrypoint if needed. If the holder is not gray,
6943 // it issues a load-load memory barrier and returns to the original
6944 // reference load.
6945 //
6946 // temp = Thread::Current()->pReadBarrierMarkReg00
6947 // // AKA &art_quick_read_barrier_mark_introspection.
6948 // if (temp != nullptr) {
6949 // temp = &field_array_thunk<holder_reg>
6950 // temp()
6951 // }
6952 // not_gray_return_address:
6953 // // The element address is pre-calculated in the TMP register before the
6954 // // thunk invocation and the thunk benefits from it.
6955 // HeapReference<mirror::Object> reference = data[index]; // Original reference load.
6956 // gray_return_address:
6957
6958 DCHECK(temp.IsInvalid());
6959 DCHECK(index.IsValid());
6960 bool reordering = __ SetReorder(false);
6961 const int32_t entry_point_offset =
6962 Thread::ReadBarrierMarkEntryPointsOffset<kMipsPointerSize>(0);
6963 // We will not do the explicit null check in the thunk as some form of a null check
6964 // must've been done earlier.
6965 DCHECK(!needs_null_check);
6966 const int thunk_disp = GetBakerMarkFieldArrayThunkDisplacement(obj, /* short_offset */ false);
6967 // Loading the entrypoint does not require a load acquire since it is only changed when
6968 // threads are suspended or running a checkpoint.
6969 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
6970 Register ref_reg = ref.AsRegister<Register>();
6971 Register index_reg = index.IsRegisterPair()
6972 ? index.AsRegisterPairLow<Register>()
6973 : index.AsRegister<Register>();
Alexey Frunze0cab6562017-07-25 15:19:36 -07006974 MipsLabel skip_call;
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006975 if (GetInstructionSetFeatures().IsR6()) {
Alexey Frunze0cab6562017-07-25 15:19:36 -07006976 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006977 __ Lsa(TMP, index_reg, obj, scale_factor); // In delay slot.
6978 __ Jialc(T9, thunk_disp);
Alexey Frunze0cab6562017-07-25 15:19:36 -07006979 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006980 } else {
6981 __ Sll(TMP, index_reg, scale_factor);
Alexey Frunze0cab6562017-07-25 15:19:36 -07006982 __ Beqz(T9, &skip_call, /* is_bare */ true);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006983 __ Addiu(T9, T9, thunk_disp); // In delay slot.
6984 __ Jalr(T9);
Alexey Frunze0cab6562017-07-25 15:19:36 -07006985 __ Bind(&skip_call);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07006986 __ Addu(TMP, TMP, obj); // In delay slot.
6987 }
6988 // /* HeapReference<Object> */ ref = *(obj + data_offset + (index << scale_factor))
6989 DCHECK(IsInt<16>(static_cast<int32_t>(data_offset))) << data_offset;
6990 __ LoadFromOffset(kLoadWord, ref_reg, TMP, data_offset); // Single instruction.
6991 __ MaybeUnpoisonHeapReference(ref_reg);
6992 __ SetReorder(reordering);
6993 return;
6994 }
6995
Alexey Frunze15958152017-02-09 19:08:30 -08006996 // /* HeapReference<Object> */ ref =
6997 // *(obj + data_offset + index * sizeof(HeapReference<Object>))
Alexey Frunze15958152017-02-09 19:08:30 -08006998 GenerateReferenceLoadWithBakerReadBarrier(instruction,
6999 ref,
7000 obj,
7001 data_offset,
7002 index,
7003 scale_factor,
7004 temp,
7005 needs_null_check);
7006}
7007
7008void CodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction,
7009 Location ref,
7010 Register obj,
7011 uint32_t offset,
7012 Location index,
7013 ScaleFactor scale_factor,
7014 Location temp,
7015 bool needs_null_check,
7016 bool always_update_field) {
7017 DCHECK(kEmitCompilerReadBarrier);
7018 DCHECK(kUseBakerReadBarrier);
7019
7020 // In slow path based read barriers, the read barrier call is
7021 // inserted after the original load. However, in fast path based
7022 // Baker's read barriers, we need to perform the load of
7023 // mirror::Object::monitor_ *before* the original reference load.
7024 // This load-load ordering is required by the read barrier.
7025 // The fast path/slow path (for Baker's algorithm) should look like:
7026 //
7027 // uint32_t rb_state = Lockword(obj->monitor_).ReadBarrierState();
7028 // lfence; // Load fence or artificial data dependency to prevent load-load reordering
7029 // HeapReference<Object> ref = *src; // Original reference load.
7030 // bool is_gray = (rb_state == ReadBarrier::GrayState());
7031 // if (is_gray) {
7032 // ref = ReadBarrier::Mark(ref); // Performed by runtime entrypoint slow path.
7033 // }
7034 //
7035 // Note: the original implementation in ReadBarrier::Barrier is
7036 // slightly more complex as it performs additional checks that we do
7037 // not do here for performance reasons.
7038
7039 Register ref_reg = ref.AsRegister<Register>();
7040 Register temp_reg = temp.AsRegister<Register>();
7041 uint32_t monitor_offset = mirror::Object::MonitorOffset().Int32Value();
7042
7043 // /* int32_t */ monitor = obj->monitor_
7044 __ LoadFromOffset(kLoadWord, temp_reg, obj, monitor_offset);
7045 if (needs_null_check) {
7046 MaybeRecordImplicitNullCheck(instruction);
7047 }
7048 // /* LockWord */ lock_word = LockWord(monitor)
7049 static_assert(sizeof(LockWord) == sizeof(int32_t),
7050 "art::LockWord and int32_t have different sizes.");
7051
7052 __ Sync(0); // Barrier to prevent load-load reordering.
7053
7054 // The actual reference load.
7055 if (index.IsValid()) {
7056 // Load types involving an "index": ArrayGet,
7057 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7058 // intrinsics.
7059 // /* HeapReference<Object> */ ref = *(obj + offset + (index << scale_factor))
7060 if (index.IsConstant()) {
7061 size_t computed_offset =
7062 (index.GetConstant()->AsIntConstant()->GetValue() << scale_factor) + offset;
7063 __ LoadFromOffset(kLoadWord, ref_reg, obj, computed_offset);
7064 } else {
7065 // Handle the special case of the
7066 // UnsafeGetObject/UnsafeGetObjectVolatile and UnsafeCASObject
7067 // intrinsics, which use a register pair as index ("long
7068 // offset"), of which only the low part contains data.
7069 Register index_reg = index.IsRegisterPair()
7070 ? index.AsRegisterPairLow<Register>()
7071 : index.AsRegister<Register>();
Chris Larsencd0295d2017-03-31 15:26:54 -07007072 __ ShiftAndAdd(TMP, index_reg, obj, scale_factor, TMP);
Alexey Frunze15958152017-02-09 19:08:30 -08007073 __ LoadFromOffset(kLoadWord, ref_reg, TMP, offset);
7074 }
7075 } else {
7076 // /* HeapReference<Object> */ ref = *(obj + offset)
7077 __ LoadFromOffset(kLoadWord, ref_reg, obj, offset);
7078 }
7079
7080 // Object* ref = ref_addr->AsMirrorPtr()
7081 __ MaybeUnpoisonHeapReference(ref_reg);
7082
7083 // Slow path marking the object `ref` when it is gray.
7084 SlowPathCodeMIPS* slow_path;
7085 if (always_update_field) {
7086 // ReadBarrierMarkAndUpdateFieldSlowPathMIPS only supports address
7087 // of the form `obj + field_offset`, where `obj` is a register and
7088 // `field_offset` is a register pair (of which only the lower half
7089 // is used). Thus `offset` and `scale_factor` above are expected
7090 // to be null in this code path.
7091 DCHECK_EQ(offset, 0u);
7092 DCHECK_EQ(scale_factor, ScaleFactor::TIMES_1);
Vladimir Marko174b2e22017-10-12 13:34:49 +01007093 slow_path = new (GetScopedAllocator())
Alexey Frunze15958152017-02-09 19:08:30 -08007094 ReadBarrierMarkAndUpdateFieldSlowPathMIPS(instruction,
7095 ref,
7096 obj,
7097 /* field_offset */ index,
7098 temp_reg);
7099 } else {
Vladimir Marko174b2e22017-10-12 13:34:49 +01007100 slow_path = new (GetScopedAllocator()) ReadBarrierMarkSlowPathMIPS(instruction, ref);
Alexey Frunze15958152017-02-09 19:08:30 -08007101 }
7102 AddSlowPath(slow_path);
7103
7104 // if (rb_state == ReadBarrier::GrayState())
7105 // ref = ReadBarrier::Mark(ref);
7106 // Given the numeric representation, it's enough to check the low bit of the
7107 // rb_state. We do that by shifting the bit into the sign bit (31) and
7108 // performing a branch on less than zero.
7109 static_assert(ReadBarrier::WhiteState() == 0, "Expecting white to have value 0");
7110 static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1");
7111 static_assert(LockWord::kReadBarrierStateSize == 1, "Expecting 1-bit read barrier state size");
7112 __ Sll(temp_reg, temp_reg, 31 - LockWord::kReadBarrierStateShift);
7113 __ Bltz(temp_reg, slow_path->GetEntryLabel());
7114 __ Bind(slow_path->GetExitLabel());
7115}
7116
7117void CodeGeneratorMIPS::GenerateReadBarrierSlow(HInstruction* instruction,
7118 Location out,
7119 Location ref,
7120 Location obj,
7121 uint32_t offset,
7122 Location index) {
7123 DCHECK(kEmitCompilerReadBarrier);
7124
7125 // Insert a slow path based read barrier *after* the reference load.
7126 //
7127 // If heap poisoning is enabled, the unpoisoning of the loaded
7128 // reference will be carried out by the runtime within the slow
7129 // path.
7130 //
7131 // Note that `ref` currently does not get unpoisoned (when heap
7132 // poisoning is enabled), which is alright as the `ref` argument is
7133 // not used by the artReadBarrierSlow entry point.
7134 //
7135 // TODO: Unpoison `ref` when it is used by artReadBarrierSlow.
Vladimir Marko174b2e22017-10-12 13:34:49 +01007136 SlowPathCodeMIPS* slow_path = new (GetScopedAllocator())
Alexey Frunze15958152017-02-09 19:08:30 -08007137 ReadBarrierForHeapReferenceSlowPathMIPS(instruction, out, ref, obj, offset, index);
7138 AddSlowPath(slow_path);
7139
7140 __ B(slow_path->GetEntryLabel());
7141 __ Bind(slow_path->GetExitLabel());
7142}
7143
7144void CodeGeneratorMIPS::MaybeGenerateReadBarrierSlow(HInstruction* instruction,
7145 Location out,
7146 Location ref,
7147 Location obj,
7148 uint32_t offset,
7149 Location index) {
7150 if (kEmitCompilerReadBarrier) {
7151 // Baker's read barriers shall be handled by the fast path
7152 // (CodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier).
7153 DCHECK(!kUseBakerReadBarrier);
7154 // If heap poisoning is enabled, unpoisoning will be taken care of
7155 // by the runtime within the slow path.
7156 GenerateReadBarrierSlow(instruction, out, ref, obj, offset, index);
7157 } else if (kPoisonHeapReferences) {
7158 __ UnpoisonHeapReference(out.AsRegister<Register>());
7159 }
7160}
7161
7162void CodeGeneratorMIPS::GenerateReadBarrierForRootSlow(HInstruction* instruction,
7163 Location out,
7164 Location root) {
7165 DCHECK(kEmitCompilerReadBarrier);
7166
7167 // Insert a slow path based read barrier *after* the GC root load.
7168 //
7169 // Note that GC roots are not affected by heap poisoning, so we do
7170 // not need to do anything special for this here.
7171 SlowPathCodeMIPS* slow_path =
Vladimir Marko174b2e22017-10-12 13:34:49 +01007172 new (GetScopedAllocator()) ReadBarrierForRootSlowPathMIPS(instruction, out, root);
Alexey Frunze15958152017-02-09 19:08:30 -08007173 AddSlowPath(slow_path);
7174
7175 __ B(slow_path->GetEntryLabel());
7176 __ Bind(slow_path->GetExitLabel());
7177}
7178
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007179void LocationsBuilderMIPS::VisitInstanceOf(HInstanceOf* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007180 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
7181 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Alexey Frunzec61c0762017-04-10 13:54:23 -07007182 bool baker_read_barrier_slow_path = false;
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007183 switch (type_check_kind) {
7184 case TypeCheckKind::kExactCheck:
7185 case TypeCheckKind::kAbstractClassCheck:
7186 case TypeCheckKind::kClassHierarchyCheck:
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007187 case TypeCheckKind::kArrayObjectCheck: {
7188 bool needs_read_barrier = CodeGenerator::InstanceOfNeedsReadBarrier(instruction);
7189 call_kind = needs_read_barrier ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall;
7190 baker_read_barrier_slow_path = kUseBakerReadBarrier && needs_read_barrier;
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007191 break;
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007192 }
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007193 case TypeCheckKind::kArrayCheck:
7194 case TypeCheckKind::kUnresolvedCheck:
7195 case TypeCheckKind::kInterfaceCheck:
7196 call_kind = LocationSummary::kCallOnSlowPath;
7197 break;
7198 }
7199
Vladimir Markoca6fff82017-10-03 14:49:14 +01007200 LocationSummary* locations =
7201 new (GetGraph()->GetAllocator()) LocationSummary(instruction, call_kind);
Alexey Frunzec61c0762017-04-10 13:54:23 -07007202 if (baker_read_barrier_slow_path) {
7203 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
7204 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007205 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00007206 locations->SetInAt(1, Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007207 // The output does overlap inputs.
7208 // Note that TypeCheckSlowPathMIPS uses this register too.
7209 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Alexey Frunze15958152017-02-09 19:08:30 -08007210 locations->AddRegisterTemps(NumberOfInstanceOfTemps(type_check_kind));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007211}
7212
7213void InstructionCodeGeneratorMIPS::VisitInstanceOf(HInstanceOf* instruction) {
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007214 TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007215 LocationSummary* locations = instruction->GetLocations();
Alexey Frunze15958152017-02-09 19:08:30 -08007216 Location obj_loc = locations->InAt(0);
7217 Register obj = obj_loc.AsRegister<Register>();
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00007218 Register cls = locations->InAt(1).AsRegister<Register>();
Alexey Frunze15958152017-02-09 19:08:30 -08007219 Location out_loc = locations->Out();
7220 Register out = out_loc.AsRegister<Register>();
7221 const size_t num_temps = NumberOfInstanceOfTemps(type_check_kind);
7222 DCHECK_LE(num_temps, 1u);
7223 Location maybe_temp_loc = (num_temps >= 1) ? locations->GetTemp(0) : Location::NoLocation();
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007224 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
7225 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
7226 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
7227 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007228 MipsLabel done;
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007229 SlowPathCodeMIPS* slow_path = nullptr;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007230
7231 // Return 0 if `obj` is null.
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007232 // Avoid this check if we know `obj` is not null.
7233 if (instruction->MustDoNullCheck()) {
7234 __ Move(out, ZERO);
7235 __ Beqz(obj, &done);
7236 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007237
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007238 switch (type_check_kind) {
7239 case TypeCheckKind::kExactCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007240 ReadBarrierOption read_barrier_option =
7241 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007242 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007243 GenerateReferenceLoadTwoRegisters(instruction,
7244 out_loc,
7245 obj_loc,
7246 class_offset,
7247 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007248 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007249 // Classes must be equal for the instanceof to succeed.
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00007250 __ Xor(out, out, cls);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007251 __ Sltiu(out, out, 1);
7252 break;
7253 }
7254
7255 case TypeCheckKind::kAbstractClassCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007256 ReadBarrierOption read_barrier_option =
7257 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007258 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007259 GenerateReferenceLoadTwoRegisters(instruction,
7260 out_loc,
7261 obj_loc,
7262 class_offset,
7263 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007264 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007265 // If the class is abstract, we eagerly fetch the super class of the
7266 // object to avoid doing a comparison we know will fail.
7267 MipsLabel loop;
7268 __ Bind(&loop);
7269 // /* HeapReference<Class> */ out = out->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08007270 GenerateReferenceLoadOneRegister(instruction,
7271 out_loc,
7272 super_offset,
7273 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007274 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007275 // If `out` is null, we use it for the result, and jump to `done`.
7276 __ Beqz(out, &done);
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00007277 __ Bne(out, cls, &loop);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007278 __ LoadConst32(out, 1);
7279 break;
7280 }
7281
7282 case TypeCheckKind::kClassHierarchyCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007283 ReadBarrierOption read_barrier_option =
7284 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007285 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007286 GenerateReferenceLoadTwoRegisters(instruction,
7287 out_loc,
7288 obj_loc,
7289 class_offset,
7290 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007291 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007292 // Walk over the class hierarchy to find a match.
7293 MipsLabel loop, success;
7294 __ Bind(&loop);
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00007295 __ Beq(out, cls, &success);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007296 // /* HeapReference<Class> */ out = out->super_class_
Alexey Frunze15958152017-02-09 19:08:30 -08007297 GenerateReferenceLoadOneRegister(instruction,
7298 out_loc,
7299 super_offset,
7300 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007301 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007302 __ Bnez(out, &loop);
7303 // If `out` is null, we use it for the result, and jump to `done`.
7304 __ B(&done);
7305 __ Bind(&success);
7306 __ LoadConst32(out, 1);
7307 break;
7308 }
7309
7310 case TypeCheckKind::kArrayObjectCheck: {
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007311 ReadBarrierOption read_barrier_option =
7312 CodeGenerator::ReadBarrierOptionForInstanceOf(instruction);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007313 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007314 GenerateReferenceLoadTwoRegisters(instruction,
7315 out_loc,
7316 obj_loc,
7317 class_offset,
7318 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007319 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007320 // Do an exact check.
7321 MipsLabel success;
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00007322 __ Beq(out, cls, &success);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007323 // Otherwise, we need to check that the object's class is a non-primitive array.
7324 // /* HeapReference<Class> */ out = out->component_type_
Alexey Frunze15958152017-02-09 19:08:30 -08007325 GenerateReferenceLoadOneRegister(instruction,
7326 out_loc,
7327 component_offset,
7328 maybe_temp_loc,
Alexey Frunzedfc30af2018-01-24 16:25:10 -08007329 read_barrier_option);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007330 // If `out` is null, we use it for the result, and jump to `done`.
7331 __ Beqz(out, &done);
7332 __ LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
7333 static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
7334 __ Sltiu(out, out, 1);
7335 __ B(&done);
7336 __ Bind(&success);
7337 __ LoadConst32(out, 1);
7338 break;
7339 }
7340
7341 case TypeCheckKind::kArrayCheck: {
7342 // No read barrier since the slow path will retry upon failure.
7343 // /* HeapReference<Class> */ out = obj->klass_
Alexey Frunze15958152017-02-09 19:08:30 -08007344 GenerateReferenceLoadTwoRegisters(instruction,
7345 out_loc,
7346 obj_loc,
7347 class_offset,
7348 maybe_temp_loc,
7349 kWithoutReadBarrier);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007350 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01007351 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathMIPS(
7352 instruction, /* is_fatal */ false);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007353 codegen_->AddSlowPath(slow_path);
Nicolas Geoffraybff7a522018-01-25 13:33:07 +00007354 __ Bne(out, cls, slow_path->GetEntryLabel());
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007355 __ LoadConst32(out, 1);
7356 break;
7357 }
7358
7359 case TypeCheckKind::kUnresolvedCheck:
7360 case TypeCheckKind::kInterfaceCheck: {
7361 // Note that we indeed only call on slow path, but we always go
7362 // into the slow path for the unresolved and interface check
7363 // cases.
7364 //
7365 // We cannot directly call the InstanceofNonTrivial runtime
7366 // entry point without resorting to a type checking slow path
7367 // here (i.e. by calling InvokeRuntime directly), as it would
7368 // require to assign fixed registers for the inputs of this
7369 // HInstanceOf instruction (following the runtime calling
7370 // convention), which might be cluttered by the potential first
7371 // read barrier emission at the beginning of this method.
7372 //
7373 // TODO: Introduce a new runtime entry point taking the object
7374 // to test (instead of its class) as argument, and let it deal
7375 // with the read barrier issues. This will let us refactor this
7376 // case of the `switch` code as it was previously (with a direct
7377 // call to the runtime not using a type checking slow path).
7378 // This should also be beneficial for the other cases above.
7379 DCHECK(locations->OnlyCallsOnSlowPath());
Vladimir Marko174b2e22017-10-12 13:34:49 +01007380 slow_path = new (codegen_->GetScopedAllocator()) TypeCheckSlowPathMIPS(
7381 instruction, /* is_fatal */ false);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007382 codegen_->AddSlowPath(slow_path);
7383 __ B(slow_path->GetEntryLabel());
7384 break;
7385 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007386 }
7387
7388 __ Bind(&done);
Alexey Frunze66b69ad2017-02-24 00:51:44 -08007389
7390 if (slow_path != nullptr) {
7391 __ Bind(slow_path->GetExitLabel());
7392 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007393}
7394
7395void LocationsBuilderMIPS::VisitIntConstant(HIntConstant* constant) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007396 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007397 locations->SetOut(Location::ConstantLocation(constant));
7398}
7399
7400void InstructionCodeGeneratorMIPS::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
7401 // Will be generated at use site.
7402}
7403
7404void LocationsBuilderMIPS::VisitNullConstant(HNullConstant* constant) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007405 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007406 locations->SetOut(Location::ConstantLocation(constant));
7407}
7408
7409void InstructionCodeGeneratorMIPS::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
7410 // Will be generated at use site.
7411}
7412
7413void LocationsBuilderMIPS::HandleInvoke(HInvoke* invoke) {
7414 InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
7415 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
7416}
7417
7418void LocationsBuilderMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
7419 HandleInvoke(invoke);
Alexey Frunze1b8464d2016-11-12 17:22:05 -08007420 // The register T7 is required to be used for the hidden argument in
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007421 // art_quick_imt_conflict_trampoline, so add the hidden argument.
Alexey Frunze1b8464d2016-11-12 17:22:05 -08007422 invoke->GetLocations()->AddTemp(Location::RegisterLocation(T7));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007423}
7424
7425void InstructionCodeGeneratorMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
7426 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
7427 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007428 Location receiver = invoke->GetLocations()->InAt(0);
7429 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07007430 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007431
7432 // Set the hidden argument.
7433 __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
7434 invoke->GetDexMethodIndex());
7435
7436 // temp = object->GetClass();
7437 if (receiver.IsStackSlot()) {
7438 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
7439 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
7440 } else {
7441 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
7442 }
7443 codegen_->MaybeRecordImplicitNullCheck(invoke);
Alexey Frunzec061de12017-02-14 13:27:23 -08007444 // Instead of simply (possibly) unpoisoning `temp` here, we should
7445 // emit a read barrier for the previous class reference load.
7446 // However this is not required in practice, as this is an
7447 // intermediate/temporary reference and because the current
7448 // concurrent copying collector keeps the from-space memory
7449 // intact/accessible until the end of the marking phase (the
7450 // concurrent copying collector may not in the future).
7451 __ MaybeUnpoisonHeapReference(temp);
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00007452 __ LoadFromOffset(kLoadWord, temp, temp,
7453 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
7454 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00007455 invoke->GetImtIndex(), kMipsPointerSize));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007456 // temp = temp->GetImtEntryAt(method_offset);
7457 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
7458 // T9 = temp->GetEntryPoint();
7459 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
7460 // T9();
7461 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07007462 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007463 DCHECK(!codegen_->IsLeafMethod());
7464 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
7465}
7466
7467void LocationsBuilderMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Chris Larsen701566a2015-10-27 15:29:13 -07007468 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
7469 if (intrinsic.TryDispatch(invoke)) {
7470 return;
7471 }
7472
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007473 HandleInvoke(invoke);
7474}
7475
7476void LocationsBuilderMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00007477 // Explicit clinit checks triggered by static invokes must have been pruned by
7478 // art::PrepareForRegisterAllocation.
7479 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007480
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007481 bool is_r6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007482 bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
7483 bool has_extra_input = invoke->HasPcRelativeMethodLoadKind() && !is_r6 && !has_irreducible_loops;
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007484
Chris Larsen701566a2015-10-27 15:29:13 -07007485 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
7486 if (intrinsic.TryDispatch(invoke)) {
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007487 if (invoke->GetLocations()->CanCall() && has_extra_input) {
7488 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any());
7489 }
Chris Larsen701566a2015-10-27 15:29:13 -07007490 return;
7491 }
7492
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007493 HandleInvoke(invoke);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007494
7495 // Add the extra input register if either the dex cache array base register
7496 // or the PC-relative base register for accessing literals is needed.
7497 if (has_extra_input) {
7498 invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister());
7499 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007500}
7501
Orion Hodsonac141392017-01-13 11:53:47 +00007502void LocationsBuilderMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
7503 HandleInvoke(invoke);
7504}
7505
7506void InstructionCodeGeneratorMIPS::VisitInvokePolymorphic(HInvokePolymorphic* invoke) {
7507 codegen_->GenerateInvokePolymorphicCall(invoke);
7508}
7509
Chris Larsen701566a2015-10-27 15:29:13 -07007510static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007511 if (invoke->GetLocations()->Intrinsified()) {
Chris Larsen701566a2015-10-27 15:29:13 -07007512 IntrinsicCodeGeneratorMIPS intrinsic(codegen);
7513 intrinsic.Dispatch(invoke);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007514 return true;
7515 }
7516 return false;
7517}
7518
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007519HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
Alexey Frunze06a46c42016-07-19 15:00:40 -07007520 HLoadString::LoadKind desired_string_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007521 switch (desired_string_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007522 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01007523 case HLoadString::LoadKind::kBootImageInternTable:
Vladimir Markoaad75c62016-10-03 08:46:48 +00007524 case HLoadString::LoadKind::kBssEntry:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007525 DCHECK(!Runtime::Current()->UseJitCompilation());
Alexey Frunze06a46c42016-07-19 15:00:40 -07007526 break;
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007527 case HLoadString::LoadKind::kJitTableAddress:
7528 DCHECK(Runtime::Current()->UseJitCompilation());
Nicolas Geoffray132d8362016-11-16 09:19:42 +00007529 break;
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007530 case HLoadString::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007531 case HLoadString::LoadKind::kRuntimeCall:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007532 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07007533 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007534 return desired_string_load_kind;
Vladimir Markocac5a7e2016-02-22 10:39:50 +00007535}
7536
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007537HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind(
7538 HLoadClass::LoadKind desired_class_load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007539 switch (desired_class_load_kind) {
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007540 case HLoadClass::LoadKind::kInvalid:
7541 LOG(FATAL) << "UNREACHABLE";
7542 UNREACHABLE();
Alexey Frunze06a46c42016-07-19 15:00:40 -07007543 case HLoadClass::LoadKind::kReferrersClass:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007544 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07007545 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko94ec2db2017-09-06 17:21:03 +01007546 case HLoadClass::LoadKind::kBootImageClassTable:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007547 case HLoadClass::LoadKind::kBssEntry:
7548 DCHECK(!Runtime::Current()->UseJitCompilation());
7549 break;
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007550 case HLoadClass::LoadKind::kJitTableAddress:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007551 DCHECK(Runtime::Current()->UseJitCompilation());
Alexey Frunze06a46c42016-07-19 15:00:40 -07007552 break;
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007553 case HLoadClass::LoadKind::kBootImageAddress:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007554 case HLoadClass::LoadKind::kRuntimeCall:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007555 break;
7556 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007557 return desired_class_load_kind;
Vladimir Markodbb7f5b2016-03-30 13:23:58 +01007558}
7559
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007560Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke,
7561 Register temp) {
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007562 CHECK(!GetInstructionSetFeatures().IsR6());
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007563 CHECK(!GetGraph()->HasIrreducibleLoops());
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007564 CHECK_EQ(invoke->InputCount(), invoke->GetNumberOfArguments() + 1u);
7565 Location location = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
7566 if (!invoke->GetLocations()->Intrinsified()) {
7567 return location.AsRegister<Register>();
7568 }
7569 // For intrinsics we allow any location, so it may be on the stack.
7570 if (!location.IsRegister()) {
7571 __ LoadFromOffset(kLoadWord, temp, SP, location.GetStackIndex());
7572 return temp;
7573 }
7574 // For register locations, check if the register was saved. If so, get it from the stack.
7575 // Note: There is a chance that the register was saved but not overwritten, so we could
7576 // save one load. However, since this is just an intrinsic slow path we prefer this
7577 // simple and more robust approach rather that trying to determine if that's the case.
7578 SlowPathCode* slow_path = GetCurrentSlowPath();
7579 DCHECK(slow_path != nullptr); // For intrinsified invokes the call is emitted on the slow path.
7580 if (slow_path->IsCoreRegisterSaved(location.AsRegister<Register>())) {
7581 int stack_offset = slow_path->GetStackOffsetOfCoreRegister(location.AsRegister<Register>());
7582 __ LoadFromOffset(kLoadWord, temp, SP, stack_offset);
7583 return temp;
7584 }
7585 return location.AsRegister<Register>();
7586}
7587
Vladimir Markodc151b22015-10-15 18:02:30 +01007588HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
7589 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
Nicolas Geoffray5e4e11e2016-09-22 13:17:41 +01007590 HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) {
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007591 return desired_dispatch_info;
Vladimir Markodc151b22015-10-15 18:02:30 +01007592}
7593
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007594void CodeGeneratorMIPS::GenerateStaticOrDirectCall(
7595 HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007596 // All registers are assumed to be correctly set up per the calling convention.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007597 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007598 HInvokeStaticOrDirect::MethodLoadKind method_load_kind = invoke->GetMethodLoadKind();
7599 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location = invoke->GetCodePtrLocation();
Alexey Frunze6b892cd2017-01-03 17:11:38 -08007600 bool is_r6 = GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007601 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
7602 Register base_reg = (invoke->HasPcRelativeMethodLoadKind() && !is_r6 && !has_irreducible_loops)
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007603 ? GetInvokeStaticOrDirectExtraParameter(invoke, temp.AsRegister<Register>())
7604 : ZERO;
7605
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007606 switch (method_load_kind) {
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007607 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007608 // temp = thread->string_init_entrypoint
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007609 uint32_t offset =
7610 GetThreadOffset<kMipsPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007611 __ LoadFromOffset(kLoadWord,
7612 temp.AsRegister<Register>(),
7613 TR,
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007614 offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007615 break;
Nicolas Geoffrayda079bb2016-09-26 17:56:07 +01007616 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007617 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00007618 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007619 break;
Vladimir Marko65979462017-05-19 17:25:12 +01007620 case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
7621 DCHECK(GetCompilerOptions().IsBootImage());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007622 PcRelativePatchInfo* info_high = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
7623 PcRelativePatchInfo* info_low =
7624 NewPcRelativeMethodPatch(invoke->GetTargetMethod(), info_high);
Vladimir Marko65979462017-05-19 17:25:12 +01007625 Register temp_reg = temp.AsRegister<Register>();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07007626 EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg);
7627 __ Addiu(temp_reg, TMP, /* placeholder */ 0x5678, &info_low->label);
Vladimir Marko65979462017-05-19 17:25:12 +01007628 break;
7629 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007630 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
7631 __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
7632 break;
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007633 case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007634 PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007635 MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007636 PcRelativePatchInfo* info_low = NewMethodBssEntryPatch(
7637 MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()), info_high);
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007638 Register temp_reg = temp.AsRegister<Register>();
Alexey Frunzea663d9d2017-07-31 18:43:18 -07007639 EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg);
7640 __ Lw(temp_reg, TMP, /* placeholder */ 0x5678, &info_low->label);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007641 break;
Vladimir Marko0eb882b2017-05-15 13:39:18 +01007642 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007643 case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: {
7644 GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path);
7645 return; // No code pointer retrieval; the runtime performs the call directly.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007646 }
7647 }
7648
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007649 switch (code_ptr_location) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007650 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
Alexey Frunzee3fb2452016-05-10 16:08:05 -07007651 __ Bal(&frame_entry_label_);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007652 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007653 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
7654 // T9 = callee_method->entry_point_from_quick_compiled_code_;
Goran Jakovljevic1a878372015-10-26 14:28:52 +01007655 __ LoadFromOffset(kLoadWord,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007656 T9,
7657 callee_method.AsRegister<Register>(),
7658 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Andreas Gampe542451c2016-07-26 09:02:02 -07007659 kMipsPointerSize).Int32Value());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007660 // T9()
7661 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07007662 __ NopIfNoReordering();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007663 break;
7664 }
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007665 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
7666
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007667 DCHECK(!IsLeafMethod());
7668}
7669
7670void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00007671 // Explicit clinit checks triggered by static invokes must have been pruned by
7672 // art::PrepareForRegisterAllocation.
7673 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007674
7675 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
7676 return;
7677 }
7678
7679 LocationSummary* locations = invoke->GetLocations();
7680 codegen_->GenerateStaticOrDirectCall(invoke,
7681 locations->HasTemps()
7682 ? locations->GetTemp(0)
7683 : Location::NoLocation());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007684}
7685
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007686void CodeGeneratorMIPS::GenerateVirtualCall(
7687 HInvokeVirtual* invoke, Location temp_location, SlowPathCode* slow_path) {
Goran Jakovljevice919b072016-10-04 10:17:34 +02007688 // Use the calling convention instead of the location of the receiver, as
7689 // intrinsics may have put the receiver in a different register. In the intrinsics
7690 // slow path, the arguments have been moved to the right place, so here we are
7691 // guaranteed that the receiver is the first register of the calling convention.
7692 InvokeDexCallingConvention calling_convention;
7693 Register receiver = calling_convention.GetRegisterAt(0);
7694
Chris Larsen3acee732015-11-18 13:31:08 -08007695 Register temp = temp_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007696 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
7697 invoke->GetVTableIndex(), kMipsPointerSize).SizeValue();
7698 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Andreas Gampe542451c2016-07-26 09:02:02 -07007699 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007700
7701 // temp = object->GetClass();
Goran Jakovljevice919b072016-10-04 10:17:34 +02007702 __ LoadFromOffset(kLoadWord, temp, receiver, class_offset);
Chris Larsen3acee732015-11-18 13:31:08 -08007703 MaybeRecordImplicitNullCheck(invoke);
Alexey Frunzec061de12017-02-14 13:27:23 -08007704 // Instead of simply (possibly) unpoisoning `temp` here, we should
7705 // emit a read barrier for the previous class reference load.
7706 // However this is not required in practice, as this is an
7707 // intermediate/temporary reference and because the current
7708 // concurrent copying collector keeps the from-space memory
7709 // intact/accessible until the end of the marking phase (the
7710 // concurrent copying collector may not in the future).
7711 __ MaybeUnpoisonHeapReference(temp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007712 // temp = temp->GetMethodAt(method_offset);
7713 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
7714 // T9 = temp->GetEntryPoint();
7715 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
7716 // T9();
7717 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07007718 __ NopIfNoReordering();
Vladimir Markoe7197bf2017-06-02 17:00:23 +01007719 RecordPcInfo(invoke, invoke->GetDexPc(), slow_path);
Chris Larsen3acee732015-11-18 13:31:08 -08007720}
7721
7722void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
7723 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
7724 return;
7725 }
7726
7727 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007728 DCHECK(!codegen_->IsLeafMethod());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007729}
7730
7731void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
Vladimir Marko41559982017-01-06 14:04:23 +00007732 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007733 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007734 InvokeRuntimeCallingConvention calling_convention;
Alexey Frunzec61c0762017-04-10 13:54:23 -07007735 Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
7736 CodeGenerator::CreateLoadClassRuntimeCallLocationSummary(cls, loc, loc);
Alexey Frunze06a46c42016-07-19 15:00:40 -07007737 return;
7738 }
Vladimir Marko41559982017-01-06 14:04:23 +00007739 DCHECK(!cls->NeedsAccessCheck());
Alexey Frunzec61c0762017-04-10 13:54:23 -07007740 const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007741 const bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
Alexey Frunze15958152017-02-09 19:08:30 -08007742 const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
7743 LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
Alexey Frunze06a46c42016-07-19 15:00:40 -07007744 ? LocationSummary::kCallOnSlowPath
7745 : LocationSummary::kNoCall;
Vladimir Markoca6fff82017-10-03 14:49:14 +01007746 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(cls, call_kind);
Alexey Frunzec61c0762017-04-10 13:54:23 -07007747 if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
7748 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
7749 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007750 switch (load_kind) {
7751 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07007752 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007753 case HLoadClass::LoadKind::kBootImageAddress:
Vladimir Marko94ec2db2017-09-06 17:21:03 +01007754 case HLoadClass::LoadKind::kBootImageClassTable:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007755 case HLoadClass::LoadKind::kBssEntry:
Alexey Frunzec61c0762017-04-10 13:54:23 -07007756 if (isR6) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007757 break;
7758 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007759 if (has_irreducible_loops) {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07007760 if (load_kind != HLoadClass::LoadKind::kBootImageAddress) {
7761 codegen_->ClobberRA();
7762 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007763 break;
7764 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007765 FALLTHROUGH_INTENDED;
Alexey Frunze06a46c42016-07-19 15:00:40 -07007766 case HLoadClass::LoadKind::kReferrersClass:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007767 locations->SetInAt(0, Location::RequiresRegister());
7768 break;
7769 default:
7770 break;
7771 }
7772 locations->SetOut(Location::RequiresRegister());
Alexey Frunzec61c0762017-04-10 13:54:23 -07007773 if (load_kind == HLoadClass::LoadKind::kBssEntry) {
7774 if (!kUseReadBarrier || kUseBakerReadBarrier) {
7775 // Rely on the type resolution or initialization and marking to save everything we need.
Alexey Frunzec61c0762017-04-10 13:54:23 -07007776 RegisterSet caller_saves = RegisterSet::Empty();
7777 InvokeRuntimeCallingConvention calling_convention;
7778 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7779 locations->SetCustomSlowPathCallerSaves(caller_saves);
7780 } else {
7781 // For non-Baker read barriers we have a temp-clobbering call.
7782 }
7783 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007784}
7785
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007786// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
7787// move.
7788void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFETY_ANALYSIS {
Vladimir Marko41559982017-01-06 14:04:23 +00007789 HLoadClass::LoadKind load_kind = cls->GetLoadKind();
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007790 if (load_kind == HLoadClass::LoadKind::kRuntimeCall) {
Vladimir Marko41559982017-01-06 14:04:23 +00007791 codegen_->GenerateLoadClassRuntimeCall(cls);
Pavle Batutae87a7182015-10-28 13:10:42 +01007792 return;
7793 }
Vladimir Marko41559982017-01-06 14:04:23 +00007794 DCHECK(!cls->NeedsAccessCheck());
Pavle Batutae87a7182015-10-28 13:10:42 +01007795
Vladimir Marko41559982017-01-06 14:04:23 +00007796 LocationSummary* locations = cls->GetLocations();
Alexey Frunze06a46c42016-07-19 15:00:40 -07007797 Location out_loc = locations->Out();
7798 Register out = out_loc.AsRegister<Register>();
7799 Register base_or_current_method_reg;
7800 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007801 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
Alexey Frunze06a46c42016-07-19 15:00:40 -07007802 switch (load_kind) {
7803 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07007804 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007805 case HLoadClass::LoadKind::kBootImageAddress:
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007806 case HLoadClass::LoadKind::kBootImageClassTable:
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007807 case HLoadClass::LoadKind::kBssEntry:
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007808 base_or_current_method_reg =
7809 (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
Alexey Frunze06a46c42016-07-19 15:00:40 -07007810 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07007811 case HLoadClass::LoadKind::kReferrersClass:
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007812 case HLoadClass::LoadKind::kRuntimeCall:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007813 base_or_current_method_reg = locations->InAt(0).AsRegister<Register>();
7814 break;
7815 default:
7816 base_or_current_method_reg = ZERO;
7817 break;
7818 }
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00007819
Alexey Frunze15958152017-02-09 19:08:30 -08007820 const ReadBarrierOption read_barrier_option = cls->IsInBootImage()
7821 ? kWithoutReadBarrier
7822 : kCompilerReadBarrierOption;
Alexey Frunze06a46c42016-07-19 15:00:40 -07007823 bool generate_null_check = false;
7824 switch (load_kind) {
7825 case HLoadClass::LoadKind::kReferrersClass: {
7826 DCHECK(!cls->CanCallRuntime());
7827 DCHECK(!cls->MustGenerateClinitCheck());
7828 // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
7829 GenerateGcRootFieldLoad(cls,
7830 out_loc,
7831 base_or_current_method_reg,
Alexey Frunze15958152017-02-09 19:08:30 -08007832 ArtMethod::DeclaringClassOffset().Int32Value(),
7833 read_barrier_option);
Alexey Frunze06a46c42016-07-19 15:00:40 -07007834 break;
7835 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007836 case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007837 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze15958152017-02-09 19:08:30 -08007838 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007839 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
Alexey Frunze06a46c42016-07-19 15:00:40 -07007840 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007841 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
7842 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007843 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
7844 out,
Alexey Frunzea663d9d2017-07-31 18:43:18 -07007845 base_or_current_method_reg);
7846 __ Addiu(out, out, /* placeholder */ 0x5678, &info_low->label);
Alexey Frunze06a46c42016-07-19 15:00:40 -07007847 break;
7848 }
7849 case HLoadClass::LoadKind::kBootImageAddress: {
Alexey Frunze15958152017-02-09 19:08:30 -08007850 DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
Nicolas Geoffray5247c082017-01-13 14:17:29 +00007851 uint32_t address = dchecked_integral_cast<uint32_t>(
7852 reinterpret_cast<uintptr_t>(cls->GetClass().Get()));
7853 DCHECK_NE(address, 0u);
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007854 if (isR6 || !has_irreducible_loops) {
7855 __ LoadLiteral(out,
7856 base_or_current_method_reg,
7857 codegen_->DeduplicateBootImageAddressLiteral(address));
7858 } else {
7859 __ LoadConst32(out, address);
7860 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007861 break;
7862 }
Vladimir Marko94ec2db2017-09-06 17:21:03 +01007863 case HLoadClass::LoadKind::kBootImageClassTable: {
7864 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
7865 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
7866 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
7867 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
7868 codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
7869 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
7870 out,
7871 base_or_current_method_reg);
7872 __ Lw(out, out, /* placeholder */ 0x5678, &info_low->label);
7873 // Extract the reference from the slot data, i.e. clear the hash bits.
7874 int32_t masked_hash = ClassTable::TableSlot::MaskHash(
7875 ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
7876 if (masked_hash != 0) {
7877 __ Addiu(out, out, -masked_hash);
7878 }
7879 break;
7880 }
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007881 case HLoadClass::LoadKind::kBssEntry: {
Vladimir Markof3c52b42017-11-17 17:32:12 +00007882 CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high =
7883 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007884 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
7885 codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex(), bss_info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07007886 codegen_->EmitPcRelativeAddressPlaceholderHigh(bss_info_high,
Vladimir Markof3c52b42017-11-17 17:32:12 +00007887 out,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007888 base_or_current_method_reg);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007889 GenerateGcRootFieldLoad(cls,
7890 out_loc,
Vladimir Markof3c52b42017-11-17 17:32:12 +00007891 out,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007892 /* placeholder */ 0x5678,
7893 read_barrier_option,
7894 &info_low->label);
Vladimir Marko6bec91c2017-01-09 15:03:12 +00007895 generate_null_check = true;
7896 break;
7897 }
Nicolas Geoffray22384ae2016-12-12 22:33:36 +00007898 case HLoadClass::LoadKind::kJitTableAddress: {
Alexey Frunze627c1a02017-01-30 19:28:14 -08007899 CodeGeneratorMIPS::JitPatchInfo* info = codegen_->NewJitRootClassPatch(cls->GetDexFile(),
7900 cls->GetTypeIndex(),
7901 cls->GetClass());
7902 bool reordering = __ SetReorder(false);
7903 __ Bind(&info->high_label);
7904 __ Lui(out, /* placeholder */ 0x1234);
Alexey Frunze627c1a02017-01-30 19:28:14 -08007905 __ SetReorder(reordering);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07007906 GenerateGcRootFieldLoad(cls,
7907 out_loc,
7908 out,
7909 /* placeholder */ 0x5678,
7910 read_barrier_option,
7911 &info->low_label);
Alexey Frunze06a46c42016-07-19 15:00:40 -07007912 break;
7913 }
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007914 case HLoadClass::LoadKind::kRuntimeCall:
Nicolas Geoffray83c8e272017-01-31 14:36:37 +00007915 case HLoadClass::LoadKind::kInvalid:
Vladimir Marko41559982017-01-06 14:04:23 +00007916 LOG(FATAL) << "UNREACHABLE";
7917 UNREACHABLE();
Alexey Frunze06a46c42016-07-19 15:00:40 -07007918 }
7919
7920 if (generate_null_check || cls->MustGenerateClinitCheck()) {
7921 DCHECK(cls->CanCallRuntime());
Vladimir Marko174b2e22017-10-12 13:34:49 +01007922 SlowPathCodeMIPS* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathMIPS(
Vladimir Markof3c52b42017-11-17 17:32:12 +00007923 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
Alexey Frunze06a46c42016-07-19 15:00:40 -07007924 codegen_->AddSlowPath(slow_path);
7925 if (generate_null_check) {
7926 __ Beqz(out, slow_path->GetEntryLabel());
7927 }
7928 if (cls->MustGenerateClinitCheck()) {
7929 GenerateClassInitializationCheck(slow_path, out);
7930 } else {
7931 __ Bind(slow_path->GetExitLabel());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007932 }
7933 }
7934}
7935
7936static int32_t GetExceptionTlsOffset() {
Andreas Gampe542451c2016-07-26 09:02:02 -07007937 return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007938}
7939
7940void LocationsBuilderMIPS::VisitLoadException(HLoadException* load) {
7941 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01007942 new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007943 locations->SetOut(Location::RequiresRegister());
7944}
7945
7946void InstructionCodeGeneratorMIPS::VisitLoadException(HLoadException* load) {
7947 Register out = load->GetLocations()->Out().AsRegister<Register>();
7948 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
7949}
7950
7951void LocationsBuilderMIPS::VisitClearException(HClearException* clear) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01007952 new (GetGraph()->GetAllocator()) LocationSummary(clear, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007953}
7954
7955void InstructionCodeGeneratorMIPS::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
7956 __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
7957}
7958
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02007959void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
Alexey Frunzef63f5692016-12-13 17:43:11 -08007960 LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
Vladimir Markoca6fff82017-10-03 14:49:14 +01007961 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(load, call_kind);
Alexey Frunze06a46c42016-07-19 15:00:40 -07007962 HLoadString::LoadKind load_kind = load->GetLoadKind();
Alexey Frunzec61c0762017-04-10 13:54:23 -07007963 const bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007964 const bool has_irreducible_loops = codegen_->GetGraph()->HasIrreducibleLoops();
Alexey Frunze06a46c42016-07-19 15:00:40 -07007965 switch (load_kind) {
7966 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07007967 case HLoadString::LoadKind::kBootImageAddress:
7968 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01007969 case HLoadString::LoadKind::kBootImageInternTable:
Vladimir Markoaad75c62016-10-03 08:46:48 +00007970 case HLoadString::LoadKind::kBssEntry:
Alexey Frunzec61c0762017-04-10 13:54:23 -07007971 if (isR6) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07007972 break;
7973 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007974 if (has_irreducible_loops) {
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07007975 if (load_kind != HLoadString::LoadKind::kBootImageAddress) {
7976 codegen_->ClobberRA();
7977 }
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02007978 break;
7979 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07007980 FALLTHROUGH_INTENDED;
7981 // We need an extra register for PC-relative dex cache accesses.
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007982 case HLoadString::LoadKind::kRuntimeCall:
Alexey Frunze06a46c42016-07-19 15:00:40 -07007983 locations->SetInAt(0, Location::RequiresRegister());
7984 break;
7985 default:
7986 break;
7987 }
Vladimir Marko847e6ce2017-06-02 13:55:07 +01007988 if (load_kind == HLoadString::LoadKind::kRuntimeCall) {
Alexey Frunzebb51df82016-11-01 16:07:32 -07007989 InvokeRuntimeCallingConvention calling_convention;
Alexey Frunzec61c0762017-04-10 13:54:23 -07007990 locations->SetOut(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Alexey Frunzebb51df82016-11-01 16:07:32 -07007991 } else {
7992 locations->SetOut(Location::RequiresRegister());
Alexey Frunzec61c0762017-04-10 13:54:23 -07007993 if (load_kind == HLoadString::LoadKind::kBssEntry) {
7994 if (!kUseReadBarrier || kUseBakerReadBarrier) {
7995 // Rely on the pResolveString and marking to save everything we need.
Alexey Frunzec61c0762017-04-10 13:54:23 -07007996 RegisterSet caller_saves = RegisterSet::Empty();
7997 InvokeRuntimeCallingConvention calling_convention;
7998 caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
7999 locations->SetCustomSlowPathCallerSaves(caller_saves);
8000 } else {
8001 // For non-Baker read barriers we have a temp-clobbering call.
8002 }
8003 }
Alexey Frunzebb51df82016-11-01 16:07:32 -07008004 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008005}
8006
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00008007// NO_THREAD_SAFETY_ANALYSIS as we manipulate handles whose internal object we know does not
8008// move.
8009void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) NO_THREAD_SAFETY_ANALYSIS {
Alexey Frunze06a46c42016-07-19 15:00:40 -07008010 HLoadString::LoadKind load_kind = load->GetLoadKind();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008011 LocationSummary* locations = load->GetLocations();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008012 Location out_loc = locations->Out();
8013 Register out = out_loc.AsRegister<Register>();
8014 Register base_or_current_method_reg;
8015 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008016 bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008017 switch (load_kind) {
8018 // We need an extra register for PC-relative literals on R2.
Alexey Frunze06a46c42016-07-19 15:00:40 -07008019 case HLoadString::LoadKind::kBootImageAddress:
8020 case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008021 case HLoadString::LoadKind::kBootImageInternTable:
Vladimir Markoaad75c62016-10-03 08:46:48 +00008022 case HLoadString::LoadKind::kBssEntry:
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008023 base_or_current_method_reg =
8024 (isR6 || has_irreducible_loops) ? ZERO : locations->InAt(0).AsRegister<Register>();
Alexey Frunze06a46c42016-07-19 15:00:40 -07008025 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008026 default:
8027 base_or_current_method_reg = ZERO;
8028 break;
8029 }
8030
8031 switch (load_kind) {
Alexey Frunze06a46c42016-07-19 15:00:40 -07008032 case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00008033 DCHECK(codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008034 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008035 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008036 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
8037 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008038 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
8039 out,
Alexey Frunzea663d9d2017-07-31 18:43:18 -07008040 base_or_current_method_reg);
8041 __ Addiu(out, out, /* placeholder */ 0x5678, &info_low->label);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008042 return;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008043 }
8044 case HLoadString::LoadKind::kBootImageAddress: {
Nicolas Geoffrayf0acfe72017-01-09 20:54:52 +00008045 uint32_t address = dchecked_integral_cast<uint32_t>(
8046 reinterpret_cast<uintptr_t>(load->GetString().Get()));
8047 DCHECK_NE(address, 0u);
Goran Jakovljevicdebb5102017-09-21 14:24:06 +02008048 if (isR6 || !has_irreducible_loops) {
8049 __ LoadLiteral(out,
8050 base_or_current_method_reg,
8051 codegen_->DeduplicateBootImageAddressLiteral(address));
8052 } else {
8053 __ LoadConst32(out, address);
8054 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008055 return;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008056 }
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008057 case HLoadString::LoadKind::kBootImageInternTable: {
Vladimir Markoaad75c62016-10-03 08:46:48 +00008058 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008059 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
Vladimir Marko6bec91c2017-01-09 15:03:12 +00008060 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008061 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
8062 codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
Vladimir Marko6cfbdbc2017-07-25 13:26:39 +01008063 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
8064 out,
8065 base_or_current_method_reg);
8066 __ Lw(out, out, /* placeholder */ 0x5678, &info_low->label);
8067 return;
8068 }
8069 case HLoadString::LoadKind::kBssEntry: {
8070 DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
8071 CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
8072 codegen_->NewStringBssEntryPatch(load->GetDexFile(), load->GetStringIndex());
8073 CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
8074 codegen_->NewStringBssEntryPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008075 codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
Vladimir Markof3c52b42017-11-17 17:32:12 +00008076 out,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008077 base_or_current_method_reg);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008078 GenerateGcRootFieldLoad(load,
8079 out_loc,
Vladimir Markof3c52b42017-11-17 17:32:12 +00008080 out,
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008081 /* placeholder */ 0x5678,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008082 kCompilerReadBarrierOption,
8083 &info_low->label);
Alexey Frunze5fa5c042017-06-01 21:07:52 -07008084 SlowPathCodeMIPS* slow_path =
Vladimir Markof3c52b42017-11-17 17:32:12 +00008085 new (codegen_->GetScopedAllocator()) LoadStringSlowPathMIPS(load);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008086 codegen_->AddSlowPath(slow_path);
8087 __ Beqz(out, slow_path->GetEntryLabel());
8088 __ Bind(slow_path->GetExitLabel());
8089 return;
8090 }
Alexey Frunze627c1a02017-01-30 19:28:14 -08008091 case HLoadString::LoadKind::kJitTableAddress: {
8092 CodeGeneratorMIPS::JitPatchInfo* info =
8093 codegen_->NewJitRootStringPatch(load->GetDexFile(),
8094 load->GetStringIndex(),
8095 load->GetString());
8096 bool reordering = __ SetReorder(false);
8097 __ Bind(&info->high_label);
8098 __ Lui(out, /* placeholder */ 0x1234);
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008099 __ SetReorder(reordering);
Alexey Frunze15958152017-02-09 19:08:30 -08008100 GenerateGcRootFieldLoad(load,
8101 out_loc,
8102 out,
8103 /* placeholder */ 0x5678,
Alexey Frunze4147fcc2017-06-17 19:57:27 -07008104 kCompilerReadBarrierOption,
8105 &info->low_label);
Alexey Frunze627c1a02017-01-30 19:28:14 -08008106 return;
8107 }
Alexey Frunze06a46c42016-07-19 15:00:40 -07008108 default:
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07008109 break;
Alexey Frunze06a46c42016-07-19 15:00:40 -07008110 }
Nicolas Geoffray917d0162015-11-24 18:25:35 +00008111
Christina Wadsworthbf44e0e2016-08-18 10:37:42 -07008112 // TODO: Re-add the compiler code to do string dex cache lookup again.
Vladimir Marko847e6ce2017-06-02 13:55:07 +01008113 DCHECK(load_kind == HLoadString::LoadKind::kRuntimeCall);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008114 InvokeRuntimeCallingConvention calling_convention;
Alexey Frunzec61c0762017-04-10 13:54:23 -07008115 DCHECK_EQ(calling_convention.GetRegisterAt(0), out);
Andreas Gampe8a0128a2016-11-28 07:38:35 -08008116 __ LoadConst32(calling_convention.GetRegisterAt(0), load->GetStringIndex().index_);
Vladimir Markoaad75c62016-10-03 08:46:48 +00008117 codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
8118 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008119}
8120
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008121void LocationsBuilderMIPS::VisitLongConstant(HLongConstant* constant) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008122 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(constant);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008123 locations->SetOut(Location::ConstantLocation(constant));
8124}
8125
8126void InstructionCodeGeneratorMIPS::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
8127 // Will be generated at use site.
8128}
8129
8130void LocationsBuilderMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008131 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8132 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008133 InvokeRuntimeCallingConvention calling_convention;
8134 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8135}
8136
8137void InstructionCodeGeneratorMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
8138 if (instruction->IsEnter()) {
Serban Constantinescufca16662016-07-14 09:21:59 +01008139 codegen_->InvokeRuntime(kQuickLockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008140 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
8141 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01008142 codegen_->InvokeRuntime(kQuickUnlockObject, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008143 }
8144 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
8145}
8146
8147void LocationsBuilderMIPS::VisitMul(HMul* mul) {
8148 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008149 new (GetGraph()->GetAllocator()) LocationSummary(mul, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008150 switch (mul->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008151 case DataType::Type::kInt32:
8152 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008153 locations->SetInAt(0, Location::RequiresRegister());
8154 locations->SetInAt(1, Location::RequiresRegister());
8155 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8156 break;
8157
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008158 case DataType::Type::kFloat32:
8159 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008160 locations->SetInAt(0, Location::RequiresFpuRegister());
8161 locations->SetInAt(1, Location::RequiresFpuRegister());
8162 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
8163 break;
8164
8165 default:
8166 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
8167 }
8168}
8169
8170void InstructionCodeGeneratorMIPS::VisitMul(HMul* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008171 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008172 LocationSummary* locations = instruction->GetLocations();
8173 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
8174
8175 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008176 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008177 Register dst = locations->Out().AsRegister<Register>();
8178 Register lhs = locations->InAt(0).AsRegister<Register>();
8179 Register rhs = locations->InAt(1).AsRegister<Register>();
8180
8181 if (isR6) {
8182 __ MulR6(dst, lhs, rhs);
8183 } else {
8184 __ MulR2(dst, lhs, rhs);
8185 }
8186 break;
8187 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008188 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008189 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8190 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8191 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8192 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
8193 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
8194 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
8195
8196 // Extra checks to protect caused by the existance of A1_A2.
8197 // The algorithm is wrong if dst_high is either lhs_lo or rhs_lo:
8198 // (e.g. lhs=a0_a1, rhs=a2_a3 and dst=a1_a2).
8199 DCHECK_NE(dst_high, lhs_low);
8200 DCHECK_NE(dst_high, rhs_low);
8201
8202 // A_B * C_D
8203 // dst_hi: [ low(A*D) + low(B*C) + hi(B*D) ]
8204 // dst_lo: [ low(B*D) ]
8205 // Note: R2 and R6 MUL produce the low 32 bit of the multiplication result.
8206
8207 if (isR6) {
8208 __ MulR6(TMP, lhs_high, rhs_low);
8209 __ MulR6(dst_high, lhs_low, rhs_high);
8210 __ Addu(dst_high, dst_high, TMP);
8211 __ MuhuR6(TMP, lhs_low, rhs_low);
8212 __ Addu(dst_high, dst_high, TMP);
8213 __ MulR6(dst_low, lhs_low, rhs_low);
8214 } else {
8215 __ MulR2(TMP, lhs_high, rhs_low);
8216 __ MulR2(dst_high, lhs_low, rhs_high);
8217 __ Addu(dst_high, dst_high, TMP);
8218 __ MultuR2(lhs_low, rhs_low);
8219 __ Mfhi(TMP);
8220 __ Addu(dst_high, dst_high, TMP);
8221 __ Mflo(dst_low);
8222 }
8223 break;
8224 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008225 case DataType::Type::kFloat32:
8226 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008227 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8228 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
8229 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008230 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008231 __ MulS(dst, lhs, rhs);
8232 } else {
8233 __ MulD(dst, lhs, rhs);
8234 }
8235 break;
8236 }
8237 default:
8238 LOG(FATAL) << "Unexpected mul type " << type;
8239 }
8240}
8241
8242void LocationsBuilderMIPS::VisitNeg(HNeg* neg) {
8243 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008244 new (GetGraph()->GetAllocator()) LocationSummary(neg, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008245 switch (neg->GetResultType()) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008246 case DataType::Type::kInt32:
8247 case DataType::Type::kInt64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008248 locations->SetInAt(0, Location::RequiresRegister());
8249 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8250 break;
8251
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008252 case DataType::Type::kFloat32:
8253 case DataType::Type::kFloat64:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008254 locations->SetInAt(0, Location::RequiresFpuRegister());
8255 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
8256 break;
8257
8258 default:
8259 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
8260 }
8261}
8262
8263void InstructionCodeGeneratorMIPS::VisitNeg(HNeg* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008264 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008265 LocationSummary* locations = instruction->GetLocations();
8266
8267 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008268 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008269 Register dst = locations->Out().AsRegister<Register>();
8270 Register src = locations->InAt(0).AsRegister<Register>();
8271 __ Subu(dst, ZERO, src);
8272 break;
8273 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008274 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008275 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8276 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8277 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8278 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
8279 __ Subu(dst_low, ZERO, src_low);
8280 __ Sltu(TMP, ZERO, dst_low);
8281 __ Subu(dst_high, ZERO, src_high);
8282 __ Subu(dst_high, dst_high, TMP);
8283 break;
8284 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008285 case DataType::Type::kFloat32:
8286 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008287 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8288 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008289 if (type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008290 __ NegS(dst, src);
8291 } else {
8292 __ NegD(dst, src);
8293 }
8294 break;
8295 }
8296 default:
8297 LOG(FATAL) << "Unexpected neg type " << type;
8298 }
8299}
8300
8301void LocationsBuilderMIPS::VisitNewArray(HNewArray* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008302 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8303 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008304 InvokeRuntimeCallingConvention calling_convention;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008305 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00008306 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8307 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008308}
8309
8310void InstructionCodeGeneratorMIPS::VisitNewArray(HNewArray* instruction) {
Alexey Frunzec061de12017-02-14 13:27:23 -08008311 // Note: if heap poisoning is enabled, the entry point takes care
8312 // of poisoning the reference.
Goran Jakovljevic854df412017-06-27 14:41:39 +02008313 QuickEntrypointEnum entrypoint =
8314 CodeGenerator::GetArrayAllocationEntrypoint(instruction->GetLoadClass()->GetClass());
8315 codegen_->InvokeRuntime(entrypoint, instruction, instruction->GetDexPc());
Nicolas Geoffraye761bcc2017-01-19 08:59:37 +00008316 CheckEntrypointTypes<kQuickAllocArrayResolved, void*, mirror::Class*, int32_t>();
Goran Jakovljevic854df412017-06-27 14:41:39 +02008317 DCHECK(!codegen_->IsLeafMethod());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008318}
8319
8320void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008321 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8322 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008323 InvokeRuntimeCallingConvention calling_convention;
David Brazdil6de19382016-01-08 17:37:10 +00008324 if (instruction->IsStringAlloc()) {
8325 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
8326 } else {
8327 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
David Brazdil6de19382016-01-08 17:37:10 +00008328 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008329 locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008330}
8331
8332void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) {
Alexey Frunzec061de12017-02-14 13:27:23 -08008333 // Note: if heap poisoning is enabled, the entry point takes care
8334 // of poisoning the reference.
David Brazdil6de19382016-01-08 17:37:10 +00008335 if (instruction->IsStringAlloc()) {
8336 // String is allocated through StringFactory. Call NewEmptyString entry point.
8337 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
Andreas Gampe542451c2016-07-26 09:02:02 -07008338 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsPointerSize);
David Brazdil6de19382016-01-08 17:37:10 +00008339 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
8340 __ LoadFromOffset(kLoadWord, T9, temp, code_offset.Int32Value());
8341 __ Jalr(T9);
Alexey Frunze57eb0f52016-07-29 22:04:46 -07008342 __ NopIfNoReordering();
David Brazdil6de19382016-01-08 17:37:10 +00008343 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
8344 } else {
Serban Constantinescufca16662016-07-14 09:21:59 +01008345 codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
Nicolas Geoffray0d3998b2017-01-12 15:35:12 +00008346 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
David Brazdil6de19382016-01-08 17:37:10 +00008347 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008348}
8349
8350void LocationsBuilderMIPS::VisitNot(HNot* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008351 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008352 locations->SetInAt(0, Location::RequiresRegister());
8353 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8354}
8355
8356void InstructionCodeGeneratorMIPS::VisitNot(HNot* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008357 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008358 LocationSummary* locations = instruction->GetLocations();
8359
8360 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008361 case DataType::Type::kInt32: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008362 Register dst = locations->Out().AsRegister<Register>();
8363 Register src = locations->InAt(0).AsRegister<Register>();
8364 __ Nor(dst, src, ZERO);
8365 break;
8366 }
8367
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008368 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008369 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8370 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8371 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8372 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
8373 __ Nor(dst_high, src_high, ZERO);
8374 __ Nor(dst_low, src_low, ZERO);
8375 break;
8376 }
8377
8378 default:
8379 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
8380 }
8381}
8382
8383void LocationsBuilderMIPS::VisitBooleanNot(HBooleanNot* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008384 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008385 locations->SetInAt(0, Location::RequiresRegister());
8386 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8387}
8388
8389void InstructionCodeGeneratorMIPS::VisitBooleanNot(HBooleanNot* instruction) {
8390 LocationSummary* locations = instruction->GetLocations();
8391 __ Xori(locations->Out().AsRegister<Register>(),
8392 locations->InAt(0).AsRegister<Register>(),
8393 1);
8394}
8395
8396void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
Vladimir Marko804b03f2016-09-14 16:26:36 +01008397 LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
8398 locations->SetInAt(0, Location::RequiresRegister());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008399}
8400
Calin Juravle2ae48182016-03-16 14:05:09 +00008401void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
8402 if (CanMoveNullCheckToUser(instruction)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008403 return;
8404 }
8405 Location obj = instruction->GetLocations()->InAt(0);
8406
8407 __ Lw(ZERO, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00008408 RecordPcInfo(instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008409}
8410
Calin Juravle2ae48182016-03-16 14:05:09 +00008411void CodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
Vladimir Marko174b2e22017-10-12 13:34:49 +01008412 SlowPathCodeMIPS* slow_path = new (GetScopedAllocator()) NullCheckSlowPathMIPS(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00008413 AddSlowPath(slow_path);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008414
8415 Location obj = instruction->GetLocations()->InAt(0);
8416
8417 __ Beqz(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
8418}
8419
8420void InstructionCodeGeneratorMIPS::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00008421 codegen_->GenerateNullCheck(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008422}
8423
8424void LocationsBuilderMIPS::VisitOr(HOr* instruction) {
8425 HandleBinaryOp(instruction);
8426}
8427
8428void InstructionCodeGeneratorMIPS::VisitOr(HOr* instruction) {
8429 HandleBinaryOp(instruction);
8430}
8431
8432void LocationsBuilderMIPS::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
8433 LOG(FATAL) << "Unreachable";
8434}
8435
8436void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) {
Vladimir Markobea75ff2017-10-11 20:39:54 +01008437 if (instruction->GetNext()->IsSuspendCheck() &&
8438 instruction->GetBlock()->GetLoopInformation() != nullptr) {
8439 HSuspendCheck* suspend_check = instruction->GetNext()->AsSuspendCheck();
8440 // The back edge will generate the suspend check.
8441 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(suspend_check, instruction);
8442 }
8443
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008444 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
8445}
8446
8447void LocationsBuilderMIPS::VisitParameterValue(HParameterValue* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008448 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008449 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
8450 if (location.IsStackSlot()) {
8451 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
8452 } else if (location.IsDoubleStackSlot()) {
8453 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
8454 }
8455 locations->SetOut(location);
8456}
8457
8458void InstructionCodeGeneratorMIPS::VisitParameterValue(HParameterValue* instruction
8459 ATTRIBUTE_UNUSED) {
8460 // Nothing to do, the parameter is already at its location.
8461}
8462
8463void LocationsBuilderMIPS::VisitCurrentMethod(HCurrentMethod* instruction) {
8464 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01008465 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008466 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
8467}
8468
8469void InstructionCodeGeneratorMIPS::VisitCurrentMethod(HCurrentMethod* instruction
8470 ATTRIBUTE_UNUSED) {
8471 // Nothing to do, the method is already at its location.
8472}
8473
8474void LocationsBuilderMIPS::VisitPhi(HPhi* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008475 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(instruction);
Vladimir Marko372f10e2016-05-17 16:30:10 +01008476 for (size_t i = 0, e = locations->GetInputCount(); i < e; ++i) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008477 locations->SetInAt(i, Location::Any());
8478 }
8479 locations->SetOut(Location::Any());
8480}
8481
8482void InstructionCodeGeneratorMIPS::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
8483 LOG(FATAL) << "Unreachable";
8484}
8485
8486void LocationsBuilderMIPS::VisitRem(HRem* rem) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008487 DataType::Type type = rem->GetResultType();
8488 LocationSummary::CallKind call_kind = (type == DataType::Type::kInt32)
8489 ? LocationSummary::kNoCall
8490 : LocationSummary::kCallOnMainOnly;
Vladimir Markoca6fff82017-10-03 14:49:14 +01008491 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(rem, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008492
8493 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008494 case DataType::Type::kInt32:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008495 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08008496 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008497 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8498 break;
8499
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008500 case DataType::Type::kInt64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008501 InvokeRuntimeCallingConvention calling_convention;
8502 locations->SetInAt(0, Location::RegisterPairLocation(
8503 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
8504 locations->SetInAt(1, Location::RegisterPairLocation(
8505 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
8506 locations->SetOut(calling_convention.GetReturnLocation(type));
8507 break;
8508 }
8509
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008510 case DataType::Type::kFloat32:
8511 case DataType::Type::kFloat64: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008512 InvokeRuntimeCallingConvention calling_convention;
8513 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
8514 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
8515 locations->SetOut(calling_convention.GetReturnLocation(type));
8516 break;
8517 }
8518
8519 default:
8520 LOG(FATAL) << "Unexpected rem type " << type;
8521 }
8522}
8523
8524void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008525 DataType::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008526
8527 switch (type) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008528 case DataType::Type::kInt32:
Alexey Frunze7e99e052015-11-24 19:28:01 -08008529 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008530 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008531 case DataType::Type::kInt64: {
Serban Constantinescufca16662016-07-14 09:21:59 +01008532 codegen_->InvokeRuntime(kQuickLmod, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008533 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
8534 break;
8535 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008536 case DataType::Type::kFloat32: {
Serban Constantinescufca16662016-07-14 09:21:59 +01008537 codegen_->InvokeRuntime(kQuickFmodf, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00008538 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008539 break;
8540 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008541 case DataType::Type::kFloat64: {
Serban Constantinescufca16662016-07-14 09:21:59 +01008542 codegen_->InvokeRuntime(kQuickFmod, instruction, instruction->GetDexPc());
Roland Levillain888d0672015-11-23 18:53:50 +00008543 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008544 break;
8545 }
8546 default:
8547 LOG(FATAL) << "Unexpected rem type " << type;
8548 }
8549}
8550
Igor Murashkind01745e2017-04-05 16:40:31 -07008551void LocationsBuilderMIPS::VisitConstructorFence(HConstructorFence* constructor_fence) {
8552 constructor_fence->SetLocations(nullptr);
8553}
8554
8555void InstructionCodeGeneratorMIPS::VisitConstructorFence(
8556 HConstructorFence* constructor_fence ATTRIBUTE_UNUSED) {
8557 GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
8558}
8559
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008560void LocationsBuilderMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
8561 memory_barrier->SetLocations(nullptr);
8562}
8563
8564void InstructionCodeGeneratorMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
8565 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
8566}
8567
8568void LocationsBuilderMIPS::VisitReturn(HReturn* ret) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008569 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(ret);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008570 DataType::Type return_type = ret->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008571 locations->SetInAt(0, MipsReturnLocation(return_type));
8572}
8573
8574void InstructionCodeGeneratorMIPS::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
8575 codegen_->GenerateFrameExit();
8576}
8577
8578void LocationsBuilderMIPS::VisitReturnVoid(HReturnVoid* ret) {
8579 ret->SetLocations(nullptr);
8580}
8581
8582void InstructionCodeGeneratorMIPS::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
8583 codegen_->GenerateFrameExit();
8584}
8585
Alexey Frunze92d90602015-12-18 18:16:36 -08008586void LocationsBuilderMIPS::VisitRor(HRor* ror) {
8587 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00008588}
8589
Alexey Frunze92d90602015-12-18 18:16:36 -08008590void InstructionCodeGeneratorMIPS::VisitRor(HRor* ror) {
8591 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00008592}
8593
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008594void LocationsBuilderMIPS::VisitShl(HShl* shl) {
8595 HandleShift(shl);
8596}
8597
8598void InstructionCodeGeneratorMIPS::VisitShl(HShl* shl) {
8599 HandleShift(shl);
8600}
8601
8602void LocationsBuilderMIPS::VisitShr(HShr* shr) {
8603 HandleShift(shr);
8604}
8605
8606void InstructionCodeGeneratorMIPS::VisitShr(HShr* shr) {
8607 HandleShift(shr);
8608}
8609
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008610void LocationsBuilderMIPS::VisitSub(HSub* instruction) {
8611 HandleBinaryOp(instruction);
8612}
8613
8614void InstructionCodeGeneratorMIPS::VisitSub(HSub* instruction) {
8615 HandleBinaryOp(instruction);
8616}
8617
8618void LocationsBuilderMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
8619 HandleFieldGet(instruction, instruction->GetFieldInfo());
8620}
8621
8622void InstructionCodeGeneratorMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
8623 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
8624}
8625
8626void LocationsBuilderMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
8627 HandleFieldSet(instruction, instruction->GetFieldInfo());
8628}
8629
8630void InstructionCodeGeneratorMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Goran Jakovljevice114da22016-12-26 14:21:43 +01008631 HandleFieldSet(instruction,
8632 instruction->GetFieldInfo(),
8633 instruction->GetDexPc(),
8634 instruction->GetValueCanBeNull());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008635}
8636
8637void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldGet(
8638 HUnresolvedInstanceFieldGet* instruction) {
8639 FieldAccessCallingConventionMIPS calling_convention;
8640 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
8641 instruction->GetFieldType(),
8642 calling_convention);
8643}
8644
8645void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldGet(
8646 HUnresolvedInstanceFieldGet* instruction) {
8647 FieldAccessCallingConventionMIPS calling_convention;
8648 codegen_->GenerateUnresolvedFieldAccess(instruction,
8649 instruction->GetFieldType(),
8650 instruction->GetFieldIndex(),
8651 instruction->GetDexPc(),
8652 calling_convention);
8653}
8654
8655void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldSet(
8656 HUnresolvedInstanceFieldSet* instruction) {
8657 FieldAccessCallingConventionMIPS calling_convention;
8658 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
8659 instruction->GetFieldType(),
8660 calling_convention);
8661}
8662
8663void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldSet(
8664 HUnresolvedInstanceFieldSet* instruction) {
8665 FieldAccessCallingConventionMIPS calling_convention;
8666 codegen_->GenerateUnresolvedFieldAccess(instruction,
8667 instruction->GetFieldType(),
8668 instruction->GetFieldIndex(),
8669 instruction->GetDexPc(),
8670 calling_convention);
8671}
8672
8673void LocationsBuilderMIPS::VisitUnresolvedStaticFieldGet(
8674 HUnresolvedStaticFieldGet* instruction) {
8675 FieldAccessCallingConventionMIPS calling_convention;
8676 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
8677 instruction->GetFieldType(),
8678 calling_convention);
8679}
8680
8681void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldGet(
8682 HUnresolvedStaticFieldGet* instruction) {
8683 FieldAccessCallingConventionMIPS calling_convention;
8684 codegen_->GenerateUnresolvedFieldAccess(instruction,
8685 instruction->GetFieldType(),
8686 instruction->GetFieldIndex(),
8687 instruction->GetDexPc(),
8688 calling_convention);
8689}
8690
8691void LocationsBuilderMIPS::VisitUnresolvedStaticFieldSet(
8692 HUnresolvedStaticFieldSet* instruction) {
8693 FieldAccessCallingConventionMIPS calling_convention;
8694 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
8695 instruction->GetFieldType(),
8696 calling_convention);
8697}
8698
8699void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldSet(
8700 HUnresolvedStaticFieldSet* instruction) {
8701 FieldAccessCallingConventionMIPS calling_convention;
8702 codegen_->GenerateUnresolvedFieldAccess(instruction,
8703 instruction->GetFieldType(),
8704 instruction->GetFieldIndex(),
8705 instruction->GetDexPc(),
8706 calling_convention);
8707}
8708
8709void LocationsBuilderMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008710 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8711 instruction, LocationSummary::kCallOnSlowPath);
Lena Djokicca8c2952017-05-29 11:31:46 +02008712 // In suspend check slow path, usually there are no caller-save registers at all.
8713 // If SIMD instructions are present, however, we force spilling all live SIMD
8714 // registers in full width (since the runtime only saves/restores lower part).
8715 locations->SetCustomSlowPathCallerSaves(
8716 GetGraph()->HasSIMD() ? RegisterSet::AllFpu() : RegisterSet::Empty());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008717}
8718
8719void InstructionCodeGeneratorMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
8720 HBasicBlock* block = instruction->GetBlock();
8721 if (block->GetLoopInformation() != nullptr) {
8722 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
8723 // The back edge will generate the suspend check.
8724 return;
8725 }
8726 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
8727 // The goto will generate the suspend check.
8728 return;
8729 }
8730 GenerateSuspendCheck(instruction, nullptr);
8731}
8732
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008733void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
Vladimir Markoca6fff82017-10-03 14:49:14 +01008734 LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(
8735 instruction, LocationSummary::kCallOnMainOnly);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008736 InvokeRuntimeCallingConvention calling_convention;
8737 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
8738}
8739
8740void InstructionCodeGeneratorMIPS::VisitThrow(HThrow* instruction) {
Serban Constantinescufca16662016-07-14 09:21:59 +01008741 codegen_->InvokeRuntime(kQuickDeliverException, instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008742 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
8743}
8744
8745void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008746 DataType::Type input_type = conversion->GetInputType();
8747 DataType::Type result_type = conversion->GetResultType();
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01008748 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
8749 << input_type << " -> " << result_type;
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008750 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008751
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008752 if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
8753 (result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008754 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
8755 }
8756
8757 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008758 if (!isR6 &&
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008759 ((DataType::IsFloatingPointType(result_type) && input_type == DataType::Type::kInt64) ||
8760 (result_type == DataType::Type::kInt64 && DataType::IsFloatingPointType(input_type)))) {
Serban Constantinescu54ff4822016-07-07 18:03:19 +01008761 call_kind = LocationSummary::kCallOnMainOnly;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008762 }
8763
Vladimir Markoca6fff82017-10-03 14:49:14 +01008764 LocationSummary* locations =
8765 new (GetGraph()->GetAllocator()) LocationSummary(conversion, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008766
8767 if (call_kind == LocationSummary::kNoCall) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008768 if (DataType::IsFloatingPointType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008769 locations->SetInAt(0, Location::RequiresFpuRegister());
8770 } else {
8771 locations->SetInAt(0, Location::RequiresRegister());
8772 }
8773
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008774 if (DataType::IsFloatingPointType(result_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008775 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
8776 } else {
8777 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
8778 }
8779 } else {
8780 InvokeRuntimeCallingConvention calling_convention;
8781
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008782 if (DataType::IsFloatingPointType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008783 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
8784 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008785 DCHECK_EQ(input_type, DataType::Type::kInt64);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008786 locations->SetInAt(0, Location::RegisterPairLocation(
8787 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
8788 }
8789
8790 locations->SetOut(calling_convention.GetReturnLocation(result_type));
8791 }
8792}
8793
8794void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversion) {
8795 LocationSummary* locations = conversion->GetLocations();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008796 DataType::Type result_type = conversion->GetResultType();
8797 DataType::Type input_type = conversion->GetInputType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008798 bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008799 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008800
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01008801 DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
8802 << input_type << " -> " << result_type;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008803
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008804 if (result_type == DataType::Type::kInt64 && DataType::IsIntegralType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008805 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8806 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
8807 Register src = locations->InAt(0).AsRegister<Register>();
8808
Alexey Frunzea871ef12016-06-27 15:20:11 -07008809 if (dst_low != src) {
8810 __ Move(dst_low, src);
8811 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008812 __ Sra(dst_high, src, 31);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008813 } else if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008814 Register dst = locations->Out().AsRegister<Register>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008815 Register src = (input_type == DataType::Type::kInt64)
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008816 ? locations->InAt(0).AsRegisterPairLow<Register>()
8817 : locations->InAt(0).AsRegister<Register>();
8818
8819 switch (result_type) {
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01008820 case DataType::Type::kUint8:
8821 __ Andi(dst, src, 0xFF);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008822 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008823 case DataType::Type::kInt8:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008824 if (has_sign_extension) {
8825 __ Seb(dst, src);
8826 } else {
8827 __ Sll(dst, src, 24);
8828 __ Sra(dst, dst, 24);
8829 }
8830 break;
Vladimir Markod5d2f2c2017-09-26 12:37:26 +01008831 case DataType::Type::kUint16:
8832 __ Andi(dst, src, 0xFFFF);
8833 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008834 case DataType::Type::kInt16:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008835 if (has_sign_extension) {
8836 __ Seh(dst, src);
8837 } else {
8838 __ Sll(dst, src, 16);
8839 __ Sra(dst, dst, 16);
8840 }
8841 break;
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008842 case DataType::Type::kInt32:
Alexey Frunzea871ef12016-06-27 15:20:11 -07008843 if (dst != src) {
8844 __ Move(dst, src);
8845 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008846 break;
8847
8848 default:
8849 LOG(FATAL) << "Unexpected type conversion from " << input_type
8850 << " to " << result_type;
8851 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008852 } else if (DataType::IsFloatingPointType(result_type) && DataType::IsIntegralType(input_type)) {
8853 if (input_type == DataType::Type::kInt64) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008854 if (isR6) {
8855 // cvt.s.l/cvt.d.l requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
8856 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
8857 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
8858 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
8859 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8860 __ Mtc1(src_low, FTMP);
8861 __ Mthc1(src_high, FTMP);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008862 if (result_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008863 __ Cvtsl(dst, FTMP);
8864 } else {
8865 __ Cvtdl(dst, FTMP);
8866 }
8867 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008868 QuickEntrypointEnum entrypoint =
8869 (result_type == DataType::Type::kFloat32) ? kQuickL2f : kQuickL2d;
Serban Constantinescufca16662016-07-14 09:21:59 +01008870 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008871 if (result_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008872 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
8873 } else {
8874 CheckEntrypointTypes<kQuickL2d, double, int64_t>();
8875 }
8876 }
8877 } else {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008878 Register src = locations->InAt(0).AsRegister<Register>();
8879 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8880 __ Mtc1(src, FTMP);
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008881 if (result_type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008882 __ Cvtsw(dst, FTMP);
8883 } else {
8884 __ Cvtdw(dst, FTMP);
8885 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008886 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008887 } else if (DataType::IsIntegralType(result_type) && DataType::IsFloatingPointType(input_type)) {
8888 CHECK(result_type == DataType::Type::kInt32 || result_type == DataType::Type::kInt64);
Lena Djokicf4e23a82017-05-09 15:43:45 +02008889
8890 // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
8891 // value of the output type if the input is outside of the range after the truncation or
8892 // produces 0 when the input is a NaN. IOW, the three special cases produce three distinct
8893 // results. This matches the desired float/double-to-int/long conversion exactly.
8894 //
8895 // When NAN2008=0 (R2 and before), the truncate instruction produces the maximum positive
8896 // value when the input is either a NaN or is outside of the range of the output type
8897 // after the truncation. IOW, the three special cases (NaN, too small, too big) produce
8898 // the same result.
8899 //
8900 // The code takes care of the different behaviors by first comparing the input to the
8901 // minimum output value (-2**-63 for truncating to long, -2**-31 for truncating to int).
8902 // If the input is greater than or equal to the minimum, it procedes to the truncate
8903 // instruction, which will handle such an input the same way irrespective of NAN2008.
8904 // Otherwise the input is compared to itself to determine whether it is a NaN or not
8905 // in order to return either zero or the minimum value.
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008906 if (result_type == DataType::Type::kInt64) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008907 if (isR6) {
8908 // trunc.l.s/trunc.l.d requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
8909 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
8910 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
8911 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
8912 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008913
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008914 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008915 __ TruncLS(FTMP, src);
8916 } else {
8917 __ TruncLD(FTMP, src);
8918 }
8919 __ Mfc1(dst_low, FTMP);
8920 __ Mfhc1(dst_high, FTMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008921 } else {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008922 QuickEntrypointEnum entrypoint =
8923 (input_type == DataType::Type::kFloat32) ? kQuickF2l : kQuickD2l;
Serban Constantinescufca16662016-07-14 09:21:59 +01008924 codegen_->InvokeRuntime(entrypoint, conversion, conversion->GetDexPc());
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008925 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008926 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
8927 } else {
8928 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
8929 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008930 }
8931 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008932 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
8933 Register dst = locations->Out().AsRegister<Register>();
8934 MipsLabel truncate;
8935 MipsLabel done;
8936
Lena Djokicf4e23a82017-05-09 15:43:45 +02008937 if (!isR6) {
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008938 if (input_type == DataType::Type::kFloat32) {
Lena Djokicf4e23a82017-05-09 15:43:45 +02008939 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
8940 __ LoadConst32(TMP, min_val);
8941 __ Mtc1(TMP, FTMP);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008942 } else {
Lena Djokicf4e23a82017-05-09 15:43:45 +02008943 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int32_t>::min());
8944 __ LoadConst32(TMP, High32Bits(min_val));
8945 __ Mtc1(ZERO, FTMP);
8946 __ MoveToFpuHigh(TMP, FTMP);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008947 }
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008948
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008949 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008950 __ ColeS(0, FTMP, src);
8951 } else {
8952 __ ColeD(0, FTMP, src);
8953 }
8954 __ Bc1t(0, &truncate);
8955
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008956 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008957 __ CeqS(0, src, src);
8958 } else {
8959 __ CeqD(0, src, src);
8960 }
8961 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
8962 __ Movf(dst, ZERO, 0);
Lena Djokicf4e23a82017-05-09 15:43:45 +02008963
8964 __ B(&done);
8965
8966 __ Bind(&truncate);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008967 }
8968
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008969 if (input_type == DataType::Type::kFloat32) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08008970 __ TruncWS(FTMP, src);
8971 } else {
8972 __ TruncWD(FTMP, src);
8973 }
8974 __ Mfc1(dst, FTMP);
8975
Lena Djokicf4e23a82017-05-09 15:43:45 +02008976 if (!isR6) {
8977 __ Bind(&done);
8978 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008979 }
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008980 } else if (DataType::IsFloatingPointType(result_type) &&
8981 DataType::IsFloatingPointType(input_type)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008982 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
8983 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
Vladimir Marko0ebe0d82017-09-21 22:50:39 +01008984 if (result_type == DataType::Type::kFloat32) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02008985 __ Cvtsd(dst, src);
8986 } else {
8987 __ Cvtds(dst, src);
8988 }
8989 } else {
8990 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
8991 << " to " << result_type;
8992 }
8993}
8994
8995void LocationsBuilderMIPS::VisitUShr(HUShr* ushr) {
8996 HandleShift(ushr);
8997}
8998
8999void InstructionCodeGeneratorMIPS::VisitUShr(HUShr* ushr) {
9000 HandleShift(ushr);
9001}
9002
9003void LocationsBuilderMIPS::VisitXor(HXor* instruction) {
9004 HandleBinaryOp(instruction);
9005}
9006
9007void InstructionCodeGeneratorMIPS::VisitXor(HXor* instruction) {
9008 HandleBinaryOp(instruction);
9009}
9010
9011void LocationsBuilderMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
9012 // Nothing to do, this should be removed during prepare for register allocator.
9013 LOG(FATAL) << "Unreachable";
9014}
9015
9016void InstructionCodeGeneratorMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
9017 // Nothing to do, this should be removed during prepare for register allocator.
9018 LOG(FATAL) << "Unreachable";
9019}
9020
9021void LocationsBuilderMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009022 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009023}
9024
9025void InstructionCodeGeneratorMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009026 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009027}
9028
9029void LocationsBuilderMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009030 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009031}
9032
9033void InstructionCodeGeneratorMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009034 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009035}
9036
9037void LocationsBuilderMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009038 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009039}
9040
9041void InstructionCodeGeneratorMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009042 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009043}
9044
9045void LocationsBuilderMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009046 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009047}
9048
9049void InstructionCodeGeneratorMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009050 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009051}
9052
9053void LocationsBuilderMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009054 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009055}
9056
9057void InstructionCodeGeneratorMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009058 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009059}
9060
9061void LocationsBuilderMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009062 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009063}
9064
9065void InstructionCodeGeneratorMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009066 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009067}
9068
9069void LocationsBuilderMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009070 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009071}
9072
9073void InstructionCodeGeneratorMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009074 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009075}
9076
9077void LocationsBuilderMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009078 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009079}
9080
9081void InstructionCodeGeneratorMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009082 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009083}
9084
9085void LocationsBuilderMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009086 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009087}
9088
9089void InstructionCodeGeneratorMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009090 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009091}
9092
9093void LocationsBuilderMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009094 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009095}
9096
9097void InstructionCodeGeneratorMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00009098 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009099}
9100
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009101void LocationsBuilderMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
9102 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01009103 new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009104 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07009105 if (!codegen_->GetInstructionSetFeatures().IsR6()) {
9106 uint32_t num_entries = switch_instr->GetNumEntries();
9107 if (num_entries > InstructionCodeGeneratorMIPS::kPackedSwitchJumpTableThreshold) {
9108 // When there's no HMipsComputeBaseMethodAddress input, R2 uses the NAL
9109 // instruction to simulate PC-relative addressing when accessing the jump table.
9110 // NAL clobbers RA. Make sure RA is preserved.
9111 codegen_->ClobberRA();
9112 }
9113 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009114}
9115
Alexey Frunze96b66822016-09-10 02:32:44 -07009116void InstructionCodeGeneratorMIPS::GenPackedSwitchWithCompares(Register value_reg,
9117 int32_t lower_bound,
9118 uint32_t num_entries,
9119 HBasicBlock* switch_block,
9120 HBasicBlock* default_block) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009121 // Create a set of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009122 Register temp_reg = TMP;
9123 __ Addiu32(temp_reg, value_reg, -lower_bound);
9124 // Jump to default if index is negative
9125 // Note: We don't check the case that index is positive while value < lower_bound, because in
9126 // this case, index >= num_entries must be true. So that we can save one branch instruction.
9127 __ Bltz(temp_reg, codegen_->GetLabelOf(default_block));
9128
Alexey Frunze96b66822016-09-10 02:32:44 -07009129 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009130 // Jump to successors[0] if value == lower_bound.
9131 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[0]));
9132 int32_t last_index = 0;
9133 for (; num_entries - last_index > 2; last_index += 2) {
9134 __ Addiu(temp_reg, temp_reg, -2);
9135 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
9136 __ Bltz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
9137 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
9138 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 2]));
9139 }
9140 if (num_entries - last_index == 2) {
9141 // The last missing case_value.
9142 __ Addiu(temp_reg, temp_reg, -1);
9143 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009144 }
9145
Vladimir Markof3e0ee22015-12-17 15:23:13 +00009146 // And the default for any other value.
Alexey Frunze96b66822016-09-10 02:32:44 -07009147 if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009148 __ B(codegen_->GetLabelOf(default_block));
9149 }
9150}
9151
Alexey Frunze96b66822016-09-10 02:32:44 -07009152void InstructionCodeGeneratorMIPS::GenTableBasedPackedSwitch(Register value_reg,
9153 Register constant_area,
9154 int32_t lower_bound,
9155 uint32_t num_entries,
9156 HBasicBlock* switch_block,
9157 HBasicBlock* default_block) {
9158 // Create a jump table.
9159 std::vector<MipsLabel*> labels(num_entries);
9160 const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
9161 for (uint32_t i = 0; i < num_entries; i++) {
9162 labels[i] = codegen_->GetLabelOf(successors[i]);
9163 }
9164 JumpTable* table = __ CreateJumpTable(std::move(labels));
9165
9166 // Is the value in range?
9167 __ Addiu32(TMP, value_reg, -lower_bound);
9168 if (IsInt<16>(static_cast<int32_t>(num_entries))) {
9169 __ Sltiu(AT, TMP, num_entries);
9170 __ Beqz(AT, codegen_->GetLabelOf(default_block));
9171 } else {
9172 __ LoadConst32(AT, num_entries);
9173 __ Bgeu(TMP, AT, codegen_->GetLabelOf(default_block));
9174 }
9175
9176 // We are in the range of the table.
9177 // Load the target address from the jump table, indexing by the value.
9178 __ LoadLabelAddress(AT, constant_area, table->GetLabel());
Chris Larsencd0295d2017-03-31 15:26:54 -07009179 __ ShiftAndAdd(TMP, TMP, AT, 2, TMP);
Alexey Frunze96b66822016-09-10 02:32:44 -07009180 __ Lw(TMP, TMP, 0);
9181 // Compute the absolute target address by adding the table start address
9182 // (the table contains offsets to targets relative to its start).
9183 __ Addu(TMP, TMP, AT);
9184 // And jump.
9185 __ Jr(TMP);
9186 __ NopIfNoReordering();
9187}
9188
9189void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
9190 int32_t lower_bound = switch_instr->GetStartValue();
9191 uint32_t num_entries = switch_instr->GetNumEntries();
9192 LocationSummary* locations = switch_instr->GetLocations();
9193 Register value_reg = locations->InAt(0).AsRegister<Register>();
9194 HBasicBlock* switch_block = switch_instr->GetBlock();
9195 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
9196
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07009197 if (num_entries > kPackedSwitchJumpTableThreshold) {
Alexey Frunze96b66822016-09-10 02:32:44 -07009198 // R6 uses PC-relative addressing to access the jump table.
Alexey Frunze3b8c82f2017-10-10 23:01:34 -07009199 //
9200 // R2, OTOH, uses an HMipsComputeBaseMethodAddress input (when available)
9201 // to access the jump table and it is implemented by changing HPackedSwitch to
9202 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress (see
9203 // VisitMipsPackedSwitch()).
9204 //
9205 // When there's no HMipsComputeBaseMethodAddress input (e.g. in presence of
9206 // irreducible loops), R2 uses the NAL instruction to simulate PC-relative
9207 // addressing.
Alexey Frunze96b66822016-09-10 02:32:44 -07009208 GenTableBasedPackedSwitch(value_reg,
9209 ZERO,
9210 lower_bound,
9211 num_entries,
9212 switch_block,
9213 default_block);
9214 } else {
9215 GenPackedSwitchWithCompares(value_reg,
9216 lower_bound,
9217 num_entries,
9218 switch_block,
9219 default_block);
9220 }
9221}
9222
9223void LocationsBuilderMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
9224 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01009225 new (GetGraph()->GetAllocator()) LocationSummary(switch_instr, LocationSummary::kNoCall);
Alexey Frunze96b66822016-09-10 02:32:44 -07009226 locations->SetInAt(0, Location::RequiresRegister());
9227 // Constant area pointer (HMipsComputeBaseMethodAddress).
9228 locations->SetInAt(1, Location::RequiresRegister());
9229}
9230
9231void InstructionCodeGeneratorMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
9232 int32_t lower_bound = switch_instr->GetStartValue();
9233 uint32_t num_entries = switch_instr->GetNumEntries();
9234 LocationSummary* locations = switch_instr->GetLocations();
9235 Register value_reg = locations->InAt(0).AsRegister<Register>();
9236 Register constant_area = locations->InAt(1).AsRegister<Register>();
9237 HBasicBlock* switch_block = switch_instr->GetBlock();
9238 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
9239
9240 // This is an R2-only path. HPackedSwitch has been changed to
9241 // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress
9242 // required to address the jump table relative to PC.
9243 GenTableBasedPackedSwitch(value_reg,
9244 constant_area,
9245 lower_bound,
9246 num_entries,
9247 switch_block,
9248 default_block);
9249}
9250
Alexey Frunzee3fb2452016-05-10 16:08:05 -07009251void LocationsBuilderMIPS::VisitMipsComputeBaseMethodAddress(
9252 HMipsComputeBaseMethodAddress* insn) {
9253 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01009254 new (GetGraph()->GetAllocator()) LocationSummary(insn, LocationSummary::kNoCall);
Alexey Frunzee3fb2452016-05-10 16:08:05 -07009255 locations->SetOut(Location::RequiresRegister());
9256}
9257
9258void InstructionCodeGeneratorMIPS::VisitMipsComputeBaseMethodAddress(
9259 HMipsComputeBaseMethodAddress* insn) {
9260 LocationSummary* locations = insn->GetLocations();
9261 Register reg = locations->Out().AsRegister<Register>();
9262
9263 CHECK(!codegen_->GetInstructionSetFeatures().IsR6());
9264
9265 // Generate a dummy PC-relative call to obtain PC.
9266 __ Nal();
9267 // Grab the return address off RA.
9268 __ Move(reg, RA);
9269
9270 // Remember this offset (the obtained PC value) for later use with constant area.
9271 __ BindPcRelBaseLabel();
9272}
9273
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009274void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
9275 // The trampoline uses the same calling convention as dex calling conventions,
9276 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
9277 // the method_idx.
9278 HandleInvoke(invoke);
9279}
9280
9281void InstructionCodeGeneratorMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
9282 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
9283}
9284
Roland Levillain2aba7cd2016-02-03 12:27:20 +00009285void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet* instruction) {
9286 LocationSummary* locations =
Vladimir Markoca6fff82017-10-03 14:49:14 +01009287 new (GetGraph()->GetAllocator()) LocationSummary(instruction, LocationSummary::kNoCall);
Roland Levillain2aba7cd2016-02-03 12:27:20 +00009288 locations->SetInAt(0, Location::RequiresRegister());
9289 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009290}
9291
Roland Levillain2aba7cd2016-02-03 12:27:20 +00009292void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
9293 LocationSummary* locations = instruction->GetLocations();
Vladimir Markoa1de9182016-02-25 11:37:38 +00009294 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009295 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
Roland Levillain2aba7cd2016-02-03 12:27:20 +00009296 instruction->GetIndex(), kMipsPointerSize).SizeValue();
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009297 __ LoadFromOffset(kLoadWord,
9298 locations->Out().AsRegister<Register>(),
9299 locations->InAt(0).AsRegister<Register>(),
9300 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +00009301 } else {
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009302 uint32_t method_offset = static_cast<uint32_t>(ImTable::OffsetOfElement(
Matthew Gharrity465ecc82016-07-19 21:32:52 +00009303 instruction->GetIndex(), kMipsPointerSize));
Artem Udovichenkoa62cb9b2016-06-30 09:18:25 +00009304 __ LoadFromOffset(kLoadWord,
9305 locations->Out().AsRegister<Register>(),
9306 locations->InAt(0).AsRegister<Register>(),
9307 mirror::Class::ImtPtrOffset(kMipsPointerSize).Uint32Value());
Nicolas Geoffrayff484b92016-07-13 14:13:48 +01009308 __ LoadFromOffset(kLoadWord,
9309 locations->Out().AsRegister<Register>(),
9310 locations->Out().AsRegister<Register>(),
9311 method_offset);
Roland Levillain2aba7cd2016-02-03 12:27:20 +00009312 }
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00009313}
9314
xueliang.zhonge0eb4832017-10-30 13:43:14 +00009315void LocationsBuilderMIPS::VisitIntermediateAddress(HIntermediateAddress* instruction
9316 ATTRIBUTE_UNUSED) {
9317 LOG(FATAL) << "Unreachable";
9318}
9319
9320void InstructionCodeGeneratorMIPS::VisitIntermediateAddress(HIntermediateAddress* instruction
9321 ATTRIBUTE_UNUSED) {
9322 LOG(FATAL) << "Unreachable";
9323}
9324
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02009325#undef __
9326#undef QUICK_ENTRY_POINT
9327
9328} // namespace mips
9329} // namespace art