blob: a29d8394db63a7de85848ff70f3364172727e0e7 [file] [log] [blame]
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_mips.h"
18
19#include "arch/mips/entrypoints_direct_mips.h"
20#include "arch/mips/instruction_set_features_mips.h"
21#include "art_method.h"
Chris Larsen701566a2015-10-27 15:29:13 -070022#include "code_generator_utils.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020023#include "entrypoints/quick/quick_entrypoints.h"
24#include "entrypoints/quick/quick_entrypoints_enum.h"
25#include "gc/accounting/card_table.h"
26#include "intrinsics.h"
Chris Larsen701566a2015-10-27 15:29:13 -070027#include "intrinsics_mips.h"
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020028#include "mirror/array-inl.h"
29#include "mirror/class-inl.h"
30#include "offsets.h"
31#include "thread.h"
32#include "utils/assembler.h"
33#include "utils/mips/assembler_mips.h"
34#include "utils/stack_checks.h"
35
36namespace art {
37namespace mips {
38
39static constexpr int kCurrentMethodStackOffset = 0;
40static constexpr Register kMethodRegisterArgument = A0;
41
Goran Jakovljevicf652cec2015-08-25 16:11:42 +020042Location MipsReturnLocation(Primitive::Type return_type) {
43 switch (return_type) {
44 case Primitive::kPrimBoolean:
45 case Primitive::kPrimByte:
46 case Primitive::kPrimChar:
47 case Primitive::kPrimShort:
48 case Primitive::kPrimInt:
49 case Primitive::kPrimNot:
50 return Location::RegisterLocation(V0);
51
52 case Primitive::kPrimLong:
53 return Location::RegisterPairLocation(V0, V1);
54
55 case Primitive::kPrimFloat:
56 case Primitive::kPrimDouble:
57 return Location::FpuRegisterLocation(F0);
58
59 case Primitive::kPrimVoid:
60 return Location();
61 }
62 UNREACHABLE();
63}
64
65Location InvokeDexCallingConventionVisitorMIPS::GetReturnLocation(Primitive::Type type) const {
66 return MipsReturnLocation(type);
67}
68
69Location InvokeDexCallingConventionVisitorMIPS::GetMethodLocation() const {
70 return Location::RegisterLocation(kMethodRegisterArgument);
71}
72
73Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(Primitive::Type type) {
74 Location next_location;
75
76 switch (type) {
77 case Primitive::kPrimBoolean:
78 case Primitive::kPrimByte:
79 case Primitive::kPrimChar:
80 case Primitive::kPrimShort:
81 case Primitive::kPrimInt:
82 case Primitive::kPrimNot: {
83 uint32_t gp_index = gp_index_++;
84 if (gp_index < calling_convention.GetNumberOfRegisters()) {
85 next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index));
86 } else {
87 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
88 next_location = Location::StackSlot(stack_offset);
89 }
90 break;
91 }
92
93 case Primitive::kPrimLong: {
94 uint32_t gp_index = gp_index_;
95 gp_index_ += 2;
96 if (gp_index + 1 < calling_convention.GetNumberOfRegisters()) {
97 if (calling_convention.GetRegisterAt(gp_index) == A1) {
98 gp_index_++; // Skip A1, and use A2_A3 instead.
99 gp_index++;
100 }
101 Register low_even = calling_convention.GetRegisterAt(gp_index);
102 Register high_odd = calling_convention.GetRegisterAt(gp_index + 1);
103 DCHECK_EQ(low_even + 1, high_odd);
104 next_location = Location::RegisterPairLocation(low_even, high_odd);
105 } else {
106 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
107 next_location = Location::DoubleStackSlot(stack_offset);
108 }
109 break;
110 }
111
112 // Note: both float and double types are stored in even FPU registers. On 32 bit FPU, double
113 // will take up the even/odd pair, while floats are stored in even regs only.
114 // On 64 bit FPU, both double and float are stored in even registers only.
115 case Primitive::kPrimFloat:
116 case Primitive::kPrimDouble: {
117 uint32_t float_index = float_index_++;
118 if (float_index < calling_convention.GetNumberOfFpuRegisters()) {
119 next_location = Location::FpuRegisterLocation(
120 calling_convention.GetFpuRegisterAt(float_index));
121 } else {
122 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_);
123 next_location = Primitive::Is64BitType(type) ? Location::DoubleStackSlot(stack_offset)
124 : Location::StackSlot(stack_offset);
125 }
126 break;
127 }
128
129 case Primitive::kPrimVoid:
130 LOG(FATAL) << "Unexpected parameter type " << type;
131 break;
132 }
133
134 // Space on the stack is reserved for all arguments.
135 stack_index_ += Primitive::Is64BitType(type) ? 2 : 1;
136
137 return next_location;
138}
139
140Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type type) {
141 return MipsReturnLocation(type);
142}
143
144#define __ down_cast<CodeGeneratorMIPS*>(codegen)->GetAssembler()->
145#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, x).Int32Value()
146
147class BoundsCheckSlowPathMIPS : public SlowPathCodeMIPS {
148 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000149 explicit BoundsCheckSlowPathMIPS(HBoundsCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200150
151 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
152 LocationSummary* locations = instruction_->GetLocations();
153 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
154 __ Bind(GetEntryLabel());
155 if (instruction_->CanThrowIntoCatchBlock()) {
156 // Live registers will be restored in the catch block if caught.
157 SaveLiveRegisters(codegen, instruction_->GetLocations());
158 }
159 // We're moving two locations to locations that could overlap, so we need a parallel
160 // move resolver.
161 InvokeRuntimeCallingConvention calling_convention;
162 codegen->EmitParallelMoves(locations->InAt(0),
163 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
164 Primitive::kPrimInt,
165 locations->InAt(1),
166 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
167 Primitive::kPrimInt);
168 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowArrayBounds),
169 instruction_,
170 instruction_->GetDexPc(),
171 this,
172 IsDirectEntrypoint(kQuickThrowArrayBounds));
173 CheckEntrypointTypes<kQuickThrowArrayBounds, void, int32_t, int32_t>();
174 }
175
176 bool IsFatal() const OVERRIDE { return true; }
177
178 const char* GetDescription() const OVERRIDE { return "BoundsCheckSlowPathMIPS"; }
179
180 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200181 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathMIPS);
182};
183
184class DivZeroCheckSlowPathMIPS : public SlowPathCodeMIPS {
185 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000186 explicit DivZeroCheckSlowPathMIPS(HDivZeroCheck* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200187
188 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
189 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
190 __ Bind(GetEntryLabel());
191 if (instruction_->CanThrowIntoCatchBlock()) {
192 // Live registers will be restored in the catch block if caught.
193 SaveLiveRegisters(codegen, instruction_->GetLocations());
194 }
195 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowDivZero),
196 instruction_,
197 instruction_->GetDexPc(),
198 this,
199 IsDirectEntrypoint(kQuickThrowDivZero));
200 CheckEntrypointTypes<kQuickThrowDivZero, void, void>();
201 }
202
203 bool IsFatal() const OVERRIDE { return true; }
204
205 const char* GetDescription() const OVERRIDE { return "DivZeroCheckSlowPathMIPS"; }
206
207 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200208 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathMIPS);
209};
210
211class LoadClassSlowPathMIPS : public SlowPathCodeMIPS {
212 public:
213 LoadClassSlowPathMIPS(HLoadClass* cls,
214 HInstruction* at,
215 uint32_t dex_pc,
216 bool do_clinit)
David Srbecky9cd6d372016-02-09 15:24:47 +0000217 : SlowPathCodeMIPS(at), cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200218 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
219 }
220
221 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
222 LocationSummary* locations = at_->GetLocations();
223 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
224
225 __ Bind(GetEntryLabel());
226 SaveLiveRegisters(codegen, locations);
227
228 InvokeRuntimeCallingConvention calling_convention;
229 __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
230
231 int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage)
232 : QUICK_ENTRY_POINT(pInitializeType);
233 bool direct = do_clinit_ ? IsDirectEntrypoint(kQuickInitializeStaticStorage)
234 : IsDirectEntrypoint(kQuickInitializeType);
235
236 mips_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this, direct);
237 if (do_clinit_) {
238 CheckEntrypointTypes<kQuickInitializeStaticStorage, void*, uint32_t>();
239 } else {
240 CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
241 }
242
243 // Move the class to the desired location.
244 Location out = locations->Out();
245 if (out.IsValid()) {
246 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
247 Primitive::Type type = at_->GetType();
248 mips_codegen->MoveLocation(out, calling_convention.GetReturnLocation(type), type);
249 }
250
251 RestoreLiveRegisters(codegen, locations);
252 __ B(GetExitLabel());
253 }
254
255 const char* GetDescription() const OVERRIDE { return "LoadClassSlowPathMIPS"; }
256
257 private:
258 // The class this slow path will load.
259 HLoadClass* const cls_;
260
261 // The instruction where this slow path is happening.
262 // (Might be the load class or an initialization check).
263 HInstruction* const at_;
264
265 // The dex PC of `at_`.
266 const uint32_t dex_pc_;
267
268 // Whether to initialize the class.
269 const bool do_clinit_;
270
271 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS);
272};
273
274class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
275 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000276 explicit LoadStringSlowPathMIPS(HLoadString* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200277
278 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
279 LocationSummary* locations = instruction_->GetLocations();
280 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
281 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
282
283 __ Bind(GetEntryLabel());
284 SaveLiveRegisters(codegen, locations);
285
286 InvokeRuntimeCallingConvention calling_convention;
David Srbecky9cd6d372016-02-09 15:24:47 +0000287 const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
288 __ LoadConst32(calling_convention.GetRegisterAt(0), string_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200289 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pResolveString),
290 instruction_,
291 instruction_->GetDexPc(),
292 this,
293 IsDirectEntrypoint(kQuickResolveString));
294 CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
295 Primitive::Type type = instruction_->GetType();
296 mips_codegen->MoveLocation(locations->Out(),
297 calling_convention.GetReturnLocation(type),
298 type);
299
300 RestoreLiveRegisters(codegen, locations);
301 __ B(GetExitLabel());
302 }
303
304 const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
305
306 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200307 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
308};
309
310class NullCheckSlowPathMIPS : public SlowPathCodeMIPS {
311 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000312 explicit NullCheckSlowPathMIPS(HNullCheck* instr) : SlowPathCodeMIPS(instr) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200313
314 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
315 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
316 __ Bind(GetEntryLabel());
317 if (instruction_->CanThrowIntoCatchBlock()) {
318 // Live registers will be restored in the catch block if caught.
319 SaveLiveRegisters(codegen, instruction_->GetLocations());
320 }
321 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pThrowNullPointer),
322 instruction_,
323 instruction_->GetDexPc(),
324 this,
325 IsDirectEntrypoint(kQuickThrowNullPointer));
326 CheckEntrypointTypes<kQuickThrowNullPointer, void, void>();
327 }
328
329 bool IsFatal() const OVERRIDE { return true; }
330
331 const char* GetDescription() const OVERRIDE { return "NullCheckSlowPathMIPS"; }
332
333 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200334 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathMIPS);
335};
336
337class SuspendCheckSlowPathMIPS : public SlowPathCodeMIPS {
338 public:
339 SuspendCheckSlowPathMIPS(HSuspendCheck* instruction, HBasicBlock* successor)
David Srbecky9cd6d372016-02-09 15:24:47 +0000340 : SlowPathCodeMIPS(instruction), successor_(successor) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200341
342 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
343 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
344 __ Bind(GetEntryLabel());
345 SaveLiveRegisters(codegen, instruction_->GetLocations());
346 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pTestSuspend),
347 instruction_,
348 instruction_->GetDexPc(),
349 this,
350 IsDirectEntrypoint(kQuickTestSuspend));
351 CheckEntrypointTypes<kQuickTestSuspend, void, void>();
352 RestoreLiveRegisters(codegen, instruction_->GetLocations());
353 if (successor_ == nullptr) {
354 __ B(GetReturnLabel());
355 } else {
356 __ B(mips_codegen->GetLabelOf(successor_));
357 }
358 }
359
360 MipsLabel* GetReturnLabel() {
361 DCHECK(successor_ == nullptr);
362 return &return_label_;
363 }
364
365 const char* GetDescription() const OVERRIDE { return "SuspendCheckSlowPathMIPS"; }
366
367 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200368 // If not null, the block to branch to after the suspend check.
369 HBasicBlock* const successor_;
370
371 // If `successor_` is null, the label to branch to after the suspend check.
372 MipsLabel return_label_;
373
374 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathMIPS);
375};
376
377class TypeCheckSlowPathMIPS : public SlowPathCodeMIPS {
378 public:
David Srbecky9cd6d372016-02-09 15:24:47 +0000379 explicit TypeCheckSlowPathMIPS(HInstruction* instruction) : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200380
381 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
382 LocationSummary* locations = instruction_->GetLocations();
383 Location object_class = instruction_->IsCheckCast() ? locations->GetTemp(0) : locations->Out();
384 uint32_t dex_pc = instruction_->GetDexPc();
385 DCHECK(instruction_->IsCheckCast()
386 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
387 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
388
389 __ Bind(GetEntryLabel());
390 SaveLiveRegisters(codegen, locations);
391
392 // We're moving two locations to locations that could overlap, so we need a parallel
393 // move resolver.
394 InvokeRuntimeCallingConvention calling_convention;
395 codegen->EmitParallelMoves(locations->InAt(1),
396 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
397 Primitive::kPrimNot,
398 object_class,
399 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
400 Primitive::kPrimNot);
401
402 if (instruction_->IsInstanceOf()) {
403 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
404 instruction_,
405 dex_pc,
406 this,
407 IsDirectEntrypoint(kQuickInstanceofNonTrivial));
Roland Levillain888d0672015-11-23 18:53:50 +0000408 CheckEntrypointTypes<
409 kQuickInstanceofNonTrivial, uint32_t, const mirror::Class*, const mirror::Class*>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200410 Primitive::Type ret_type = instruction_->GetType();
411 Location ret_loc = calling_convention.GetReturnLocation(ret_type);
412 mips_codegen->MoveLocation(locations->Out(), ret_loc, ret_type);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200413 } else {
414 DCHECK(instruction_->IsCheckCast());
415 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
416 instruction_,
417 dex_pc,
418 this,
419 IsDirectEntrypoint(kQuickCheckCast));
420 CheckEntrypointTypes<kQuickCheckCast, void, const mirror::Class*, const mirror::Class*>();
421 }
422
423 RestoreLiveRegisters(codegen, locations);
424 __ B(GetExitLabel());
425 }
426
427 const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathMIPS"; }
428
429 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200430 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathMIPS);
431};
432
433class DeoptimizationSlowPathMIPS : public SlowPathCodeMIPS {
434 public:
Aart Bik42249c32016-01-07 15:33:50 -0800435 explicit DeoptimizationSlowPathMIPS(HDeoptimize* instruction)
David Srbecky9cd6d372016-02-09 15:24:47 +0000436 : SlowPathCodeMIPS(instruction) {}
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200437
438 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Aart Bik42249c32016-01-07 15:33:50 -0800439 CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200440 __ Bind(GetEntryLabel());
441 SaveLiveRegisters(codegen, instruction_->GetLocations());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200442 mips_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize),
443 instruction_,
Aart Bik42249c32016-01-07 15:33:50 -0800444 instruction_->GetDexPc(),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200445 this,
446 IsDirectEntrypoint(kQuickDeoptimize));
Roland Levillain888d0672015-11-23 18:53:50 +0000447 CheckEntrypointTypes<kQuickDeoptimize, void, void>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200448 }
449
450 const char* GetDescription() const OVERRIDE { return "DeoptimizationSlowPathMIPS"; }
451
452 private:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200453 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathMIPS);
454};
455
456CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph,
457 const MipsInstructionSetFeatures& isa_features,
458 const CompilerOptions& compiler_options,
459 OptimizingCompilerStats* stats)
460 : CodeGenerator(graph,
461 kNumberOfCoreRegisters,
462 kNumberOfFRegisters,
463 kNumberOfRegisterPairs,
464 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
465 arraysize(kCoreCalleeSaves)),
466 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves),
467 arraysize(kFpuCalleeSaves)),
468 compiler_options,
469 stats),
470 block_labels_(nullptr),
471 location_builder_(graph, this),
472 instruction_visitor_(graph, this),
473 move_resolver_(graph->GetArena(), this),
474 assembler_(&isa_features),
475 isa_features_(isa_features) {
476 // Save RA (containing the return address) to mimic Quick.
477 AddAllocatedRegister(Location::RegisterLocation(RA));
478}
479
480#undef __
481#define __ down_cast<MipsAssembler*>(GetAssembler())->
482#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kMipsWordSize, x).Int32Value()
483
484void CodeGeneratorMIPS::Finalize(CodeAllocator* allocator) {
485 // Ensure that we fix up branches.
486 __ FinalizeCode();
487
488 // Adjust native pc offsets in stack maps.
489 for (size_t i = 0, num = stack_map_stream_.GetNumberOfStackMaps(); i != num; ++i) {
490 uint32_t old_position = stack_map_stream_.GetStackMap(i).native_pc_offset;
491 uint32_t new_position = __ GetAdjustedPosition(old_position);
492 DCHECK_GE(new_position, old_position);
493 stack_map_stream_.SetStackMapNativePcOffset(i, new_position);
494 }
495
496 // Adjust pc offsets for the disassembly information.
497 if (disasm_info_ != nullptr) {
498 GeneratedCodeInterval* frame_entry_interval = disasm_info_->GetFrameEntryInterval();
499 frame_entry_interval->start = __ GetAdjustedPosition(frame_entry_interval->start);
500 frame_entry_interval->end = __ GetAdjustedPosition(frame_entry_interval->end);
501 for (auto& it : *disasm_info_->GetInstructionIntervals()) {
502 it.second.start = __ GetAdjustedPosition(it.second.start);
503 it.second.end = __ GetAdjustedPosition(it.second.end);
504 }
505 for (auto& it : *disasm_info_->GetSlowPathIntervals()) {
506 it.code_interval.start = __ GetAdjustedPosition(it.code_interval.start);
507 it.code_interval.end = __ GetAdjustedPosition(it.code_interval.end);
508 }
509 }
510
511 CodeGenerator::Finalize(allocator);
512}
513
514MipsAssembler* ParallelMoveResolverMIPS::GetAssembler() const {
515 return codegen_->GetAssembler();
516}
517
518void ParallelMoveResolverMIPS::EmitMove(size_t index) {
519 DCHECK_LT(index, moves_.size());
520 MoveOperands* move = moves_[index];
521 codegen_->MoveLocation(move->GetDestination(), move->GetSource(), move->GetType());
522}
523
524void ParallelMoveResolverMIPS::EmitSwap(size_t index) {
525 DCHECK_LT(index, moves_.size());
526 MoveOperands* move = moves_[index];
527 Primitive::Type type = move->GetType();
528 Location loc1 = move->GetDestination();
529 Location loc2 = move->GetSource();
530
531 DCHECK(!loc1.IsConstant());
532 DCHECK(!loc2.IsConstant());
533
534 if (loc1.Equals(loc2)) {
535 return;
536 }
537
538 if (loc1.IsRegister() && loc2.IsRegister()) {
539 // Swap 2 GPRs.
540 Register r1 = loc1.AsRegister<Register>();
541 Register r2 = loc2.AsRegister<Register>();
542 __ Move(TMP, r2);
543 __ Move(r2, r1);
544 __ Move(r1, TMP);
545 } else if (loc1.IsFpuRegister() && loc2.IsFpuRegister()) {
546 FRegister f1 = loc1.AsFpuRegister<FRegister>();
547 FRegister f2 = loc2.AsFpuRegister<FRegister>();
548 if (type == Primitive::kPrimFloat) {
549 __ MovS(FTMP, f2);
550 __ MovS(f2, f1);
551 __ MovS(f1, FTMP);
552 } else {
553 DCHECK_EQ(type, Primitive::kPrimDouble);
554 __ MovD(FTMP, f2);
555 __ MovD(f2, f1);
556 __ MovD(f1, FTMP);
557 }
558 } else if ((loc1.IsRegister() && loc2.IsFpuRegister()) ||
559 (loc1.IsFpuRegister() && loc2.IsRegister())) {
560 // Swap FPR and GPR.
561 DCHECK_EQ(type, Primitive::kPrimFloat); // Can only swap a float.
562 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
563 : loc2.AsFpuRegister<FRegister>();
564 Register r2 = loc1.IsRegister() ? loc1.AsRegister<Register>()
565 : loc2.AsRegister<Register>();
566 __ Move(TMP, r2);
567 __ Mfc1(r2, f1);
568 __ Mtc1(TMP, f1);
569 } else if (loc1.IsRegisterPair() && loc2.IsRegisterPair()) {
570 // Swap 2 GPR register pairs.
571 Register r1 = loc1.AsRegisterPairLow<Register>();
572 Register r2 = loc2.AsRegisterPairLow<Register>();
573 __ Move(TMP, r2);
574 __ Move(r2, r1);
575 __ Move(r1, TMP);
576 r1 = loc1.AsRegisterPairHigh<Register>();
577 r2 = loc2.AsRegisterPairHigh<Register>();
578 __ Move(TMP, r2);
579 __ Move(r2, r1);
580 __ Move(r1, TMP);
581 } else if ((loc1.IsRegisterPair() && loc2.IsFpuRegister()) ||
582 (loc1.IsFpuRegister() && loc2.IsRegisterPair())) {
583 // Swap FPR and GPR register pair.
584 DCHECK_EQ(type, Primitive::kPrimDouble);
585 FRegister f1 = loc1.IsFpuRegister() ? loc1.AsFpuRegister<FRegister>()
586 : loc2.AsFpuRegister<FRegister>();
587 Register r2_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
588 : loc2.AsRegisterPairLow<Register>();
589 Register r2_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
590 : loc2.AsRegisterPairHigh<Register>();
591 // Use 2 temporary registers because we can't first swap the low 32 bits of an FPR and
592 // then swap the high 32 bits of the same FPR. mtc1 makes the high 32 bits of an FPR
593 // unpredictable and the following mfch1 will fail.
594 __ Mfc1(TMP, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800595 __ MoveFromFpuHigh(AT, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200596 __ Mtc1(r2_l, f1);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800597 __ MoveToFpuHigh(r2_h, f1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200598 __ Move(r2_l, TMP);
599 __ Move(r2_h, AT);
600 } else if (loc1.IsStackSlot() && loc2.IsStackSlot()) {
601 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ false);
602 } else if (loc1.IsDoubleStackSlot() && loc2.IsDoubleStackSlot()) {
603 Exchange(loc1.GetStackIndex(), loc2.GetStackIndex(), /* double_slot */ true);
David Brazdilcc0f3112016-01-28 17:14:52 +0000604 } else if ((loc1.IsRegister() && loc2.IsStackSlot()) ||
605 (loc1.IsStackSlot() && loc2.IsRegister())) {
606 Register reg = loc1.IsRegister() ? loc1.AsRegister<Register>()
607 : loc2.AsRegister<Register>();
608 intptr_t offset = loc1.IsStackSlot() ? loc1.GetStackIndex()
609 : loc2.GetStackIndex();
610 __ Move(TMP, reg);
611 __ LoadFromOffset(kLoadWord, reg, SP, offset);
612 __ StoreToOffset(kStoreWord, TMP, SP, offset);
613 } else if ((loc1.IsRegisterPair() && loc2.IsDoubleStackSlot()) ||
614 (loc1.IsDoubleStackSlot() && loc2.IsRegisterPair())) {
615 Register reg_l = loc1.IsRegisterPair() ? loc1.AsRegisterPairLow<Register>()
616 : loc2.AsRegisterPairLow<Register>();
617 Register reg_h = loc1.IsRegisterPair() ? loc1.AsRegisterPairHigh<Register>()
618 : loc2.AsRegisterPairHigh<Register>();
619 intptr_t offset_l = loc1.IsDoubleStackSlot() ? loc1.GetStackIndex()
620 : loc2.GetStackIndex();
621 intptr_t offset_h = loc1.IsDoubleStackSlot() ? loc1.GetHighStackIndex(kMipsWordSize)
622 : loc2.GetHighStackIndex(kMipsWordSize);
623 __ Move(TMP, reg_l);
David Brazdilcc0f3112016-01-28 17:14:52 +0000624 __ LoadFromOffset(kLoadWord, reg_l, SP, offset_l);
David Brazdilcc0f3112016-01-28 17:14:52 +0000625 __ StoreToOffset(kStoreWord, TMP, SP, offset_l);
David Brazdil04d3e872016-01-29 09:50:09 +0000626 __ Move(TMP, reg_h);
627 __ LoadFromOffset(kLoadWord, reg_h, SP, offset_h);
628 __ StoreToOffset(kStoreWord, TMP, SP, offset_h);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200629 } else {
630 LOG(FATAL) << "Swap between " << loc1 << " and " << loc2 << " is unsupported";
631 }
632}
633
634void ParallelMoveResolverMIPS::RestoreScratch(int reg) {
635 __ Pop(static_cast<Register>(reg));
636}
637
638void ParallelMoveResolverMIPS::SpillScratch(int reg) {
639 __ Push(static_cast<Register>(reg));
640}
641
642void ParallelMoveResolverMIPS::Exchange(int index1, int index2, bool double_slot) {
643 // Allocate a scratch register other than TMP, if available.
644 // Else, spill V0 (arbitrary choice) and use it as a scratch register (it will be
645 // automatically unspilled when the scratch scope object is destroyed).
646 ScratchRegisterScope ensure_scratch(this, TMP, V0, codegen_->GetNumberOfCoreRegisters());
647 // If V0 spills onto the stack, SP-relative offsets need to be adjusted.
648 int stack_offset = ensure_scratch.IsSpilled() ? kMipsWordSize : 0;
649 for (int i = 0; i <= (double_slot ? 1 : 0); i++, stack_offset += kMipsWordSize) {
650 __ LoadFromOffset(kLoadWord,
651 Register(ensure_scratch.GetRegister()),
652 SP,
653 index1 + stack_offset);
654 __ LoadFromOffset(kLoadWord,
655 TMP,
656 SP,
657 index2 + stack_offset);
658 __ StoreToOffset(kStoreWord,
659 Register(ensure_scratch.GetRegister()),
660 SP,
661 index2 + stack_offset);
662 __ StoreToOffset(kStoreWord, TMP, SP, index1 + stack_offset);
663 }
664}
665
666static dwarf::Reg DWARFReg(Register reg) {
667 return dwarf::Reg::MipsCore(static_cast<int>(reg));
668}
669
670// TODO: mapping of floating-point registers to DWARF.
671
672void CodeGeneratorMIPS::GenerateFrameEntry() {
673 __ Bind(&frame_entry_label_);
674
675 bool do_overflow_check = FrameNeedsStackCheck(GetFrameSize(), kMips) || !IsLeafMethod();
676
677 if (do_overflow_check) {
678 __ LoadFromOffset(kLoadWord,
679 ZERO,
680 SP,
681 -static_cast<int32_t>(GetStackOverflowReservedBytes(kMips)));
682 RecordPcInfo(nullptr, 0);
683 }
684
685 if (HasEmptyFrame()) {
686 return;
687 }
688
689 // Make sure the frame size isn't unreasonably large.
690 if (GetFrameSize() > GetStackOverflowReservedBytes(kMips)) {
691 LOG(FATAL) << "Stack frame larger than " << GetStackOverflowReservedBytes(kMips) << " bytes";
692 }
693
694 // Spill callee-saved registers.
695 // Note that their cumulative size is small and they can be indexed using
696 // 16-bit offsets.
697
698 // TODO: increment/decrement SP in one step instead of two or remove this comment.
699
700 uint32_t ofs = FrameEntrySpillSize();
701 bool unaligned_float = ofs & 0x7;
702 bool fpu_32bit = isa_features_.Is32BitFloatingPoint();
703 __ IncreaseFrameSize(ofs);
704
705 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
706 Register reg = kCoreCalleeSaves[i];
707 if (allocated_registers_.ContainsCoreRegister(reg)) {
708 ofs -= kMipsWordSize;
709 __ Sw(reg, SP, ofs);
710 __ cfi().RelOffset(DWARFReg(reg), ofs);
711 }
712 }
713
714 for (int i = arraysize(kFpuCalleeSaves) - 1; i >= 0; --i) {
715 FRegister reg = kFpuCalleeSaves[i];
716 if (allocated_registers_.ContainsFloatingPointRegister(reg)) {
717 ofs -= kMipsDoublewordSize;
718 // TODO: Change the frame to avoid unaligned accesses for fpu registers.
719 if (unaligned_float) {
720 if (fpu_32bit) {
721 __ Swc1(reg, SP, ofs);
722 __ Swc1(static_cast<FRegister>(reg + 1), SP, ofs + 4);
723 } else {
724 __ Mfhc1(TMP, reg);
725 __ Swc1(reg, SP, ofs);
726 __ Sw(TMP, SP, ofs + 4);
727 }
728 } else {
729 __ Sdc1(reg, SP, ofs);
730 }
731 // TODO: __ cfi().RelOffset(DWARFReg(reg), ofs);
732 }
733 }
734
735 // Allocate the rest of the frame and store the current method pointer
736 // at its end.
737
738 __ IncreaseFrameSize(GetFrameSize() - FrameEntrySpillSize());
739
740 static_assert(IsInt<16>(kCurrentMethodStackOffset),
741 "kCurrentMethodStackOffset must fit into int16_t");
742 __ Sw(kMethodRegisterArgument, SP, kCurrentMethodStackOffset);
743}
744
745void CodeGeneratorMIPS::GenerateFrameExit() {
746 __ cfi().RememberState();
747
748 if (!HasEmptyFrame()) {
749 // Deallocate the rest of the frame.
750
751 __ DecreaseFrameSize(GetFrameSize() - FrameEntrySpillSize());
752
753 // Restore callee-saved registers.
754 // Note that their cumulative size is small and they can be indexed using
755 // 16-bit offsets.
756
757 // TODO: increment/decrement SP in one step instead of two or remove this comment.
758
759 uint32_t ofs = 0;
760 bool unaligned_float = FrameEntrySpillSize() & 0x7;
761 bool fpu_32bit = isa_features_.Is32BitFloatingPoint();
762
763 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) {
764 FRegister reg = kFpuCalleeSaves[i];
765 if (allocated_registers_.ContainsFloatingPointRegister(reg)) {
766 if (unaligned_float) {
767 if (fpu_32bit) {
768 __ Lwc1(reg, SP, ofs);
769 __ Lwc1(static_cast<FRegister>(reg + 1), SP, ofs + 4);
770 } else {
771 __ Lwc1(reg, SP, ofs);
772 __ Lw(TMP, SP, ofs + 4);
773 __ Mthc1(TMP, reg);
774 }
775 } else {
776 __ Ldc1(reg, SP, ofs);
777 }
778 ofs += kMipsDoublewordSize;
779 // TODO: __ cfi().Restore(DWARFReg(reg));
780 }
781 }
782
783 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
784 Register reg = kCoreCalleeSaves[i];
785 if (allocated_registers_.ContainsCoreRegister(reg)) {
786 __ Lw(reg, SP, ofs);
787 ofs += kMipsWordSize;
788 __ cfi().Restore(DWARFReg(reg));
789 }
790 }
791
792 DCHECK_EQ(ofs, FrameEntrySpillSize());
793 __ DecreaseFrameSize(ofs);
794 }
795
796 __ Jr(RA);
797 __ Nop();
798
799 __ cfi().RestoreState();
800 __ cfi().DefCFAOffset(GetFrameSize());
801}
802
803void CodeGeneratorMIPS::Bind(HBasicBlock* block) {
804 __ Bind(GetLabelOf(block));
805}
806
807void CodeGeneratorMIPS::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
808 if (src.Equals(dst)) {
809 return;
810 }
811
812 if (src.IsConstant()) {
813 MoveConstant(dst, src.GetConstant());
814 } else {
815 if (Primitive::Is64BitType(dst_type)) {
816 Move64(dst, src);
817 } else {
818 Move32(dst, src);
819 }
820 }
821}
822
823void CodeGeneratorMIPS::Move32(Location destination, Location source) {
824 if (source.Equals(destination)) {
825 return;
826 }
827
828 if (destination.IsRegister()) {
829 if (source.IsRegister()) {
830 __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
831 } else if (source.IsFpuRegister()) {
832 __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
833 } else {
834 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
835 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
836 }
837 } else if (destination.IsFpuRegister()) {
838 if (source.IsRegister()) {
839 __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
840 } else if (source.IsFpuRegister()) {
841 __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
842 } else {
843 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
844 __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
845 }
846 } else {
847 DCHECK(destination.IsStackSlot()) << destination;
848 if (source.IsRegister()) {
849 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
850 } else if (source.IsFpuRegister()) {
851 __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, destination.GetStackIndex());
852 } else {
853 DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
854 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
855 __ StoreToOffset(kStoreWord, TMP, SP, destination.GetStackIndex());
856 }
857 }
858}
859
860void CodeGeneratorMIPS::Move64(Location destination, Location source) {
861 if (source.Equals(destination)) {
862 return;
863 }
864
865 if (destination.IsRegisterPair()) {
866 if (source.IsRegisterPair()) {
867 __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
868 __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
869 } else if (source.IsFpuRegister()) {
870 Register dst_high = destination.AsRegisterPairHigh<Register>();
871 Register dst_low = destination.AsRegisterPairLow<Register>();
872 FRegister src = source.AsFpuRegister<FRegister>();
873 __ Mfc1(dst_low, src);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800874 __ MoveFromFpuHigh(dst_high, src);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200875 } else {
876 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
877 int32_t off = source.GetStackIndex();
878 Register r = destination.AsRegisterPairLow<Register>();
879 __ LoadFromOffset(kLoadDoubleword, r, SP, off);
880 }
881 } else if (destination.IsFpuRegister()) {
882 if (source.IsRegisterPair()) {
883 FRegister dst = destination.AsFpuRegister<FRegister>();
884 Register src_high = source.AsRegisterPairHigh<Register>();
885 Register src_low = source.AsRegisterPairLow<Register>();
886 __ Mtc1(src_low, dst);
Alexey Frunzebb9863a2016-01-11 15:51:16 -0800887 __ MoveToFpuHigh(src_high, dst);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200888 } else if (source.IsFpuRegister()) {
889 __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
890 } else {
891 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
892 __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
893 }
894 } else {
895 DCHECK(destination.IsDoubleStackSlot()) << destination;
896 int32_t off = destination.GetStackIndex();
897 if (source.IsRegisterPair()) {
898 __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, off);
899 } else if (source.IsFpuRegister()) {
900 __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, off);
901 } else {
902 DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
903 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
904 __ StoreToOffset(kStoreWord, TMP, SP, off);
905 __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
906 __ StoreToOffset(kStoreWord, TMP, SP, off + 4);
907 }
908 }
909}
910
911void CodeGeneratorMIPS::MoveConstant(Location destination, HConstant* c) {
912 if (c->IsIntConstant() || c->IsNullConstant()) {
913 // Move 32 bit constant.
914 int32_t value = GetInt32ValueOf(c);
915 if (destination.IsRegister()) {
916 Register dst = destination.AsRegister<Register>();
917 __ LoadConst32(dst, value);
918 } else {
919 DCHECK(destination.IsStackSlot())
920 << "Cannot move " << c->DebugName() << " to " << destination;
921 __ StoreConst32ToOffset(value, SP, destination.GetStackIndex(), TMP);
922 }
923 } else if (c->IsLongConstant()) {
924 // Move 64 bit constant.
925 int64_t value = GetInt64ValueOf(c);
926 if (destination.IsRegisterPair()) {
927 Register r_h = destination.AsRegisterPairHigh<Register>();
928 Register r_l = destination.AsRegisterPairLow<Register>();
929 __ LoadConst64(r_h, r_l, value);
930 } else {
931 DCHECK(destination.IsDoubleStackSlot())
932 << "Cannot move " << c->DebugName() << " to " << destination;
933 __ StoreConst64ToOffset(value, SP, destination.GetStackIndex(), TMP);
934 }
935 } else if (c->IsFloatConstant()) {
936 // Move 32 bit float constant.
937 int32_t value = GetInt32ValueOf(c);
938 if (destination.IsFpuRegister()) {
939 __ LoadSConst32(destination.AsFpuRegister<FRegister>(), value, TMP);
940 } else {
941 DCHECK(destination.IsStackSlot())
942 << "Cannot move " << c->DebugName() << " to " << destination;
943 __ StoreConst32ToOffset(value, SP, destination.GetStackIndex(), TMP);
944 }
945 } else {
946 // Move 64 bit double constant.
947 DCHECK(c->IsDoubleConstant()) << c->DebugName();
948 int64_t value = GetInt64ValueOf(c);
949 if (destination.IsFpuRegister()) {
950 FRegister fd = destination.AsFpuRegister<FRegister>();
951 __ LoadDConst64(fd, value, TMP);
952 } else {
953 DCHECK(destination.IsDoubleStackSlot())
954 << "Cannot move " << c->DebugName() << " to " << destination;
955 __ StoreConst64ToOffset(value, SP, destination.GetStackIndex(), TMP);
956 }
957 }
958}
959
960void CodeGeneratorMIPS::MoveConstant(Location destination, int32_t value) {
961 DCHECK(destination.IsRegister());
962 Register dst = destination.AsRegister<Register>();
963 __ LoadConst32(dst, value);
964}
965
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200966void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
967 if (location.IsRegister()) {
968 locations->AddTemp(location);
Alexey Frunzec9e94f32015-10-26 16:11:39 -0700969 } else if (location.IsRegisterPair()) {
970 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
971 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +0200972 } else {
973 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
974 }
975}
976
977Location CodeGeneratorMIPS::GetStackLocation(HLoadLocal* load) const {
978 Primitive::Type type = load->GetType();
979
980 switch (type) {
981 case Primitive::kPrimNot:
982 case Primitive::kPrimInt:
983 case Primitive::kPrimFloat:
984 return Location::StackSlot(GetStackSlot(load->GetLocal()));
985
986 case Primitive::kPrimLong:
987 case Primitive::kPrimDouble:
988 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
989
990 case Primitive::kPrimBoolean:
991 case Primitive::kPrimByte:
992 case Primitive::kPrimChar:
993 case Primitive::kPrimShort:
994 case Primitive::kPrimVoid:
995 LOG(FATAL) << "Unexpected type " << type;
996 }
997
998 LOG(FATAL) << "Unreachable";
999 return Location::NoLocation();
1000}
1001
1002void CodeGeneratorMIPS::MarkGCCard(Register object, Register value) {
1003 MipsLabel done;
1004 Register card = AT;
1005 Register temp = TMP;
1006 __ Beqz(value, &done);
1007 __ LoadFromOffset(kLoadWord,
1008 card,
1009 TR,
1010 Thread::CardTableOffset<kMipsWordSize>().Int32Value());
1011 __ Srl(temp, object, gc::accounting::CardTable::kCardShift);
1012 __ Addu(temp, card, temp);
1013 __ Sb(card, temp, 0);
1014 __ Bind(&done);
1015}
1016
David Brazdil58282f42016-01-14 12:45:10 +00001017void CodeGeneratorMIPS::SetupBlockedRegisters() const {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001018 // Don't allocate the dalvik style register pair passing.
1019 blocked_register_pairs_[A1_A2] = true;
1020
1021 // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated.
1022 blocked_core_registers_[ZERO] = true;
1023 blocked_core_registers_[K0] = true;
1024 blocked_core_registers_[K1] = true;
1025 blocked_core_registers_[GP] = true;
1026 blocked_core_registers_[SP] = true;
1027 blocked_core_registers_[RA] = true;
1028
1029 // AT and TMP(T8) are used as temporary/scratch registers
1030 // (similar to how AT is used by MIPS assemblers).
1031 blocked_core_registers_[AT] = true;
1032 blocked_core_registers_[TMP] = true;
1033 blocked_fpu_registers_[FTMP] = true;
1034
1035 // Reserve suspend and thread registers.
1036 blocked_core_registers_[S0] = true;
1037 blocked_core_registers_[TR] = true;
1038
1039 // Reserve T9 for function calls
1040 blocked_core_registers_[T9] = true;
1041
1042 // Reserve odd-numbered FPU registers.
1043 for (size_t i = 1; i < kNumberOfFRegisters; i += 2) {
1044 blocked_fpu_registers_[i] = true;
1045 }
1046
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001047 UpdateBlockedPairRegisters();
1048}
1049
1050void CodeGeneratorMIPS::UpdateBlockedPairRegisters() const {
1051 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
1052 MipsManagedRegister current =
1053 MipsManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
1054 if (blocked_core_registers_[current.AsRegisterPairLow()]
1055 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
1056 blocked_register_pairs_[i] = true;
1057 }
1058 }
1059}
1060
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001061size_t CodeGeneratorMIPS::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
1062 __ StoreToOffset(kStoreWord, Register(reg_id), SP, stack_index);
1063 return kMipsWordSize;
1064}
1065
1066size_t CodeGeneratorMIPS::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
1067 __ LoadFromOffset(kLoadWord, Register(reg_id), SP, stack_index);
1068 return kMipsWordSize;
1069}
1070
1071size_t CodeGeneratorMIPS::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1072 __ StoreDToOffset(FRegister(reg_id), SP, stack_index);
1073 return kMipsDoublewordSize;
1074}
1075
1076size_t CodeGeneratorMIPS::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
1077 __ LoadDFromOffset(FRegister(reg_id), SP, stack_index);
1078 return kMipsDoublewordSize;
1079}
1080
1081void CodeGeneratorMIPS::DumpCoreRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001082 stream << Register(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001083}
1084
1085void CodeGeneratorMIPS::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
Vladimir Marko623a7a22016-02-02 18:14:52 +00001086 stream << FRegister(reg);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001087}
1088
1089void CodeGeneratorMIPS::InvokeRuntime(QuickEntrypointEnum entrypoint,
1090 HInstruction* instruction,
1091 uint32_t dex_pc,
1092 SlowPathCode* slow_path) {
1093 InvokeRuntime(GetThreadOffset<kMipsWordSize>(entrypoint).Int32Value(),
1094 instruction,
1095 dex_pc,
1096 slow_path,
1097 IsDirectEntrypoint(entrypoint));
1098}
1099
1100constexpr size_t kMipsDirectEntrypointRuntimeOffset = 16;
1101
1102void CodeGeneratorMIPS::InvokeRuntime(int32_t entry_point_offset,
1103 HInstruction* instruction,
1104 uint32_t dex_pc,
1105 SlowPathCode* slow_path,
1106 bool is_direct_entrypoint) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001107 __ LoadFromOffset(kLoadWord, T9, TR, entry_point_offset);
1108 __ Jalr(T9);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001109 if (is_direct_entrypoint) {
1110 // Reserve argument space on stack (for $a0-$a3) for
1111 // entrypoints that directly reference native implementations.
1112 // Called function may use this space to store $a0-$a3 regs.
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001113 __ IncreaseFrameSize(kMipsDirectEntrypointRuntimeOffset); // Single instruction in delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001114 __ DecreaseFrameSize(kMipsDirectEntrypointRuntimeOffset);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001115 } else {
1116 __ Nop(); // In delay slot.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001117 }
1118 RecordPcInfo(instruction, dex_pc, slow_path);
1119}
1120
1121void InstructionCodeGeneratorMIPS::GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path,
1122 Register class_reg) {
1123 __ LoadFromOffset(kLoadWord, TMP, class_reg, mirror::Class::StatusOffset().Int32Value());
1124 __ LoadConst32(AT, mirror::Class::kStatusInitialized);
1125 __ Blt(TMP, AT, slow_path->GetEntryLabel());
1126 // Even if the initialized flag is set, we need to ensure consistent memory ordering.
1127 __ Sync(0);
1128 __ Bind(slow_path->GetExitLabel());
1129}
1130
1131void InstructionCodeGeneratorMIPS::GenerateMemoryBarrier(MemBarrierKind kind ATTRIBUTE_UNUSED) {
1132 __ Sync(0); // Only stype 0 is supported.
1133}
1134
1135void InstructionCodeGeneratorMIPS::GenerateSuspendCheck(HSuspendCheck* instruction,
1136 HBasicBlock* successor) {
1137 SuspendCheckSlowPathMIPS* slow_path =
1138 new (GetGraph()->GetArena()) SuspendCheckSlowPathMIPS(instruction, successor);
1139 codegen_->AddSlowPath(slow_path);
1140
1141 __ LoadFromOffset(kLoadUnsignedHalfword,
1142 TMP,
1143 TR,
1144 Thread::ThreadFlagsOffset<kMipsWordSize>().Int32Value());
1145 if (successor == nullptr) {
1146 __ Bnez(TMP, slow_path->GetEntryLabel());
1147 __ Bind(slow_path->GetReturnLabel());
1148 } else {
1149 __ Beqz(TMP, codegen_->GetLabelOf(successor));
1150 __ B(slow_path->GetEntryLabel());
1151 // slow_path will return to GetLabelOf(successor).
1152 }
1153}
1154
1155InstructionCodeGeneratorMIPS::InstructionCodeGeneratorMIPS(HGraph* graph,
1156 CodeGeneratorMIPS* codegen)
Aart Bik42249c32016-01-07 15:33:50 -08001157 : InstructionCodeGenerator(graph, codegen),
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001158 assembler_(codegen->GetAssembler()),
1159 codegen_(codegen) {}
1160
1161void LocationsBuilderMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1162 DCHECK_EQ(instruction->InputCount(), 2U);
1163 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1164 Primitive::Type type = instruction->GetResultType();
1165 switch (type) {
1166 case Primitive::kPrimInt: {
1167 locations->SetInAt(0, Location::RequiresRegister());
1168 HInstruction* right = instruction->InputAt(1);
1169 bool can_use_imm = false;
1170 if (right->IsConstant()) {
1171 int32_t imm = CodeGenerator::GetInt32ValueOf(right->AsConstant());
1172 if (instruction->IsAnd() || instruction->IsOr() || instruction->IsXor()) {
1173 can_use_imm = IsUint<16>(imm);
1174 } else if (instruction->IsAdd()) {
1175 can_use_imm = IsInt<16>(imm);
1176 } else {
1177 DCHECK(instruction->IsSub());
1178 can_use_imm = IsInt<16>(-imm);
1179 }
1180 }
1181 if (can_use_imm)
1182 locations->SetInAt(1, Location::ConstantLocation(right->AsConstant()));
1183 else
1184 locations->SetInAt(1, Location::RequiresRegister());
1185 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1186 break;
1187 }
1188
1189 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001190 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001191 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1192 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001193 break;
1194 }
1195
1196 case Primitive::kPrimFloat:
1197 case Primitive::kPrimDouble:
1198 DCHECK(instruction->IsAdd() || instruction->IsSub());
1199 locations->SetInAt(0, Location::RequiresFpuRegister());
1200 locations->SetInAt(1, Location::RequiresFpuRegister());
1201 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1202 break;
1203
1204 default:
1205 LOG(FATAL) << "Unexpected " << instruction->DebugName() << " type " << type;
1206 }
1207}
1208
1209void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
1210 Primitive::Type type = instruction->GetType();
1211 LocationSummary* locations = instruction->GetLocations();
1212
1213 switch (type) {
1214 case Primitive::kPrimInt: {
1215 Register dst = locations->Out().AsRegister<Register>();
1216 Register lhs = locations->InAt(0).AsRegister<Register>();
1217 Location rhs_location = locations->InAt(1);
1218
1219 Register rhs_reg = ZERO;
1220 int32_t rhs_imm = 0;
1221 bool use_imm = rhs_location.IsConstant();
1222 if (use_imm) {
1223 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
1224 } else {
1225 rhs_reg = rhs_location.AsRegister<Register>();
1226 }
1227
1228 if (instruction->IsAnd()) {
1229 if (use_imm)
1230 __ Andi(dst, lhs, rhs_imm);
1231 else
1232 __ And(dst, lhs, rhs_reg);
1233 } else if (instruction->IsOr()) {
1234 if (use_imm)
1235 __ Ori(dst, lhs, rhs_imm);
1236 else
1237 __ Or(dst, lhs, rhs_reg);
1238 } else if (instruction->IsXor()) {
1239 if (use_imm)
1240 __ Xori(dst, lhs, rhs_imm);
1241 else
1242 __ Xor(dst, lhs, rhs_reg);
1243 } else if (instruction->IsAdd()) {
1244 if (use_imm)
1245 __ Addiu(dst, lhs, rhs_imm);
1246 else
1247 __ Addu(dst, lhs, rhs_reg);
1248 } else {
1249 DCHECK(instruction->IsSub());
1250 if (use_imm)
1251 __ Addiu(dst, lhs, -rhs_imm);
1252 else
1253 __ Subu(dst, lhs, rhs_reg);
1254 }
1255 break;
1256 }
1257
1258 case Primitive::kPrimLong: {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001259 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
1260 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
1261 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
1262 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001263 Location rhs_location = locations->InAt(1);
1264 bool use_imm = rhs_location.IsConstant();
1265 if (!use_imm) {
1266 Register rhs_high = rhs_location.AsRegisterPairHigh<Register>();
1267 Register rhs_low = rhs_location.AsRegisterPairLow<Register>();
1268 if (instruction->IsAnd()) {
1269 __ And(dst_low, lhs_low, rhs_low);
1270 __ And(dst_high, lhs_high, rhs_high);
1271 } else if (instruction->IsOr()) {
1272 __ Or(dst_low, lhs_low, rhs_low);
1273 __ Or(dst_high, lhs_high, rhs_high);
1274 } else if (instruction->IsXor()) {
1275 __ Xor(dst_low, lhs_low, rhs_low);
1276 __ Xor(dst_high, lhs_high, rhs_high);
1277 } else if (instruction->IsAdd()) {
1278 if (lhs_low == rhs_low) {
1279 // Special case for lhs = rhs and the sum potentially overwriting both lhs and rhs.
1280 __ Slt(TMP, lhs_low, ZERO);
1281 __ Addu(dst_low, lhs_low, rhs_low);
1282 } else {
1283 __ Addu(dst_low, lhs_low, rhs_low);
1284 // If the sum overwrites rhs, lhs remains unchanged, otherwise rhs remains unchanged.
1285 __ Sltu(TMP, dst_low, (dst_low == rhs_low) ? lhs_low : rhs_low);
1286 }
1287 __ Addu(dst_high, lhs_high, rhs_high);
1288 __ Addu(dst_high, dst_high, TMP);
1289 } else {
1290 DCHECK(instruction->IsSub());
1291 __ Sltu(TMP, lhs_low, rhs_low);
1292 __ Subu(dst_low, lhs_low, rhs_low);
1293 __ Subu(dst_high, lhs_high, rhs_high);
1294 __ Subu(dst_high, dst_high, TMP);
1295 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001296 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001297 int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
1298 if (instruction->IsOr()) {
1299 uint32_t low = Low32Bits(value);
1300 uint32_t high = High32Bits(value);
1301 if (IsUint<16>(low)) {
1302 if (dst_low != lhs_low || low != 0) {
1303 __ Ori(dst_low, lhs_low, low);
1304 }
1305 } else {
1306 __ LoadConst32(TMP, low);
1307 __ Or(dst_low, lhs_low, TMP);
1308 }
1309 if (IsUint<16>(high)) {
1310 if (dst_high != lhs_high || high != 0) {
1311 __ Ori(dst_high, lhs_high, high);
1312 }
1313 } else {
1314 if (high != low) {
1315 __ LoadConst32(TMP, high);
1316 }
1317 __ Or(dst_high, lhs_high, TMP);
1318 }
1319 } else if (instruction->IsXor()) {
1320 uint32_t low = Low32Bits(value);
1321 uint32_t high = High32Bits(value);
1322 if (IsUint<16>(low)) {
1323 if (dst_low != lhs_low || low != 0) {
1324 __ Xori(dst_low, lhs_low, low);
1325 }
1326 } else {
1327 __ LoadConst32(TMP, low);
1328 __ Xor(dst_low, lhs_low, TMP);
1329 }
1330 if (IsUint<16>(high)) {
1331 if (dst_high != lhs_high || high != 0) {
1332 __ Xori(dst_high, lhs_high, high);
1333 }
1334 } else {
1335 if (high != low) {
1336 __ LoadConst32(TMP, high);
1337 }
1338 __ Xor(dst_high, lhs_high, TMP);
1339 }
1340 } else if (instruction->IsAnd()) {
1341 uint32_t low = Low32Bits(value);
1342 uint32_t high = High32Bits(value);
1343 if (IsUint<16>(low)) {
1344 __ Andi(dst_low, lhs_low, low);
1345 } else if (low != 0xFFFFFFFF) {
1346 __ LoadConst32(TMP, low);
1347 __ And(dst_low, lhs_low, TMP);
1348 } else if (dst_low != lhs_low) {
1349 __ Move(dst_low, lhs_low);
1350 }
1351 if (IsUint<16>(high)) {
1352 __ Andi(dst_high, lhs_high, high);
1353 } else if (high != 0xFFFFFFFF) {
1354 if (high != low) {
1355 __ LoadConst32(TMP, high);
1356 }
1357 __ And(dst_high, lhs_high, TMP);
1358 } else if (dst_high != lhs_high) {
1359 __ Move(dst_high, lhs_high);
1360 }
1361 } else {
1362 if (instruction->IsSub()) {
1363 value = -value;
1364 } else {
1365 DCHECK(instruction->IsAdd());
1366 }
1367 int32_t low = Low32Bits(value);
1368 int32_t high = High32Bits(value);
1369 if (IsInt<16>(low)) {
1370 if (dst_low != lhs_low || low != 0) {
1371 __ Addiu(dst_low, lhs_low, low);
1372 }
1373 if (low != 0) {
1374 __ Sltiu(AT, dst_low, low);
1375 }
1376 } else {
1377 __ LoadConst32(TMP, low);
1378 __ Addu(dst_low, lhs_low, TMP);
1379 __ Sltu(AT, dst_low, TMP);
1380 }
1381 if (IsInt<16>(high)) {
1382 if (dst_high != lhs_high || high != 0) {
1383 __ Addiu(dst_high, lhs_high, high);
1384 }
1385 } else {
1386 if (high != low) {
1387 __ LoadConst32(TMP, high);
1388 }
1389 __ Addu(dst_high, lhs_high, TMP);
1390 }
1391 if (low != 0) {
1392 __ Addu(dst_high, dst_high, AT);
1393 }
1394 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001395 }
1396 break;
1397 }
1398
1399 case Primitive::kPrimFloat:
1400 case Primitive::kPrimDouble: {
1401 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
1402 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
1403 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
1404 if (instruction->IsAdd()) {
1405 if (type == Primitive::kPrimFloat) {
1406 __ AddS(dst, lhs, rhs);
1407 } else {
1408 __ AddD(dst, lhs, rhs);
1409 }
1410 } else {
1411 DCHECK(instruction->IsSub());
1412 if (type == Primitive::kPrimFloat) {
1413 __ SubS(dst, lhs, rhs);
1414 } else {
1415 __ SubD(dst, lhs, rhs);
1416 }
1417 }
1418 break;
1419 }
1420
1421 default:
1422 LOG(FATAL) << "Unexpected binary operation type " << type;
1423 }
1424}
1425
1426void LocationsBuilderMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001427 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001428
1429 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr);
1430 Primitive::Type type = instr->GetResultType();
1431 switch (type) {
1432 case Primitive::kPrimInt:
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001433 locations->SetInAt(0, Location::RequiresRegister());
1434 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1435 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1436 break;
1437 case Primitive::kPrimLong:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001438 locations->SetInAt(0, Location::RequiresRegister());
1439 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1)));
1440 locations->SetOut(Location::RequiresRegister());
1441 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001442 default:
1443 LOG(FATAL) << "Unexpected shift type " << type;
1444 }
1445}
1446
1447static constexpr size_t kMipsBitsPerWord = kMipsWordSize * kBitsPerByte;
1448
1449void InstructionCodeGeneratorMIPS::HandleShift(HBinaryOperation* instr) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001450 DCHECK(instr->IsShl() || instr->IsShr() || instr->IsUShr() || instr->IsRor());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001451 LocationSummary* locations = instr->GetLocations();
1452 Primitive::Type type = instr->GetType();
1453
1454 Location rhs_location = locations->InAt(1);
1455 bool use_imm = rhs_location.IsConstant();
1456 Register rhs_reg = use_imm ? ZERO : rhs_location.AsRegister<Register>();
1457 int64_t rhs_imm = use_imm ? CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()) : 0;
Roland Levillain5b5b9312016-03-22 14:57:31 +00001458 const uint32_t shift_mask =
1459 (type == Primitive::kPrimInt) ? kMaxIntShiftDistance : kMaxLongShiftDistance;
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001460 const uint32_t shift_value = rhs_imm & shift_mask;
Alexey Frunze92d90602015-12-18 18:16:36 -08001461 // Are the INS (Insert Bit Field) and ROTR instructions supported?
1462 bool has_ins_rotr = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001463
1464 switch (type) {
1465 case Primitive::kPrimInt: {
1466 Register dst = locations->Out().AsRegister<Register>();
1467 Register lhs = locations->InAt(0).AsRegister<Register>();
1468 if (use_imm) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001469 if (shift_value == 0) {
1470 if (dst != lhs) {
1471 __ Move(dst, lhs);
1472 }
1473 } else if (instr->IsShl()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001474 __ Sll(dst, lhs, shift_value);
1475 } else if (instr->IsShr()) {
1476 __ Sra(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001477 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001478 __ Srl(dst, lhs, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001479 } else {
1480 if (has_ins_rotr) {
1481 __ Rotr(dst, lhs, shift_value);
1482 } else {
1483 __ Sll(TMP, lhs, (kMipsBitsPerWord - shift_value) & shift_mask);
1484 __ Srl(dst, lhs, shift_value);
1485 __ Or(dst, dst, TMP);
1486 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001487 }
1488 } else {
1489 if (instr->IsShl()) {
1490 __ Sllv(dst, lhs, rhs_reg);
1491 } else if (instr->IsShr()) {
1492 __ Srav(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08001493 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001494 __ Srlv(dst, lhs, rhs_reg);
Alexey Frunze92d90602015-12-18 18:16:36 -08001495 } else {
1496 if (has_ins_rotr) {
1497 __ Rotrv(dst, lhs, rhs_reg);
1498 } else {
1499 __ Subu(TMP, ZERO, rhs_reg);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001500 // 32-bit shift instructions use the 5 least significant bits of the shift count, so
1501 // shifting by `-rhs_reg` is equivalent to shifting by `(32 - rhs_reg) & 31`. The case
1502 // when `rhs_reg & 31 == 0` is OK even though we don't shift `lhs` left all the way out
1503 // by 32, because the result in this case is computed as `(lhs >> 0) | (lhs << 0)`,
1504 // IOW, the OR'd values are equal.
Alexey Frunze92d90602015-12-18 18:16:36 -08001505 __ Sllv(TMP, lhs, TMP);
1506 __ Srlv(dst, lhs, rhs_reg);
1507 __ Or(dst, dst, TMP);
1508 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001509 }
1510 }
1511 break;
1512 }
1513
1514 case Primitive::kPrimLong: {
1515 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
1516 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
1517 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
1518 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
1519 if (use_imm) {
1520 if (shift_value == 0) {
1521 codegen_->Move64(locations->Out(), locations->InAt(0));
1522 } else if (shift_value < kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001523 if (has_ins_rotr) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001524 if (instr->IsShl()) {
1525 __ Srl(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
1526 __ Ins(dst_high, lhs_high, shift_value, kMipsBitsPerWord - shift_value);
1527 __ Sll(dst_low, lhs_low, shift_value);
1528 } else if (instr->IsShr()) {
1529 __ Srl(dst_low, lhs_low, shift_value);
1530 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1531 __ Sra(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001532 } else if (instr->IsUShr()) {
1533 __ Srl(dst_low, lhs_low, shift_value);
1534 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1535 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001536 } else {
1537 __ Srl(dst_low, lhs_low, shift_value);
1538 __ Ins(dst_low, lhs_high, kMipsBitsPerWord - shift_value, shift_value);
1539 __ Srl(dst_high, lhs_high, shift_value);
Alexey Frunze92d90602015-12-18 18:16:36 -08001540 __ Ins(dst_high, lhs_low, kMipsBitsPerWord - shift_value, shift_value);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001541 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001542 } else {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001543 if (instr->IsShl()) {
1544 __ Sll(dst_low, lhs_low, shift_value);
1545 __ Srl(TMP, lhs_low, kMipsBitsPerWord - shift_value);
1546 __ Sll(dst_high, lhs_high, shift_value);
1547 __ Or(dst_high, dst_high, TMP);
1548 } else if (instr->IsShr()) {
1549 __ Sra(dst_high, lhs_high, shift_value);
1550 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
1551 __ Srl(dst_low, lhs_low, shift_value);
1552 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08001553 } else if (instr->IsUShr()) {
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001554 __ Srl(dst_high, lhs_high, shift_value);
1555 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value);
1556 __ Srl(dst_low, lhs_low, shift_value);
1557 __ Or(dst_low, dst_low, TMP);
Alexey Frunze92d90602015-12-18 18:16:36 -08001558 } else {
1559 __ Srl(TMP, lhs_low, shift_value);
1560 __ Sll(dst_low, lhs_high, kMipsBitsPerWord - shift_value);
1561 __ Or(dst_low, dst_low, TMP);
1562 __ Srl(TMP, lhs_high, shift_value);
1563 __ Sll(dst_high, lhs_low, kMipsBitsPerWord - shift_value);
1564 __ Or(dst_high, dst_high, TMP);
Alexey Frunze5c7aed32015-11-25 19:41:54 -08001565 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001566 }
1567 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001568 const uint32_t shift_value_high = shift_value - kMipsBitsPerWord;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001569 if (instr->IsShl()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001570 __ Sll(dst_high, lhs_low, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001571 __ Move(dst_low, ZERO);
1572 } else if (instr->IsShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001573 __ Sra(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001574 __ Sra(dst_high, dst_low, kMipsBitsPerWord - 1);
Alexey Frunze92d90602015-12-18 18:16:36 -08001575 } else if (instr->IsUShr()) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001576 __ Srl(dst_low, lhs_high, shift_value_high);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001577 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08001578 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001579 if (shift_value == kMipsBitsPerWord) {
Alexey Frunze92d90602015-12-18 18:16:36 -08001580 // 64-bit rotation by 32 is just a swap.
1581 __ Move(dst_low, lhs_high);
1582 __ Move(dst_high, lhs_low);
1583 } else {
1584 if (has_ins_rotr) {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001585 __ Srl(dst_low, lhs_high, shift_value_high);
1586 __ Ins(dst_low, lhs_low, kMipsBitsPerWord - shift_value_high, shift_value_high);
1587 __ Srl(dst_high, lhs_low, shift_value_high);
1588 __ Ins(dst_high, lhs_high, kMipsBitsPerWord - shift_value_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001589 } else {
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001590 __ Sll(TMP, lhs_low, kMipsBitsPerWord - shift_value_high);
1591 __ Srl(dst_low, lhs_high, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001592 __ Or(dst_low, dst_low, TMP);
Alexey Frunze0d9150b2016-01-13 16:24:25 -08001593 __ Sll(TMP, lhs_high, kMipsBitsPerWord - shift_value_high);
1594 __ Srl(dst_high, lhs_low, shift_value_high);
Alexey Frunze92d90602015-12-18 18:16:36 -08001595 __ Or(dst_high, dst_high, TMP);
1596 }
1597 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001598 }
1599 }
1600 } else {
1601 MipsLabel done;
1602 if (instr->IsShl()) {
1603 __ Sllv(dst_low, lhs_low, rhs_reg);
1604 __ Nor(AT, ZERO, rhs_reg);
1605 __ Srl(TMP, lhs_low, 1);
1606 __ Srlv(TMP, TMP, AT);
1607 __ Sllv(dst_high, lhs_high, rhs_reg);
1608 __ Or(dst_high, dst_high, TMP);
1609 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1610 __ Beqz(TMP, &done);
1611 __ Move(dst_high, dst_low);
1612 __ Move(dst_low, ZERO);
1613 } else if (instr->IsShr()) {
1614 __ Srav(dst_high, lhs_high, rhs_reg);
1615 __ Nor(AT, ZERO, rhs_reg);
1616 __ Sll(TMP, lhs_high, 1);
1617 __ Sllv(TMP, TMP, AT);
1618 __ Srlv(dst_low, lhs_low, rhs_reg);
1619 __ Or(dst_low, dst_low, TMP);
1620 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1621 __ Beqz(TMP, &done);
1622 __ Move(dst_low, dst_high);
1623 __ Sra(dst_high, dst_high, 31);
Alexey Frunze92d90602015-12-18 18:16:36 -08001624 } else if (instr->IsUShr()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001625 __ Srlv(dst_high, lhs_high, rhs_reg);
1626 __ Nor(AT, ZERO, rhs_reg);
1627 __ Sll(TMP, lhs_high, 1);
1628 __ Sllv(TMP, TMP, AT);
1629 __ Srlv(dst_low, lhs_low, rhs_reg);
1630 __ Or(dst_low, dst_low, TMP);
1631 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1632 __ Beqz(TMP, &done);
1633 __ Move(dst_low, dst_high);
1634 __ Move(dst_high, ZERO);
Alexey Frunze92d90602015-12-18 18:16:36 -08001635 } else {
1636 __ Nor(AT, ZERO, rhs_reg);
1637 __ Srlv(TMP, lhs_low, rhs_reg);
1638 __ Sll(dst_low, lhs_high, 1);
1639 __ Sllv(dst_low, dst_low, AT);
1640 __ Or(dst_low, dst_low, TMP);
1641 __ Srlv(TMP, lhs_high, rhs_reg);
1642 __ Sll(dst_high, lhs_low, 1);
1643 __ Sllv(dst_high, dst_high, AT);
1644 __ Or(dst_high, dst_high, TMP);
1645 __ Andi(TMP, rhs_reg, kMipsBitsPerWord);
1646 __ Beqz(TMP, &done);
1647 __ Move(TMP, dst_high);
1648 __ Move(dst_high, dst_low);
1649 __ Move(dst_low, TMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001650 }
1651 __ Bind(&done);
1652 }
1653 break;
1654 }
1655
1656 default:
1657 LOG(FATAL) << "Unexpected shift operation type " << type;
1658 }
1659}
1660
1661void LocationsBuilderMIPS::VisitAdd(HAdd* instruction) {
1662 HandleBinaryOp(instruction);
1663}
1664
1665void InstructionCodeGeneratorMIPS::VisitAdd(HAdd* instruction) {
1666 HandleBinaryOp(instruction);
1667}
1668
1669void LocationsBuilderMIPS::VisitAnd(HAnd* instruction) {
1670 HandleBinaryOp(instruction);
1671}
1672
1673void InstructionCodeGeneratorMIPS::VisitAnd(HAnd* instruction) {
1674 HandleBinaryOp(instruction);
1675}
1676
1677void LocationsBuilderMIPS::VisitArrayGet(HArrayGet* instruction) {
1678 LocationSummary* locations =
1679 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
1680 locations->SetInAt(0, Location::RequiresRegister());
1681 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1682 if (Primitive::IsFloatingPointType(instruction->GetType())) {
1683 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
1684 } else {
1685 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1686 }
1687}
1688
1689void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
1690 LocationSummary* locations = instruction->GetLocations();
1691 Register obj = locations->InAt(0).AsRegister<Register>();
1692 Location index = locations->InAt(1);
1693 Primitive::Type type = instruction->GetType();
1694
1695 switch (type) {
1696 case Primitive::kPrimBoolean: {
1697 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1698 Register out = locations->Out().AsRegister<Register>();
1699 if (index.IsConstant()) {
1700 size_t offset =
1701 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1702 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset);
1703 } else {
1704 __ Addu(TMP, obj, index.AsRegister<Register>());
1705 __ LoadFromOffset(kLoadUnsignedByte, out, TMP, data_offset);
1706 }
1707 break;
1708 }
1709
1710 case Primitive::kPrimByte: {
1711 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1712 Register out = locations->Out().AsRegister<Register>();
1713 if (index.IsConstant()) {
1714 size_t offset =
1715 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1716 __ LoadFromOffset(kLoadSignedByte, out, obj, offset);
1717 } else {
1718 __ Addu(TMP, obj, index.AsRegister<Register>());
1719 __ LoadFromOffset(kLoadSignedByte, out, TMP, data_offset);
1720 }
1721 break;
1722 }
1723
1724 case Primitive::kPrimShort: {
1725 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1726 Register out = locations->Out().AsRegister<Register>();
1727 if (index.IsConstant()) {
1728 size_t offset =
1729 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1730 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset);
1731 } else {
1732 __ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
1733 __ Addu(TMP, obj, TMP);
1734 __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset);
1735 }
1736 break;
1737 }
1738
1739 case Primitive::kPrimChar: {
1740 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1741 Register out = locations->Out().AsRegister<Register>();
1742 if (index.IsConstant()) {
1743 size_t offset =
1744 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1745 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset);
1746 } else {
1747 __ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
1748 __ Addu(TMP, obj, TMP);
1749 __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
1750 }
1751 break;
1752 }
1753
1754 case Primitive::kPrimInt:
1755 case Primitive::kPrimNot: {
1756 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1757 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1758 Register out = locations->Out().AsRegister<Register>();
1759 if (index.IsConstant()) {
1760 size_t offset =
1761 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1762 __ LoadFromOffset(kLoadWord, out, obj, offset);
1763 } else {
1764 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
1765 __ Addu(TMP, obj, TMP);
1766 __ LoadFromOffset(kLoadWord, out, TMP, data_offset);
1767 }
1768 break;
1769 }
1770
1771 case Primitive::kPrimLong: {
1772 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1773 Register out = locations->Out().AsRegisterPairLow<Register>();
1774 if (index.IsConstant()) {
1775 size_t offset =
1776 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1777 __ LoadFromOffset(kLoadDoubleword, out, obj, offset);
1778 } else {
1779 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
1780 __ Addu(TMP, obj, TMP);
1781 __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset);
1782 }
1783 break;
1784 }
1785
1786 case Primitive::kPrimFloat: {
1787 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
1788 FRegister out = locations->Out().AsFpuRegister<FRegister>();
1789 if (index.IsConstant()) {
1790 size_t offset =
1791 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1792 __ LoadSFromOffset(out, obj, offset);
1793 } else {
1794 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
1795 __ Addu(TMP, obj, TMP);
1796 __ LoadSFromOffset(out, TMP, data_offset);
1797 }
1798 break;
1799 }
1800
1801 case Primitive::kPrimDouble: {
1802 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
1803 FRegister out = locations->Out().AsFpuRegister<FRegister>();
1804 if (index.IsConstant()) {
1805 size_t offset =
1806 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1807 __ LoadDFromOffset(out, obj, offset);
1808 } else {
1809 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
1810 __ Addu(TMP, obj, TMP);
1811 __ LoadDFromOffset(out, TMP, data_offset);
1812 }
1813 break;
1814 }
1815
1816 case Primitive::kPrimVoid:
1817 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1818 UNREACHABLE();
1819 }
1820 codegen_->MaybeRecordImplicitNullCheck(instruction);
1821}
1822
1823void LocationsBuilderMIPS::VisitArrayLength(HArrayLength* instruction) {
1824 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1825 locations->SetInAt(0, Location::RequiresRegister());
1826 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1827}
1828
1829void InstructionCodeGeneratorMIPS::VisitArrayLength(HArrayLength* instruction) {
1830 LocationSummary* locations = instruction->GetLocations();
1831 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1832 Register obj = locations->InAt(0).AsRegister<Register>();
1833 Register out = locations->Out().AsRegister<Register>();
1834 __ LoadFromOffset(kLoadWord, out, obj, offset);
1835 codegen_->MaybeRecordImplicitNullCheck(instruction);
1836}
1837
1838void LocationsBuilderMIPS::VisitArraySet(HArraySet* instruction) {
Pavle Batuta934808f2015-11-03 13:23:54 +01001839 bool needs_runtime_call = instruction->NeedsTypeCheck();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001840 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1841 instruction,
Pavle Batuta934808f2015-11-03 13:23:54 +01001842 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
1843 if (needs_runtime_call) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02001844 InvokeRuntimeCallingConvention calling_convention;
1845 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1846 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1847 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1848 } else {
1849 locations->SetInAt(0, Location::RequiresRegister());
1850 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1851 if (Primitive::IsFloatingPointType(instruction->InputAt(2)->GetType())) {
1852 locations->SetInAt(2, Location::RequiresFpuRegister());
1853 } else {
1854 locations->SetInAt(2, Location::RequiresRegister());
1855 }
1856 }
1857}
1858
1859void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
1860 LocationSummary* locations = instruction->GetLocations();
1861 Register obj = locations->InAt(0).AsRegister<Register>();
1862 Location index = locations->InAt(1);
1863 Primitive::Type value_type = instruction->GetComponentType();
1864 bool needs_runtime_call = locations->WillCall();
1865 bool needs_write_barrier =
1866 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
1867
1868 switch (value_type) {
1869 case Primitive::kPrimBoolean:
1870 case Primitive::kPrimByte: {
1871 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1872 Register value = locations->InAt(2).AsRegister<Register>();
1873 if (index.IsConstant()) {
1874 size_t offset =
1875 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1876 __ StoreToOffset(kStoreByte, value, obj, offset);
1877 } else {
1878 __ Addu(TMP, obj, index.AsRegister<Register>());
1879 __ StoreToOffset(kStoreByte, value, TMP, data_offset);
1880 }
1881 break;
1882 }
1883
1884 case Primitive::kPrimShort:
1885 case Primitive::kPrimChar: {
1886 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1887 Register value = locations->InAt(2).AsRegister<Register>();
1888 if (index.IsConstant()) {
1889 size_t offset =
1890 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1891 __ StoreToOffset(kStoreHalfword, value, obj, offset);
1892 } else {
1893 __ Sll(TMP, index.AsRegister<Register>(), TIMES_2);
1894 __ Addu(TMP, obj, TMP);
1895 __ StoreToOffset(kStoreHalfword, value, TMP, data_offset);
1896 }
1897 break;
1898 }
1899
1900 case Primitive::kPrimInt:
1901 case Primitive::kPrimNot: {
1902 if (!needs_runtime_call) {
1903 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1904 Register value = locations->InAt(2).AsRegister<Register>();
1905 if (index.IsConstant()) {
1906 size_t offset =
1907 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1908 __ StoreToOffset(kStoreWord, value, obj, offset);
1909 } else {
1910 DCHECK(index.IsRegister()) << index;
1911 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
1912 __ Addu(TMP, obj, TMP);
1913 __ StoreToOffset(kStoreWord, value, TMP, data_offset);
1914 }
1915 codegen_->MaybeRecordImplicitNullCheck(instruction);
1916 if (needs_write_barrier) {
1917 DCHECK_EQ(value_type, Primitive::kPrimNot);
1918 codegen_->MarkGCCard(obj, value);
1919 }
1920 } else {
1921 DCHECK_EQ(value_type, Primitive::kPrimNot);
1922 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
1923 instruction,
1924 instruction->GetDexPc(),
1925 nullptr,
1926 IsDirectEntrypoint(kQuickAputObject));
1927 CheckEntrypointTypes<kQuickAputObject, void, mirror::Array*, int32_t, mirror::Object*>();
1928 }
1929 break;
1930 }
1931
1932 case Primitive::kPrimLong: {
1933 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1934 Register value = locations->InAt(2).AsRegisterPairLow<Register>();
1935 if (index.IsConstant()) {
1936 size_t offset =
1937 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1938 __ StoreToOffset(kStoreDoubleword, value, obj, offset);
1939 } else {
1940 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
1941 __ Addu(TMP, obj, TMP);
1942 __ StoreToOffset(kStoreDoubleword, value, TMP, data_offset);
1943 }
1944 break;
1945 }
1946
1947 case Primitive::kPrimFloat: {
1948 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
1949 FRegister value = locations->InAt(2).AsFpuRegister<FRegister>();
1950 DCHECK(locations->InAt(2).IsFpuRegister());
1951 if (index.IsConstant()) {
1952 size_t offset =
1953 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1954 __ StoreSToOffset(value, obj, offset);
1955 } else {
1956 __ Sll(TMP, index.AsRegister<Register>(), TIMES_4);
1957 __ Addu(TMP, obj, TMP);
1958 __ StoreSToOffset(value, TMP, data_offset);
1959 }
1960 break;
1961 }
1962
1963 case Primitive::kPrimDouble: {
1964 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
1965 FRegister value = locations->InAt(2).AsFpuRegister<FRegister>();
1966 DCHECK(locations->InAt(2).IsFpuRegister());
1967 if (index.IsConstant()) {
1968 size_t offset =
1969 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1970 __ StoreDToOffset(value, obj, offset);
1971 } else {
1972 __ Sll(TMP, index.AsRegister<Register>(), TIMES_8);
1973 __ Addu(TMP, obj, TMP);
1974 __ StoreDToOffset(value, TMP, data_offset);
1975 }
1976 break;
1977 }
1978
1979 case Primitive::kPrimVoid:
1980 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1981 UNREACHABLE();
1982 }
1983
1984 // Ints and objects are handled in the switch.
1985 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) {
1986 codegen_->MaybeRecordImplicitNullCheck(instruction);
1987 }
1988}
1989
1990void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
1991 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
1992 ? LocationSummary::kCallOnSlowPath
1993 : LocationSummary::kNoCall;
1994 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
1995 locations->SetInAt(0, Location::RequiresRegister());
1996 locations->SetInAt(1, Location::RequiresRegister());
1997 if (instruction->HasUses()) {
1998 locations->SetOut(Location::SameAsFirstInput());
1999 }
2000}
2001
2002void InstructionCodeGeneratorMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
2003 LocationSummary* locations = instruction->GetLocations();
2004 BoundsCheckSlowPathMIPS* slow_path =
2005 new (GetGraph()->GetArena()) BoundsCheckSlowPathMIPS(instruction);
2006 codegen_->AddSlowPath(slow_path);
2007
2008 Register index = locations->InAt(0).AsRegister<Register>();
2009 Register length = locations->InAt(1).AsRegister<Register>();
2010
2011 // length is limited by the maximum positive signed 32-bit integer.
2012 // Unsigned comparison of length and index checks for index < 0
2013 // and for length <= index simultaneously.
2014 __ Bgeu(index, length, slow_path->GetEntryLabel());
2015}
2016
2017void LocationsBuilderMIPS::VisitCheckCast(HCheckCast* instruction) {
2018 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
2019 instruction,
2020 LocationSummary::kCallOnSlowPath);
2021 locations->SetInAt(0, Location::RequiresRegister());
2022 locations->SetInAt(1, Location::RequiresRegister());
2023 // Note that TypeCheckSlowPathMIPS uses this register too.
2024 locations->AddTemp(Location::RequiresRegister());
2025}
2026
2027void InstructionCodeGeneratorMIPS::VisitCheckCast(HCheckCast* instruction) {
2028 LocationSummary* locations = instruction->GetLocations();
2029 Register obj = locations->InAt(0).AsRegister<Register>();
2030 Register cls = locations->InAt(1).AsRegister<Register>();
2031 Register obj_cls = locations->GetTemp(0).AsRegister<Register>();
2032
2033 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction);
2034 codegen_->AddSlowPath(slow_path);
2035
2036 // TODO: avoid this check if we know obj is not null.
2037 __ Beqz(obj, slow_path->GetExitLabel());
2038 // Compare the class of `obj` with `cls`.
2039 __ LoadFromOffset(kLoadWord, obj_cls, obj, mirror::Object::ClassOffset().Int32Value());
2040 __ Bne(obj_cls, cls, slow_path->GetEntryLabel());
2041 __ Bind(slow_path->GetExitLabel());
2042}
2043
2044void LocationsBuilderMIPS::VisitClinitCheck(HClinitCheck* check) {
2045 LocationSummary* locations =
2046 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2047 locations->SetInAt(0, Location::RequiresRegister());
2048 if (check->HasUses()) {
2049 locations->SetOut(Location::SameAsFirstInput());
2050 }
2051}
2052
2053void InstructionCodeGeneratorMIPS::VisitClinitCheck(HClinitCheck* check) {
2054 // We assume the class is not null.
2055 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
2056 check->GetLoadClass(),
2057 check,
2058 check->GetDexPc(),
2059 true);
2060 codegen_->AddSlowPath(slow_path);
2061 GenerateClassInitializationCheck(slow_path,
2062 check->GetLocations()->InAt(0).AsRegister<Register>());
2063}
2064
2065void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
2066 Primitive::Type in_type = compare->InputAt(0)->GetType();
2067
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002068 LocationSummary* locations =
2069 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002070
2071 switch (in_type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002072 case Primitive::kPrimBoolean:
2073 case Primitive::kPrimByte:
2074 case Primitive::kPrimShort:
2075 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002076 case Primitive::kPrimInt:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002077 case Primitive::kPrimLong:
2078 locations->SetInAt(0, Location::RequiresRegister());
2079 locations->SetInAt(1, Location::RequiresRegister());
2080 // Output overlaps because it is written before doing the low comparison.
2081 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
2082 break;
2083
2084 case Primitive::kPrimFloat:
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002085 case Primitive::kPrimDouble:
2086 locations->SetInAt(0, Location::RequiresFpuRegister());
2087 locations->SetInAt(1, Location::RequiresFpuRegister());
2088 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002089 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002090
2091 default:
2092 LOG(FATAL) << "Unexpected type for compare operation " << in_type;
2093 }
2094}
2095
2096void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
2097 LocationSummary* locations = instruction->GetLocations();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002098 Register res = locations->Out().AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002099 Primitive::Type in_type = instruction->InputAt(0)->GetType();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002100 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002101
2102 // 0 if: left == right
2103 // 1 if: left > right
2104 // -1 if: left < right
2105 switch (in_type) {
Roland Levillaina5c4a402016-03-15 15:02:50 +00002106 case Primitive::kPrimBoolean:
2107 case Primitive::kPrimByte:
2108 case Primitive::kPrimShort:
2109 case Primitive::kPrimChar:
Aart Bika19616e2016-02-01 18:57:58 -08002110 case Primitive::kPrimInt: {
2111 Register lhs = locations->InAt(0).AsRegister<Register>();
2112 Register rhs = locations->InAt(1).AsRegister<Register>();
2113 __ Slt(TMP, lhs, rhs);
2114 __ Slt(res, rhs, lhs);
2115 __ Subu(res, res, TMP);
2116 break;
2117 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002118 case Primitive::kPrimLong: {
2119 MipsLabel done;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002120 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2121 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2122 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
2123 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
2124 // TODO: more efficient (direct) comparison with a constant.
2125 __ Slt(TMP, lhs_high, rhs_high);
2126 __ Slt(AT, rhs_high, lhs_high); // Inverted: is actually gt.
2127 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
2128 __ Bnez(res, &done); // If we compared ==, check if lower bits are also equal.
2129 __ Sltu(TMP, lhs_low, rhs_low);
2130 __ Sltu(AT, rhs_low, lhs_low); // Inverted: is actually gt.
2131 __ Subu(res, AT, TMP); // Result -1:1:0 for [ <, >, == ].
2132 __ Bind(&done);
2133 break;
2134 }
2135
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002136 case Primitive::kPrimFloat: {
Roland Levillain32ca3752016-02-17 16:49:37 +00002137 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002138 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2139 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2140 MipsLabel done;
2141 if (isR6) {
2142 __ CmpEqS(FTMP, lhs, rhs);
2143 __ LoadConst32(res, 0);
2144 __ Bc1nez(FTMP, &done);
2145 if (gt_bias) {
2146 __ CmpLtS(FTMP, lhs, rhs);
2147 __ LoadConst32(res, -1);
2148 __ Bc1nez(FTMP, &done);
2149 __ LoadConst32(res, 1);
2150 } else {
2151 __ CmpLtS(FTMP, rhs, lhs);
2152 __ LoadConst32(res, 1);
2153 __ Bc1nez(FTMP, &done);
2154 __ LoadConst32(res, -1);
2155 }
2156 } else {
2157 if (gt_bias) {
2158 __ ColtS(0, lhs, rhs);
2159 __ LoadConst32(res, -1);
2160 __ Bc1t(0, &done);
2161 __ CeqS(0, lhs, rhs);
2162 __ LoadConst32(res, 1);
2163 __ Movt(res, ZERO, 0);
2164 } else {
2165 __ ColtS(0, rhs, lhs);
2166 __ LoadConst32(res, 1);
2167 __ Bc1t(0, &done);
2168 __ CeqS(0, lhs, rhs);
2169 __ LoadConst32(res, -1);
2170 __ Movt(res, ZERO, 0);
2171 }
2172 }
2173 __ Bind(&done);
2174 break;
2175 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002176 case Primitive::kPrimDouble: {
Roland Levillain32ca3752016-02-17 16:49:37 +00002177 bool gt_bias = instruction->IsGtBias();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002178 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2179 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2180 MipsLabel done;
2181 if (isR6) {
2182 __ CmpEqD(FTMP, lhs, rhs);
2183 __ LoadConst32(res, 0);
2184 __ Bc1nez(FTMP, &done);
2185 if (gt_bias) {
2186 __ CmpLtD(FTMP, lhs, rhs);
2187 __ LoadConst32(res, -1);
2188 __ Bc1nez(FTMP, &done);
2189 __ LoadConst32(res, 1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002190 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002191 __ CmpLtD(FTMP, rhs, lhs);
2192 __ LoadConst32(res, 1);
2193 __ Bc1nez(FTMP, &done);
2194 __ LoadConst32(res, -1);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002195 }
2196 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002197 if (gt_bias) {
2198 __ ColtD(0, lhs, rhs);
2199 __ LoadConst32(res, -1);
2200 __ Bc1t(0, &done);
2201 __ CeqD(0, lhs, rhs);
2202 __ LoadConst32(res, 1);
2203 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002204 } else {
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002205 __ ColtD(0, rhs, lhs);
2206 __ LoadConst32(res, 1);
2207 __ Bc1t(0, &done);
2208 __ CeqD(0, lhs, rhs);
2209 __ LoadConst32(res, -1);
2210 __ Movt(res, ZERO, 0);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002211 }
2212 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002213 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002214 break;
2215 }
2216
2217 default:
2218 LOG(FATAL) << "Unimplemented compare type " << in_type;
2219 }
2220}
2221
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002222void LocationsBuilderMIPS::HandleCondition(HCondition* instruction) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002223 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002224 switch (instruction->InputAt(0)->GetType()) {
2225 default:
2226 case Primitive::kPrimLong:
2227 locations->SetInAt(0, Location::RequiresRegister());
2228 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
2229 break;
2230
2231 case Primitive::kPrimFloat:
2232 case Primitive::kPrimDouble:
2233 locations->SetInAt(0, Location::RequiresFpuRegister());
2234 locations->SetInAt(1, Location::RequiresFpuRegister());
2235 break;
2236 }
David Brazdilb3e773e2016-01-26 11:28:37 +00002237 if (!instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002238 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2239 }
2240}
2241
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00002242void InstructionCodeGeneratorMIPS::HandleCondition(HCondition* instruction) {
David Brazdilb3e773e2016-01-26 11:28:37 +00002243 if (instruction->IsEmittedAtUseSite()) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002244 return;
2245 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002246
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002247 Primitive::Type type = instruction->InputAt(0)->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002248 LocationSummary* locations = instruction->GetLocations();
2249 Register dst = locations->Out().AsRegister<Register>();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002250 MipsLabel true_label;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002251
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002252 switch (type) {
2253 default:
2254 // Integer case.
2255 GenerateIntCompare(instruction->GetCondition(), locations);
2256 return;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002257
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002258 case Primitive::kPrimLong:
2259 // TODO: don't use branches.
2260 GenerateLongCompareAndBranch(instruction->GetCondition(), locations, &true_label);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002261 break;
2262
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002263 case Primitive::kPrimFloat:
2264 case Primitive::kPrimDouble:
2265 // TODO: don't use branches.
2266 GenerateFpCompareAndBranch(instruction->GetCondition(),
2267 instruction->IsGtBias(),
2268 type,
2269 locations,
2270 &true_label);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002271 break;
2272 }
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002273
2274 // Convert the branches into the result.
2275 MipsLabel done;
2276
2277 // False case: result = 0.
2278 __ LoadConst32(dst, 0);
2279 __ B(&done);
2280
2281 // True case: result = 1.
2282 __ Bind(&true_label);
2283 __ LoadConst32(dst, 1);
2284 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002285}
2286
Alexey Frunze7e99e052015-11-24 19:28:01 -08002287void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2288 DCHECK(instruction->IsDiv() || instruction->IsRem());
2289 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2290
2291 LocationSummary* locations = instruction->GetLocations();
2292 Location second = locations->InAt(1);
2293 DCHECK(second.IsConstant());
2294
2295 Register out = locations->Out().AsRegister<Register>();
2296 Register dividend = locations->InAt(0).AsRegister<Register>();
2297 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2298 DCHECK(imm == 1 || imm == -1);
2299
2300 if (instruction->IsRem()) {
2301 __ Move(out, ZERO);
2302 } else {
2303 if (imm == -1) {
2304 __ Subu(out, ZERO, dividend);
2305 } else if (out != dividend) {
2306 __ Move(out, dividend);
2307 }
2308 }
2309}
2310
2311void InstructionCodeGeneratorMIPS::DivRemByPowerOfTwo(HBinaryOperation* instruction) {
2312 DCHECK(instruction->IsDiv() || instruction->IsRem());
2313 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2314
2315 LocationSummary* locations = instruction->GetLocations();
2316 Location second = locations->InAt(1);
2317 DCHECK(second.IsConstant());
2318
2319 Register out = locations->Out().AsRegister<Register>();
2320 Register dividend = locations->InAt(0).AsRegister<Register>();
2321 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002322 uint32_t abs_imm = static_cast<uint32_t>(AbsOrMin(imm));
Alexey Frunze7e99e052015-11-24 19:28:01 -08002323 int ctz_imm = CTZ(abs_imm);
2324
2325 if (instruction->IsDiv()) {
2326 if (ctz_imm == 1) {
2327 // Fast path for division by +/-2, which is very common.
2328 __ Srl(TMP, dividend, 31);
2329 } else {
2330 __ Sra(TMP, dividend, 31);
2331 __ Srl(TMP, TMP, 32 - ctz_imm);
2332 }
2333 __ Addu(out, dividend, TMP);
2334 __ Sra(out, out, ctz_imm);
2335 if (imm < 0) {
2336 __ Subu(out, ZERO, out);
2337 }
2338 } else {
2339 if (ctz_imm == 1) {
2340 // Fast path for modulo +/-2, which is very common.
2341 __ Sra(TMP, dividend, 31);
2342 __ Subu(out, dividend, TMP);
2343 __ Andi(out, out, 1);
2344 __ Addu(out, out, TMP);
2345 } else {
2346 __ Sra(TMP, dividend, 31);
2347 __ Srl(TMP, TMP, 32 - ctz_imm);
2348 __ Addu(out, dividend, TMP);
2349 if (IsUint<16>(abs_imm - 1)) {
2350 __ Andi(out, out, abs_imm - 1);
2351 } else {
2352 __ Sll(out, out, 32 - ctz_imm);
2353 __ Srl(out, out, 32 - ctz_imm);
2354 }
2355 __ Subu(out, out, TMP);
2356 }
2357 }
2358}
2359
2360void InstructionCodeGeneratorMIPS::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2361 DCHECK(instruction->IsDiv() || instruction->IsRem());
2362 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2363
2364 LocationSummary* locations = instruction->GetLocations();
2365 Location second = locations->InAt(1);
2366 DCHECK(second.IsConstant());
2367
2368 Register out = locations->Out().AsRegister<Register>();
2369 Register dividend = locations->InAt(0).AsRegister<Register>();
2370 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2371
2372 int64_t magic;
2373 int shift;
2374 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2375
2376 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
2377
2378 __ LoadConst32(TMP, magic);
2379 if (isR6) {
2380 __ MuhR6(TMP, dividend, TMP);
2381 } else {
2382 __ MultR2(dividend, TMP);
2383 __ Mfhi(TMP);
2384 }
2385 if (imm > 0 && magic < 0) {
2386 __ Addu(TMP, TMP, dividend);
2387 } else if (imm < 0 && magic > 0) {
2388 __ Subu(TMP, TMP, dividend);
2389 }
2390
2391 if (shift != 0) {
2392 __ Sra(TMP, TMP, shift);
2393 }
2394
2395 if (instruction->IsDiv()) {
2396 __ Sra(out, TMP, 31);
2397 __ Subu(out, TMP, out);
2398 } else {
2399 __ Sra(AT, TMP, 31);
2400 __ Subu(AT, TMP, AT);
2401 __ LoadConst32(TMP, imm);
2402 if (isR6) {
2403 __ MulR6(TMP, AT, TMP);
2404 } else {
2405 __ MulR2(TMP, AT, TMP);
2406 }
2407 __ Subu(out, dividend, TMP);
2408 }
2409}
2410
2411void InstructionCodeGeneratorMIPS::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2412 DCHECK(instruction->IsDiv() || instruction->IsRem());
2413 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimInt);
2414
2415 LocationSummary* locations = instruction->GetLocations();
2416 Register out = locations->Out().AsRegister<Register>();
2417 Location second = locations->InAt(1);
2418
2419 if (second.IsConstant()) {
2420 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
2421 if (imm == 0) {
2422 // Do not generate anything. DivZeroCheck would prevent any code to be executed.
2423 } else if (imm == 1 || imm == -1) {
2424 DivRemOneOrMinusOne(instruction);
Nicolas Geoffray68f62892016-01-04 08:39:49 +00002425 } else if (IsPowerOfTwo(AbsOrMin(imm))) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08002426 DivRemByPowerOfTwo(instruction);
2427 } else {
2428 DCHECK(imm <= -2 || imm >= 2);
2429 GenerateDivRemWithAnyConstant(instruction);
2430 }
2431 } else {
2432 Register dividend = locations->InAt(0).AsRegister<Register>();
2433 Register divisor = second.AsRegister<Register>();
2434 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
2435 if (instruction->IsDiv()) {
2436 if (isR6) {
2437 __ DivR6(out, dividend, divisor);
2438 } else {
2439 __ DivR2(out, dividend, divisor);
2440 }
2441 } else {
2442 if (isR6) {
2443 __ ModR6(out, dividend, divisor);
2444 } else {
2445 __ ModR2(out, dividend, divisor);
2446 }
2447 }
2448 }
2449}
2450
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002451void LocationsBuilderMIPS::VisitDiv(HDiv* div) {
2452 Primitive::Type type = div->GetResultType();
2453 LocationSummary::CallKind call_kind = (type == Primitive::kPrimLong)
2454 ? LocationSummary::kCall
2455 : LocationSummary::kNoCall;
2456
2457 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2458
2459 switch (type) {
2460 case Primitive::kPrimInt:
2461 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08002462 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002463 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2464 break;
2465
2466 case Primitive::kPrimLong: {
2467 InvokeRuntimeCallingConvention calling_convention;
2468 locations->SetInAt(0, Location::RegisterPairLocation(
2469 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2470 locations->SetInAt(1, Location::RegisterPairLocation(
2471 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2472 locations->SetOut(calling_convention.GetReturnLocation(type));
2473 break;
2474 }
2475
2476 case Primitive::kPrimFloat:
2477 case Primitive::kPrimDouble:
2478 locations->SetInAt(0, Location::RequiresFpuRegister());
2479 locations->SetInAt(1, Location::RequiresFpuRegister());
2480 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2481 break;
2482
2483 default:
2484 LOG(FATAL) << "Unexpected div type " << type;
2485 }
2486}
2487
2488void InstructionCodeGeneratorMIPS::VisitDiv(HDiv* instruction) {
2489 Primitive::Type type = instruction->GetType();
2490 LocationSummary* locations = instruction->GetLocations();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002491
2492 switch (type) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08002493 case Primitive::kPrimInt:
2494 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002495 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002496 case Primitive::kPrimLong: {
2497 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv),
2498 instruction,
2499 instruction->GetDexPc(),
2500 nullptr,
2501 IsDirectEntrypoint(kQuickLdiv));
2502 CheckEntrypointTypes<kQuickLdiv, int64_t, int64_t, int64_t>();
2503 break;
2504 }
2505 case Primitive::kPrimFloat:
2506 case Primitive::kPrimDouble: {
2507 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
2508 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
2509 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
2510 if (type == Primitive::kPrimFloat) {
2511 __ DivS(dst, lhs, rhs);
2512 } else {
2513 __ DivD(dst, lhs, rhs);
2514 }
2515 break;
2516 }
2517 default:
2518 LOG(FATAL) << "Unexpected div type " << type;
2519 }
2520}
2521
2522void LocationsBuilderMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2523 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
2524 ? LocationSummary::kCallOnSlowPath
2525 : LocationSummary::kNoCall;
2526 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
2527 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2528 if (instruction->HasUses()) {
2529 locations->SetOut(Location::SameAsFirstInput());
2530 }
2531}
2532
2533void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2534 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathMIPS(instruction);
2535 codegen_->AddSlowPath(slow_path);
2536 Location value = instruction->GetLocations()->InAt(0);
2537 Primitive::Type type = instruction->GetType();
2538
2539 switch (type) {
Nicolas Geoffraye5671612016-03-16 11:03:54 +00002540 case Primitive::kPrimBoolean:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02002541 case Primitive::kPrimByte:
2542 case Primitive::kPrimChar:
2543 case Primitive::kPrimShort:
2544 case Primitive::kPrimInt: {
2545 if (value.IsConstant()) {
2546 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2547 __ B(slow_path->GetEntryLabel());
2548 } else {
2549 // A division by a non-null constant is valid. We don't need to perform
2550 // any check, so simply fall through.
2551 }
2552 } else {
2553 DCHECK(value.IsRegister()) << value;
2554 __ Beqz(value.AsRegister<Register>(), slow_path->GetEntryLabel());
2555 }
2556 break;
2557 }
2558 case Primitive::kPrimLong: {
2559 if (value.IsConstant()) {
2560 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2561 __ B(slow_path->GetEntryLabel());
2562 } else {
2563 // A division by a non-null constant is valid. We don't need to perform
2564 // any check, so simply fall through.
2565 }
2566 } else {
2567 DCHECK(value.IsRegisterPair()) << value;
2568 __ Or(TMP, value.AsRegisterPairHigh<Register>(), value.AsRegisterPairLow<Register>());
2569 __ Beqz(TMP, slow_path->GetEntryLabel());
2570 }
2571 break;
2572 }
2573 default:
2574 LOG(FATAL) << "Unexpected type " << type << " for DivZeroCheck.";
2575 }
2576}
2577
2578void LocationsBuilderMIPS::VisitDoubleConstant(HDoubleConstant* constant) {
2579 LocationSummary* locations =
2580 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2581 locations->SetOut(Location::ConstantLocation(constant));
2582}
2583
2584void InstructionCodeGeneratorMIPS::VisitDoubleConstant(HDoubleConstant* cst ATTRIBUTE_UNUSED) {
2585 // Will be generated at use site.
2586}
2587
2588void LocationsBuilderMIPS::VisitExit(HExit* exit) {
2589 exit->SetLocations(nullptr);
2590}
2591
2592void InstructionCodeGeneratorMIPS::VisitExit(HExit* exit ATTRIBUTE_UNUSED) {
2593}
2594
2595void LocationsBuilderMIPS::VisitFloatConstant(HFloatConstant* constant) {
2596 LocationSummary* locations =
2597 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
2598 locations->SetOut(Location::ConstantLocation(constant));
2599}
2600
2601void InstructionCodeGeneratorMIPS::VisitFloatConstant(HFloatConstant* constant ATTRIBUTE_UNUSED) {
2602 // Will be generated at use site.
2603}
2604
2605void LocationsBuilderMIPS::VisitGoto(HGoto* got) {
2606 got->SetLocations(nullptr);
2607}
2608
2609void InstructionCodeGeneratorMIPS::HandleGoto(HInstruction* got, HBasicBlock* successor) {
2610 DCHECK(!successor->IsExitBlock());
2611 HBasicBlock* block = got->GetBlock();
2612 HInstruction* previous = got->GetPrevious();
2613 HLoopInformation* info = block->GetLoopInformation();
2614
2615 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
2616 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
2617 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
2618 return;
2619 }
2620 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
2621 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
2622 }
2623 if (!codegen_->GoesToNextBlock(block, successor)) {
2624 __ B(codegen_->GetLabelOf(successor));
2625 }
2626}
2627
2628void InstructionCodeGeneratorMIPS::VisitGoto(HGoto* got) {
2629 HandleGoto(got, got->GetSuccessor());
2630}
2631
2632void LocationsBuilderMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
2633 try_boundary->SetLocations(nullptr);
2634}
2635
2636void InstructionCodeGeneratorMIPS::VisitTryBoundary(HTryBoundary* try_boundary) {
2637 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
2638 if (!successor->IsExitBlock()) {
2639 HandleGoto(try_boundary, successor);
2640 }
2641}
2642
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08002643void InstructionCodeGeneratorMIPS::GenerateIntCompare(IfCondition cond,
2644 LocationSummary* locations) {
2645 Register dst = locations->Out().AsRegister<Register>();
2646 Register lhs = locations->InAt(0).AsRegister<Register>();
2647 Location rhs_location = locations->InAt(1);
2648 Register rhs_reg = ZERO;
2649 int64_t rhs_imm = 0;
2650 bool use_imm = rhs_location.IsConstant();
2651 if (use_imm) {
2652 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
2653 } else {
2654 rhs_reg = rhs_location.AsRegister<Register>();
2655 }
2656
2657 switch (cond) {
2658 case kCondEQ:
2659 case kCondNE:
2660 if (use_imm && IsUint<16>(rhs_imm)) {
2661 __ Xori(dst, lhs, rhs_imm);
2662 } else {
2663 if (use_imm) {
2664 rhs_reg = TMP;
2665 __ LoadConst32(rhs_reg, rhs_imm);
2666 }
2667 __ Xor(dst, lhs, rhs_reg);
2668 }
2669 if (cond == kCondEQ) {
2670 __ Sltiu(dst, dst, 1);
2671 } else {
2672 __ Sltu(dst, ZERO, dst);
2673 }
2674 break;
2675
2676 case kCondLT:
2677 case kCondGE:
2678 if (use_imm && IsInt<16>(rhs_imm)) {
2679 __ Slti(dst, lhs, rhs_imm);
2680 } else {
2681 if (use_imm) {
2682 rhs_reg = TMP;
2683 __ LoadConst32(rhs_reg, rhs_imm);
2684 }
2685 __ Slt(dst, lhs, rhs_reg);
2686 }
2687 if (cond == kCondGE) {
2688 // Simulate lhs >= rhs via !(lhs < rhs) since there's
2689 // only the slt instruction but no sge.
2690 __ Xori(dst, dst, 1);
2691 }
2692 break;
2693
2694 case kCondLE:
2695 case kCondGT:
2696 if (use_imm && IsInt<16>(rhs_imm + 1)) {
2697 // Simulate lhs <= rhs via lhs < rhs + 1.
2698 __ Slti(dst, lhs, rhs_imm + 1);
2699 if (cond == kCondGT) {
2700 // Simulate lhs > rhs via !(lhs <= rhs) since there's
2701 // only the slti instruction but no sgti.
2702 __ Xori(dst, dst, 1);
2703 }
2704 } else {
2705 if (use_imm) {
2706 rhs_reg = TMP;
2707 __ LoadConst32(rhs_reg, rhs_imm);
2708 }
2709 __ Slt(dst, rhs_reg, lhs);
2710 if (cond == kCondLE) {
2711 // Simulate lhs <= rhs via !(rhs < lhs) since there's
2712 // only the slt instruction but no sle.
2713 __ Xori(dst, dst, 1);
2714 }
2715 }
2716 break;
2717
2718 case kCondB:
2719 case kCondAE:
2720 if (use_imm && IsInt<16>(rhs_imm)) {
2721 // Sltiu sign-extends its 16-bit immediate operand before
2722 // the comparison and thus lets us compare directly with
2723 // unsigned values in the ranges [0, 0x7fff] and
2724 // [0xffff8000, 0xffffffff].
2725 __ Sltiu(dst, lhs, rhs_imm);
2726 } else {
2727 if (use_imm) {
2728 rhs_reg = TMP;
2729 __ LoadConst32(rhs_reg, rhs_imm);
2730 }
2731 __ Sltu(dst, lhs, rhs_reg);
2732 }
2733 if (cond == kCondAE) {
2734 // Simulate lhs >= rhs via !(lhs < rhs) since there's
2735 // only the sltu instruction but no sgeu.
2736 __ Xori(dst, dst, 1);
2737 }
2738 break;
2739
2740 case kCondBE:
2741 case kCondA:
2742 if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) {
2743 // Simulate lhs <= rhs via lhs < rhs + 1.
2744 // Note that this only works if rhs + 1 does not overflow
2745 // to 0, hence the check above.
2746 // Sltiu sign-extends its 16-bit immediate operand before
2747 // the comparison and thus lets us compare directly with
2748 // unsigned values in the ranges [0, 0x7fff] and
2749 // [0xffff8000, 0xffffffff].
2750 __ Sltiu(dst, lhs, rhs_imm + 1);
2751 if (cond == kCondA) {
2752 // Simulate lhs > rhs via !(lhs <= rhs) since there's
2753 // only the sltiu instruction but no sgtiu.
2754 __ Xori(dst, dst, 1);
2755 }
2756 } else {
2757 if (use_imm) {
2758 rhs_reg = TMP;
2759 __ LoadConst32(rhs_reg, rhs_imm);
2760 }
2761 __ Sltu(dst, rhs_reg, lhs);
2762 if (cond == kCondBE) {
2763 // Simulate lhs <= rhs via !(rhs < lhs) since there's
2764 // only the sltu instruction but no sleu.
2765 __ Xori(dst, dst, 1);
2766 }
2767 }
2768 break;
2769 }
2770}
2771
2772void InstructionCodeGeneratorMIPS::GenerateIntCompareAndBranch(IfCondition cond,
2773 LocationSummary* locations,
2774 MipsLabel* label) {
2775 Register lhs = locations->InAt(0).AsRegister<Register>();
2776 Location rhs_location = locations->InAt(1);
2777 Register rhs_reg = ZERO;
2778 int32_t rhs_imm = 0;
2779 bool use_imm = rhs_location.IsConstant();
2780 if (use_imm) {
2781 rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
2782 } else {
2783 rhs_reg = rhs_location.AsRegister<Register>();
2784 }
2785
2786 if (use_imm && rhs_imm == 0) {
2787 switch (cond) {
2788 case kCondEQ:
2789 case kCondBE: // <= 0 if zero
2790 __ Beqz(lhs, label);
2791 break;
2792 case kCondNE:
2793 case kCondA: // > 0 if non-zero
2794 __ Bnez(lhs, label);
2795 break;
2796 case kCondLT:
2797 __ Bltz(lhs, label);
2798 break;
2799 case kCondGE:
2800 __ Bgez(lhs, label);
2801 break;
2802 case kCondLE:
2803 __ Blez(lhs, label);
2804 break;
2805 case kCondGT:
2806 __ Bgtz(lhs, label);
2807 break;
2808 case kCondB: // always false
2809 break;
2810 case kCondAE: // always true
2811 __ B(label);
2812 break;
2813 }
2814 } else {
2815 if (use_imm) {
2816 // TODO: more efficient comparison with 16-bit constants without loading them into TMP.
2817 rhs_reg = TMP;
2818 __ LoadConst32(rhs_reg, rhs_imm);
2819 }
2820 switch (cond) {
2821 case kCondEQ:
2822 __ Beq(lhs, rhs_reg, label);
2823 break;
2824 case kCondNE:
2825 __ Bne(lhs, rhs_reg, label);
2826 break;
2827 case kCondLT:
2828 __ Blt(lhs, rhs_reg, label);
2829 break;
2830 case kCondGE:
2831 __ Bge(lhs, rhs_reg, label);
2832 break;
2833 case kCondLE:
2834 __ Bge(rhs_reg, lhs, label);
2835 break;
2836 case kCondGT:
2837 __ Blt(rhs_reg, lhs, label);
2838 break;
2839 case kCondB:
2840 __ Bltu(lhs, rhs_reg, label);
2841 break;
2842 case kCondAE:
2843 __ Bgeu(lhs, rhs_reg, label);
2844 break;
2845 case kCondBE:
2846 __ Bgeu(rhs_reg, lhs, label);
2847 break;
2848 case kCondA:
2849 __ Bltu(rhs_reg, lhs, label);
2850 break;
2851 }
2852 }
2853}
2854
2855void InstructionCodeGeneratorMIPS::GenerateLongCompareAndBranch(IfCondition cond,
2856 LocationSummary* locations,
2857 MipsLabel* label) {
2858 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
2859 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
2860 Location rhs_location = locations->InAt(1);
2861 Register rhs_high = ZERO;
2862 Register rhs_low = ZERO;
2863 int64_t imm = 0;
2864 uint32_t imm_high = 0;
2865 uint32_t imm_low = 0;
2866 bool use_imm = rhs_location.IsConstant();
2867 if (use_imm) {
2868 imm = rhs_location.GetConstant()->AsLongConstant()->GetValue();
2869 imm_high = High32Bits(imm);
2870 imm_low = Low32Bits(imm);
2871 } else {
2872 rhs_high = rhs_location.AsRegisterPairHigh<Register>();
2873 rhs_low = rhs_location.AsRegisterPairLow<Register>();
2874 }
2875
2876 if (use_imm && imm == 0) {
2877 switch (cond) {
2878 case kCondEQ:
2879 case kCondBE: // <= 0 if zero
2880 __ Or(TMP, lhs_high, lhs_low);
2881 __ Beqz(TMP, label);
2882 break;
2883 case kCondNE:
2884 case kCondA: // > 0 if non-zero
2885 __ Or(TMP, lhs_high, lhs_low);
2886 __ Bnez(TMP, label);
2887 break;
2888 case kCondLT:
2889 __ Bltz(lhs_high, label);
2890 break;
2891 case kCondGE:
2892 __ Bgez(lhs_high, label);
2893 break;
2894 case kCondLE:
2895 __ Or(TMP, lhs_high, lhs_low);
2896 __ Sra(AT, lhs_high, 31);
2897 __ Bgeu(AT, TMP, label);
2898 break;
2899 case kCondGT:
2900 __ Or(TMP, lhs_high, lhs_low);
2901 __ Sra(AT, lhs_high, 31);
2902 __ Bltu(AT, TMP, label);
2903 break;
2904 case kCondB: // always false
2905 break;
2906 case kCondAE: // always true
2907 __ B(label);
2908 break;
2909 }
2910 } else if (use_imm) {
2911 // TODO: more efficient comparison with constants without loading them into TMP/AT.
2912 switch (cond) {
2913 case kCondEQ:
2914 __ LoadConst32(TMP, imm_high);
2915 __ Xor(TMP, TMP, lhs_high);
2916 __ LoadConst32(AT, imm_low);
2917 __ Xor(AT, AT, lhs_low);
2918 __ Or(TMP, TMP, AT);
2919 __ Beqz(TMP, label);
2920 break;
2921 case kCondNE:
2922 __ LoadConst32(TMP, imm_high);
2923 __ Xor(TMP, TMP, lhs_high);
2924 __ LoadConst32(AT, imm_low);
2925 __ Xor(AT, AT, lhs_low);
2926 __ Or(TMP, TMP, AT);
2927 __ Bnez(TMP, label);
2928 break;
2929 case kCondLT:
2930 __ LoadConst32(TMP, imm_high);
2931 __ Blt(lhs_high, TMP, label);
2932 __ Slt(TMP, TMP, lhs_high);
2933 __ LoadConst32(AT, imm_low);
2934 __ Sltu(AT, lhs_low, AT);
2935 __ Blt(TMP, AT, label);
2936 break;
2937 case kCondGE:
2938 __ LoadConst32(TMP, imm_high);
2939 __ Blt(TMP, lhs_high, label);
2940 __ Slt(TMP, lhs_high, TMP);
2941 __ LoadConst32(AT, imm_low);
2942 __ Sltu(AT, lhs_low, AT);
2943 __ Or(TMP, TMP, AT);
2944 __ Beqz(TMP, label);
2945 break;
2946 case kCondLE:
2947 __ LoadConst32(TMP, imm_high);
2948 __ Blt(lhs_high, TMP, label);
2949 __ Slt(TMP, TMP, lhs_high);
2950 __ LoadConst32(AT, imm_low);
2951 __ Sltu(AT, AT, lhs_low);
2952 __ Or(TMP, TMP, AT);
2953 __ Beqz(TMP, label);
2954 break;
2955 case kCondGT:
2956 __ LoadConst32(TMP, imm_high);
2957 __ Blt(TMP, lhs_high, label);
2958 __ Slt(TMP, lhs_high, TMP);
2959 __ LoadConst32(AT, imm_low);
2960 __ Sltu(AT, AT, lhs_low);
2961 __ Blt(TMP, AT, label);
2962 break;
2963 case kCondB:
2964 __ LoadConst32(TMP, imm_high);
2965 __ Bltu(lhs_high, TMP, label);
2966 __ Sltu(TMP, TMP, lhs_high);
2967 __ LoadConst32(AT, imm_low);
2968 __ Sltu(AT, lhs_low, AT);
2969 __ Blt(TMP, AT, label);
2970 break;
2971 case kCondAE:
2972 __ LoadConst32(TMP, imm_high);
2973 __ Bltu(TMP, lhs_high, label);
2974 __ Sltu(TMP, lhs_high, TMP);
2975 __ LoadConst32(AT, imm_low);
2976 __ Sltu(AT, lhs_low, AT);
2977 __ Or(TMP, TMP, AT);
2978 __ Beqz(TMP, label);
2979 break;
2980 case kCondBE:
2981 __ LoadConst32(TMP, imm_high);
2982 __ Bltu(lhs_high, TMP, label);
2983 __ Sltu(TMP, TMP, lhs_high);
2984 __ LoadConst32(AT, imm_low);
2985 __ Sltu(AT, AT, lhs_low);
2986 __ Or(TMP, TMP, AT);
2987 __ Beqz(TMP, label);
2988 break;
2989 case kCondA:
2990 __ LoadConst32(TMP, imm_high);
2991 __ Bltu(TMP, lhs_high, label);
2992 __ Sltu(TMP, lhs_high, TMP);
2993 __ LoadConst32(AT, imm_low);
2994 __ Sltu(AT, AT, lhs_low);
2995 __ Blt(TMP, AT, label);
2996 break;
2997 }
2998 } else {
2999 switch (cond) {
3000 case kCondEQ:
3001 __ Xor(TMP, lhs_high, rhs_high);
3002 __ Xor(AT, lhs_low, rhs_low);
3003 __ Or(TMP, TMP, AT);
3004 __ Beqz(TMP, label);
3005 break;
3006 case kCondNE:
3007 __ Xor(TMP, lhs_high, rhs_high);
3008 __ Xor(AT, lhs_low, rhs_low);
3009 __ Or(TMP, TMP, AT);
3010 __ Bnez(TMP, label);
3011 break;
3012 case kCondLT:
3013 __ Blt(lhs_high, rhs_high, label);
3014 __ Slt(TMP, rhs_high, lhs_high);
3015 __ Sltu(AT, lhs_low, rhs_low);
3016 __ Blt(TMP, AT, label);
3017 break;
3018 case kCondGE:
3019 __ Blt(rhs_high, lhs_high, label);
3020 __ Slt(TMP, lhs_high, rhs_high);
3021 __ Sltu(AT, lhs_low, rhs_low);
3022 __ Or(TMP, TMP, AT);
3023 __ Beqz(TMP, label);
3024 break;
3025 case kCondLE:
3026 __ Blt(lhs_high, rhs_high, label);
3027 __ Slt(TMP, rhs_high, lhs_high);
3028 __ Sltu(AT, rhs_low, lhs_low);
3029 __ Or(TMP, TMP, AT);
3030 __ Beqz(TMP, label);
3031 break;
3032 case kCondGT:
3033 __ Blt(rhs_high, lhs_high, label);
3034 __ Slt(TMP, lhs_high, rhs_high);
3035 __ Sltu(AT, rhs_low, lhs_low);
3036 __ Blt(TMP, AT, label);
3037 break;
3038 case kCondB:
3039 __ Bltu(lhs_high, rhs_high, label);
3040 __ Sltu(TMP, rhs_high, lhs_high);
3041 __ Sltu(AT, lhs_low, rhs_low);
3042 __ Blt(TMP, AT, label);
3043 break;
3044 case kCondAE:
3045 __ Bltu(rhs_high, lhs_high, label);
3046 __ Sltu(TMP, lhs_high, rhs_high);
3047 __ Sltu(AT, lhs_low, rhs_low);
3048 __ Or(TMP, TMP, AT);
3049 __ Beqz(TMP, label);
3050 break;
3051 case kCondBE:
3052 __ Bltu(lhs_high, rhs_high, label);
3053 __ Sltu(TMP, rhs_high, lhs_high);
3054 __ Sltu(AT, rhs_low, lhs_low);
3055 __ Or(TMP, TMP, AT);
3056 __ Beqz(TMP, label);
3057 break;
3058 case kCondA:
3059 __ Bltu(rhs_high, lhs_high, label);
3060 __ Sltu(TMP, lhs_high, rhs_high);
3061 __ Sltu(AT, rhs_low, lhs_low);
3062 __ Blt(TMP, AT, label);
3063 break;
3064 }
3065 }
3066}
3067
3068void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
3069 bool gt_bias,
3070 Primitive::Type type,
3071 LocationSummary* locations,
3072 MipsLabel* label) {
3073 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
3074 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
3075 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
3076 if (type == Primitive::kPrimFloat) {
3077 if (isR6) {
3078 switch (cond) {
3079 case kCondEQ:
3080 __ CmpEqS(FTMP, lhs, rhs);
3081 __ Bc1nez(FTMP, label);
3082 break;
3083 case kCondNE:
3084 __ CmpEqS(FTMP, lhs, rhs);
3085 __ Bc1eqz(FTMP, label);
3086 break;
3087 case kCondLT:
3088 if (gt_bias) {
3089 __ CmpLtS(FTMP, lhs, rhs);
3090 } else {
3091 __ CmpUltS(FTMP, lhs, rhs);
3092 }
3093 __ Bc1nez(FTMP, label);
3094 break;
3095 case kCondLE:
3096 if (gt_bias) {
3097 __ CmpLeS(FTMP, lhs, rhs);
3098 } else {
3099 __ CmpUleS(FTMP, lhs, rhs);
3100 }
3101 __ Bc1nez(FTMP, label);
3102 break;
3103 case kCondGT:
3104 if (gt_bias) {
3105 __ CmpUltS(FTMP, rhs, lhs);
3106 } else {
3107 __ CmpLtS(FTMP, rhs, lhs);
3108 }
3109 __ Bc1nez(FTMP, label);
3110 break;
3111 case kCondGE:
3112 if (gt_bias) {
3113 __ CmpUleS(FTMP, rhs, lhs);
3114 } else {
3115 __ CmpLeS(FTMP, rhs, lhs);
3116 }
3117 __ Bc1nez(FTMP, label);
3118 break;
3119 default:
3120 LOG(FATAL) << "Unexpected non-floating-point condition";
3121 }
3122 } else {
3123 switch (cond) {
3124 case kCondEQ:
3125 __ CeqS(0, lhs, rhs);
3126 __ Bc1t(0, label);
3127 break;
3128 case kCondNE:
3129 __ CeqS(0, lhs, rhs);
3130 __ Bc1f(0, label);
3131 break;
3132 case kCondLT:
3133 if (gt_bias) {
3134 __ ColtS(0, lhs, rhs);
3135 } else {
3136 __ CultS(0, lhs, rhs);
3137 }
3138 __ Bc1t(0, label);
3139 break;
3140 case kCondLE:
3141 if (gt_bias) {
3142 __ ColeS(0, lhs, rhs);
3143 } else {
3144 __ CuleS(0, lhs, rhs);
3145 }
3146 __ Bc1t(0, label);
3147 break;
3148 case kCondGT:
3149 if (gt_bias) {
3150 __ CultS(0, rhs, lhs);
3151 } else {
3152 __ ColtS(0, rhs, lhs);
3153 }
3154 __ Bc1t(0, label);
3155 break;
3156 case kCondGE:
3157 if (gt_bias) {
3158 __ CuleS(0, rhs, lhs);
3159 } else {
3160 __ ColeS(0, rhs, lhs);
3161 }
3162 __ Bc1t(0, label);
3163 break;
3164 default:
3165 LOG(FATAL) << "Unexpected non-floating-point condition";
3166 }
3167 }
3168 } else {
3169 DCHECK_EQ(type, Primitive::kPrimDouble);
3170 if (isR6) {
3171 switch (cond) {
3172 case kCondEQ:
3173 __ CmpEqD(FTMP, lhs, rhs);
3174 __ Bc1nez(FTMP, label);
3175 break;
3176 case kCondNE:
3177 __ CmpEqD(FTMP, lhs, rhs);
3178 __ Bc1eqz(FTMP, label);
3179 break;
3180 case kCondLT:
3181 if (gt_bias) {
3182 __ CmpLtD(FTMP, lhs, rhs);
3183 } else {
3184 __ CmpUltD(FTMP, lhs, rhs);
3185 }
3186 __ Bc1nez(FTMP, label);
3187 break;
3188 case kCondLE:
3189 if (gt_bias) {
3190 __ CmpLeD(FTMP, lhs, rhs);
3191 } else {
3192 __ CmpUleD(FTMP, lhs, rhs);
3193 }
3194 __ Bc1nez(FTMP, label);
3195 break;
3196 case kCondGT:
3197 if (gt_bias) {
3198 __ CmpUltD(FTMP, rhs, lhs);
3199 } else {
3200 __ CmpLtD(FTMP, rhs, lhs);
3201 }
3202 __ Bc1nez(FTMP, label);
3203 break;
3204 case kCondGE:
3205 if (gt_bias) {
3206 __ CmpUleD(FTMP, rhs, lhs);
3207 } else {
3208 __ CmpLeD(FTMP, rhs, lhs);
3209 }
3210 __ Bc1nez(FTMP, label);
3211 break;
3212 default:
3213 LOG(FATAL) << "Unexpected non-floating-point condition";
3214 }
3215 } else {
3216 switch (cond) {
3217 case kCondEQ:
3218 __ CeqD(0, lhs, rhs);
3219 __ Bc1t(0, label);
3220 break;
3221 case kCondNE:
3222 __ CeqD(0, lhs, rhs);
3223 __ Bc1f(0, label);
3224 break;
3225 case kCondLT:
3226 if (gt_bias) {
3227 __ ColtD(0, lhs, rhs);
3228 } else {
3229 __ CultD(0, lhs, rhs);
3230 }
3231 __ Bc1t(0, label);
3232 break;
3233 case kCondLE:
3234 if (gt_bias) {
3235 __ ColeD(0, lhs, rhs);
3236 } else {
3237 __ CuleD(0, lhs, rhs);
3238 }
3239 __ Bc1t(0, label);
3240 break;
3241 case kCondGT:
3242 if (gt_bias) {
3243 __ CultD(0, rhs, lhs);
3244 } else {
3245 __ ColtD(0, rhs, lhs);
3246 }
3247 __ Bc1t(0, label);
3248 break;
3249 case kCondGE:
3250 if (gt_bias) {
3251 __ CuleD(0, rhs, lhs);
3252 } else {
3253 __ ColeD(0, rhs, lhs);
3254 }
3255 __ Bc1t(0, label);
3256 break;
3257 default:
3258 LOG(FATAL) << "Unexpected non-floating-point condition";
3259 }
3260 }
3261 }
3262}
3263
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003264void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instruction,
David Brazdil0debae72015-11-12 18:37:00 +00003265 size_t condition_input_index,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003266 MipsLabel* true_target,
David Brazdil0debae72015-11-12 18:37:00 +00003267 MipsLabel* false_target) {
3268 HInstruction* cond = instruction->InputAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003269
David Brazdil0debae72015-11-12 18:37:00 +00003270 if (true_target == nullptr && false_target == nullptr) {
3271 // Nothing to do. The code always falls through.
3272 return;
3273 } else if (cond->IsIntConstant()) {
Roland Levillain1a653882016-03-18 18:05:57 +00003274 // Constant condition, statically compared against "true" (integer value 1).
3275 if (cond->AsIntConstant()->IsTrue()) {
David Brazdil0debae72015-11-12 18:37:00 +00003276 if (true_target != nullptr) {
3277 __ B(true_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003278 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003279 } else {
Roland Levillain1a653882016-03-18 18:05:57 +00003280 DCHECK(cond->AsIntConstant()->IsFalse()) << cond->AsIntConstant()->GetValue();
David Brazdil0debae72015-11-12 18:37:00 +00003281 if (false_target != nullptr) {
3282 __ B(false_target);
3283 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003284 }
David Brazdil0debae72015-11-12 18:37:00 +00003285 return;
3286 }
3287
3288 // The following code generates these patterns:
3289 // (1) true_target == nullptr && false_target != nullptr
3290 // - opposite condition true => branch to false_target
3291 // (2) true_target != nullptr && false_target == nullptr
3292 // - condition true => branch to true_target
3293 // (3) true_target != nullptr && false_target != nullptr
3294 // - condition true => branch to true_target
3295 // - branch to false_target
3296 if (IsBooleanValueOrMaterializedCondition(cond)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003297 // The condition instruction has been materialized, compare the output to 0.
David Brazdil0debae72015-11-12 18:37:00 +00003298 Location cond_val = instruction->GetLocations()->InAt(condition_input_index);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003299 DCHECK(cond_val.IsRegister());
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003300 if (true_target == nullptr) {
David Brazdil0debae72015-11-12 18:37:00 +00003301 __ Beqz(cond_val.AsRegister<Register>(), false_target);
3302 } else {
3303 __ Bnez(cond_val.AsRegister<Register>(), true_target);
3304 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003305 } else {
3306 // The condition instruction has not been materialized, use its inputs as
3307 // the comparison and its condition as the branch condition.
David Brazdil0debae72015-11-12 18:37:00 +00003308 HCondition* condition = cond->AsCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003309 Primitive::Type type = condition->InputAt(0)->GetType();
3310 LocationSummary* locations = cond->GetLocations();
3311 IfCondition if_cond = condition->GetCondition();
3312 MipsLabel* branch_target = true_target;
David Brazdil0debae72015-11-12 18:37:00 +00003313
David Brazdil0debae72015-11-12 18:37:00 +00003314 if (true_target == nullptr) {
3315 if_cond = condition->GetOppositeCondition();
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003316 branch_target = false_target;
David Brazdil0debae72015-11-12 18:37:00 +00003317 }
3318
Alexey Frunzecd7b0ee2015-12-03 16:46:38 -08003319 switch (type) {
3320 default:
3321 GenerateIntCompareAndBranch(if_cond, locations, branch_target);
3322 break;
3323 case Primitive::kPrimLong:
3324 GenerateLongCompareAndBranch(if_cond, locations, branch_target);
3325 break;
3326 case Primitive::kPrimFloat:
3327 case Primitive::kPrimDouble:
3328 GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target);
3329 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003330 }
3331 }
David Brazdil0debae72015-11-12 18:37:00 +00003332
3333 // If neither branch falls through (case 3), the conditional branch to `true_target`
3334 // was already emitted (case 2) and we need to emit a jump to `false_target`.
3335 if (true_target != nullptr && false_target != nullptr) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003336 __ B(false_target);
3337 }
3338}
3339
3340void LocationsBuilderMIPS::VisitIf(HIf* if_instr) {
3341 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
David Brazdil0debae72015-11-12 18:37:00 +00003342 if (IsBooleanValueOrMaterializedCondition(if_instr->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003343 locations->SetInAt(0, Location::RequiresRegister());
3344 }
3345}
3346
3347void InstructionCodeGeneratorMIPS::VisitIf(HIf* if_instr) {
David Brazdil0debae72015-11-12 18:37:00 +00003348 HBasicBlock* true_successor = if_instr->IfTrueSuccessor();
3349 HBasicBlock* false_successor = if_instr->IfFalseSuccessor();
3350 MipsLabel* true_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), true_successor) ?
3351 nullptr : codegen_->GetLabelOf(true_successor);
3352 MipsLabel* false_target = codegen_->GoesToNextBlock(if_instr->GetBlock(), false_successor) ?
3353 nullptr : codegen_->GetLabelOf(false_successor);
3354 GenerateTestAndBranch(if_instr, /* condition_input_index */ 0, true_target, false_target);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003355}
3356
3357void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
3358 LocationSummary* locations = new (GetGraph()->GetArena())
3359 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
David Brazdil0debae72015-11-12 18:37:00 +00003360 if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003361 locations->SetInAt(0, Location::RequiresRegister());
3362 }
3363}
3364
3365void InstructionCodeGeneratorMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
Aart Bik42249c32016-01-07 15:33:50 -08003366 SlowPathCodeMIPS* slow_path =
3367 deopt_slow_paths_.NewSlowPath<DeoptimizationSlowPathMIPS>(deoptimize);
David Brazdil0debae72015-11-12 18:37:00 +00003368 GenerateTestAndBranch(deoptimize,
3369 /* condition_input_index */ 0,
3370 slow_path->GetEntryLabel(),
3371 /* false_target */ nullptr);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003372}
3373
David Brazdil74eb1b22015-12-14 11:44:01 +00003374void LocationsBuilderMIPS::VisitSelect(HSelect* select) {
3375 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
3376 if (Primitive::IsFloatingPointType(select->GetType())) {
3377 locations->SetInAt(0, Location::RequiresFpuRegister());
3378 locations->SetInAt(1, Location::RequiresFpuRegister());
3379 } else {
3380 locations->SetInAt(0, Location::RequiresRegister());
3381 locations->SetInAt(1, Location::RequiresRegister());
3382 }
3383 if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
3384 locations->SetInAt(2, Location::RequiresRegister());
3385 }
3386 locations->SetOut(Location::SameAsFirstInput());
3387}
3388
3389void InstructionCodeGeneratorMIPS::VisitSelect(HSelect* select) {
3390 LocationSummary* locations = select->GetLocations();
3391 MipsLabel false_target;
3392 GenerateTestAndBranch(select,
3393 /* condition_input_index */ 2,
3394 /* true_target */ nullptr,
3395 &false_target);
3396 codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
3397 __ Bind(&false_target);
3398}
3399
David Srbecky0cf44932015-12-09 14:09:59 +00003400void LocationsBuilderMIPS::VisitNativeDebugInfo(HNativeDebugInfo* info) {
3401 new (GetGraph()->GetArena()) LocationSummary(info);
3402}
3403
David Srbeckyd28f4a02016-03-14 17:14:24 +00003404void InstructionCodeGeneratorMIPS::VisitNativeDebugInfo(HNativeDebugInfo*) {
3405 // MaybeRecordNativeDebugInfo is already called implicitly in CodeGenerator::Compile.
David Srbeckyc7098ff2016-02-09 14:30:11 +00003406}
3407
3408void CodeGeneratorMIPS::GenerateNop() {
3409 __ Nop();
David Srbecky0cf44932015-12-09 14:09:59 +00003410}
3411
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003412void LocationsBuilderMIPS::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3413 Primitive::Type field_type = field_info.GetFieldType();
3414 bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
3415 bool generate_volatile = field_info.IsVolatile() && is_wide;
3416 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3417 instruction, generate_volatile ? LocationSummary::kCall : LocationSummary::kNoCall);
3418
3419 locations->SetInAt(0, Location::RequiresRegister());
3420 if (generate_volatile) {
3421 InvokeRuntimeCallingConvention calling_convention;
3422 // need A0 to hold base + offset
3423 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3424 if (field_type == Primitive::kPrimLong) {
3425 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimLong));
3426 } else {
3427 locations->SetOut(Location::RequiresFpuRegister());
3428 // Need some temp core regs since FP results are returned in core registers
3429 Location reg = calling_convention.GetReturnLocation(Primitive::kPrimLong);
3430 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairLow<Register>()));
3431 locations->AddTemp(Location::RegisterLocation(reg.AsRegisterPairHigh<Register>()));
3432 }
3433 } else {
3434 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3435 locations->SetOut(Location::RequiresFpuRegister());
3436 } else {
3437 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3438 }
3439 }
3440}
3441
3442void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
3443 const FieldInfo& field_info,
3444 uint32_t dex_pc) {
3445 Primitive::Type type = field_info.GetFieldType();
3446 LocationSummary* locations = instruction->GetLocations();
3447 Register obj = locations->InAt(0).AsRegister<Register>();
3448 LoadOperandType load_type = kLoadUnsignedByte;
3449 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003450 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003451
3452 switch (type) {
3453 case Primitive::kPrimBoolean:
3454 load_type = kLoadUnsignedByte;
3455 break;
3456 case Primitive::kPrimByte:
3457 load_type = kLoadSignedByte;
3458 break;
3459 case Primitive::kPrimShort:
3460 load_type = kLoadSignedHalfword;
3461 break;
3462 case Primitive::kPrimChar:
3463 load_type = kLoadUnsignedHalfword;
3464 break;
3465 case Primitive::kPrimInt:
3466 case Primitive::kPrimFloat:
3467 case Primitive::kPrimNot:
3468 load_type = kLoadWord;
3469 break;
3470 case Primitive::kPrimLong:
3471 case Primitive::kPrimDouble:
3472 load_type = kLoadDoubleword;
3473 break;
3474 case Primitive::kPrimVoid:
3475 LOG(FATAL) << "Unreachable type " << type;
3476 UNREACHABLE();
3477 }
3478
3479 if (is_volatile && load_type == kLoadDoubleword) {
3480 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003481 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003482 // Do implicit Null check
3483 __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
3484 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3485 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pA64Load),
3486 instruction,
3487 dex_pc,
3488 nullptr,
3489 IsDirectEntrypoint(kQuickA64Load));
3490 CheckEntrypointTypes<kQuickA64Load, int64_t, volatile const int64_t*>();
3491 if (type == Primitive::kPrimDouble) {
3492 // Need to move to FP regs since FP results are returned in core registers.
3493 __ Mtc1(locations->GetTemp(1).AsRegister<Register>(),
3494 locations->Out().AsFpuRegister<FRegister>());
Alexey Frunzebb9863a2016-01-11 15:51:16 -08003495 __ MoveToFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
3496 locations->Out().AsFpuRegister<FRegister>());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003497 }
3498 } else {
3499 if (!Primitive::IsFloatingPointType(type)) {
3500 Register dst;
3501 if (type == Primitive::kPrimLong) {
3502 DCHECK(locations->Out().IsRegisterPair());
3503 dst = locations->Out().AsRegisterPairLow<Register>();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003504 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
3505 if (obj == dst) {
3506 __ LoadFromOffset(kLoadWord, dst_high, obj, offset + kMipsWordSize);
3507 codegen_->MaybeRecordImplicitNullCheck(instruction);
3508 __ LoadFromOffset(kLoadWord, dst, obj, offset);
3509 } else {
3510 __ LoadFromOffset(kLoadWord, dst, obj, offset);
3511 codegen_->MaybeRecordImplicitNullCheck(instruction);
3512 __ LoadFromOffset(kLoadWord, dst_high, obj, offset + kMipsWordSize);
3513 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003514 } else {
3515 DCHECK(locations->Out().IsRegister());
3516 dst = locations->Out().AsRegister<Register>();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003517 __ LoadFromOffset(load_type, dst, obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003518 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003519 } else {
3520 DCHECK(locations->Out().IsFpuRegister());
3521 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
3522 if (type == Primitive::kPrimFloat) {
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003523 __ LoadSFromOffset(dst, obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003524 } else {
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003525 __ LoadDFromOffset(dst, obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003526 }
3527 }
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003528 // Longs are handled earlier.
3529 if (type != Primitive::kPrimLong) {
3530 codegen_->MaybeRecordImplicitNullCheck(instruction);
3531 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003532 }
3533
3534 if (is_volatile) {
3535 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3536 }
3537}
3538
3539void LocationsBuilderMIPS::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3540 Primitive::Type field_type = field_info.GetFieldType();
3541 bool is_wide = (field_type == Primitive::kPrimLong) || (field_type == Primitive::kPrimDouble);
3542 bool generate_volatile = field_info.IsVolatile() && is_wide;
3543 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3544 instruction, generate_volatile ? LocationSummary::kCall : LocationSummary::kNoCall);
3545
3546 locations->SetInAt(0, Location::RequiresRegister());
3547 if (generate_volatile) {
3548 InvokeRuntimeCallingConvention calling_convention;
3549 // need A0 to hold base + offset
3550 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3551 if (field_type == Primitive::kPrimLong) {
3552 locations->SetInAt(1, Location::RegisterPairLocation(
3553 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3554 } else {
3555 locations->SetInAt(1, Location::RequiresFpuRegister());
3556 // Pass FP parameters in core registers.
3557 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
3558 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
3559 }
3560 } else {
3561 if (Primitive::IsFloatingPointType(field_type)) {
3562 locations->SetInAt(1, Location::RequiresFpuRegister());
3563 } else {
3564 locations->SetInAt(1, Location::RequiresRegister());
3565 }
3566 }
3567}
3568
3569void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction,
3570 const FieldInfo& field_info,
3571 uint32_t dex_pc) {
3572 Primitive::Type type = field_info.GetFieldType();
3573 LocationSummary* locations = instruction->GetLocations();
3574 Register obj = locations->InAt(0).AsRegister<Register>();
3575 StoreOperandType store_type = kStoreByte;
3576 bool is_volatile = field_info.IsVolatile();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003577 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003578
3579 switch (type) {
3580 case Primitive::kPrimBoolean:
3581 case Primitive::kPrimByte:
3582 store_type = kStoreByte;
3583 break;
3584 case Primitive::kPrimShort:
3585 case Primitive::kPrimChar:
3586 store_type = kStoreHalfword;
3587 break;
3588 case Primitive::kPrimInt:
3589 case Primitive::kPrimFloat:
3590 case Primitive::kPrimNot:
3591 store_type = kStoreWord;
3592 break;
3593 case Primitive::kPrimLong:
3594 case Primitive::kPrimDouble:
3595 store_type = kStoreDoubleword;
3596 break;
3597 case Primitive::kPrimVoid:
3598 LOG(FATAL) << "Unreachable type " << type;
3599 UNREACHABLE();
3600 }
3601
3602 if (is_volatile) {
3603 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3604 }
3605
3606 if (is_volatile && store_type == kStoreDoubleword) {
3607 InvokeRuntimeCallingConvention calling_convention;
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003608 __ Addiu32(locations->GetTemp(0).AsRegister<Register>(), obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003609 // Do implicit Null check.
3610 __ Lw(ZERO, locations->GetTemp(0).AsRegister<Register>(), 0);
3611 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3612 if (type == Primitive::kPrimDouble) {
3613 // Pass FP parameters in core registers.
3614 __ Mfc1(locations->GetTemp(1).AsRegister<Register>(),
3615 locations->InAt(1).AsFpuRegister<FRegister>());
Alexey Frunzebb9863a2016-01-11 15:51:16 -08003616 __ MoveFromFpuHigh(locations->GetTemp(2).AsRegister<Register>(),
3617 locations->InAt(1).AsFpuRegister<FRegister>());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003618 }
3619 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pA64Store),
3620 instruction,
3621 dex_pc,
3622 nullptr,
3623 IsDirectEntrypoint(kQuickA64Store));
3624 CheckEntrypointTypes<kQuickA64Store, void, volatile int64_t *, int64_t>();
3625 } else {
3626 if (!Primitive::IsFloatingPointType(type)) {
3627 Register src;
3628 if (type == Primitive::kPrimLong) {
3629 DCHECK(locations->InAt(1).IsRegisterPair());
3630 src = locations->InAt(1).AsRegisterPairLow<Register>();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003631 Register src_high = locations->InAt(1).AsRegisterPairHigh<Register>();
3632 __ StoreToOffset(kStoreWord, src, obj, offset);
3633 codegen_->MaybeRecordImplicitNullCheck(instruction);
3634 __ StoreToOffset(kStoreWord, src_high, obj, offset + kMipsWordSize);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003635 } else {
3636 DCHECK(locations->InAt(1).IsRegister());
3637 src = locations->InAt(1).AsRegister<Register>();
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003638 __ StoreToOffset(store_type, src, obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003639 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003640 } else {
3641 DCHECK(locations->InAt(1).IsFpuRegister());
3642 FRegister src = locations->InAt(1).AsFpuRegister<FRegister>();
3643 if (type == Primitive::kPrimFloat) {
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003644 __ StoreSToOffset(src, obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003645 } else {
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003646 __ StoreDToOffset(src, obj, offset);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003647 }
3648 }
Goran Jakovljevic73a42652015-11-20 17:22:57 +01003649 // Longs are handled earlier.
3650 if (type != Primitive::kPrimLong) {
3651 codegen_->MaybeRecordImplicitNullCheck(instruction);
3652 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003653 }
3654
3655 // TODO: memory barriers?
3656 if (CodeGenerator::StoreNeedsWriteBarrier(type, instruction->InputAt(1))) {
3657 DCHECK(locations->InAt(1).IsRegister());
3658 Register src = locations->InAt(1).AsRegister<Register>();
3659 codegen_->MarkGCCard(obj, src);
3660 }
3661
3662 if (is_volatile) {
3663 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3664 }
3665}
3666
3667void LocationsBuilderMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3668 HandleFieldGet(instruction, instruction->GetFieldInfo());
3669}
3670
3671void InstructionCodeGeneratorMIPS::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3672 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
3673}
3674
3675void LocationsBuilderMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3676 HandleFieldSet(instruction, instruction->GetFieldInfo());
3677}
3678
3679void InstructionCodeGeneratorMIPS::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3680 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
3681}
3682
3683void LocationsBuilderMIPS::VisitInstanceOf(HInstanceOf* instruction) {
3684 LocationSummary::CallKind call_kind =
3685 instruction->IsExactCheck() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath;
3686 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3687 locations->SetInAt(0, Location::RequiresRegister());
3688 locations->SetInAt(1, Location::RequiresRegister());
3689 // The output does overlap inputs.
3690 // Note that TypeCheckSlowPathMIPS uses this register too.
3691 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
3692}
3693
3694void InstructionCodeGeneratorMIPS::VisitInstanceOf(HInstanceOf* instruction) {
3695 LocationSummary* locations = instruction->GetLocations();
3696 Register obj = locations->InAt(0).AsRegister<Register>();
3697 Register cls = locations->InAt(1).AsRegister<Register>();
3698 Register out = locations->Out().AsRegister<Register>();
3699
3700 MipsLabel done;
3701
3702 // Return 0 if `obj` is null.
3703 // TODO: Avoid this check if we know `obj` is not null.
3704 __ Move(out, ZERO);
3705 __ Beqz(obj, &done);
3706
3707 // Compare the class of `obj` with `cls`.
3708 __ LoadFromOffset(kLoadWord, out, obj, mirror::Object::ClassOffset().Int32Value());
3709 if (instruction->IsExactCheck()) {
3710 // Classes must be equal for the instanceof to succeed.
3711 __ Xor(out, out, cls);
3712 __ Sltiu(out, out, 1);
3713 } else {
3714 // If the classes are not equal, we go into a slow path.
3715 DCHECK(locations->OnlyCallsOnSlowPath());
3716 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathMIPS(instruction);
3717 codegen_->AddSlowPath(slow_path);
3718 __ Bne(out, cls, slow_path->GetEntryLabel());
3719 __ LoadConst32(out, 1);
3720 __ Bind(slow_path->GetExitLabel());
3721 }
3722
3723 __ Bind(&done);
3724}
3725
3726void LocationsBuilderMIPS::VisitIntConstant(HIntConstant* constant) {
3727 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
3728 locations->SetOut(Location::ConstantLocation(constant));
3729}
3730
3731void InstructionCodeGeneratorMIPS::VisitIntConstant(HIntConstant* constant ATTRIBUTE_UNUSED) {
3732 // Will be generated at use site.
3733}
3734
3735void LocationsBuilderMIPS::VisitNullConstant(HNullConstant* constant) {
3736 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
3737 locations->SetOut(Location::ConstantLocation(constant));
3738}
3739
3740void InstructionCodeGeneratorMIPS::VisitNullConstant(HNullConstant* constant ATTRIBUTE_UNUSED) {
3741 // Will be generated at use site.
3742}
3743
3744void LocationsBuilderMIPS::HandleInvoke(HInvoke* invoke) {
3745 InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
3746 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
3747}
3748
3749void LocationsBuilderMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
3750 HandleInvoke(invoke);
3751 // The register T0 is required to be used for the hidden argument in
3752 // art_quick_imt_conflict_trampoline, so add the hidden argument.
3753 invoke->GetLocations()->AddTemp(Location::RegisterLocation(T0));
3754}
3755
3756void InstructionCodeGeneratorMIPS::VisitInvokeInterface(HInvokeInterface* invoke) {
3757 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
3758 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
3759 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
3760 invoke->GetImtIndex() % mirror::Class::kImtSize, kMipsPointerSize).Uint32Value();
3761 Location receiver = invoke->GetLocations()->InAt(0);
3762 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3763 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsWordSize);
3764
3765 // Set the hidden argument.
3766 __ LoadConst32(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(),
3767 invoke->GetDexMethodIndex());
3768
3769 // temp = object->GetClass();
3770 if (receiver.IsStackSlot()) {
3771 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex());
3772 __ LoadFromOffset(kLoadWord, temp, temp, class_offset);
3773 } else {
3774 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
3775 }
3776 codegen_->MaybeRecordImplicitNullCheck(invoke);
3777 // temp = temp->GetImtEntryAt(method_offset);
3778 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
3779 // T9 = temp->GetEntryPoint();
3780 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
3781 // T9();
3782 __ Jalr(T9);
3783 __ Nop();
3784 DCHECK(!codegen_->IsLeafMethod());
3785 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3786}
3787
3788void LocationsBuilderMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Chris Larsen701566a2015-10-27 15:29:13 -07003789 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
3790 if (intrinsic.TryDispatch(invoke)) {
3791 return;
3792 }
3793
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003794 HandleInvoke(invoke);
3795}
3796
3797void LocationsBuilderMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003798 // Explicit clinit checks triggered by static invokes must have been pruned by
3799 // art::PrepareForRegisterAllocation.
3800 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003801
Chris Larsen701566a2015-10-27 15:29:13 -07003802 IntrinsicLocationsBuilderMIPS intrinsic(codegen_);
3803 if (intrinsic.TryDispatch(invoke)) {
3804 return;
3805 }
3806
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003807 HandleInvoke(invoke);
3808}
3809
Chris Larsen701566a2015-10-27 15:29:13 -07003810static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003811 if (invoke->GetLocations()->Intrinsified()) {
Chris Larsen701566a2015-10-27 15:29:13 -07003812 IntrinsicCodeGeneratorMIPS intrinsic(codegen);
3813 intrinsic.Dispatch(invoke);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003814 return true;
3815 }
3816 return false;
3817}
3818
Vladimir Markodc151b22015-10-15 18:02:30 +01003819HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch(
3820 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
3821 MethodReference target_method ATTRIBUTE_UNUSED) {
3822 switch (desired_dispatch_info.method_load_kind) {
3823 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
3824 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
3825 // TODO: Implement these types. For the moment, we fall back to kDexCacheViaMethod.
3826 return HInvokeStaticOrDirect::DispatchInfo {
3827 HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod,
3828 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
3829 0u,
3830 0u
3831 };
3832 default:
3833 break;
3834 }
3835 switch (desired_dispatch_info.code_ptr_location) {
3836 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
3837 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
3838 // TODO: Implement these types. For the moment, we fall back to kCallArtMethod.
3839 return HInvokeStaticOrDirect::DispatchInfo {
3840 desired_dispatch_info.method_load_kind,
3841 HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
3842 desired_dispatch_info.method_load_data,
3843 0u
3844 };
3845 default:
3846 return desired_dispatch_info;
3847 }
3848}
3849
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003850void CodeGeneratorMIPS::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
3851 // All registers are assumed to be correctly set up per the calling convention.
3852
3853 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
3854 switch (invoke->GetMethodLoadKind()) {
3855 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
3856 // temp = thread->string_init_entrypoint
3857 __ LoadFromOffset(kLoadWord,
3858 temp.AsRegister<Register>(),
3859 TR,
3860 invoke->GetStringInitOffset());
3861 break;
3862 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
Vladimir Markoc53c0792015-11-19 15:48:33 +00003863 callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003864 break;
3865 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
3866 __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
3867 break;
3868 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003869 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
Vladimir Markodc151b22015-10-15 18:02:30 +01003870 // TODO: Implement these types.
3871 // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch().
3872 LOG(FATAL) << "Unsupported";
3873 UNREACHABLE();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003874 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
Vladimir Markoc53c0792015-11-19 15:48:33 +00003875 Location current_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003876 Register reg = temp.AsRegister<Register>();
3877 Register method_reg;
3878 if (current_method.IsRegister()) {
3879 method_reg = current_method.AsRegister<Register>();
3880 } else {
3881 // TODO: use the appropriate DCHECK() here if possible.
3882 // DCHECK(invoke->GetLocations()->Intrinsified());
3883 DCHECK(!current_method.IsValid());
3884 method_reg = reg;
3885 __ Lw(reg, SP, kCurrentMethodStackOffset);
3886 }
3887
3888 // temp = temp->dex_cache_resolved_methods_;
3889 __ LoadFromOffset(kLoadWord,
3890 reg,
3891 method_reg,
3892 ArtMethod::DexCacheResolvedMethodsOffset(kMipsPointerSize).Int32Value());
3893 // temp = temp[index_in_cache]
3894 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
3895 __ LoadFromOffset(kLoadWord,
3896 reg,
3897 reg,
3898 CodeGenerator::GetCachePointerOffset(index_in_cache));
3899 break;
3900 }
3901 }
3902
3903 switch (invoke->GetCodePtrLocation()) {
3904 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
3905 __ Jalr(&frame_entry_label_, T9);
3906 break;
3907 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
3908 // LR = invoke->GetDirectCodePtr();
3909 __ LoadConst32(T9, invoke->GetDirectCodePtr());
3910 // LR()
3911 __ Jalr(T9);
3912 __ Nop();
3913 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003914 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
Vladimir Markodc151b22015-10-15 18:02:30 +01003915 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
3916 // TODO: Implement these types.
3917 // Currently filtered out by GetSupportedInvokeStaticOrDirectDispatch().
3918 LOG(FATAL) << "Unsupported";
3919 UNREACHABLE();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003920 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
3921 // T9 = callee_method->entry_point_from_quick_compiled_code_;
Goran Jakovljevic1a878372015-10-26 14:28:52 +01003922 __ LoadFromOffset(kLoadWord,
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003923 T9,
3924 callee_method.AsRegister<Register>(),
3925 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
3926 kMipsWordSize).Int32Value());
3927 // T9()
3928 __ Jalr(T9);
3929 __ Nop();
3930 break;
3931 }
3932 DCHECK(!IsLeafMethod());
3933}
3934
3935void InstructionCodeGeneratorMIPS::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
David Brazdil58282f42016-01-14 12:45:10 +00003936 // Explicit clinit checks triggered by static invokes must have been pruned by
3937 // art::PrepareForRegisterAllocation.
3938 DCHECK(!invoke->IsStaticWithExplicitClinitCheck());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003939
3940 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3941 return;
3942 }
3943
3944 LocationSummary* locations = invoke->GetLocations();
3945 codegen_->GenerateStaticOrDirectCall(invoke,
3946 locations->HasTemps()
3947 ? locations->GetTemp(0)
3948 : Location::NoLocation());
3949 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3950}
3951
Chris Larsen3acee732015-11-18 13:31:08 -08003952void CodeGeneratorMIPS::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003953 LocationSummary* locations = invoke->GetLocations();
3954 Location receiver = locations->InAt(0);
Chris Larsen3acee732015-11-18 13:31:08 -08003955 Register temp = temp_location.AsRegister<Register>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003956 size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
3957 invoke->GetVTableIndex(), kMipsPointerSize).SizeValue();
3958 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3959 Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsWordSize);
3960
3961 // temp = object->GetClass();
Chris Larsen3acee732015-11-18 13:31:08 -08003962 DCHECK(receiver.IsRegister());
3963 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
3964 MaybeRecordImplicitNullCheck(invoke);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003965 // temp = temp->GetMethodAt(method_offset);
3966 __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
3967 // T9 = temp->GetEntryPoint();
3968 __ LoadFromOffset(kLoadWord, T9, temp, entry_point.Int32Value());
3969 // T9();
3970 __ Jalr(T9);
3971 __ Nop();
Chris Larsen3acee732015-11-18 13:31:08 -08003972}
3973
3974void InstructionCodeGeneratorMIPS::VisitInvokeVirtual(HInvokeVirtual* invoke) {
3975 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
3976 return;
3977 }
3978
3979 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003980 DCHECK(!codegen_->IsLeafMethod());
3981 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
3982}
3983
3984void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) {
Pavle Batutae87a7182015-10-28 13:10:42 +01003985 InvokeRuntimeCallingConvention calling_convention;
3986 CodeGenerator::CreateLoadClassLocationSummary(
3987 cls,
3988 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
3989 Location::RegisterLocation(V0));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02003990}
3991
3992void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
3993 LocationSummary* locations = cls->GetLocations();
Pavle Batutae87a7182015-10-28 13:10:42 +01003994 if (cls->NeedsAccessCheck()) {
3995 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
3996 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
3997 cls,
3998 cls->GetDexPc(),
3999 nullptr,
4000 IsDirectEntrypoint(kQuickInitializeTypeAndVerifyAccess));
Roland Levillain888d0672015-11-23 18:53:50 +00004001 CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
Pavle Batutae87a7182015-10-28 13:10:42 +01004002 return;
4003 }
4004
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004005 Register out = locations->Out().AsRegister<Register>();
4006 Register current_method = locations->InAt(0).AsRegister<Register>();
4007 if (cls->IsReferrersClass()) {
4008 DCHECK(!cls->CanCallRuntime());
4009 DCHECK(!cls->MustGenerateClinitCheck());
4010 __ LoadFromOffset(kLoadWord, out, current_method,
4011 ArtMethod::DeclaringClassOffset().Int32Value());
4012 } else {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004013 __ LoadFromOffset(kLoadWord, out, current_method,
4014 ArtMethod::DexCacheResolvedTypesOffset(kMipsPointerSize).Int32Value());
4015 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
Nicolas Geoffray42e372e2015-11-24 15:48:56 +00004016
4017 if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
4018 DCHECK(cls->CanCallRuntime());
4019 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
4020 cls,
4021 cls,
4022 cls->GetDexPc(),
4023 cls->MustGenerateClinitCheck());
4024 codegen_->AddSlowPath(slow_path);
4025 if (!cls->IsInDexCache()) {
4026 __ Beqz(out, slow_path->GetEntryLabel());
4027 }
4028 if (cls->MustGenerateClinitCheck()) {
4029 GenerateClassInitializationCheck(slow_path, out);
4030 } else {
4031 __ Bind(slow_path->GetExitLabel());
4032 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004033 }
4034 }
4035}
4036
4037static int32_t GetExceptionTlsOffset() {
4038 return Thread::ExceptionOffset<kMipsWordSize>().Int32Value();
4039}
4040
4041void LocationsBuilderMIPS::VisitLoadException(HLoadException* load) {
4042 LocationSummary* locations =
4043 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4044 locations->SetOut(Location::RequiresRegister());
4045}
4046
4047void InstructionCodeGeneratorMIPS::VisitLoadException(HLoadException* load) {
4048 Register out = load->GetLocations()->Out().AsRegister<Register>();
4049 __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
4050}
4051
4052void LocationsBuilderMIPS::VisitClearException(HClearException* clear) {
4053 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4054}
4055
4056void InstructionCodeGeneratorMIPS::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4057 __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
4058}
4059
4060void LocationsBuilderMIPS::VisitLoadLocal(HLoadLocal* load) {
4061 load->SetLocations(nullptr);
4062}
4063
4064void InstructionCodeGeneratorMIPS::VisitLoadLocal(HLoadLocal* load ATTRIBUTE_UNUSED) {
4065 // Nothing to do, this is driven by the code generator.
4066}
4067
4068void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
Roland Levillain698fa972015-12-16 17:06:47 +00004069 LocationSummary::CallKind call_kind = load->IsInDexCache()
4070 ? LocationSummary::kNoCall
4071 : LocationSummary::kCallOnSlowPath;
Nicolas Geoffray917d0162015-11-24 18:25:35 +00004072 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004073 locations->SetInAt(0, Location::RequiresRegister());
4074 locations->SetOut(Location::RequiresRegister());
4075}
4076
4077void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004078 LocationSummary* locations = load->GetLocations();
4079 Register out = locations->Out().AsRegister<Register>();
4080 Register current_method = locations->InAt(0).AsRegister<Register>();
4081 __ LoadFromOffset(kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
4082 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
4083 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
Nicolas Geoffray917d0162015-11-24 18:25:35 +00004084
4085 if (!load->IsInDexCache()) {
4086 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
4087 codegen_->AddSlowPath(slow_path);
4088 __ Beqz(out, slow_path->GetEntryLabel());
4089 __ Bind(slow_path->GetExitLabel());
4090 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004091}
4092
4093void LocationsBuilderMIPS::VisitLocal(HLocal* local) {
4094 local->SetLocations(nullptr);
4095}
4096
4097void InstructionCodeGeneratorMIPS::VisitLocal(HLocal* local) {
4098 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
4099}
4100
4101void LocationsBuilderMIPS::VisitLongConstant(HLongConstant* constant) {
4102 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
4103 locations->SetOut(Location::ConstantLocation(constant));
4104}
4105
4106void InstructionCodeGeneratorMIPS::VisitLongConstant(HLongConstant* constant ATTRIBUTE_UNUSED) {
4107 // Will be generated at use site.
4108}
4109
4110void LocationsBuilderMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
4111 LocationSummary* locations =
4112 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4113 InvokeRuntimeCallingConvention calling_convention;
4114 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4115}
4116
4117void InstructionCodeGeneratorMIPS::VisitMonitorOperation(HMonitorOperation* instruction) {
4118 if (instruction->IsEnter()) {
4119 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLockObject),
4120 instruction,
4121 instruction->GetDexPc(),
4122 nullptr,
4123 IsDirectEntrypoint(kQuickLockObject));
4124 CheckEntrypointTypes<kQuickLockObject, void, mirror::Object*>();
4125 } else {
4126 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pUnlockObject),
4127 instruction,
4128 instruction->GetDexPc(),
4129 nullptr,
4130 IsDirectEntrypoint(kQuickUnlockObject));
4131 }
4132 CheckEntrypointTypes<kQuickUnlockObject, void, mirror::Object*>();
4133}
4134
4135void LocationsBuilderMIPS::VisitMul(HMul* mul) {
4136 LocationSummary* locations =
4137 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
4138 switch (mul->GetResultType()) {
4139 case Primitive::kPrimInt:
4140 case Primitive::kPrimLong:
4141 locations->SetInAt(0, Location::RequiresRegister());
4142 locations->SetInAt(1, Location::RequiresRegister());
4143 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4144 break;
4145
4146 case Primitive::kPrimFloat:
4147 case Primitive::kPrimDouble:
4148 locations->SetInAt(0, Location::RequiresFpuRegister());
4149 locations->SetInAt(1, Location::RequiresFpuRegister());
4150 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4151 break;
4152
4153 default:
4154 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
4155 }
4156}
4157
4158void InstructionCodeGeneratorMIPS::VisitMul(HMul* instruction) {
4159 Primitive::Type type = instruction->GetType();
4160 LocationSummary* locations = instruction->GetLocations();
4161 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4162
4163 switch (type) {
4164 case Primitive::kPrimInt: {
4165 Register dst = locations->Out().AsRegister<Register>();
4166 Register lhs = locations->InAt(0).AsRegister<Register>();
4167 Register rhs = locations->InAt(1).AsRegister<Register>();
4168
4169 if (isR6) {
4170 __ MulR6(dst, lhs, rhs);
4171 } else {
4172 __ MulR2(dst, lhs, rhs);
4173 }
4174 break;
4175 }
4176 case Primitive::kPrimLong: {
4177 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
4178 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
4179 Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4180 Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
4181 Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>();
4182 Register rhs_low = locations->InAt(1).AsRegisterPairLow<Register>();
4183
4184 // Extra checks to protect caused by the existance of A1_A2.
4185 // The algorithm is wrong if dst_high is either lhs_lo or rhs_lo:
4186 // (e.g. lhs=a0_a1, rhs=a2_a3 and dst=a1_a2).
4187 DCHECK_NE(dst_high, lhs_low);
4188 DCHECK_NE(dst_high, rhs_low);
4189
4190 // A_B * C_D
4191 // dst_hi: [ low(A*D) + low(B*C) + hi(B*D) ]
4192 // dst_lo: [ low(B*D) ]
4193 // Note: R2 and R6 MUL produce the low 32 bit of the multiplication result.
4194
4195 if (isR6) {
4196 __ MulR6(TMP, lhs_high, rhs_low);
4197 __ MulR6(dst_high, lhs_low, rhs_high);
4198 __ Addu(dst_high, dst_high, TMP);
4199 __ MuhuR6(TMP, lhs_low, rhs_low);
4200 __ Addu(dst_high, dst_high, TMP);
4201 __ MulR6(dst_low, lhs_low, rhs_low);
4202 } else {
4203 __ MulR2(TMP, lhs_high, rhs_low);
4204 __ MulR2(dst_high, lhs_low, rhs_high);
4205 __ Addu(dst_high, dst_high, TMP);
4206 __ MultuR2(lhs_low, rhs_low);
4207 __ Mfhi(TMP);
4208 __ Addu(dst_high, dst_high, TMP);
4209 __ Mflo(dst_low);
4210 }
4211 break;
4212 }
4213 case Primitive::kPrimFloat:
4214 case Primitive::kPrimDouble: {
4215 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4216 FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
4217 FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
4218 if (type == Primitive::kPrimFloat) {
4219 __ MulS(dst, lhs, rhs);
4220 } else {
4221 __ MulD(dst, lhs, rhs);
4222 }
4223 break;
4224 }
4225 default:
4226 LOG(FATAL) << "Unexpected mul type " << type;
4227 }
4228}
4229
4230void LocationsBuilderMIPS::VisitNeg(HNeg* neg) {
4231 LocationSummary* locations =
4232 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
4233 switch (neg->GetResultType()) {
4234 case Primitive::kPrimInt:
4235 case Primitive::kPrimLong:
4236 locations->SetInAt(0, Location::RequiresRegister());
4237 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4238 break;
4239
4240 case Primitive::kPrimFloat:
4241 case Primitive::kPrimDouble:
4242 locations->SetInAt(0, Location::RequiresFpuRegister());
4243 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4244 break;
4245
4246 default:
4247 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
4248 }
4249}
4250
4251void InstructionCodeGeneratorMIPS::VisitNeg(HNeg* instruction) {
4252 Primitive::Type type = instruction->GetType();
4253 LocationSummary* locations = instruction->GetLocations();
4254
4255 switch (type) {
4256 case Primitive::kPrimInt: {
4257 Register dst = locations->Out().AsRegister<Register>();
4258 Register src = locations->InAt(0).AsRegister<Register>();
4259 __ Subu(dst, ZERO, src);
4260 break;
4261 }
4262 case Primitive::kPrimLong: {
4263 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
4264 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
4265 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4266 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
4267 __ Subu(dst_low, ZERO, src_low);
4268 __ Sltu(TMP, ZERO, dst_low);
4269 __ Subu(dst_high, ZERO, src_high);
4270 __ Subu(dst_high, dst_high, TMP);
4271 break;
4272 }
4273 case Primitive::kPrimFloat:
4274 case Primitive::kPrimDouble: {
4275 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4276 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
4277 if (type == Primitive::kPrimFloat) {
4278 __ NegS(dst, src);
4279 } else {
4280 __ NegD(dst, src);
4281 }
4282 break;
4283 }
4284 default:
4285 LOG(FATAL) << "Unexpected neg type " << type;
4286 }
4287}
4288
4289void LocationsBuilderMIPS::VisitNewArray(HNewArray* instruction) {
4290 LocationSummary* locations =
4291 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4292 InvokeRuntimeCallingConvention calling_convention;
4293 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4294 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
4295 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
4296 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4297}
4298
4299void InstructionCodeGeneratorMIPS::VisitNewArray(HNewArray* instruction) {
4300 InvokeRuntimeCallingConvention calling_convention;
4301 Register current_method_register = calling_convention.GetRegisterAt(2);
4302 __ Lw(current_method_register, SP, kCurrentMethodStackOffset);
4303 // Move an uint16_t value to a register.
4304 __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
4305 codegen_->InvokeRuntime(
4306 GetThreadOffset<kMipsWordSize>(instruction->GetEntrypoint()).Int32Value(),
4307 instruction,
4308 instruction->GetDexPc(),
4309 nullptr,
4310 IsDirectEntrypoint(kQuickAllocArrayWithAccessCheck));
4311 CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
4312 void*, uint32_t, int32_t, ArtMethod*>();
4313}
4314
4315void LocationsBuilderMIPS::VisitNewInstance(HNewInstance* instruction) {
4316 LocationSummary* locations =
4317 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4318 InvokeRuntimeCallingConvention calling_convention;
David Brazdil6de19382016-01-08 17:37:10 +00004319 if (instruction->IsStringAlloc()) {
4320 locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument));
4321 } else {
4322 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4323 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4324 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004325 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot));
4326}
4327
4328void InstructionCodeGeneratorMIPS::VisitNewInstance(HNewInstance* instruction) {
David Brazdil6de19382016-01-08 17:37:10 +00004329 if (instruction->IsStringAlloc()) {
4330 // String is allocated through StringFactory. Call NewEmptyString entry point.
4331 Register temp = instruction->GetLocations()->GetTemp(0).AsRegister<Register>();
4332 MemberOffset code_offset = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kMipsWordSize);
4333 __ LoadFromOffset(kLoadWord, temp, TR, QUICK_ENTRY_POINT(pNewEmptyString));
4334 __ LoadFromOffset(kLoadWord, T9, temp, code_offset.Int32Value());
4335 __ Jalr(T9);
4336 __ Nop();
4337 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4338 } else {
4339 codegen_->InvokeRuntime(
4340 GetThreadOffset<kMipsWordSize>(instruction->GetEntrypoint()).Int32Value(),
4341 instruction,
4342 instruction->GetDexPc(),
4343 nullptr,
4344 IsDirectEntrypoint(kQuickAllocObjectWithAccessCheck));
4345 CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>();
4346 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004347}
4348
4349void LocationsBuilderMIPS::VisitNot(HNot* instruction) {
4350 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
4351 locations->SetInAt(0, Location::RequiresRegister());
4352 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4353}
4354
4355void InstructionCodeGeneratorMIPS::VisitNot(HNot* instruction) {
4356 Primitive::Type type = instruction->GetType();
4357 LocationSummary* locations = instruction->GetLocations();
4358
4359 switch (type) {
4360 case Primitive::kPrimInt: {
4361 Register dst = locations->Out().AsRegister<Register>();
4362 Register src = locations->InAt(0).AsRegister<Register>();
4363 __ Nor(dst, src, ZERO);
4364 break;
4365 }
4366
4367 case Primitive::kPrimLong: {
4368 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
4369 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
4370 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4371 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
4372 __ Nor(dst_high, src_high, ZERO);
4373 __ Nor(dst_low, src_low, ZERO);
4374 break;
4375 }
4376
4377 default:
4378 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType();
4379 }
4380}
4381
4382void LocationsBuilderMIPS::VisitBooleanNot(HBooleanNot* instruction) {
4383 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
4384 locations->SetInAt(0, Location::RequiresRegister());
4385 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4386}
4387
4388void InstructionCodeGeneratorMIPS::VisitBooleanNot(HBooleanNot* instruction) {
4389 LocationSummary* locations = instruction->GetLocations();
4390 __ Xori(locations->Out().AsRegister<Register>(),
4391 locations->InAt(0).AsRegister<Register>(),
4392 1);
4393}
4394
4395void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
4396 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4397 ? LocationSummary::kCallOnSlowPath
4398 : LocationSummary::kNoCall;
4399 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4400 locations->SetInAt(0, Location::RequiresRegister());
4401 if (instruction->HasUses()) {
4402 locations->SetOut(Location::SameAsFirstInput());
4403 }
4404}
4405
Calin Juravle2ae48182016-03-16 14:05:09 +00004406void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
4407 if (CanMoveNullCheckToUser(instruction)) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004408 return;
4409 }
4410 Location obj = instruction->GetLocations()->InAt(0);
4411
4412 __ Lw(ZERO, obj.AsRegister<Register>(), 0);
Calin Juravle2ae48182016-03-16 14:05:09 +00004413 RecordPcInfo(instruction, instruction->GetDexPc());
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004414}
4415
Calin Juravle2ae48182016-03-16 14:05:09 +00004416void CodeGeneratorMIPS::GenerateExplicitNullCheck(HNullCheck* instruction) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004417 SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathMIPS(instruction);
Calin Juravle2ae48182016-03-16 14:05:09 +00004418 AddSlowPath(slow_path);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004419
4420 Location obj = instruction->GetLocations()->InAt(0);
4421
4422 __ Beqz(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
4423}
4424
4425void InstructionCodeGeneratorMIPS::VisitNullCheck(HNullCheck* instruction) {
Calin Juravle2ae48182016-03-16 14:05:09 +00004426 codegen_->GenerateNullCheck(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004427}
4428
4429void LocationsBuilderMIPS::VisitOr(HOr* instruction) {
4430 HandleBinaryOp(instruction);
4431}
4432
4433void InstructionCodeGeneratorMIPS::VisitOr(HOr* instruction) {
4434 HandleBinaryOp(instruction);
4435}
4436
4437void LocationsBuilderMIPS::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
4438 LOG(FATAL) << "Unreachable";
4439}
4440
4441void InstructionCodeGeneratorMIPS::VisitParallelMove(HParallelMove* instruction) {
4442 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4443}
4444
4445void LocationsBuilderMIPS::VisitParameterValue(HParameterValue* instruction) {
4446 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
4447 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
4448 if (location.IsStackSlot()) {
4449 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4450 } else if (location.IsDoubleStackSlot()) {
4451 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
4452 }
4453 locations->SetOut(location);
4454}
4455
4456void InstructionCodeGeneratorMIPS::VisitParameterValue(HParameterValue* instruction
4457 ATTRIBUTE_UNUSED) {
4458 // Nothing to do, the parameter is already at its location.
4459}
4460
4461void LocationsBuilderMIPS::VisitCurrentMethod(HCurrentMethod* instruction) {
4462 LocationSummary* locations =
4463 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4464 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
4465}
4466
4467void InstructionCodeGeneratorMIPS::VisitCurrentMethod(HCurrentMethod* instruction
4468 ATTRIBUTE_UNUSED) {
4469 // Nothing to do, the method is already at its location.
4470}
4471
4472void LocationsBuilderMIPS::VisitPhi(HPhi* instruction) {
4473 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
4474 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
4475 locations->SetInAt(i, Location::Any());
4476 }
4477 locations->SetOut(Location::Any());
4478}
4479
4480void InstructionCodeGeneratorMIPS::VisitPhi(HPhi* instruction ATTRIBUTE_UNUSED) {
4481 LOG(FATAL) << "Unreachable";
4482}
4483
4484void LocationsBuilderMIPS::VisitRem(HRem* rem) {
4485 Primitive::Type type = rem->GetResultType();
4486 LocationSummary::CallKind call_kind =
4487 (type == Primitive::kPrimInt) ? LocationSummary::kNoCall : LocationSummary::kCall;
4488 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
4489
4490 switch (type) {
4491 case Primitive::kPrimInt:
4492 locations->SetInAt(0, Location::RequiresRegister());
Alexey Frunze7e99e052015-11-24 19:28:01 -08004493 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004494 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4495 break;
4496
4497 case Primitive::kPrimLong: {
4498 InvokeRuntimeCallingConvention calling_convention;
4499 locations->SetInAt(0, Location::RegisterPairLocation(
4500 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4501 locations->SetInAt(1, Location::RegisterPairLocation(
4502 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
4503 locations->SetOut(calling_convention.GetReturnLocation(type));
4504 break;
4505 }
4506
4507 case Primitive::kPrimFloat:
4508 case Primitive::kPrimDouble: {
4509 InvokeRuntimeCallingConvention calling_convention;
4510 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
4511 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
4512 locations->SetOut(calling_convention.GetReturnLocation(type));
4513 break;
4514 }
4515
4516 default:
4517 LOG(FATAL) << "Unexpected rem type " << type;
4518 }
4519}
4520
4521void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) {
4522 Primitive::Type type = instruction->GetType();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004523
4524 switch (type) {
Alexey Frunze7e99e052015-11-24 19:28:01 -08004525 case Primitive::kPrimInt:
4526 GenerateDivRemIntegral(instruction);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004527 break;
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004528 case Primitive::kPrimLong: {
4529 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod),
4530 instruction,
4531 instruction->GetDexPc(),
4532 nullptr,
4533 IsDirectEntrypoint(kQuickLmod));
4534 CheckEntrypointTypes<kQuickLmod, int64_t, int64_t, int64_t>();
4535 break;
4536 }
4537 case Primitive::kPrimFloat: {
4538 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf),
4539 instruction, instruction->GetDexPc(),
4540 nullptr,
4541 IsDirectEntrypoint(kQuickFmodf));
Roland Levillain888d0672015-11-23 18:53:50 +00004542 CheckEntrypointTypes<kQuickFmodf, float, float, float>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004543 break;
4544 }
4545 case Primitive::kPrimDouble: {
4546 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod),
4547 instruction, instruction->GetDexPc(),
4548 nullptr,
4549 IsDirectEntrypoint(kQuickFmod));
Roland Levillain888d0672015-11-23 18:53:50 +00004550 CheckEntrypointTypes<kQuickFmod, double, double, double>();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004551 break;
4552 }
4553 default:
4554 LOG(FATAL) << "Unexpected rem type " << type;
4555 }
4556}
4557
4558void LocationsBuilderMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
4559 memory_barrier->SetLocations(nullptr);
4560}
4561
4562void InstructionCodeGeneratorMIPS::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
4563 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
4564}
4565
4566void LocationsBuilderMIPS::VisitReturn(HReturn* ret) {
4567 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
4568 Primitive::Type return_type = ret->InputAt(0)->GetType();
4569 locations->SetInAt(0, MipsReturnLocation(return_type));
4570}
4571
4572void InstructionCodeGeneratorMIPS::VisitReturn(HReturn* ret ATTRIBUTE_UNUSED) {
4573 codegen_->GenerateFrameExit();
4574}
4575
4576void LocationsBuilderMIPS::VisitReturnVoid(HReturnVoid* ret) {
4577 ret->SetLocations(nullptr);
4578}
4579
4580void InstructionCodeGeneratorMIPS::VisitReturnVoid(HReturnVoid* ret ATTRIBUTE_UNUSED) {
4581 codegen_->GenerateFrameExit();
4582}
4583
Alexey Frunze92d90602015-12-18 18:16:36 -08004584void LocationsBuilderMIPS::VisitRor(HRor* ror) {
4585 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004586}
4587
Alexey Frunze92d90602015-12-18 18:16:36 -08004588void InstructionCodeGeneratorMIPS::VisitRor(HRor* ror) {
4589 HandleShift(ror);
Scott Wakeling40a04bf2015-12-11 09:50:36 +00004590}
4591
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004592void LocationsBuilderMIPS::VisitShl(HShl* shl) {
4593 HandleShift(shl);
4594}
4595
4596void InstructionCodeGeneratorMIPS::VisitShl(HShl* shl) {
4597 HandleShift(shl);
4598}
4599
4600void LocationsBuilderMIPS::VisitShr(HShr* shr) {
4601 HandleShift(shr);
4602}
4603
4604void InstructionCodeGeneratorMIPS::VisitShr(HShr* shr) {
4605 HandleShift(shr);
4606}
4607
4608void LocationsBuilderMIPS::VisitStoreLocal(HStoreLocal* store) {
4609 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
4610 Primitive::Type field_type = store->InputAt(1)->GetType();
4611 switch (field_type) {
4612 case Primitive::kPrimNot:
4613 case Primitive::kPrimBoolean:
4614 case Primitive::kPrimByte:
4615 case Primitive::kPrimChar:
4616 case Primitive::kPrimShort:
4617 case Primitive::kPrimInt:
4618 case Primitive::kPrimFloat:
4619 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
4620 break;
4621
4622 case Primitive::kPrimLong:
4623 case Primitive::kPrimDouble:
4624 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
4625 break;
4626
4627 default:
4628 LOG(FATAL) << "Unimplemented local type " << field_type;
4629 }
4630}
4631
4632void InstructionCodeGeneratorMIPS::VisitStoreLocal(HStoreLocal* store ATTRIBUTE_UNUSED) {
4633}
4634
4635void LocationsBuilderMIPS::VisitSub(HSub* instruction) {
4636 HandleBinaryOp(instruction);
4637}
4638
4639void InstructionCodeGeneratorMIPS::VisitSub(HSub* instruction) {
4640 HandleBinaryOp(instruction);
4641}
4642
4643void LocationsBuilderMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4644 HandleFieldGet(instruction, instruction->GetFieldInfo());
4645}
4646
4647void InstructionCodeGeneratorMIPS::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4648 HandleFieldGet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
4649}
4650
4651void LocationsBuilderMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4652 HandleFieldSet(instruction, instruction->GetFieldInfo());
4653}
4654
4655void InstructionCodeGeneratorMIPS::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4656 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetDexPc());
4657}
4658
4659void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldGet(
4660 HUnresolvedInstanceFieldGet* instruction) {
4661 FieldAccessCallingConventionMIPS calling_convention;
4662 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
4663 instruction->GetFieldType(),
4664 calling_convention);
4665}
4666
4667void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldGet(
4668 HUnresolvedInstanceFieldGet* instruction) {
4669 FieldAccessCallingConventionMIPS calling_convention;
4670 codegen_->GenerateUnresolvedFieldAccess(instruction,
4671 instruction->GetFieldType(),
4672 instruction->GetFieldIndex(),
4673 instruction->GetDexPc(),
4674 calling_convention);
4675}
4676
4677void LocationsBuilderMIPS::VisitUnresolvedInstanceFieldSet(
4678 HUnresolvedInstanceFieldSet* instruction) {
4679 FieldAccessCallingConventionMIPS calling_convention;
4680 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
4681 instruction->GetFieldType(),
4682 calling_convention);
4683}
4684
4685void InstructionCodeGeneratorMIPS::VisitUnresolvedInstanceFieldSet(
4686 HUnresolvedInstanceFieldSet* instruction) {
4687 FieldAccessCallingConventionMIPS calling_convention;
4688 codegen_->GenerateUnresolvedFieldAccess(instruction,
4689 instruction->GetFieldType(),
4690 instruction->GetFieldIndex(),
4691 instruction->GetDexPc(),
4692 calling_convention);
4693}
4694
4695void LocationsBuilderMIPS::VisitUnresolvedStaticFieldGet(
4696 HUnresolvedStaticFieldGet* instruction) {
4697 FieldAccessCallingConventionMIPS calling_convention;
4698 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
4699 instruction->GetFieldType(),
4700 calling_convention);
4701}
4702
4703void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldGet(
4704 HUnresolvedStaticFieldGet* instruction) {
4705 FieldAccessCallingConventionMIPS calling_convention;
4706 codegen_->GenerateUnresolvedFieldAccess(instruction,
4707 instruction->GetFieldType(),
4708 instruction->GetFieldIndex(),
4709 instruction->GetDexPc(),
4710 calling_convention);
4711}
4712
4713void LocationsBuilderMIPS::VisitUnresolvedStaticFieldSet(
4714 HUnresolvedStaticFieldSet* instruction) {
4715 FieldAccessCallingConventionMIPS calling_convention;
4716 codegen_->CreateUnresolvedFieldLocationSummary(instruction,
4717 instruction->GetFieldType(),
4718 calling_convention);
4719}
4720
4721void InstructionCodeGeneratorMIPS::VisitUnresolvedStaticFieldSet(
4722 HUnresolvedStaticFieldSet* instruction) {
4723 FieldAccessCallingConventionMIPS calling_convention;
4724 codegen_->GenerateUnresolvedFieldAccess(instruction,
4725 instruction->GetFieldType(),
4726 instruction->GetFieldIndex(),
4727 instruction->GetDexPc(),
4728 calling_convention);
4729}
4730
4731void LocationsBuilderMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
4732 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4733}
4734
4735void InstructionCodeGeneratorMIPS::VisitSuspendCheck(HSuspendCheck* instruction) {
4736 HBasicBlock* block = instruction->GetBlock();
4737 if (block->GetLoopInformation() != nullptr) {
4738 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4739 // The back edge will generate the suspend check.
4740 return;
4741 }
4742 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4743 // The goto will generate the suspend check.
4744 return;
4745 }
4746 GenerateSuspendCheck(instruction, nullptr);
4747}
4748
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004749void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
4750 LocationSummary* locations =
4751 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4752 InvokeRuntimeCallingConvention calling_convention;
4753 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4754}
4755
4756void InstructionCodeGeneratorMIPS::VisitThrow(HThrow* instruction) {
4757 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
4758 instruction,
4759 instruction->GetDexPc(),
4760 nullptr,
4761 IsDirectEntrypoint(kQuickDeliverException));
4762 CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
4763}
4764
4765void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
4766 Primitive::Type input_type = conversion->GetInputType();
4767 Primitive::Type result_type = conversion->GetResultType();
4768 DCHECK_NE(input_type, result_type);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08004769 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004770
4771 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) ||
4772 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) {
4773 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
4774 }
4775
4776 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
Alexey Frunzebaf60b72015-12-22 15:15:03 -08004777 if (!isR6 &&
4778 ((Primitive::IsFloatingPointType(result_type) && input_type == Primitive::kPrimLong) ||
4779 (result_type == Primitive::kPrimLong && Primitive::IsFloatingPointType(input_type)))) {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004780 call_kind = LocationSummary::kCall;
4781 }
4782
4783 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
4784
4785 if (call_kind == LocationSummary::kNoCall) {
4786 if (Primitive::IsFloatingPointType(input_type)) {
4787 locations->SetInAt(0, Location::RequiresFpuRegister());
4788 } else {
4789 locations->SetInAt(0, Location::RequiresRegister());
4790 }
4791
4792 if (Primitive::IsFloatingPointType(result_type)) {
4793 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4794 } else {
4795 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
4796 }
4797 } else {
4798 InvokeRuntimeCallingConvention calling_convention;
4799
4800 if (Primitive::IsFloatingPointType(input_type)) {
4801 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
4802 } else {
4803 DCHECK_EQ(input_type, Primitive::kPrimLong);
4804 locations->SetInAt(0, Location::RegisterPairLocation(
4805 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
4806 }
4807
4808 locations->SetOut(calling_convention.GetReturnLocation(result_type));
4809 }
4810}
4811
4812void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversion) {
4813 LocationSummary* locations = conversion->GetLocations();
4814 Primitive::Type result_type = conversion->GetResultType();
4815 Primitive::Type input_type = conversion->GetInputType();
4816 bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
Alexey Frunzebaf60b72015-12-22 15:15:03 -08004817 bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
4818 bool fpu_32bit = codegen_->GetInstructionSetFeatures().Is32BitFloatingPoint();
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004819
4820 DCHECK_NE(input_type, result_type);
4821
4822 if (result_type == Primitive::kPrimLong && Primitive::IsIntegralType(input_type)) {
4823 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
4824 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
4825 Register src = locations->InAt(0).AsRegister<Register>();
4826
4827 __ Move(dst_low, src);
4828 __ Sra(dst_high, src, 31);
4829 } else if (Primitive::IsIntegralType(result_type) && Primitive::IsIntegralType(input_type)) {
4830 Register dst = locations->Out().AsRegister<Register>();
4831 Register src = (input_type == Primitive::kPrimLong)
4832 ? locations->InAt(0).AsRegisterPairLow<Register>()
4833 : locations->InAt(0).AsRegister<Register>();
4834
4835 switch (result_type) {
4836 case Primitive::kPrimChar:
4837 __ Andi(dst, src, 0xFFFF);
4838 break;
4839 case Primitive::kPrimByte:
4840 if (has_sign_extension) {
4841 __ Seb(dst, src);
4842 } else {
4843 __ Sll(dst, src, 24);
4844 __ Sra(dst, dst, 24);
4845 }
4846 break;
4847 case Primitive::kPrimShort:
4848 if (has_sign_extension) {
4849 __ Seh(dst, src);
4850 } else {
4851 __ Sll(dst, src, 16);
4852 __ Sra(dst, dst, 16);
4853 }
4854 break;
4855 case Primitive::kPrimInt:
4856 __ Move(dst, src);
4857 break;
4858
4859 default:
4860 LOG(FATAL) << "Unexpected type conversion from " << input_type
4861 << " to " << result_type;
4862 }
4863 } else if (Primitive::IsFloatingPointType(result_type) && Primitive::IsIntegralType(input_type)) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08004864 if (input_type == Primitive::kPrimLong) {
4865 if (isR6) {
4866 // cvt.s.l/cvt.d.l requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
4867 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
4868 Register src_high = locations->InAt(0).AsRegisterPairHigh<Register>();
4869 Register src_low = locations->InAt(0).AsRegisterPairLow<Register>();
4870 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4871 __ Mtc1(src_low, FTMP);
4872 __ Mthc1(src_high, FTMP);
4873 if (result_type == Primitive::kPrimFloat) {
4874 __ Cvtsl(dst, FTMP);
4875 } else {
4876 __ Cvtdl(dst, FTMP);
4877 }
4878 } else {
4879 int32_t entry_offset = (result_type == Primitive::kPrimFloat) ? QUICK_ENTRY_POINT(pL2f)
4880 : QUICK_ENTRY_POINT(pL2d);
4881 bool direct = (result_type == Primitive::kPrimFloat) ? IsDirectEntrypoint(kQuickL2f)
4882 : IsDirectEntrypoint(kQuickL2d);
4883 codegen_->InvokeRuntime(entry_offset,
4884 conversion,
4885 conversion->GetDexPc(),
4886 nullptr,
4887 direct);
4888 if (result_type == Primitive::kPrimFloat) {
4889 CheckEntrypointTypes<kQuickL2f, float, int64_t>();
4890 } else {
4891 CheckEntrypointTypes<kQuickL2d, double, int64_t>();
4892 }
4893 }
4894 } else {
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004895 Register src = locations->InAt(0).AsRegister<Register>();
4896 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
4897 __ Mtc1(src, FTMP);
4898 if (result_type == Primitive::kPrimFloat) {
4899 __ Cvtsw(dst, FTMP);
4900 } else {
4901 __ Cvtdw(dst, FTMP);
4902 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004903 }
4904 } else if (Primitive::IsIntegralType(result_type) && Primitive::IsFloatingPointType(input_type)) {
4905 CHECK(result_type == Primitive::kPrimInt || result_type == Primitive::kPrimLong);
Alexey Frunzebaf60b72015-12-22 15:15:03 -08004906 if (result_type == Primitive::kPrimLong) {
4907 if (isR6) {
4908 // trunc.l.s/trunc.l.d requires MIPSR2+ with FR=1. MIPS32R6 is implemented as a secondary
4909 // architecture on top of MIPS64R6, which has FR=1, and therefore can use the instruction.
4910 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
4911 Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
4912 Register dst_low = locations->Out().AsRegisterPairLow<Register>();
4913 MipsLabel truncate;
4914 MipsLabel done;
4915
4916 // When NAN2008=0 (R2 and before), the truncate instruction produces the maximum positive
4917 // value when the input is either a NaN or is outside of the range of the output type
4918 // after the truncation. IOW, the three special cases (NaN, too small, too big) produce
4919 // the same result.
4920 //
4921 // When NAN2008=1 (R6), the truncate instruction caps the output at the minimum/maximum
4922 // value of the output type if the input is outside of the range after the truncation or
4923 // produces 0 when the input is a NaN. IOW, the three special cases produce three distinct
4924 // results. This matches the desired float/double-to-int/long conversion exactly.
4925 //
4926 // So, NAN2008 affects handling of negative values and NaNs by the truncate instruction.
4927 //
4928 // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
4929 // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
4930 // even though it must be NAN2008=1 on R6.
4931 //
4932 // The code takes care of the different behaviors by first comparing the input to the
4933 // minimum output value (-2**-63 for truncating to long, -2**-31 for truncating to int).
4934 // If the input is greater than or equal to the minimum, it procedes to the truncate
4935 // instruction, which will handle such an input the same way irrespective of NAN2008.
4936 // Otherwise the input is compared to itself to determine whether it is a NaN or not
4937 // in order to return either zero or the minimum value.
4938 //
4939 // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
4940 // truncate instruction for MIPS64R6.
4941 if (input_type == Primitive::kPrimFloat) {
4942 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int64_t>::min());
4943 __ LoadConst32(TMP, min_val);
4944 __ Mtc1(TMP, FTMP);
4945 __ CmpLeS(FTMP, FTMP, src);
4946 } else {
4947 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int64_t>::min());
4948 __ LoadConst32(TMP, High32Bits(min_val));
4949 __ Mtc1(ZERO, FTMP);
4950 __ Mthc1(TMP, FTMP);
4951 __ CmpLeD(FTMP, FTMP, src);
4952 }
4953
4954 __ Bc1nez(FTMP, &truncate);
4955
4956 if (input_type == Primitive::kPrimFloat) {
4957 __ CmpEqS(FTMP, src, src);
4958 } else {
4959 __ CmpEqD(FTMP, src, src);
4960 }
4961 __ Move(dst_low, ZERO);
4962 __ LoadConst32(dst_high, std::numeric_limits<int32_t>::min());
4963 __ Mfc1(TMP, FTMP);
4964 __ And(dst_high, dst_high, TMP);
4965
4966 __ B(&done);
4967
4968 __ Bind(&truncate);
4969
4970 if (input_type == Primitive::kPrimFloat) {
4971 __ TruncLS(FTMP, src);
4972 } else {
4973 __ TruncLD(FTMP, src);
4974 }
4975 __ Mfc1(dst_low, FTMP);
4976 __ Mfhc1(dst_high, FTMP);
4977
4978 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004979 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08004980 int32_t entry_offset = (input_type == Primitive::kPrimFloat) ? QUICK_ENTRY_POINT(pF2l)
4981 : QUICK_ENTRY_POINT(pD2l);
4982 bool direct = (result_type == Primitive::kPrimFloat) ? IsDirectEntrypoint(kQuickF2l)
4983 : IsDirectEntrypoint(kQuickD2l);
4984 codegen_->InvokeRuntime(entry_offset, conversion, conversion->GetDexPc(), nullptr, direct);
4985 if (input_type == Primitive::kPrimFloat) {
4986 CheckEntrypointTypes<kQuickF2l, int64_t, float>();
4987 } else {
4988 CheckEntrypointTypes<kQuickD2l, int64_t, double>();
4989 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02004990 }
4991 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08004992 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
4993 Register dst = locations->Out().AsRegister<Register>();
4994 MipsLabel truncate;
4995 MipsLabel done;
4996
4997 // The following code supports both NAN2008=0 and NAN2008=1 behaviors of the truncate
4998 // instruction, the reason being that the emulator implements NAN2008=0 on MIPS64R6,
4999 // even though it must be NAN2008=1 on R6.
5000 //
5001 // For details see the large comment above for the truncation of float/double to long on R6.
5002 //
5003 // TODO: simplify this when the emulator correctly implements NAN2008=1 behavior of the
5004 // truncate instruction for MIPS64R6.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005005 if (input_type == Primitive::kPrimFloat) {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005006 uint32_t min_val = bit_cast<uint32_t, float>(std::numeric_limits<int32_t>::min());
5007 __ LoadConst32(TMP, min_val);
5008 __ Mtc1(TMP, FTMP);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005009 } else {
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005010 uint64_t min_val = bit_cast<uint64_t, double>(std::numeric_limits<int32_t>::min());
5011 __ LoadConst32(TMP, High32Bits(min_val));
5012 __ Mtc1(ZERO, FTMP);
5013 if (fpu_32bit) {
5014 __ Mtc1(TMP, static_cast<FRegister>(FTMP + 1));
5015 } else {
5016 __ Mthc1(TMP, FTMP);
5017 }
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005018 }
Alexey Frunzebaf60b72015-12-22 15:15:03 -08005019
5020 if (isR6) {
5021 if (input_type == Primitive::kPrimFloat) {
5022 __ CmpLeS(FTMP, FTMP, src);
5023 } else {
5024 __ CmpLeD(FTMP, FTMP, src);
5025 }
5026 __ Bc1nez(FTMP, &truncate);
5027
5028 if (input_type == Primitive::kPrimFloat) {
5029 __ CmpEqS(FTMP, src, src);
5030 } else {
5031 __ CmpEqD(FTMP, src, src);
5032 }
5033 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
5034 __ Mfc1(TMP, FTMP);
5035 __ And(dst, dst, TMP);
5036 } else {
5037 if (input_type == Primitive::kPrimFloat) {
5038 __ ColeS(0, FTMP, src);
5039 } else {
5040 __ ColeD(0, FTMP, src);
5041 }
5042 __ Bc1t(0, &truncate);
5043
5044 if (input_type == Primitive::kPrimFloat) {
5045 __ CeqS(0, src, src);
5046 } else {
5047 __ CeqD(0, src, src);
5048 }
5049 __ LoadConst32(dst, std::numeric_limits<int32_t>::min());
5050 __ Movf(dst, ZERO, 0);
5051 }
5052
5053 __ B(&done);
5054
5055 __ Bind(&truncate);
5056
5057 if (input_type == Primitive::kPrimFloat) {
5058 __ TruncWS(FTMP, src);
5059 } else {
5060 __ TruncWD(FTMP, src);
5061 }
5062 __ Mfc1(dst, FTMP);
5063
5064 __ Bind(&done);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005065 }
5066 } else if (Primitive::IsFloatingPointType(result_type) &&
5067 Primitive::IsFloatingPointType(input_type)) {
5068 FRegister dst = locations->Out().AsFpuRegister<FRegister>();
5069 FRegister src = locations->InAt(0).AsFpuRegister<FRegister>();
5070 if (result_type == Primitive::kPrimFloat) {
5071 __ Cvtsd(dst, src);
5072 } else {
5073 __ Cvtds(dst, src);
5074 }
5075 } else {
5076 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type
5077 << " to " << result_type;
5078 }
5079}
5080
5081void LocationsBuilderMIPS::VisitUShr(HUShr* ushr) {
5082 HandleShift(ushr);
5083}
5084
5085void InstructionCodeGeneratorMIPS::VisitUShr(HUShr* ushr) {
5086 HandleShift(ushr);
5087}
5088
5089void LocationsBuilderMIPS::VisitXor(HXor* instruction) {
5090 HandleBinaryOp(instruction);
5091}
5092
5093void InstructionCodeGeneratorMIPS::VisitXor(HXor* instruction) {
5094 HandleBinaryOp(instruction);
5095}
5096
5097void LocationsBuilderMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
5098 // Nothing to do, this should be removed during prepare for register allocator.
5099 LOG(FATAL) << "Unreachable";
5100}
5101
5102void InstructionCodeGeneratorMIPS::VisitBoundType(HBoundType* instruction ATTRIBUTE_UNUSED) {
5103 // Nothing to do, this should be removed during prepare for register allocator.
5104 LOG(FATAL) << "Unreachable";
5105}
5106
5107void LocationsBuilderMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005108 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005109}
5110
5111void InstructionCodeGeneratorMIPS::VisitEqual(HEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005112 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005113}
5114
5115void LocationsBuilderMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005116 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005117}
5118
5119void InstructionCodeGeneratorMIPS::VisitNotEqual(HNotEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005120 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005121}
5122
5123void LocationsBuilderMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005124 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005125}
5126
5127void InstructionCodeGeneratorMIPS::VisitLessThan(HLessThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005128 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005129}
5130
5131void LocationsBuilderMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005132 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005133}
5134
5135void InstructionCodeGeneratorMIPS::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005136 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005137}
5138
5139void LocationsBuilderMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005140 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005141}
5142
5143void InstructionCodeGeneratorMIPS::VisitGreaterThan(HGreaterThan* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005144 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005145}
5146
5147void LocationsBuilderMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005148 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005149}
5150
5151void InstructionCodeGeneratorMIPS::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005152 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005153}
5154
5155void LocationsBuilderMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005156 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005157}
5158
5159void InstructionCodeGeneratorMIPS::VisitBelow(HBelow* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005160 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005161}
5162
5163void LocationsBuilderMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005164 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005165}
5166
5167void InstructionCodeGeneratorMIPS::VisitBelowOrEqual(HBelowOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005168 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005169}
5170
5171void LocationsBuilderMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005172 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005173}
5174
5175void InstructionCodeGeneratorMIPS::VisitAbove(HAbove* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005176 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005177}
5178
5179void LocationsBuilderMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005180 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005181}
5182
5183void InstructionCodeGeneratorMIPS::VisitAboveOrEqual(HAboveOrEqual* comp) {
Vladimir Marko5f7b58e2015-11-23 19:49:34 +00005184 HandleCondition(comp);
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005185}
5186
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005187void LocationsBuilderMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5188 LocationSummary* locations =
5189 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5190 locations->SetInAt(0, Location::RequiresRegister());
5191}
5192
5193void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5194 int32_t lower_bound = switch_instr->GetStartValue();
5195 int32_t num_entries = switch_instr->GetNumEntries();
5196 LocationSummary* locations = switch_instr->GetLocations();
5197 Register value_reg = locations->InAt(0).AsRegister<Register>();
5198 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5199
5200 // Create a set of compare/jumps.
Vladimir Markof3e0ee22015-12-17 15:23:13 +00005201 Register temp_reg = TMP;
5202 __ Addiu32(temp_reg, value_reg, -lower_bound);
5203 // Jump to default if index is negative
5204 // Note: We don't check the case that index is positive while value < lower_bound, because in
5205 // this case, index >= num_entries must be true. So that we can save one branch instruction.
5206 __ Bltz(temp_reg, codegen_->GetLabelOf(default_block));
5207
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005208 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
Vladimir Markof3e0ee22015-12-17 15:23:13 +00005209 // Jump to successors[0] if value == lower_bound.
5210 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[0]));
5211 int32_t last_index = 0;
5212 for (; num_entries - last_index > 2; last_index += 2) {
5213 __ Addiu(temp_reg, temp_reg, -2);
5214 // Jump to successors[last_index + 1] if value < case_value[last_index + 2].
5215 __ Bltz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
5216 // Jump to successors[last_index + 2] if value == case_value[last_index + 2].
5217 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 2]));
5218 }
5219 if (num_entries - last_index == 2) {
5220 // The last missing case_value.
5221 __ Addiu(temp_reg, temp_reg, -1);
5222 __ Beqz(temp_reg, codegen_->GetLabelOf(successors[last_index + 1]));
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005223 }
5224
Vladimir Markof3e0ee22015-12-17 15:23:13 +00005225 // And the default for any other value.
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005226 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5227 __ B(codegen_->GetLabelOf(default_block));
5228 }
5229}
5230
5231void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
5232 // The trampoline uses the same calling convention as dex calling conventions,
5233 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
5234 // the method_idx.
5235 HandleInvoke(invoke);
5236}
5237
5238void InstructionCodeGeneratorMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
5239 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
5240}
5241
Roland Levillain2aba7cd2016-02-03 12:27:20 +00005242void LocationsBuilderMIPS::VisitClassTableGet(HClassTableGet* instruction) {
5243 LocationSummary* locations =
5244 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5245 locations->SetInAt(0, Location::RequiresRegister());
5246 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005247}
5248
Roland Levillain2aba7cd2016-02-03 12:27:20 +00005249void InstructionCodeGeneratorMIPS::VisitClassTableGet(HClassTableGet* instruction) {
5250 LocationSummary* locations = instruction->GetLocations();
5251 uint32_t method_offset = 0;
Vladimir Markoa1de9182016-02-25 11:37:38 +00005252 if (instruction->GetTableKind() == HClassTableGet::TableKind::kVTable) {
Roland Levillain2aba7cd2016-02-03 12:27:20 +00005253 method_offset = mirror::Class::EmbeddedVTableEntryOffset(
5254 instruction->GetIndex(), kMipsPointerSize).SizeValue();
5255 } else {
5256 method_offset = mirror::Class::EmbeddedImTableEntryOffset(
5257 instruction->GetIndex() % mirror::Class::kImtSize, kMipsPointerSize).Uint32Value();
5258 }
5259 __ LoadFromOffset(kLoadWord,
5260 locations->Out().AsRegister<Register>(),
5261 locations->InAt(0).AsRegister<Register>(),
5262 method_offset);
Nicolas Geoffraya42363f2015-12-17 14:57:09 +00005263}
5264
Goran Jakovljevicf652cec2015-08-25 16:11:42 +02005265#undef __
5266#undef QUICK_ENTRY_POINT
5267
5268} // namespace mips
5269} // namespace art