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