blob: 74be954a7584863b1693bb975a1a2538fd6ee9f0 [file] [log] [blame]
Chris Larsen3039e382015-08-26 07:54:08 -07001/*
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 "intrinsics_mips64.h"
18
19#include "arch/mips64/instruction_set_features_mips64.h"
20#include "art_method.h"
21#include "code_generator_mips64.h"
22#include "entrypoints/quick/quick_entrypoints.h"
23#include "intrinsics.h"
24#include "mirror/array-inl.h"
Andreas Gampe895f9222017-07-05 09:53:32 -070025#include "mirror/object_array-inl.h"
Chris Larsen3039e382015-08-26 07:54:08 -070026#include "mirror/string.h"
Andreas Gampe508fdf32017-06-05 16:42:13 -070027#include "scoped_thread_state_change-inl.h"
Chris Larsen3039e382015-08-26 07:54:08 -070028#include "thread.h"
29#include "utils/mips64/assembler_mips64.h"
30#include "utils/mips64/constants_mips64.h"
31
32namespace art {
33
34namespace mips64 {
35
36IntrinsicLocationsBuilderMIPS64::IntrinsicLocationsBuilderMIPS64(CodeGeneratorMIPS64* codegen)
Chris Larsen5633ce72017-04-10 15:47:40 -070037 : codegen_(codegen), arena_(codegen->GetGraph()->GetArena()) {
Chris Larsen3039e382015-08-26 07:54:08 -070038}
39
40Mips64Assembler* IntrinsicCodeGeneratorMIPS64::GetAssembler() {
41 return reinterpret_cast<Mips64Assembler*>(codegen_->GetAssembler());
42}
43
44ArenaAllocator* IntrinsicCodeGeneratorMIPS64::GetAllocator() {
45 return codegen_->GetGraph()->GetArena();
46}
47
Chris Larsen9701c2e2015-09-04 17:22:47 -070048#define __ codegen->GetAssembler()->
49
50static void MoveFromReturnRegister(Location trg,
51 Primitive::Type type,
52 CodeGeneratorMIPS64* codegen) {
53 if (!trg.IsValid()) {
54 DCHECK_EQ(type, Primitive::kPrimVoid);
55 return;
56 }
57
58 DCHECK_NE(type, Primitive::kPrimVoid);
59
60 if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
61 GpuRegister trg_reg = trg.AsRegister<GpuRegister>();
62 if (trg_reg != V0) {
63 __ Move(V0, trg_reg);
64 }
65 } else {
66 FpuRegister trg_reg = trg.AsFpuRegister<FpuRegister>();
67 if (trg_reg != F0) {
68 if (type == Primitive::kPrimFloat) {
69 __ MovS(F0, trg_reg);
70 } else {
71 __ MovD(F0, trg_reg);
72 }
73 }
74 }
75}
76
77static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS64* codegen) {
78 InvokeDexCallingConventionVisitorMIPS64 calling_convention_visitor;
79 IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
80}
81
82// Slow-path for fallback (calling the managed code to handle the
83// intrinsic) in an intrinsified call. This will copy the arguments
84// into the positions for a regular call.
85//
86// Note: The actual parameters are required to be in the locations
87// given by the invoke's location summary. If an intrinsic
88// modifies those locations before a slowpath call, they must be
89// restored!
90class IntrinsicSlowPathMIPS64 : public SlowPathCodeMIPS64 {
91 public:
David Srbecky9cd6d372016-02-09 15:24:47 +000092 explicit IntrinsicSlowPathMIPS64(HInvoke* invoke)
93 : SlowPathCodeMIPS64(invoke), invoke_(invoke) { }
Chris Larsen9701c2e2015-09-04 17:22:47 -070094
95 void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
96 CodeGeneratorMIPS64* codegen = down_cast<CodeGeneratorMIPS64*>(codegen_in);
97
98 __ Bind(GetEntryLabel());
99
100 SaveLiveRegisters(codegen, invoke_->GetLocations());
101
102 MoveArguments(invoke_, codegen);
103
104 if (invoke_->IsInvokeStaticOrDirect()) {
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100105 codegen->GenerateStaticOrDirectCall(
106 invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(A0), this);
Chris Larsen9701c2e2015-09-04 17:22:47 -0700107 } else {
Vladimir Markoe7197bf2017-06-02 17:00:23 +0100108 codegen->GenerateVirtualCall(
109 invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0), this);
Chris Larsen9701c2e2015-09-04 17:22:47 -0700110 }
111
112 // Copy the result back to the expected output.
113 Location out = invoke_->GetLocations()->Out();
114 if (out.IsValid()) {
115 DCHECK(out.IsRegister()); // TODO: Replace this when we support output in memory.
116 DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
117 MoveFromReturnRegister(out, invoke_->GetType(), codegen);
118 }
119
120 RestoreLiveRegisters(codegen, invoke_->GetLocations());
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700121 __ Bc(GetExitLabel());
Chris Larsen9701c2e2015-09-04 17:22:47 -0700122 }
123
124 const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS64"; }
125
126 private:
127 // The instruction where this slow path is happening.
128 HInvoke* const invoke_;
129
130 DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS64);
131};
132
133#undef __
134
Chris Larsen3039e382015-08-26 07:54:08 -0700135bool IntrinsicLocationsBuilderMIPS64::TryDispatch(HInvoke* invoke) {
136 Dispatch(invoke);
137 LocationSummary* res = invoke->GetLocations();
138 return res != nullptr && res->Intrinsified();
139}
140
141#define __ assembler->
142
143static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
144 LocationSummary* locations = new (arena) LocationSummary(invoke,
145 LocationSummary::kNoCall,
146 kIntrinsified);
147 locations->SetInAt(0, Location::RequiresFpuRegister());
148 locations->SetOut(Location::RequiresRegister());
149}
150
151static void MoveFPToInt(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
152 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
153 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
154
155 if (is64bit) {
156 __ Dmfc1(out, in);
157 } else {
158 __ Mfc1(out, in);
159 }
160}
161
162// long java.lang.Double.doubleToRawLongBits(double)
163void IntrinsicLocationsBuilderMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
164 CreateFPToIntLocations(arena_, invoke);
165}
166
167void IntrinsicCodeGeneratorMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000168 MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen3039e382015-08-26 07:54:08 -0700169}
170
171// int java.lang.Float.floatToRawIntBits(float)
172void IntrinsicLocationsBuilderMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
173 CreateFPToIntLocations(arena_, invoke);
174}
175
176void IntrinsicCodeGeneratorMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000177 MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen3039e382015-08-26 07:54:08 -0700178}
179
180static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
181 LocationSummary* locations = new (arena) LocationSummary(invoke,
182 LocationSummary::kNoCall,
183 kIntrinsified);
184 locations->SetInAt(0, Location::RequiresRegister());
185 locations->SetOut(Location::RequiresFpuRegister());
186}
187
188static void MoveIntToFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
189 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
190 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
191
192 if (is64bit) {
193 __ Dmtc1(in, out);
194 } else {
195 __ Mtc1(in, out);
196 }
197}
198
199// double java.lang.Double.longBitsToDouble(long)
200void IntrinsicLocationsBuilderMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
201 CreateIntToFPLocations(arena_, invoke);
202}
203
204void IntrinsicCodeGeneratorMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000205 MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen3039e382015-08-26 07:54:08 -0700206}
207
208// float java.lang.Float.intBitsToFloat(int)
209void IntrinsicLocationsBuilderMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
210 CreateIntToFPLocations(arena_, invoke);
211}
212
213void IntrinsicCodeGeneratorMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000214 MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen3039e382015-08-26 07:54:08 -0700215}
216
217static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
218 LocationSummary* locations = new (arena) LocationSummary(invoke,
219 LocationSummary::kNoCall,
220 kIntrinsified);
221 locations->SetInAt(0, Location::RequiresRegister());
222 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
223}
224
225static void GenReverseBytes(LocationSummary* locations,
226 Primitive::Type type,
227 Mips64Assembler* assembler) {
228 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
229 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
230
231 switch (type) {
232 case Primitive::kPrimShort:
233 __ Dsbh(out, in);
234 __ Seh(out, out);
235 break;
236 case Primitive::kPrimInt:
237 __ Rotr(out, in, 16);
238 __ Wsbh(out, out);
239 break;
240 case Primitive::kPrimLong:
241 __ Dsbh(out, in);
242 __ Dshd(out, out);
243 break;
244 default:
245 LOG(FATAL) << "Unexpected size for reverse-bytes: " << type;
246 UNREACHABLE();
247 }
248}
249
250// int java.lang.Integer.reverseBytes(int)
251void IntrinsicLocationsBuilderMIPS64::VisitIntegerReverseBytes(HInvoke* invoke) {
252 CreateIntToIntLocations(arena_, invoke);
253}
254
255void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverseBytes(HInvoke* invoke) {
256 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
257}
258
259// long java.lang.Long.reverseBytes(long)
260void IntrinsicLocationsBuilderMIPS64::VisitLongReverseBytes(HInvoke* invoke) {
261 CreateIntToIntLocations(arena_, invoke);
262}
263
264void IntrinsicCodeGeneratorMIPS64::VisitLongReverseBytes(HInvoke* invoke) {
265 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
266}
267
268// short java.lang.Short.reverseBytes(short)
269void IntrinsicLocationsBuilderMIPS64::VisitShortReverseBytes(HInvoke* invoke) {
270 CreateIntToIntLocations(arena_, invoke);
271}
272
273void IntrinsicCodeGeneratorMIPS64::VisitShortReverseBytes(HInvoke* invoke) {
274 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
275}
276
Chris Larsen81284372015-10-21 15:28:53 -0700277static void GenNumberOfLeadingZeroes(LocationSummary* locations,
278 bool is64bit,
279 Mips64Assembler* assembler) {
Chris Larsen3039e382015-08-26 07:54:08 -0700280 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
281 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
282
283 if (is64bit) {
284 __ Dclz(out, in);
285 } else {
286 __ Clz(out, in);
287 }
288}
289
290// int java.lang.Integer.numberOfLeadingZeros(int i)
291void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
292 CreateIntToIntLocations(arena_, invoke);
293}
294
295void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000296 GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen3039e382015-08-26 07:54:08 -0700297}
298
299// int java.lang.Long.numberOfLeadingZeros(long i)
300void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
301 CreateIntToIntLocations(arena_, invoke);
302}
303
304void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000305 GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen0646da72015-09-22 16:02:40 -0700306}
307
Chris Larsen81284372015-10-21 15:28:53 -0700308static void GenNumberOfTrailingZeroes(LocationSummary* locations,
309 bool is64bit,
310 Mips64Assembler* assembler) {
Chris Larsen0646da72015-09-22 16:02:40 -0700311 Location in = locations->InAt(0);
312 Location out = locations->Out();
313
314 if (is64bit) {
315 __ Dsbh(out.AsRegister<GpuRegister>(), in.AsRegister<GpuRegister>());
316 __ Dshd(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
317 __ Dbitswap(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
318 __ Dclz(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
319 } else {
320 __ Rotr(out.AsRegister<GpuRegister>(), in.AsRegister<GpuRegister>(), 16);
321 __ Wsbh(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
322 __ Bitswap(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
323 __ Clz(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
324 }
325}
326
327// int java.lang.Integer.numberOfTrailingZeros(int i)
328void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
329 CreateIntToIntLocations(arena_, invoke);
330}
331
332void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000333 GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen0646da72015-09-22 16:02:40 -0700334}
335
336// int java.lang.Long.numberOfTrailingZeros(long i)
337void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
338 CreateIntToIntLocations(arena_, invoke);
339}
340
341void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000342 GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen3039e382015-08-26 07:54:08 -0700343}
344
345static void GenReverse(LocationSummary* locations,
346 Primitive::Type type,
347 Mips64Assembler* assembler) {
348 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
349
350 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
351 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
352
353 if (type == Primitive::kPrimInt) {
354 __ Rotr(out, in, 16);
355 __ Wsbh(out, out);
356 __ Bitswap(out, out);
357 } else {
358 __ Dsbh(out, in);
359 __ Dshd(out, out);
360 __ Dbitswap(out, out);
361 }
362}
363
364// int java.lang.Integer.reverse(int)
365void IntrinsicLocationsBuilderMIPS64::VisitIntegerReverse(HInvoke* invoke) {
366 CreateIntToIntLocations(arena_, invoke);
367}
368
369void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverse(HInvoke* invoke) {
370 GenReverse(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
371}
372
373// long java.lang.Long.reverse(long)
374void IntrinsicLocationsBuilderMIPS64::VisitLongReverse(HInvoke* invoke) {
375 CreateIntToIntLocations(arena_, invoke);
376}
377
378void IntrinsicCodeGeneratorMIPS64::VisitLongReverse(HInvoke* invoke) {
379 GenReverse(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
380}
381
Chris Larsen0b7ac982015-09-04 12:54:28 -0700382static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
383 LocationSummary* locations = new (arena) LocationSummary(invoke,
384 LocationSummary::kNoCall,
385 kIntrinsified);
386 locations->SetInAt(0, Location::RequiresFpuRegister());
387 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
388}
389
Chris Larsen7fda7852016-04-21 16:00:36 -0700390static void GenBitCount(LocationSummary* locations,
391 const Primitive::Type type,
392 Mips64Assembler* assembler) {
393 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
394 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
395
396 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
397
398 // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
399 //
400 // A generalization of the best bit counting method to integers of
401 // bit-widths up to 128 (parameterized by type T) is this:
402 //
403 // v = v - ((v >> 1) & (T)~(T)0/3); // temp
404 // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); // temp
405 // v = (v + (v >> 4)) & (T)~(T)0/255*15; // temp
406 // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; // count
407 //
408 // For comparison, for 32-bit quantities, this algorithm can be executed
409 // using 20 MIPS instructions (the calls to LoadConst32() generate two
410 // machine instructions each for the values being used in this algorithm).
411 // A(n unrolled) loop-based algorithm requires 25 instructions.
412 //
413 // For a 64-bit operand this can be performed in 24 instructions compared
414 // to a(n unrolled) loop based algorithm which requires 38 instructions.
415 //
416 // There are algorithms which are faster in the cases where very few
417 // bits are set but the algorithm here attempts to minimize the total
418 // number of instructions executed even when a large number of bits
419 // are set.
420
421 if (type == Primitive::kPrimInt) {
422 __ Srl(TMP, in, 1);
423 __ LoadConst32(AT, 0x55555555);
424 __ And(TMP, TMP, AT);
425 __ Subu(TMP, in, TMP);
426 __ LoadConst32(AT, 0x33333333);
427 __ And(out, TMP, AT);
428 __ Srl(TMP, TMP, 2);
429 __ And(TMP, TMP, AT);
430 __ Addu(TMP, out, TMP);
431 __ Srl(out, TMP, 4);
432 __ Addu(out, out, TMP);
433 __ LoadConst32(AT, 0x0F0F0F0F);
434 __ And(out, out, AT);
435 __ LoadConst32(TMP, 0x01010101);
436 __ MulR6(out, out, TMP);
437 __ Srl(out, out, 24);
438 } else if (type == Primitive::kPrimLong) {
439 __ Dsrl(TMP, in, 1);
440 __ LoadConst64(AT, 0x5555555555555555L);
441 __ And(TMP, TMP, AT);
442 __ Dsubu(TMP, in, TMP);
443 __ LoadConst64(AT, 0x3333333333333333L);
444 __ And(out, TMP, AT);
445 __ Dsrl(TMP, TMP, 2);
446 __ And(TMP, TMP, AT);
447 __ Daddu(TMP, out, TMP);
448 __ Dsrl(out, TMP, 4);
449 __ Daddu(out, out, TMP);
450 __ LoadConst64(AT, 0x0F0F0F0F0F0F0F0FL);
451 __ And(out, out, AT);
452 __ LoadConst64(TMP, 0x0101010101010101L);
453 __ Dmul(out, out, TMP);
454 __ Dsrl32(out, out, 24);
455 }
456}
457
458// int java.lang.Integer.bitCount(int)
459void IntrinsicLocationsBuilderMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
460 CreateIntToIntLocations(arena_, invoke);
461}
462
463void IntrinsicCodeGeneratorMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
464 GenBitCount(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
465}
466
467// int java.lang.Long.bitCount(long)
468void IntrinsicLocationsBuilderMIPS64::VisitLongBitCount(HInvoke* invoke) {
469 CreateIntToIntLocations(arena_, invoke);
470}
471
472void IntrinsicCodeGeneratorMIPS64::VisitLongBitCount(HInvoke* invoke) {
473 GenBitCount(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
474}
475
Chris Larsen0b7ac982015-09-04 12:54:28 -0700476static void MathAbsFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
477 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
478 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
479
480 if (is64bit) {
481 __ AbsD(out, in);
482 } else {
483 __ AbsS(out, in);
484 }
485}
486
487// double java.lang.Math.abs(double)
488void IntrinsicLocationsBuilderMIPS64::VisitMathAbsDouble(HInvoke* invoke) {
489 CreateFPToFPLocations(arena_, invoke);
490}
491
492void IntrinsicCodeGeneratorMIPS64::VisitMathAbsDouble(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000493 MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700494}
495
496// float java.lang.Math.abs(float)
497void IntrinsicLocationsBuilderMIPS64::VisitMathAbsFloat(HInvoke* invoke) {
498 CreateFPToFPLocations(arena_, invoke);
499}
500
501void IntrinsicCodeGeneratorMIPS64::VisitMathAbsFloat(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000502 MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700503}
504
505static void CreateIntToInt(ArenaAllocator* arena, HInvoke* invoke) {
506 LocationSummary* locations = new (arena) LocationSummary(invoke,
507 LocationSummary::kNoCall,
508 kIntrinsified);
509 locations->SetInAt(0, Location::RequiresRegister());
510 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
511}
512
513static void GenAbsInteger(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
514 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
515 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
516
517 if (is64bit) {
518 __ Dsra32(AT, in, 31);
519 __ Xor(out, in, AT);
520 __ Dsubu(out, out, AT);
521 } else {
522 __ Sra(AT, in, 31);
523 __ Xor(out, in, AT);
524 __ Subu(out, out, AT);
525 }
526}
527
528// int java.lang.Math.abs(int)
529void IntrinsicLocationsBuilderMIPS64::VisitMathAbsInt(HInvoke* invoke) {
530 CreateIntToInt(arena_, invoke);
531}
532
533void IntrinsicCodeGeneratorMIPS64::VisitMathAbsInt(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000534 GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700535}
536
537// long java.lang.Math.abs(long)
538void IntrinsicLocationsBuilderMIPS64::VisitMathAbsLong(HInvoke* invoke) {
539 CreateIntToInt(arena_, invoke);
540}
541
542void IntrinsicCodeGeneratorMIPS64::VisitMathAbsLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000543 GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700544}
545
546static void GenMinMaxFP(LocationSummary* locations,
547 bool is_min,
Chris Larsenb74353a2015-11-20 09:07:09 -0800548 Primitive::Type type,
Chris Larsen0b7ac982015-09-04 12:54:28 -0700549 Mips64Assembler* assembler) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800550 FpuRegister a = locations->InAt(0).AsFpuRegister<FpuRegister>();
551 FpuRegister b = locations->InAt(1).AsFpuRegister<FpuRegister>();
Chris Larsen0b7ac982015-09-04 12:54:28 -0700552 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
553
Chris Larsenb74353a2015-11-20 09:07:09 -0800554 Mips64Label noNaNs;
555 Mips64Label done;
556 FpuRegister ftmp = ((out != a) && (out != b)) ? out : FTMP;
557
558 // When Java computes min/max it prefers a NaN to a number; the
559 // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of
560 // the inputs is a NaN and the other is a valid number, the MIPS
561 // instruction will return the number; Java wants the NaN value
562 // returned. This is why there is extra logic preceding the use of
563 // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
564 // NaN, return the NaN, otherwise return the min/max.
565 if (type == Primitive::kPrimDouble) {
566 __ CmpUnD(FTMP, a, b);
567 __ Bc1eqz(FTMP, &noNaNs);
568
569 // One of the inputs is a NaN
570 __ CmpEqD(ftmp, a, a);
571 // If a == a then b is the NaN, otherwise a is the NaN.
572 __ SelD(ftmp, a, b);
573
574 if (ftmp != out) {
575 __ MovD(out, ftmp);
576 }
577
578 __ Bc(&done);
579
580 __ Bind(&noNaNs);
581
Chris Larsen0b7ac982015-09-04 12:54:28 -0700582 if (is_min) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800583 __ MinD(out, a, b);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700584 } else {
Chris Larsenb74353a2015-11-20 09:07:09 -0800585 __ MaxD(out, a, b);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700586 }
587 } else {
Chris Larsenb74353a2015-11-20 09:07:09 -0800588 DCHECK_EQ(type, Primitive::kPrimFloat);
589 __ CmpUnS(FTMP, a, b);
590 __ Bc1eqz(FTMP, &noNaNs);
591
592 // One of the inputs is a NaN
593 __ CmpEqS(ftmp, a, a);
594 // If a == a then b is the NaN, otherwise a is the NaN.
595 __ SelS(ftmp, a, b);
596
597 if (ftmp != out) {
598 __ MovS(out, ftmp);
599 }
600
601 __ Bc(&done);
602
603 __ Bind(&noNaNs);
604
Chris Larsen0b7ac982015-09-04 12:54:28 -0700605 if (is_min) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800606 __ MinS(out, a, b);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700607 } else {
Chris Larsenb74353a2015-11-20 09:07:09 -0800608 __ MaxS(out, a, b);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700609 }
610 }
Chris Larsenb74353a2015-11-20 09:07:09 -0800611
612 __ Bind(&done);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700613}
614
615static void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
616 LocationSummary* locations = new (arena) LocationSummary(invoke,
617 LocationSummary::kNoCall,
618 kIntrinsified);
619 locations->SetInAt(0, Location::RequiresFpuRegister());
620 locations->SetInAt(1, Location::RequiresFpuRegister());
621 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
622}
623
624// double java.lang.Math.min(double, double)
625void IntrinsicLocationsBuilderMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) {
626 CreateFPFPToFPLocations(arena_, invoke);
627}
628
629void IntrinsicCodeGeneratorMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800630 GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, Primitive::kPrimDouble, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700631}
632
633// float java.lang.Math.min(float, float)
634void IntrinsicLocationsBuilderMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) {
635 CreateFPFPToFPLocations(arena_, invoke);
636}
637
638void IntrinsicCodeGeneratorMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800639 GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, Primitive::kPrimFloat, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700640}
641
642// double java.lang.Math.max(double, double)
643void IntrinsicLocationsBuilderMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
644 CreateFPFPToFPLocations(arena_, invoke);
645}
646
647void IntrinsicCodeGeneratorMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800648 GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, Primitive::kPrimDouble, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700649}
650
651// float java.lang.Math.max(float, float)
652void IntrinsicLocationsBuilderMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) {
653 CreateFPFPToFPLocations(arena_, invoke);
654}
655
656void IntrinsicCodeGeneratorMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) {
Chris Larsenb74353a2015-11-20 09:07:09 -0800657 GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, Primitive::kPrimFloat, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700658}
659
660static void GenMinMax(LocationSummary* locations,
661 bool is_min,
662 Mips64Assembler* assembler) {
663 GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
664 GpuRegister rhs = locations->InAt(1).AsRegister<GpuRegister>();
665 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
666
Chris Larsenb74353a2015-11-20 09:07:09 -0800667 if (lhs == rhs) {
668 if (out != lhs) {
669 __ Move(out, lhs);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700670 }
671 } else {
Chris Larsenb74353a2015-11-20 09:07:09 -0800672 // Some architectures, such as ARM and MIPS (prior to r6), have a
673 // conditional move instruction which only changes the target
674 // (output) register if the condition is true (MIPS prior to r6 had
675 // MOVF, MOVT, and MOVZ). The SELEQZ and SELNEZ instructions always
676 // change the target (output) register. If the condition is true the
677 // output register gets the contents of the "rs" register; otherwise,
678 // the output register is set to zero. One consequence of this is
679 // that to implement something like "rd = c==0 ? rs : rt" MIPS64r6
680 // needs to use a pair of SELEQZ/SELNEZ instructions. After
681 // executing this pair of instructions one of the output registers
682 // from the pair will necessarily contain zero. Then the code ORs the
683 // output registers from the SELEQZ/SELNEZ instructions to get the
684 // final result.
685 //
686 // The initial test to see if the output register is same as the
687 // first input register is needed to make sure that value in the
688 // first input register isn't clobbered before we've finished
689 // computing the output value. The logic in the corresponding else
690 // clause performs the same task but makes sure the second input
691 // register isn't clobbered in the event that it's the same register
692 // as the output register; the else clause also handles the case
693 // where the output register is distinct from both the first, and the
694 // second input registers.
695 if (out == lhs) {
696 __ Slt(AT, rhs, lhs);
697 if (is_min) {
698 __ Seleqz(out, lhs, AT);
699 __ Selnez(AT, rhs, AT);
700 } else {
701 __ Selnez(out, lhs, AT);
702 __ Seleqz(AT, rhs, AT);
703 }
Chris Larsen0b7ac982015-09-04 12:54:28 -0700704 } else {
Chris Larsenb74353a2015-11-20 09:07:09 -0800705 __ Slt(AT, lhs, rhs);
706 if (is_min) {
707 __ Seleqz(out, rhs, AT);
708 __ Selnez(AT, lhs, AT);
709 } else {
710 __ Selnez(out, rhs, AT);
711 __ Seleqz(AT, lhs, AT);
712 }
Chris Larsen0b7ac982015-09-04 12:54:28 -0700713 }
Chris Larsenb74353a2015-11-20 09:07:09 -0800714 __ Or(out, out, AT);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700715 }
Chris Larsen0b7ac982015-09-04 12:54:28 -0700716}
717
718static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
719 LocationSummary* locations = new (arena) LocationSummary(invoke,
720 LocationSummary::kNoCall,
721 kIntrinsified);
722 locations->SetInAt(0, Location::RequiresRegister());
723 locations->SetInAt(1, Location::RequiresRegister());
724 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
725}
726
727// int java.lang.Math.min(int, int)
728void IntrinsicLocationsBuilderMIPS64::VisitMathMinIntInt(HInvoke* invoke) {
729 CreateIntIntToIntLocations(arena_, invoke);
730}
731
732void IntrinsicCodeGeneratorMIPS64::VisitMathMinIntInt(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000733 GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700734}
735
736// long java.lang.Math.min(long, long)
737void IntrinsicLocationsBuilderMIPS64::VisitMathMinLongLong(HInvoke* invoke) {
738 CreateIntIntToIntLocations(arena_, invoke);
739}
740
741void IntrinsicCodeGeneratorMIPS64::VisitMathMinLongLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000742 GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700743}
744
745// int java.lang.Math.max(int, int)
746void IntrinsicLocationsBuilderMIPS64::VisitMathMaxIntInt(HInvoke* invoke) {
747 CreateIntIntToIntLocations(arena_, invoke);
748}
749
750void IntrinsicCodeGeneratorMIPS64::VisitMathMaxIntInt(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000751 GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700752}
753
754// long java.lang.Math.max(long, long)
755void IntrinsicLocationsBuilderMIPS64::VisitMathMaxLongLong(HInvoke* invoke) {
756 CreateIntIntToIntLocations(arena_, invoke);
757}
758
759void IntrinsicCodeGeneratorMIPS64::VisitMathMaxLongLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +0000760 GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700761}
762
763// double java.lang.Math.sqrt(double)
764void IntrinsicLocationsBuilderMIPS64::VisitMathSqrt(HInvoke* invoke) {
765 CreateFPToFPLocations(arena_, invoke);
766}
767
768void IntrinsicCodeGeneratorMIPS64::VisitMathSqrt(HInvoke* invoke) {
769 LocationSummary* locations = invoke->GetLocations();
770 Mips64Assembler* assembler = GetAssembler();
771 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
772 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
773
774 __ SqrtD(out, in);
775}
776
Chris Larsen81284372015-10-21 15:28:53 -0700777static void CreateFPToFP(ArenaAllocator* arena,
778 HInvoke* invoke,
779 Location::OutputOverlap overlaps = Location::kOutputOverlap) {
Chris Larsen0b7ac982015-09-04 12:54:28 -0700780 LocationSummary* locations = new (arena) LocationSummary(invoke,
781 LocationSummary::kNoCall,
782 kIntrinsified);
783 locations->SetInAt(0, Location::RequiresFpuRegister());
Chris Larsen81284372015-10-21 15:28:53 -0700784 locations->SetOut(Location::RequiresFpuRegister(), overlaps);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700785}
786
787// double java.lang.Math.rint(double)
788void IntrinsicLocationsBuilderMIPS64::VisitMathRint(HInvoke* invoke) {
Chris Larsen81284372015-10-21 15:28:53 -0700789 CreateFPToFP(arena_, invoke, Location::kNoOutputOverlap);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700790}
791
792void IntrinsicCodeGeneratorMIPS64::VisitMathRint(HInvoke* invoke) {
793 LocationSummary* locations = invoke->GetLocations();
794 Mips64Assembler* assembler = GetAssembler();
795 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
796 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
797
798 __ RintD(out, in);
799}
800
801// double java.lang.Math.floor(double)
802void IntrinsicLocationsBuilderMIPS64::VisitMathFloor(HInvoke* invoke) {
803 CreateFPToFP(arena_, invoke);
804}
805
Chris Larsen14500822015-10-01 11:35:18 -0700806const constexpr uint16_t kFPLeaveUnchanged = kPositiveZero |
807 kPositiveInfinity |
808 kNegativeZero |
809 kNegativeInfinity |
810 kQuietNaN |
811 kSignalingNaN;
Chris Larsen0b7ac982015-09-04 12:54:28 -0700812
Chris Larsen81284372015-10-21 15:28:53 -0700813enum FloatRoundingMode {
814 kFloor,
815 kCeil,
816};
817
818static void GenRoundingMode(LocationSummary* locations,
819 FloatRoundingMode mode,
820 Mips64Assembler* assembler) {
Chris Larsen0b7ac982015-09-04 12:54:28 -0700821 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
822 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
823
Chris Larsen81284372015-10-21 15:28:53 -0700824 DCHECK_NE(in, out);
825
Alexey Frunzea0e87b02015-09-24 22:57:20 -0700826 Mips64Label done;
Chris Larsen0b7ac982015-09-04 12:54:28 -0700827
Chris Larsen81284372015-10-21 15:28:53 -0700828 // double floor/ceil(double in) {
Chris Larsen0b7ac982015-09-04 12:54:28 -0700829 // if in.isNaN || in.isInfinite || in.isZero {
830 // return in;
831 // }
832 __ ClassD(out, in);
833 __ Dmfc1(AT, out);
Chris Larsen14500822015-10-01 11:35:18 -0700834 __ Andi(AT, AT, kFPLeaveUnchanged); // +0.0 | +Inf | -0.0 | -Inf | qNaN | sNaN
Chris Larsen0b7ac982015-09-04 12:54:28 -0700835 __ MovD(out, in);
836 __ Bnezc(AT, &done);
837
Chris Larsen81284372015-10-21 15:28:53 -0700838 // Long outLong = floor/ceil(in);
Goran Jakovljevic716d0732017-04-07 11:18:59 +0200839 // if (outLong == Long.MAX_VALUE) || (outLong == Long.MIN_VALUE) {
Chris Larsen81284372015-10-21 15:28:53 -0700840 // // floor()/ceil() has almost certainly returned a value
841 // // which can't be successfully represented as a signed
842 // // 64-bit number. Java expects that the input value will
843 // // be returned in these cases.
844 // // There is also a small probability that floor(in)/ceil(in)
845 // // correctly truncates/rounds up the input value to
Goran Jakovljevic716d0732017-04-07 11:18:59 +0200846 // // Long.MAX_VALUE or Long.MIN_VALUE. In these cases, this
847 // // exception handling code still does the correct thing.
Chris Larsen0b7ac982015-09-04 12:54:28 -0700848 // return in;
849 // }
Chris Larsen81284372015-10-21 15:28:53 -0700850 if (mode == kFloor) {
851 __ FloorLD(out, in);
852 } else if (mode == kCeil) {
853 __ CeilLD(out, in);
854 }
Chris Larsen0b7ac982015-09-04 12:54:28 -0700855 __ Dmfc1(AT, out);
856 __ MovD(out, in);
Goran Jakovljevic716d0732017-04-07 11:18:59 +0200857 __ Daddiu(TMP, AT, 1);
858 __ Dati(TMP, 0x8000); // TMP = AT + 0x8000 0000 0000 0001
859 // or AT - 0x7FFF FFFF FFFF FFFF.
860 // IOW, TMP = 1 if AT = Long.MIN_VALUE
861 // or TMP = 0 if AT = Long.MAX_VALUE.
862 __ Dsrl(TMP, TMP, 1); // TMP = 0 if AT = Long.MIN_VALUE
863 // or AT = Long.MAX_VALUE.
864 __ Beqzc(TMP, &done);
Chris Larsen0b7ac982015-09-04 12:54:28 -0700865
866 // double out = outLong;
867 // return out;
868 __ Dmtc1(AT, out);
869 __ Cvtdl(out, out);
870 __ Bind(&done);
871 // }
872}
873
Chris Larsen81284372015-10-21 15:28:53 -0700874void IntrinsicCodeGeneratorMIPS64::VisitMathFloor(HInvoke* invoke) {
875 GenRoundingMode(invoke->GetLocations(), kFloor, GetAssembler());
876}
877
Chris Larsen0b7ac982015-09-04 12:54:28 -0700878// double java.lang.Math.ceil(double)
879void IntrinsicLocationsBuilderMIPS64::VisitMathCeil(HInvoke* invoke) {
880 CreateFPToFP(arena_, invoke);
881}
882
883void IntrinsicCodeGeneratorMIPS64::VisitMathCeil(HInvoke* invoke) {
Chris Larsen81284372015-10-21 15:28:53 -0700884 GenRoundingMode(invoke->GetLocations(), kCeil, GetAssembler());
Chris Larsen0b7ac982015-09-04 12:54:28 -0700885}
886
Chris Larsen7adaab02016-04-21 14:49:20 -0700887static void GenRound(LocationSummary* locations, Mips64Assembler* assembler, Primitive::Type type) {
888 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
889 FpuRegister half = locations->GetTemp(0).AsFpuRegister<FpuRegister>();
890 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
891
892 DCHECK(type == Primitive::kPrimFloat || type == Primitive::kPrimDouble);
893
894 Mips64Label done;
Chris Larsen7adaab02016-04-21 14:49:20 -0700895
Chris Larsen7adaab02016-04-21 14:49:20 -0700896 // out = floor(in);
897 //
Lena Djokicf4e23a82017-05-09 15:43:45 +0200898 // if (out != MAX_VALUE && out != MIN_VALUE) {
899 // TMP = ((in - out) >= 0.5) ? 1 : 0;
Chris Larsen7adaab02016-04-21 14:49:20 -0700900 // return out += TMP;
901 // }
Lena Djokicf4e23a82017-05-09 15:43:45 +0200902 // return out;
Chris Larsen7adaab02016-04-21 14:49:20 -0700903
904 // out = floor(in);
905 if (type == Primitive::kPrimDouble) {
906 __ FloorLD(FTMP, in);
907 __ Dmfc1(out, FTMP);
908 } else {
909 __ FloorWS(FTMP, in);
910 __ Mfc1(out, FTMP);
911 }
912
Lena Djokicf4e23a82017-05-09 15:43:45 +0200913 // if (out != MAX_VALUE && out != MIN_VALUE)
Chris Larsen7adaab02016-04-21 14:49:20 -0700914 if (type == Primitive::kPrimDouble) {
Lena Djokicf4e23a82017-05-09 15:43:45 +0200915 __ Daddiu(TMP, out, 1);
916 __ Dati(TMP, 0x8000); // TMP = out + 0x8000 0000 0000 0001
917 // or out - 0x7FFF FFFF FFFF FFFF.
918 // IOW, TMP = 1 if out = Long.MIN_VALUE
919 // or TMP = 0 if out = Long.MAX_VALUE.
920 __ Dsrl(TMP, TMP, 1); // TMP = 0 if out = Long.MIN_VALUE
921 // or out = Long.MAX_VALUE.
922 __ Beqzc(TMP, &done);
Chris Larsen7adaab02016-04-21 14:49:20 -0700923 } else {
Lena Djokicf4e23a82017-05-09 15:43:45 +0200924 __ Addiu(TMP, out, 1);
925 __ Aui(TMP, TMP, 0x8000); // TMP = out + 0x8000 0001
926 // or out - 0x7FFF FFFF.
927 // IOW, TMP = 1 if out = Int.MIN_VALUE
928 // or TMP = 0 if out = Int.MAX_VALUE.
929 __ Srl(TMP, TMP, 1); // TMP = 0 if out = Int.MIN_VALUE
930 // or out = Int.MAX_VALUE.
931 __ Beqzc(TMP, &done);
Chris Larsen7adaab02016-04-21 14:49:20 -0700932 }
Chris Larsen7adaab02016-04-21 14:49:20 -0700933
934 // TMP = (0.5 <= (in - out)) ? -1 : 0;
935 if (type == Primitive::kPrimDouble) {
936 __ Cvtdl(FTMP, FTMP); // Convert output of floor.l.d back to "double".
937 __ LoadConst64(AT, bit_cast<int64_t, double>(0.5));
938 __ SubD(FTMP, in, FTMP);
939 __ Dmtc1(AT, half);
940 __ CmpLeD(FTMP, half, FTMP);
Lena Djokicf4e23a82017-05-09 15:43:45 +0200941 __ Dmfc1(TMP, FTMP);
Chris Larsen7adaab02016-04-21 14:49:20 -0700942 } else {
943 __ Cvtsw(FTMP, FTMP); // Convert output of floor.w.s back to "float".
944 __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
945 __ SubS(FTMP, in, FTMP);
946 __ Mtc1(AT, half);
947 __ CmpLeS(FTMP, half, FTMP);
Lena Djokicf4e23a82017-05-09 15:43:45 +0200948 __ Mfc1(TMP, FTMP);
Chris Larsen7adaab02016-04-21 14:49:20 -0700949 }
950
Chris Larsen7adaab02016-04-21 14:49:20 -0700951 // Return out -= TMP.
952 if (type == Primitive::kPrimDouble) {
Lena Djokicf4e23a82017-05-09 15:43:45 +0200953 __ Dsubu(out, out, TMP);
Chris Larsen7adaab02016-04-21 14:49:20 -0700954 } else {
Lena Djokicf4e23a82017-05-09 15:43:45 +0200955 __ Subu(out, out, TMP);
Chris Larsen7adaab02016-04-21 14:49:20 -0700956 }
957
958 __ Bind(&done);
959}
960
961// int java.lang.Math.round(float)
962void IntrinsicLocationsBuilderMIPS64::VisitMathRoundFloat(HInvoke* invoke) {
963 LocationSummary* locations = new (arena_) LocationSummary(invoke,
964 LocationSummary::kNoCall,
965 kIntrinsified);
966 locations->SetInAt(0, Location::RequiresFpuRegister());
967 locations->AddTemp(Location::RequiresFpuRegister());
968 locations->SetOut(Location::RequiresRegister());
969}
970
971void IntrinsicCodeGeneratorMIPS64::VisitMathRoundFloat(HInvoke* invoke) {
972 GenRound(invoke->GetLocations(), GetAssembler(), Primitive::kPrimFloat);
973}
974
975// long java.lang.Math.round(double)
976void IntrinsicLocationsBuilderMIPS64::VisitMathRoundDouble(HInvoke* invoke) {
977 LocationSummary* locations = new (arena_) LocationSummary(invoke,
978 LocationSummary::kNoCall,
979 kIntrinsified);
980 locations->SetInAt(0, Location::RequiresFpuRegister());
981 locations->AddTemp(Location::RequiresFpuRegister());
982 locations->SetOut(Location::RequiresRegister());
983}
984
985void IntrinsicCodeGeneratorMIPS64::VisitMathRoundDouble(HInvoke* invoke) {
986 GenRound(invoke->GetLocations(), GetAssembler(), Primitive::kPrimDouble);
987}
988
Chris Larsen70fb1f42015-09-04 10:15:27 -0700989// byte libcore.io.Memory.peekByte(long address)
990void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekByte(HInvoke* invoke) {
991 CreateIntToIntLocations(arena_, invoke);
992}
993
994void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekByte(HInvoke* invoke) {
995 Mips64Assembler* assembler = GetAssembler();
996 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
997 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
998
999 __ Lb(out, adr, 0);
1000}
1001
1002// short libcore.io.Memory.peekShort(long address)
1003void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekShortNative(HInvoke* invoke) {
1004 CreateIntToIntLocations(arena_, invoke);
1005}
1006
1007void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekShortNative(HInvoke* invoke) {
1008 Mips64Assembler* assembler = GetAssembler();
1009 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1010 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1011
1012 __ Lh(out, adr, 0);
1013}
1014
1015// int libcore.io.Memory.peekInt(long address)
1016void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekIntNative(HInvoke* invoke) {
1017 CreateIntToIntLocations(arena_, invoke);
1018}
1019
1020void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekIntNative(HInvoke* invoke) {
1021 Mips64Assembler* assembler = GetAssembler();
1022 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1023 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1024
1025 __ Lw(out, adr, 0);
1026}
1027
1028// long libcore.io.Memory.peekLong(long address)
1029void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekLongNative(HInvoke* invoke) {
1030 CreateIntToIntLocations(arena_, invoke);
1031}
1032
1033void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekLongNative(HInvoke* invoke) {
1034 Mips64Assembler* assembler = GetAssembler();
1035 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1036 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1037
1038 __ Ld(out, adr, 0);
1039}
1040
1041static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
1042 LocationSummary* locations = new (arena) LocationSummary(invoke,
1043 LocationSummary::kNoCall,
1044 kIntrinsified);
1045 locations->SetInAt(0, Location::RequiresRegister());
1046 locations->SetInAt(1, Location::RequiresRegister());
1047}
1048
1049// void libcore.io.Memory.pokeByte(long address, byte value)
1050void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeByte(HInvoke* invoke) {
1051 CreateIntIntToVoidLocations(arena_, invoke);
1052}
1053
1054void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeByte(HInvoke* invoke) {
1055 Mips64Assembler* assembler = GetAssembler();
1056 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1057 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1058
1059 __ Sb(val, adr, 0);
1060}
1061
1062// void libcore.io.Memory.pokeShort(long address, short value)
1063void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeShortNative(HInvoke* invoke) {
1064 CreateIntIntToVoidLocations(arena_, invoke);
1065}
1066
1067void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeShortNative(HInvoke* invoke) {
1068 Mips64Assembler* assembler = GetAssembler();
1069 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1070 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1071
1072 __ Sh(val, adr, 0);
1073}
1074
1075// void libcore.io.Memory.pokeInt(long address, int value)
1076void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeIntNative(HInvoke* invoke) {
1077 CreateIntIntToVoidLocations(arena_, invoke);
1078}
1079
1080void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeIntNative(HInvoke* invoke) {
1081 Mips64Assembler* assembler = GetAssembler();
1082 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1083 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1084
1085 __ Sw(val, adr, 00);
1086}
1087
1088// void libcore.io.Memory.pokeLong(long address, long value)
1089void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeLongNative(HInvoke* invoke) {
1090 CreateIntIntToVoidLocations(arena_, invoke);
1091}
1092
1093void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeLongNative(HInvoke* invoke) {
1094 Mips64Assembler* assembler = GetAssembler();
1095 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1096 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1097
1098 __ Sd(val, adr, 0);
1099}
1100
Chris Larsen49e55392015-09-04 16:04:03 -07001101// Thread java.lang.Thread.currentThread()
1102void IntrinsicLocationsBuilderMIPS64::VisitThreadCurrentThread(HInvoke* invoke) {
1103 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1104 LocationSummary::kNoCall,
1105 kIntrinsified);
1106 locations->SetOut(Location::RequiresRegister());
1107}
1108
1109void IntrinsicCodeGeneratorMIPS64::VisitThreadCurrentThread(HInvoke* invoke) {
1110 Mips64Assembler* assembler = GetAssembler();
1111 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1112
1113 __ LoadFromOffset(kLoadUnsignedWord,
1114 out,
1115 TR,
1116 Thread::PeerOffset<kMips64PointerSize>().Int32Value());
1117}
1118
Alexey Frunze15958152017-02-09 19:08:30 -08001119static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
1120 HInvoke* invoke,
1121 Primitive::Type type) {
1122 bool can_call = kEmitCompilerReadBarrier &&
1123 (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
1124 invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
Chris Larsen1360ada2015-09-04 23:38:16 -07001125 LocationSummary* locations = new (arena) LocationSummary(invoke,
Alexey Frunze15958152017-02-09 19:08:30 -08001126 (can_call
1127 ? LocationSummary::kCallOnSlowPath
1128 : LocationSummary::kNoCall),
Chris Larsen1360ada2015-09-04 23:38:16 -07001129 kIntrinsified);
Alexey Frunzec61c0762017-04-10 13:54:23 -07001130 if (can_call && kUseBakerReadBarrier) {
1131 locations->SetCustomSlowPathCallerSaves(RegisterSet::Empty()); // No caller-save registers.
1132 }
Chris Larsen1360ada2015-09-04 23:38:16 -07001133 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1134 locations->SetInAt(1, Location::RequiresRegister());
1135 locations->SetInAt(2, Location::RequiresRegister());
Alexey Frunze15958152017-02-09 19:08:30 -08001136 locations->SetOut(Location::RequiresRegister(),
1137 (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
1138 if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1139 // We need a temporary register for the read barrier marking slow
1140 // path in InstructionCodeGeneratorMIPS64::GenerateReferenceLoadWithBakerReadBarrier.
1141 locations->AddTemp(Location::RequiresRegister());
1142 }
Chris Larsen1360ada2015-09-04 23:38:16 -07001143}
1144
Alexey Frunze15958152017-02-09 19:08:30 -08001145// Note that the caller must supply a properly aligned memory address.
1146// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Chris Larsen1360ada2015-09-04 23:38:16 -07001147static void GenUnsafeGet(HInvoke* invoke,
1148 Primitive::Type type,
1149 bool is_volatile,
1150 CodeGeneratorMIPS64* codegen) {
1151 LocationSummary* locations = invoke->GetLocations();
1152 DCHECK((type == Primitive::kPrimInt) ||
1153 (type == Primitive::kPrimLong) ||
Alexey Frunze15958152017-02-09 19:08:30 -08001154 (type == Primitive::kPrimNot)) << type;
Chris Larsen1360ada2015-09-04 23:38:16 -07001155 Mips64Assembler* assembler = codegen->GetAssembler();
Alexey Frunze15958152017-02-09 19:08:30 -08001156 // Target register.
1157 Location trg_loc = locations->Out();
1158 GpuRegister trg = trg_loc.AsRegister<GpuRegister>();
Chris Larsen1360ada2015-09-04 23:38:16 -07001159 // Object pointer.
Alexey Frunze15958152017-02-09 19:08:30 -08001160 Location base_loc = locations->InAt(1);
1161 GpuRegister base = base_loc.AsRegister<GpuRegister>();
Chris Larsen1360ada2015-09-04 23:38:16 -07001162 // Long offset.
Alexey Frunze15958152017-02-09 19:08:30 -08001163 Location offset_loc = locations->InAt(2);
1164 GpuRegister offset = offset_loc.AsRegister<GpuRegister>();
Chris Larsen1360ada2015-09-04 23:38:16 -07001165
Alexey Frunze15958152017-02-09 19:08:30 -08001166 if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == Primitive::kPrimNot))) {
1167 __ Daddu(TMP, base, offset);
Chris Larsen1360ada2015-09-04 23:38:16 -07001168 }
Alexey Frunze15958152017-02-09 19:08:30 -08001169
Chris Larsen1360ada2015-09-04 23:38:16 -07001170 switch (type) {
Alexey Frunze15958152017-02-09 19:08:30 -08001171 case Primitive::kPrimLong:
1172 __ Ld(trg, TMP, 0);
1173 if (is_volatile) {
1174 __ Sync(0);
1175 }
1176 break;
1177
Chris Larsen1360ada2015-09-04 23:38:16 -07001178 case Primitive::kPrimInt:
1179 __ Lw(trg, TMP, 0);
Alexey Frunze15958152017-02-09 19:08:30 -08001180 if (is_volatile) {
1181 __ Sync(0);
1182 }
Chris Larsen1360ada2015-09-04 23:38:16 -07001183 break;
1184
1185 case Primitive::kPrimNot:
Alexey Frunze15958152017-02-09 19:08:30 -08001186 if (kEmitCompilerReadBarrier) {
1187 if (kUseBakerReadBarrier) {
1188 Location temp = locations->GetTemp(0);
1189 codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
1190 trg_loc,
1191 base,
1192 /* offset */ 0U,
1193 /* index */ offset_loc,
1194 TIMES_1,
1195 temp,
1196 /* needs_null_check */ false);
1197 if (is_volatile) {
1198 __ Sync(0);
1199 }
1200 } else {
1201 __ Lwu(trg, TMP, 0);
1202 if (is_volatile) {
1203 __ Sync(0);
1204 }
1205 codegen->GenerateReadBarrierSlow(invoke,
1206 trg_loc,
1207 trg_loc,
1208 base_loc,
1209 /* offset */ 0U,
1210 /* index */ offset_loc);
1211 }
1212 } else {
1213 __ Lwu(trg, TMP, 0);
1214 if (is_volatile) {
1215 __ Sync(0);
1216 }
1217 __ MaybeUnpoisonHeapReference(trg);
1218 }
Chris Larsen1360ada2015-09-04 23:38:16 -07001219 break;
1220
1221 default:
1222 LOG(FATAL) << "Unsupported op size " << type;
1223 UNREACHABLE();
1224 }
1225}
1226
1227// int sun.misc.Unsafe.getInt(Object o, long offset)
1228void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGet(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001229 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
Chris Larsen1360ada2015-09-04 23:38:16 -07001230}
1231
1232void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGet(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001233 GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001234}
1235
1236// int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
1237void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001238 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
Chris Larsen1360ada2015-09-04 23:38:16 -07001239}
1240
1241void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001242 GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001243}
1244
1245// long sun.misc.Unsafe.getLong(Object o, long offset)
1246void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001247 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
Chris Larsen1360ada2015-09-04 23:38:16 -07001248}
1249
1250void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001251 GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001252}
1253
1254// long sun.misc.Unsafe.getLongVolatile(Object o, long offset)
1255void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001256 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
Chris Larsen1360ada2015-09-04 23:38:16 -07001257}
1258
1259void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001260 GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001261}
1262
1263// Object sun.misc.Unsafe.getObject(Object o, long offset)
1264void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001265 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
Chris Larsen1360ada2015-09-04 23:38:16 -07001266}
1267
1268void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001269 GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001270}
1271
1272// Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
1273void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001274 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
Chris Larsen1360ada2015-09-04 23:38:16 -07001275}
1276
1277void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001278 GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001279}
1280
1281static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, HInvoke* invoke) {
1282 LocationSummary* locations = new (arena) LocationSummary(invoke,
1283 LocationSummary::kNoCall,
1284 kIntrinsified);
1285 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1286 locations->SetInAt(1, Location::RequiresRegister());
1287 locations->SetInAt(2, Location::RequiresRegister());
1288 locations->SetInAt(3, Location::RequiresRegister());
1289}
1290
Alexey Frunze15958152017-02-09 19:08:30 -08001291// Note that the caller must supply a properly aligned memory address.
1292// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
Chris Larsen1360ada2015-09-04 23:38:16 -07001293static void GenUnsafePut(LocationSummary* locations,
1294 Primitive::Type type,
1295 bool is_volatile,
1296 bool is_ordered,
1297 CodeGeneratorMIPS64* codegen) {
1298 DCHECK((type == Primitive::kPrimInt) ||
1299 (type == Primitive::kPrimLong) ||
1300 (type == Primitive::kPrimNot));
1301 Mips64Assembler* assembler = codegen->GetAssembler();
1302 // Object pointer.
1303 GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
1304 // Long offset.
1305 GpuRegister offset = locations->InAt(2).AsRegister<GpuRegister>();
1306 GpuRegister value = locations->InAt(3).AsRegister<GpuRegister>();
1307
1308 __ Daddu(TMP, base, offset);
1309 if (is_volatile || is_ordered) {
1310 __ Sync(0);
1311 }
1312 switch (type) {
1313 case Primitive::kPrimInt:
1314 case Primitive::kPrimNot:
Alexey Frunzec061de12017-02-14 13:27:23 -08001315 if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1316 __ PoisonHeapReference(AT, value);
1317 __ Sw(AT, TMP, 0);
1318 } else {
1319 __ Sw(value, TMP, 0);
1320 }
Chris Larsen1360ada2015-09-04 23:38:16 -07001321 break;
1322
1323 case Primitive::kPrimLong:
1324 __ Sd(value, TMP, 0);
1325 break;
1326
1327 default:
1328 LOG(FATAL) << "Unsupported op size " << type;
1329 UNREACHABLE();
1330 }
1331 if (is_volatile) {
1332 __ Sync(0);
1333 }
1334
1335 if (type == Primitive::kPrimNot) {
Goran Jakovljevic8ed18262016-01-22 13:01:00 +01001336 bool value_can_be_null = true; // TODO: Worth finding out this information?
1337 codegen->MarkGCCard(base, value, value_can_be_null);
Chris Larsen1360ada2015-09-04 23:38:16 -07001338 }
1339}
1340
1341// void sun.misc.Unsafe.putInt(Object o, long offset, int x)
1342void IntrinsicLocationsBuilderMIPS64::VisitUnsafePut(HInvoke* invoke) {
1343 CreateIntIntIntIntToVoid(arena_, invoke);
1344}
1345
1346void IntrinsicCodeGeneratorMIPS64::VisitUnsafePut(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001347 GenUnsafePut(invoke->GetLocations(),
1348 Primitive::kPrimInt,
1349 /* is_volatile */ false,
1350 /* is_ordered */ false,
1351 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001352}
1353
1354// void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x)
1355void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) {
1356 CreateIntIntIntIntToVoid(arena_, invoke);
1357}
1358
1359void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001360 GenUnsafePut(invoke->GetLocations(),
1361 Primitive::kPrimInt,
1362 /* is_volatile */ false,
1363 /* is_ordered */ true,
1364 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001365}
1366
1367// void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x)
1368void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) {
1369 CreateIntIntIntIntToVoid(arena_, invoke);
1370}
1371
1372void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001373 GenUnsafePut(invoke->GetLocations(),
1374 Primitive::kPrimInt,
1375 /* is_volatile */ true,
1376 /* is_ordered */ false,
1377 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001378}
1379
1380// void sun.misc.Unsafe.putObject(Object o, long offset, Object x)
1381void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObject(HInvoke* invoke) {
1382 CreateIntIntIntIntToVoid(arena_, invoke);
1383}
1384
1385void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObject(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001386 GenUnsafePut(invoke->GetLocations(),
1387 Primitive::kPrimNot,
1388 /* is_volatile */ false,
1389 /* is_ordered */ false,
1390 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001391}
1392
1393// void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x)
1394void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1395 CreateIntIntIntIntToVoid(arena_, invoke);
1396}
1397
1398void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001399 GenUnsafePut(invoke->GetLocations(),
1400 Primitive::kPrimNot,
1401 /* is_volatile */ false,
1402 /* is_ordered */ true,
1403 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001404}
1405
1406// void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x)
1407void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1408 CreateIntIntIntIntToVoid(arena_, invoke);
1409}
1410
1411void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001412 GenUnsafePut(invoke->GetLocations(),
1413 Primitive::kPrimNot,
1414 /* is_volatile */ true,
1415 /* is_ordered */ false,
1416 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001417}
1418
1419// void sun.misc.Unsafe.putLong(Object o, long offset, long x)
1420void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLong(HInvoke* invoke) {
1421 CreateIntIntIntIntToVoid(arena_, invoke);
1422}
1423
1424void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLong(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001425 GenUnsafePut(invoke->GetLocations(),
1426 Primitive::kPrimLong,
1427 /* is_volatile */ false,
1428 /* is_ordered */ false,
1429 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001430}
1431
1432// void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x)
1433void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1434 CreateIntIntIntIntToVoid(arena_, invoke);
1435}
1436
1437void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001438 GenUnsafePut(invoke->GetLocations(),
1439 Primitive::kPrimLong,
1440 /* is_volatile */ false,
1441 /* is_ordered */ true,
1442 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001443}
1444
1445// void sun.misc.Unsafe.putLongVolatile(Object o, long offset, long x)
1446void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1447 CreateIntIntIntIntToVoid(arena_, invoke);
1448}
1449
1450void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001451 GenUnsafePut(invoke->GetLocations(),
1452 Primitive::kPrimLong,
1453 /* is_volatile */ true,
1454 /* is_ordered */ false,
1455 codegen_);
Chris Larsen1360ada2015-09-04 23:38:16 -07001456}
1457
Alexey Frunze15958152017-02-09 19:08:30 -08001458static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, HInvoke* invoke) {
1459 bool can_call = kEmitCompilerReadBarrier &&
1460 kUseBakerReadBarrier &&
1461 (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
Chris Larsen36427492015-10-23 02:19:38 -07001462 LocationSummary* locations = new (arena) LocationSummary(invoke,
Alexey Frunze15958152017-02-09 19:08:30 -08001463 (can_call
1464 ? LocationSummary::kCallOnSlowPath
1465 : LocationSummary::kNoCall),
Chris Larsen36427492015-10-23 02:19:38 -07001466 kIntrinsified);
1467 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1468 locations->SetInAt(1, Location::RequiresRegister());
1469 locations->SetInAt(2, Location::RequiresRegister());
1470 locations->SetInAt(3, Location::RequiresRegister());
1471 locations->SetInAt(4, Location::RequiresRegister());
Chris Larsen36427492015-10-23 02:19:38 -07001472 locations->SetOut(Location::RequiresRegister());
Alexey Frunze15958152017-02-09 19:08:30 -08001473
1474 // Temporary register used in CAS by (Baker) read barrier.
1475 if (can_call) {
1476 locations->AddTemp(Location::RequiresRegister());
1477 }
Chris Larsen36427492015-10-23 02:19:38 -07001478}
1479
Alexey Frunze15958152017-02-09 19:08:30 -08001480// Note that the caller must supply a properly aligned memory address.
1481// If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
1482static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorMIPS64* codegen) {
Chris Larsen36427492015-10-23 02:19:38 -07001483 Mips64Assembler* assembler = codegen->GetAssembler();
Alexey Frunze15958152017-02-09 19:08:30 -08001484 LocationSummary* locations = invoke->GetLocations();
Chris Larsen36427492015-10-23 02:19:38 -07001485 GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
Alexey Frunze15958152017-02-09 19:08:30 -08001486 Location offset_loc = locations->InAt(2);
1487 GpuRegister offset = offset_loc.AsRegister<GpuRegister>();
Chris Larsen36427492015-10-23 02:19:38 -07001488 GpuRegister expected = locations->InAt(3).AsRegister<GpuRegister>();
1489 GpuRegister value = locations->InAt(4).AsRegister<GpuRegister>();
Alexey Frunze15958152017-02-09 19:08:30 -08001490 Location out_loc = locations->Out();
1491 GpuRegister out = out_loc.AsRegister<GpuRegister>();
Chris Larsen36427492015-10-23 02:19:38 -07001492
1493 DCHECK_NE(base, out);
1494 DCHECK_NE(offset, out);
1495 DCHECK_NE(expected, out);
1496
Goran Jakovljevic8ed18262016-01-22 13:01:00 +01001497 if (type == Primitive::kPrimNot) {
Alexey Frunze15958152017-02-09 19:08:30 -08001498 // The only read barrier implementation supporting the
1499 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1500 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1501
1502 // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
1503 // object and scan the receiver at the next GC for nothing.
Goran Jakovljevic8ed18262016-01-22 13:01:00 +01001504 bool value_can_be_null = true; // TODO: Worth finding out this information?
1505 codegen->MarkGCCard(base, value, value_can_be_null);
Alexey Frunze15958152017-02-09 19:08:30 -08001506
1507 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1508 Location temp = locations->GetTemp(0);
1509 // Need to make sure the reference stored in the field is a to-space
1510 // one before attempting the CAS or the CAS could fail incorrectly.
1511 codegen->GenerateReferenceLoadWithBakerReadBarrier(
1512 invoke,
1513 out_loc, // Unused, used only as a "temporary" within the read barrier.
1514 base,
1515 /* offset */ 0u,
1516 /* index */ offset_loc,
1517 ScaleFactor::TIMES_1,
1518 temp,
1519 /* needs_null_check */ false,
1520 /* always_update_field */ true);
1521 }
Goran Jakovljevic8ed18262016-01-22 13:01:00 +01001522 }
1523
Alexey Frunzec061de12017-02-14 13:27:23 -08001524 Mips64Label loop_head, exit_loop;
1525 __ Daddu(TMP, base, offset);
1526
1527 if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1528 __ PoisonHeapReference(expected);
1529 // Do not poison `value`, if it is the same register as
1530 // `expected`, which has just been poisoned.
1531 if (value != expected) {
1532 __ PoisonHeapReference(value);
1533 }
1534 }
1535
Chris Larsen36427492015-10-23 02:19:38 -07001536 // do {
1537 // tmp_value = [tmp_ptr] - expected;
1538 // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
1539 // result = tmp_value != 0;
1540
Chris Larsen36427492015-10-23 02:19:38 -07001541 __ Sync(0);
1542 __ Bind(&loop_head);
1543 if (type == Primitive::kPrimLong) {
1544 __ Lld(out, TMP);
1545 } else {
Roland Levillain391b8662015-12-18 11:43:38 +00001546 // Note: We will need a read barrier here, when read barrier
1547 // support is added to the MIPS64 back end.
Chris Larsen36427492015-10-23 02:19:38 -07001548 __ Ll(out, TMP);
Alexey Frunzec061de12017-02-14 13:27:23 -08001549 if (type == Primitive::kPrimNot) {
1550 // The LL instruction sign-extends the 32-bit value, but
1551 // 32-bit references must be zero-extended. Zero-extend `out`.
1552 __ Dext(out, out, 0, 32);
1553 }
Chris Larsen36427492015-10-23 02:19:38 -07001554 }
1555 __ Dsubu(out, out, expected); // If we didn't get the 'expected'
1556 __ Sltiu(out, out, 1); // value, set 'out' to false, and
1557 __ Beqzc(out, &exit_loop); // return.
1558 __ Move(out, value); // Use 'out' for the 'store conditional' instruction.
1559 // If we use 'value' directly, we would lose 'value'
1560 // in the case that the store fails. Whether the
1561 // store succeeds, or fails, it will load the
Roland Levillain5e8d5f02016-10-18 18:03:43 +01001562 // correct Boolean value into the 'out' register.
Chris Larsen36427492015-10-23 02:19:38 -07001563 if (type == Primitive::kPrimLong) {
1564 __ Scd(out, TMP);
1565 } else {
1566 __ Sc(out, TMP);
1567 }
1568 __ Beqzc(out, &loop_head); // If we couldn't do the read-modify-write
1569 // cycle atomically then retry.
1570 __ Bind(&exit_loop);
1571 __ Sync(0);
Alexey Frunzec061de12017-02-14 13:27:23 -08001572
1573 if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1574 __ UnpoisonHeapReference(expected);
1575 // Do not unpoison `value`, if it is the same register as
1576 // `expected`, which has just been unpoisoned.
1577 if (value != expected) {
1578 __ UnpoisonHeapReference(value);
1579 }
1580 }
Chris Larsen36427492015-10-23 02:19:38 -07001581}
1582
1583// boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
1584void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASInt(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001585 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
Chris Larsen36427492015-10-23 02:19:38 -07001586}
1587
1588void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASInt(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001589 GenCas(invoke, Primitive::kPrimInt, codegen_);
Chris Larsen36427492015-10-23 02:19:38 -07001590}
1591
1592// boolean sun.misc.Unsafe.compareAndSwapLong(Object o, long offset, long expected, long x)
1593void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASLong(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001594 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
Chris Larsen36427492015-10-23 02:19:38 -07001595}
1596
1597void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASLong(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001598 GenCas(invoke, Primitive::kPrimLong, codegen_);
Chris Larsen36427492015-10-23 02:19:38 -07001599}
1600
1601// boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
1602void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASObject(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001603 // The only read barrier implementation supporting the
1604 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1605 if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) {
1606 return;
1607 }
1608
1609 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
Chris Larsen36427492015-10-23 02:19:38 -07001610}
1611
1612void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASObject(HInvoke* invoke) {
Alexey Frunze15958152017-02-09 19:08:30 -08001613 // The only read barrier implementation supporting the
1614 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1615 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1616
1617 GenCas(invoke, Primitive::kPrimNot, codegen_);
Chris Larsen36427492015-10-23 02:19:38 -07001618}
1619
Chris Larsen9701c2e2015-09-04 17:22:47 -07001620// int java.lang.String.compareTo(String anotherString)
1621void IntrinsicLocationsBuilderMIPS64::VisitStringCompareTo(HInvoke* invoke) {
1622 LocationSummary* locations = new (arena_) LocationSummary(invoke,
Serban Constantinescufc734082016-07-19 17:18:07 +01001623 LocationSummary::kCallOnMainAndSlowPath,
Chris Larsen9701c2e2015-09-04 17:22:47 -07001624 kIntrinsified);
1625 InvokeRuntimeCallingConvention calling_convention;
1626 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1627 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1628 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1629 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1630}
1631
1632void IntrinsicCodeGeneratorMIPS64::VisitStringCompareTo(HInvoke* invoke) {
1633 Mips64Assembler* assembler = GetAssembler();
1634 LocationSummary* locations = invoke->GetLocations();
1635
1636 // Note that the null check must have been done earlier.
1637 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1638
1639 GpuRegister argument = locations->InAt(1).AsRegister<GpuRegister>();
1640 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
1641 codegen_->AddSlowPath(slow_path);
1642 __ Beqzc(argument, slow_path->GetEntryLabel());
1643
Serban Constantinescufc734082016-07-19 17:18:07 +01001644 codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
Chris Larsen9701c2e2015-09-04 17:22:47 -07001645 __ Bind(slow_path->GetExitLabel());
1646}
1647
Chris Larsen972d6d72015-10-20 11:29:12 -07001648// boolean java.lang.String.equals(Object anObject)
1649void IntrinsicLocationsBuilderMIPS64::VisitStringEquals(HInvoke* invoke) {
1650 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1651 LocationSummary::kNoCall,
1652 kIntrinsified);
1653 locations->SetInAt(0, Location::RequiresRegister());
1654 locations->SetInAt(1, Location::RequiresRegister());
1655 locations->SetOut(Location::RequiresRegister());
1656
1657 // Temporary registers to store lengths of strings and for calculations.
1658 locations->AddTemp(Location::RequiresRegister());
1659 locations->AddTemp(Location::RequiresRegister());
1660 locations->AddTemp(Location::RequiresRegister());
1661}
1662
1663void IntrinsicCodeGeneratorMIPS64::VisitStringEquals(HInvoke* invoke) {
1664 Mips64Assembler* assembler = GetAssembler();
1665 LocationSummary* locations = invoke->GetLocations();
1666
1667 GpuRegister str = locations->InAt(0).AsRegister<GpuRegister>();
1668 GpuRegister arg = locations->InAt(1).AsRegister<GpuRegister>();
1669 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
1670
1671 GpuRegister temp1 = locations->GetTemp(0).AsRegister<GpuRegister>();
1672 GpuRegister temp2 = locations->GetTemp(1).AsRegister<GpuRegister>();
1673 GpuRegister temp3 = locations->GetTemp(2).AsRegister<GpuRegister>();
1674
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001675 Mips64Label loop;
1676 Mips64Label end;
1677 Mips64Label return_true;
1678 Mips64Label return_false;
Chris Larsen972d6d72015-10-20 11:29:12 -07001679
1680 // Get offsets of count, value, and class fields within a string object.
1681 const int32_t count_offset = mirror::String::CountOffset().Int32Value();
1682 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
1683 const int32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1684
1685 // Note that the null check must have been done earlier.
1686 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1687
1688 // If the register containing the pointer to "this", and the register
1689 // containing the pointer to "anObject" are the same register then
1690 // "this", and "anObject" are the same object and we can
1691 // short-circuit the logic to a true result.
1692 if (str == arg) {
1693 __ LoadConst64(out, 1);
1694 return;
1695 }
1696
Goran Jakovljevic64fa84f2017-02-27 13:14:57 +01001697 StringEqualsOptimizations optimizations(invoke);
1698 if (!optimizations.GetArgumentNotNull()) {
1699 // Check if input is null, return false if it is.
1700 __ Beqzc(arg, &return_false);
1701 }
Chris Larsen972d6d72015-10-20 11:29:12 -07001702
1703 // Reference equality check, return true if same reference.
1704 __ Beqc(str, arg, &return_true);
1705
Goran Jakovljevic64fa84f2017-02-27 13:14:57 +01001706 if (!optimizations.GetArgumentIsString()) {
1707 // Instanceof check for the argument by comparing class fields.
1708 // All string objects must have the same type since String cannot be subclassed.
1709 // Receiver must be a string object, so its class field is equal to all strings' class fields.
1710 // If the argument is a string object, its class field must be equal to receiver's class field.
1711 __ Lw(temp1, str, class_offset);
1712 __ Lw(temp2, arg, class_offset);
1713 __ Bnec(temp1, temp2, &return_false);
1714 }
Chris Larsen972d6d72015-10-20 11:29:12 -07001715
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001716 // Load `count` fields of this and argument strings.
Chris Larsen972d6d72015-10-20 11:29:12 -07001717 __ Lw(temp1, str, count_offset);
1718 __ Lw(temp2, arg, count_offset);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001719 // Check if `count` fields are equal, return false if they're not.
1720 // Also compares the compression style, if differs return false.
Chris Larsen972d6d72015-10-20 11:29:12 -07001721 __ Bnec(temp1, temp2, &return_false);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001722 // Return true if both strings are empty. Even with string compression `count == 0` means empty.
1723 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1724 "Expecting 0=compressed, 1=uncompressed");
Chris Larsen972d6d72015-10-20 11:29:12 -07001725 __ Beqzc(temp1, &return_true);
1726
1727 // Don't overwrite input registers
1728 __ Move(TMP, str);
1729 __ Move(temp3, arg);
1730
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001731 // Assertions that must hold in order to compare strings 8 bytes at a time.
Chris Larsen972d6d72015-10-20 11:29:12 -07001732 DCHECK_ALIGNED(value_offset, 8);
1733 static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
1734
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001735 if (mirror::kUseStringCompression) {
1736 // For string compression, calculate the number of bytes to compare (not chars).
1737 __ Dext(temp2, temp1, 0, 1); // Extract compression flag.
1738 __ Srl(temp1, temp1, 1); // Extract length.
1739 __ Sllv(temp1, temp1, temp2); // Double the byte count if uncompressed.
1740 }
1741
1742 // Loop to compare strings 8 bytes at a time starting at the beginning of the string.
1743 // Ok to do this because strings are zero-padded to kObjectAlignment.
Chris Larsen972d6d72015-10-20 11:29:12 -07001744 __ Bind(&loop);
1745 __ Ld(out, TMP, value_offset);
1746 __ Ld(temp2, temp3, value_offset);
1747 __ Bnec(out, temp2, &return_false);
1748 __ Daddiu(TMP, TMP, 8);
1749 __ Daddiu(temp3, temp3, 8);
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01001750 // With string compression, we have compared 8 bytes, otherwise 4 chars.
1751 __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -8 : -4);
Chris Larsen972d6d72015-10-20 11:29:12 -07001752 __ Bgtzc(temp1, &loop);
1753
1754 // Return true and exit the function.
1755 // If loop does not result in returning false, we return true.
1756 __ Bind(&return_true);
1757 __ LoadConst64(out, 1);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001758 __ Bc(&end);
Chris Larsen972d6d72015-10-20 11:29:12 -07001759
1760 // Return false and exit the function.
1761 __ Bind(&return_false);
1762 __ LoadConst64(out, 0);
1763 __ Bind(&end);
1764}
1765
Chris Larsen9701c2e2015-09-04 17:22:47 -07001766static void GenerateStringIndexOf(HInvoke* invoke,
1767 Mips64Assembler* assembler,
1768 CodeGeneratorMIPS64* codegen,
1769 ArenaAllocator* allocator,
1770 bool start_at_zero) {
1771 LocationSummary* locations = invoke->GetLocations();
1772 GpuRegister tmp_reg = start_at_zero ? locations->GetTemp(0).AsRegister<GpuRegister>() : TMP;
1773
1774 // Note that the null check must have been done earlier.
1775 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1776
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001777 // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
1778 // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
Chris Larsen9701c2e2015-09-04 17:22:47 -07001779 SlowPathCodeMIPS64* slow_path = nullptr;
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001780 HInstruction* code_point = invoke->InputAt(1);
1781 if (code_point->IsIntConstant()) {
Vladimir Markoda051082016-05-17 16:10:20 +01001782 if (!IsUint<16>(code_point->AsIntConstant()->GetValue())) {
Chris Larsen9701c2e2015-09-04 17:22:47 -07001783 // Always needs the slow-path. We could directly dispatch to it,
1784 // but this case should be rare, so for simplicity just put the
1785 // full slow-path down and branch unconditionally.
1786 slow_path = new (allocator) IntrinsicSlowPathMIPS64(invoke);
1787 codegen->AddSlowPath(slow_path);
Alexey Frunzea0e87b02015-09-24 22:57:20 -07001788 __ Bc(slow_path->GetEntryLabel());
Chris Larsen9701c2e2015-09-04 17:22:47 -07001789 __ Bind(slow_path->GetExitLabel());
1790 return;
1791 }
Vladimir Markofb6c90a2016-05-06 15:52:12 +01001792 } else if (code_point->GetType() != Primitive::kPrimChar) {
Chris Larsen9701c2e2015-09-04 17:22:47 -07001793 GpuRegister char_reg = locations->InAt(1).AsRegister<GpuRegister>();
1794 __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
1795 slow_path = new (allocator) IntrinsicSlowPathMIPS64(invoke);
1796 codegen->AddSlowPath(slow_path);
1797 __ Bltuc(tmp_reg, char_reg, slow_path->GetEntryLabel()); // UTF-16 required
1798 }
1799
1800 if (start_at_zero) {
1801 DCHECK_EQ(tmp_reg, A2);
1802 // Start-index = 0.
1803 __ Clear(tmp_reg);
Chris Larsen9701c2e2015-09-04 17:22:47 -07001804 }
1805
Serban Constantinescufc734082016-07-19 17:18:07 +01001806 codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
Roland Levillain42ad2882016-02-29 18:26:54 +00001807 CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>();
Chris Larsen9701c2e2015-09-04 17:22:47 -07001808
1809 if (slow_path != nullptr) {
1810 __ Bind(slow_path->GetExitLabel());
1811 }
1812}
1813
1814// int java.lang.String.indexOf(int ch)
1815void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOf(HInvoke* invoke) {
1816 LocationSummary* locations = new (arena_) LocationSummary(invoke,
Serban Constantinescu806f0122016-03-09 11:10:16 +00001817 LocationSummary::kCallOnMainAndSlowPath,
Chris Larsen9701c2e2015-09-04 17:22:47 -07001818 kIntrinsified);
1819 // We have a hand-crafted assembly stub that follows the runtime
1820 // calling convention. So it's best to align the inputs accordingly.
1821 InvokeRuntimeCallingConvention calling_convention;
1822 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1823 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1824 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1825 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1826
1827 // Need a temp for slow-path codepoint compare, and need to send start-index=0.
1828 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1829}
1830
1831void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOf(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001832 GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true);
Chris Larsen9701c2e2015-09-04 17:22:47 -07001833}
1834
1835// int java.lang.String.indexOf(int ch, int fromIndex)
1836void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
1837 LocationSummary* locations = new (arena_) LocationSummary(invoke,
Serban Constantinescu806f0122016-03-09 11:10:16 +00001838 LocationSummary::kCallOnMainAndSlowPath,
Chris Larsen9701c2e2015-09-04 17:22:47 -07001839 kIntrinsified);
1840 // We have a hand-crafted assembly stub that follows the runtime
1841 // calling convention. So it's best to align the inputs accordingly.
1842 InvokeRuntimeCallingConvention calling_convention;
1843 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1844 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1845 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1846 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1847 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1848}
1849
1850void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
Roland Levillainbf84a3d2015-12-04 14:33:02 +00001851 GenerateStringIndexOf(
1852 invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false);
Chris Larsen9701c2e2015-09-04 17:22:47 -07001853}
1854
Roland Levillaincc3839c2016-02-29 16:23:48 +00001855// java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
Chris Larsen9701c2e2015-09-04 17:22:47 -07001856void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
1857 LocationSummary* locations = new (arena_) LocationSummary(invoke,
Serban Constantinescu806f0122016-03-09 11:10:16 +00001858 LocationSummary::kCallOnMainAndSlowPath,
Chris Larsen9701c2e2015-09-04 17:22:47 -07001859 kIntrinsified);
1860 InvokeRuntimeCallingConvention calling_convention;
1861 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1862 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1863 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1864 locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
1865 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1866 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1867}
1868
1869void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
1870 Mips64Assembler* assembler = GetAssembler();
1871 LocationSummary* locations = invoke->GetLocations();
1872
1873 GpuRegister byte_array = locations->InAt(0).AsRegister<GpuRegister>();
1874 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
1875 codegen_->AddSlowPath(slow_path);
1876 __ Beqzc(byte_array, slow_path->GetEntryLabel());
1877
Serban Constantinescufc734082016-07-19 17:18:07 +01001878 codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
Roland Levillainf969a202016-03-09 16:14:00 +00001879 CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
Chris Larsen9701c2e2015-09-04 17:22:47 -07001880 __ Bind(slow_path->GetExitLabel());
1881}
1882
Roland Levillaincc3839c2016-02-29 16:23:48 +00001883// java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
Chris Larsen9701c2e2015-09-04 17:22:47 -07001884void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) {
1885 LocationSummary* locations = new (arena_) LocationSummary(invoke,
Serban Constantinescu54ff4822016-07-07 18:03:19 +01001886 LocationSummary::kCallOnMainOnly,
Chris Larsen9701c2e2015-09-04 17:22:47 -07001887 kIntrinsified);
1888 InvokeRuntimeCallingConvention calling_convention;
1889 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1890 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1891 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1892 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1893 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1894}
1895
1896void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) {
Roland Levillaincc3839c2016-02-29 16:23:48 +00001897 // No need to emit code checking whether `locations->InAt(2)` is a null
1898 // pointer, as callers of the native method
1899 //
1900 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1901 //
1902 // all include a null check on `data` before calling that method.
Serban Constantinescufc734082016-07-19 17:18:07 +01001903 codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
Roland Levillainf969a202016-03-09 16:14:00 +00001904 CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
Chris Larsen9701c2e2015-09-04 17:22:47 -07001905}
1906
Roland Levillainf969a202016-03-09 16:14:00 +00001907// java.lang.StringFactory.newStringFromString(String toCopy)
Chris Larsen9701c2e2015-09-04 17:22:47 -07001908void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
1909 LocationSummary* locations = new (arena_) LocationSummary(invoke,
Serban Constantinescu806f0122016-03-09 11:10:16 +00001910 LocationSummary::kCallOnMainAndSlowPath,
Chris Larsen9701c2e2015-09-04 17:22:47 -07001911 kIntrinsified);
1912 InvokeRuntimeCallingConvention calling_convention;
1913 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Chris Larsen9701c2e2015-09-04 17:22:47 -07001914 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1915 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1916}
1917
1918void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
1919 Mips64Assembler* assembler = GetAssembler();
1920 LocationSummary* locations = invoke->GetLocations();
1921
1922 GpuRegister string_to_copy = locations->InAt(0).AsRegister<GpuRegister>();
1923 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
1924 codegen_->AddSlowPath(slow_path);
1925 __ Beqzc(string_to_copy, slow_path->GetEntryLabel());
1926
Serban Constantinescufc734082016-07-19 17:18:07 +01001927 codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc(), slow_path);
Roland Levillainf969a202016-03-09 16:14:00 +00001928 CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
Chris Larsen9701c2e2015-09-04 17:22:47 -07001929 __ Bind(slow_path->GetExitLabel());
1930}
1931
Chris Larsenddec7f92016-02-16 12:35:04 -08001932static void GenIsInfinite(LocationSummary* locations,
1933 bool is64bit,
1934 Mips64Assembler* assembler) {
1935 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
1936 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
1937
1938 if (is64bit) {
1939 __ ClassD(FTMP, in);
1940 } else {
1941 __ ClassS(FTMP, in);
1942 }
1943 __ Mfc1(out, FTMP);
1944 __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
1945 __ Sltu(out, ZERO, out);
1946}
1947
1948// boolean java.lang.Float.isInfinite(float)
1949void IntrinsicLocationsBuilderMIPS64::VisitFloatIsInfinite(HInvoke* invoke) {
1950 CreateFPToIntLocations(arena_, invoke);
1951}
1952
1953void IntrinsicCodeGeneratorMIPS64::VisitFloatIsInfinite(HInvoke* invoke) {
1954 GenIsInfinite(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
1955}
1956
1957// boolean java.lang.Double.isInfinite(double)
1958void IntrinsicLocationsBuilderMIPS64::VisitDoubleIsInfinite(HInvoke* invoke) {
1959 CreateFPToIntLocations(arena_, invoke);
1960}
1961
1962void IntrinsicCodeGeneratorMIPS64::VisitDoubleIsInfinite(HInvoke* invoke) {
1963 GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
1964}
1965
Chris Larsene3660592016-11-09 11:13:42 -08001966// void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
1967void IntrinsicLocationsBuilderMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1968 LocationSummary* locations = new (arena_) LocationSummary(invoke,
Chris Larsen366d4332017-03-23 09:02:56 -07001969 LocationSummary::kNoCall,
Chris Larsene3660592016-11-09 11:13:42 -08001970 kIntrinsified);
1971 locations->SetInAt(0, Location::RequiresRegister());
1972 locations->SetInAt(1, Location::RequiresRegister());
1973 locations->SetInAt(2, Location::RequiresRegister());
1974 locations->SetInAt(3, Location::RequiresRegister());
1975 locations->SetInAt(4, Location::RequiresRegister());
1976
Chris Larsen366d4332017-03-23 09:02:56 -07001977 locations->AddTemp(Location::RequiresRegister());
1978 locations->AddTemp(Location::RequiresRegister());
1979 locations->AddTemp(Location::RequiresRegister());
Chris Larsene3660592016-11-09 11:13:42 -08001980}
1981
1982void IntrinsicCodeGeneratorMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
1983 Mips64Assembler* assembler = GetAssembler();
1984 LocationSummary* locations = invoke->GetLocations();
1985
1986 // Check assumption that sizeof(Char) is 2 (used in scaling below).
1987 const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
1988 DCHECK_EQ(char_size, 2u);
1989 const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
1990
1991 GpuRegister srcObj = locations->InAt(0).AsRegister<GpuRegister>();
1992 GpuRegister srcBegin = locations->InAt(1).AsRegister<GpuRegister>();
1993 GpuRegister srcEnd = locations->InAt(2).AsRegister<GpuRegister>();
1994 GpuRegister dstObj = locations->InAt(3).AsRegister<GpuRegister>();
1995 GpuRegister dstBegin = locations->InAt(4).AsRegister<GpuRegister>();
1996
1997 GpuRegister dstPtr = locations->GetTemp(0).AsRegister<GpuRegister>();
Chris Larsene3660592016-11-09 11:13:42 -08001998 GpuRegister srcPtr = locations->GetTemp(1).AsRegister<GpuRegister>();
Chris Larsene3660592016-11-09 11:13:42 -08001999 GpuRegister numChrs = locations->GetTemp(2).AsRegister<GpuRegister>();
Chris Larsene3660592016-11-09 11:13:42 -08002000
2001 Mips64Label done;
Chris Larsen366d4332017-03-23 09:02:56 -07002002 Mips64Label loop;
Chris Larsene3660592016-11-09 11:13:42 -08002003
2004 // Location of data in char array buffer.
2005 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2006
2007 // Get offset of value field within a string object.
2008 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
2009
2010 __ Beqc(srcEnd, srcBegin, &done); // No characters to move.
2011
2012 // Calculate number of characters to be copied.
2013 __ Dsubu(numChrs, srcEnd, srcBegin);
2014
2015 // Calculate destination address.
2016 __ Daddiu(dstPtr, dstObj, data_offset);
2017 __ Dlsa(dstPtr, dstBegin, dstPtr, char_shift);
2018
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002019 if (mirror::kUseStringCompression) {
2020 Mips64Label uncompressed_copy, compressed_loop;
2021 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2022 // Load count field and extract compression flag.
2023 __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset);
2024 __ Dext(TMP, TMP, 0, 1);
2025
Chris Larsen366d4332017-03-23 09:02:56 -07002026 // If string is uncompressed, use uncompressed path.
Goran Jakovljevicf94fa812017-02-10 17:48:52 +01002027 __ Bnezc(TMP, &uncompressed_copy);
2028
2029 // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
2030 __ Daddu(srcPtr, srcObj, srcBegin);
2031 __ Bind(&compressed_loop);
2032 __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset);
2033 __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0);
2034 __ Daddiu(numChrs, numChrs, -1);
2035 __ Daddiu(srcPtr, srcPtr, 1);
2036 __ Daddiu(dstPtr, dstPtr, 2);
2037 __ Bnezc(numChrs, &compressed_loop);
2038
2039 __ Bc(&done);
2040 __ Bind(&uncompressed_copy);
2041 }
2042
Chris Larsene3660592016-11-09 11:13:42 -08002043 // Calculate source address.
2044 __ Daddiu(srcPtr, srcObj, value_offset);
2045 __ Dlsa(srcPtr, srcBegin, srcPtr, char_shift);
2046
Chris Larsen366d4332017-03-23 09:02:56 -07002047 __ Bind(&loop);
2048 __ Lh(AT, srcPtr, 0);
2049 __ Daddiu(numChrs, numChrs, -1);
2050 __ Daddiu(srcPtr, srcPtr, char_size);
2051 __ Sh(AT, dstPtr, 0);
2052 __ Daddiu(dstPtr, dstPtr, char_size);
2053 __ Bnezc(numChrs, &loop);
Chris Larsene3660592016-11-09 11:13:42 -08002054
2055 __ Bind(&done);
2056}
2057
Chris Larsen5863f852017-03-23 15:41:37 -07002058// static void java.lang.System.arraycopy(Object src, int srcPos,
2059// Object dest, int destPos,
2060// int length)
2061void IntrinsicLocationsBuilderMIPS64::VisitSystemArrayCopyChar(HInvoke* invoke) {
2062 HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
2063 HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
2064 HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
2065
2066 // As long as we are checking, we might as well check to see if the src and dest
2067 // positions are >= 0.
2068 if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
2069 (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
2070 // We will have to fail anyways.
2071 return;
2072 }
2073
2074 // And since we are already checking, check the length too.
2075 if (length != nullptr) {
2076 int32_t len = length->GetValue();
2077 if (len < 0) {
2078 // Just call as normal.
2079 return;
2080 }
2081 }
2082
2083 // Okay, it is safe to generate inline code.
2084 LocationSummary* locations =
2085 new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
2086 // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
2087 locations->SetInAt(0, Location::RequiresRegister());
2088 locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
2089 locations->SetInAt(2, Location::RequiresRegister());
2090 locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
2091 locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
2092
2093 locations->AddTemp(Location::RequiresRegister());
2094 locations->AddTemp(Location::RequiresRegister());
2095 locations->AddTemp(Location::RequiresRegister());
2096}
2097
2098// Utility routine to verify that "length(input) - pos >= length"
2099static void EnoughItems(Mips64Assembler* assembler,
2100 GpuRegister length_input_minus_pos,
2101 Location length,
2102 SlowPathCodeMIPS64* slow_path) {
2103 if (length.IsConstant()) {
2104 int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
2105
2106 if (IsInt<16>(length_constant)) {
2107 __ Slti(TMP, length_input_minus_pos, length_constant);
2108 __ Bnezc(TMP, slow_path->GetEntryLabel());
2109 } else {
2110 __ LoadConst32(TMP, length_constant);
2111 __ Bltc(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
2112 }
2113 } else {
2114 __ Bltc(length_input_minus_pos, length.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
2115 }
2116}
2117
2118static void CheckPosition(Mips64Assembler* assembler,
2119 Location pos,
2120 GpuRegister input,
2121 Location length,
2122 SlowPathCodeMIPS64* slow_path,
2123 bool length_is_input_length = false) {
2124 // Where is the length in the Array?
2125 const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
2126
2127 // Calculate length(input) - pos.
2128 if (pos.IsConstant()) {
2129 int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
2130 if (pos_const == 0) {
2131 if (!length_is_input_length) {
2132 // Check that length(input) >= length.
2133 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2134 EnoughItems(assembler, AT, length, slow_path);
2135 }
2136 } else {
2137 // Check that (length(input) - pos) >= zero.
2138 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2139 DCHECK_GT(pos_const, 0);
2140 __ Addiu32(AT, AT, -pos_const);
2141 __ Bltzc(AT, slow_path->GetEntryLabel());
2142
2143 // Verify that (length(input) - pos) >= length.
2144 EnoughItems(assembler, AT, length, slow_path);
2145 }
2146 } else if (length_is_input_length) {
2147 // The only way the copy can succeed is if pos is zero.
2148 GpuRegister pos_reg = pos.AsRegister<GpuRegister>();
2149 __ Bnezc(pos_reg, slow_path->GetEntryLabel());
2150 } else {
2151 // Verify that pos >= 0.
2152 GpuRegister pos_reg = pos.AsRegister<GpuRegister>();
2153 __ Bltzc(pos_reg, slow_path->GetEntryLabel());
2154
2155 // Check that (length(input) - pos) >= zero.
2156 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2157 __ Subu(AT, AT, pos_reg);
2158 __ Bltzc(AT, slow_path->GetEntryLabel());
2159
2160 // Verify that (length(input) - pos) >= length.
2161 EnoughItems(assembler, AT, length, slow_path);
2162 }
2163}
2164
2165void IntrinsicCodeGeneratorMIPS64::VisitSystemArrayCopyChar(HInvoke* invoke) {
2166 Mips64Assembler* assembler = GetAssembler();
2167 LocationSummary* locations = invoke->GetLocations();
2168
2169 GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
2170 Location src_pos = locations->InAt(1);
2171 GpuRegister dest = locations->InAt(2).AsRegister<GpuRegister>();
2172 Location dest_pos = locations->InAt(3);
2173 Location length = locations->InAt(4);
2174
2175 Mips64Label loop;
2176
2177 GpuRegister dest_base = locations->GetTemp(0).AsRegister<GpuRegister>();
2178 GpuRegister src_base = locations->GetTemp(1).AsRegister<GpuRegister>();
2179 GpuRegister count = locations->GetTemp(2).AsRegister<GpuRegister>();
2180
2181 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
2182 codegen_->AddSlowPath(slow_path);
2183
2184 // Bail out if the source and destination are the same (to handle overlap).
2185 __ Beqc(src, dest, slow_path->GetEntryLabel());
2186
2187 // Bail out if the source is null.
2188 __ Beqzc(src, slow_path->GetEntryLabel());
2189
2190 // Bail out if the destination is null.
2191 __ Beqzc(dest, slow_path->GetEntryLabel());
2192
2193 // Load length into register for count.
2194 if (length.IsConstant()) {
2195 __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
2196 } else {
2197 // If the length is negative, bail out.
2198 // We have already checked in the LocationsBuilder for the constant case.
2199 __ Bltzc(length.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
2200
2201 __ Move(count, length.AsRegister<GpuRegister>());
2202 }
2203
2204 // Validity checks: source.
2205 CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
2206
2207 // Validity checks: dest.
2208 CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
2209
2210 // If count is zero, we're done.
2211 __ Beqzc(count, slow_path->GetExitLabel());
2212
2213 // Okay, everything checks out. Finally time to do the copy.
2214 // Check assumption that sizeof(Char) is 2 (used in scaling below).
2215 const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
2216 DCHECK_EQ(char_size, 2u);
2217
2218 const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
2219
2220 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2221
2222 // Calculate source and destination addresses.
2223 if (src_pos.IsConstant()) {
2224 int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
2225
2226 __ Daddiu64(src_base, src, data_offset + char_size * src_pos_const, TMP);
2227 } else {
2228 __ Daddiu64(src_base, src, data_offset, TMP);
2229 __ Dlsa(src_base, src_pos.AsRegister<GpuRegister>(), src_base, char_shift);
2230 }
2231 if (dest_pos.IsConstant()) {
2232 int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
2233
2234 __ Daddiu64(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
2235 } else {
2236 __ Daddiu64(dest_base, dest, data_offset, TMP);
2237 __ Dlsa(dest_base, dest_pos.AsRegister<GpuRegister>(), dest_base, char_shift);
2238 }
2239
2240 __ Bind(&loop);
2241 __ Lh(TMP, src_base, 0);
2242 __ Daddiu(src_base, src_base, char_size);
2243 __ Daddiu(count, count, -1);
2244 __ Sh(TMP, dest_base, 0);
2245 __ Daddiu(dest_base, dest_base, char_size);
2246 __ Bnezc(count, &loop);
2247
2248 __ Bind(slow_path->GetExitLabel());
2249}
2250
Chris Larsenab922502016-04-15 10:00:56 -07002251static void GenHighestOneBit(LocationSummary* locations,
2252 Primitive::Type type,
2253 Mips64Assembler* assembler) {
2254 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << PrettyDescriptor(type);
2255
2256 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
2257 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
2258
2259 if (type == Primitive::kPrimLong) {
2260 __ Dclz(TMP, in);
2261 __ LoadConst64(AT, INT64_C(0x8000000000000000));
Chris Larsen68db2a92016-09-14 15:41:29 -07002262 __ Dsrlv(AT, AT, TMP);
Chris Larsenab922502016-04-15 10:00:56 -07002263 } else {
2264 __ Clz(TMP, in);
2265 __ LoadConst32(AT, 0x80000000);
Chris Larsen68db2a92016-09-14 15:41:29 -07002266 __ Srlv(AT, AT, TMP);
Chris Larsenab922502016-04-15 10:00:56 -07002267 }
2268 // For either value of "type", when "in" is zero, "out" should also
2269 // be zero. Without this extra "and" operation, when "in" is zero,
2270 // "out" would be either Integer.MIN_VALUE, or Long.MIN_VALUE because
2271 // the MIPS logical shift operations "dsrlv", and "srlv" don't use
2272 // the shift amount (TMP) directly; they use either (TMP % 64) or
2273 // (TMP % 32), respectively.
Chris Larsen68db2a92016-09-14 15:41:29 -07002274 __ And(out, AT, in);
Chris Larsenab922502016-04-15 10:00:56 -07002275}
2276
2277// int java.lang.Integer.highestOneBit(int)
2278void IntrinsicLocationsBuilderMIPS64::VisitIntegerHighestOneBit(HInvoke* invoke) {
2279 CreateIntToIntLocations(arena_, invoke);
2280}
2281
2282void IntrinsicCodeGeneratorMIPS64::VisitIntegerHighestOneBit(HInvoke* invoke) {
2283 GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
2284}
2285
2286// long java.lang.Long.highestOneBit(long)
2287void IntrinsicLocationsBuilderMIPS64::VisitLongHighestOneBit(HInvoke* invoke) {
2288 CreateIntToIntLocations(arena_, invoke);
2289}
2290
2291void IntrinsicCodeGeneratorMIPS64::VisitLongHighestOneBit(HInvoke* invoke) {
2292 GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
2293}
2294
2295static void GenLowestOneBit(LocationSummary* locations,
2296 Primitive::Type type,
2297 Mips64Assembler* assembler) {
2298 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << PrettyDescriptor(type);
2299
2300 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
2301 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
2302
2303 if (type == Primitive::kPrimLong) {
2304 __ Dsubu(TMP, ZERO, in);
2305 } else {
2306 __ Subu(TMP, ZERO, in);
2307 }
2308 __ And(out, TMP, in);
2309}
2310
2311// int java.lang.Integer.lowestOneBit(int)
2312void IntrinsicLocationsBuilderMIPS64::VisitIntegerLowestOneBit(HInvoke* invoke) {
2313 CreateIntToIntLocations(arena_, invoke);
2314}
2315
2316void IntrinsicCodeGeneratorMIPS64::VisitIntegerLowestOneBit(HInvoke* invoke) {
2317 GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
2318}
2319
2320// long java.lang.Long.lowestOneBit(long)
2321void IntrinsicLocationsBuilderMIPS64::VisitLongLowestOneBit(HInvoke* invoke) {
2322 CreateIntToIntLocations(arena_, invoke);
2323}
2324
2325void IntrinsicCodeGeneratorMIPS64::VisitLongLowestOneBit(HInvoke* invoke) {
2326 GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
2327}
2328
Chris Larsen74c20582017-03-28 22:17:35 -07002329static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
2330 LocationSummary* locations = new (arena) LocationSummary(invoke,
2331 LocationSummary::kCallOnMainOnly,
2332 kIntrinsified);
2333 InvokeRuntimeCallingConvention calling_convention;
2334
2335 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2336 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
2337}
2338
2339static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
2340 LocationSummary* locations = new (arena) LocationSummary(invoke,
2341 LocationSummary::kCallOnMainOnly,
2342 kIntrinsified);
2343 InvokeRuntimeCallingConvention calling_convention;
2344
2345 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2346 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2347 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
2348}
2349
2350static void GenFPToFPCall(HInvoke* invoke,
2351 CodeGeneratorMIPS64* codegen,
2352 QuickEntrypointEnum entry) {
2353 LocationSummary* locations = invoke->GetLocations();
2354 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
2355 DCHECK_EQ(in, F12);
2356 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
2357 DCHECK_EQ(out, F0);
2358
2359 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2360}
2361
2362static void GenFPFPToFPCall(HInvoke* invoke,
2363 CodeGeneratorMIPS64* codegen,
2364 QuickEntrypointEnum entry) {
2365 LocationSummary* locations = invoke->GetLocations();
2366 FpuRegister in0 = locations->InAt(0).AsFpuRegister<FpuRegister>();
2367 DCHECK_EQ(in0, F12);
2368 FpuRegister in1 = locations->InAt(1).AsFpuRegister<FpuRegister>();
2369 DCHECK_EQ(in1, F13);
2370 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
2371 DCHECK_EQ(out, F0);
2372
2373 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2374}
2375
2376// static double java.lang.Math.cos(double a)
2377void IntrinsicLocationsBuilderMIPS64::VisitMathCos(HInvoke* invoke) {
2378 CreateFPToFPCallLocations(arena_, invoke);
2379}
2380
2381void IntrinsicCodeGeneratorMIPS64::VisitMathCos(HInvoke* invoke) {
2382 GenFPToFPCall(invoke, codegen_, kQuickCos);
2383}
2384
2385// static double java.lang.Math.sin(double a)
2386void IntrinsicLocationsBuilderMIPS64::VisitMathSin(HInvoke* invoke) {
2387 CreateFPToFPCallLocations(arena_, invoke);
2388}
2389
2390void IntrinsicCodeGeneratorMIPS64::VisitMathSin(HInvoke* invoke) {
2391 GenFPToFPCall(invoke, codegen_, kQuickSin);
2392}
2393
2394// static double java.lang.Math.acos(double a)
2395void IntrinsicLocationsBuilderMIPS64::VisitMathAcos(HInvoke* invoke) {
2396 CreateFPToFPCallLocations(arena_, invoke);
2397}
2398
2399void IntrinsicCodeGeneratorMIPS64::VisitMathAcos(HInvoke* invoke) {
2400 GenFPToFPCall(invoke, codegen_, kQuickAcos);
2401}
2402
2403// static double java.lang.Math.asin(double a)
2404void IntrinsicLocationsBuilderMIPS64::VisitMathAsin(HInvoke* invoke) {
2405 CreateFPToFPCallLocations(arena_, invoke);
2406}
2407
2408void IntrinsicCodeGeneratorMIPS64::VisitMathAsin(HInvoke* invoke) {
2409 GenFPToFPCall(invoke, codegen_, kQuickAsin);
2410}
2411
2412// static double java.lang.Math.atan(double a)
2413void IntrinsicLocationsBuilderMIPS64::VisitMathAtan(HInvoke* invoke) {
2414 CreateFPToFPCallLocations(arena_, invoke);
2415}
2416
2417void IntrinsicCodeGeneratorMIPS64::VisitMathAtan(HInvoke* invoke) {
2418 GenFPToFPCall(invoke, codegen_, kQuickAtan);
2419}
2420
2421// static double java.lang.Math.atan2(double y, double x)
2422void IntrinsicLocationsBuilderMIPS64::VisitMathAtan2(HInvoke* invoke) {
2423 CreateFPFPToFPCallLocations(arena_, invoke);
2424}
2425
2426void IntrinsicCodeGeneratorMIPS64::VisitMathAtan2(HInvoke* invoke) {
2427 GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
2428}
2429
2430// static double java.lang.Math.cbrt(double a)
2431void IntrinsicLocationsBuilderMIPS64::VisitMathCbrt(HInvoke* invoke) {
2432 CreateFPToFPCallLocations(arena_, invoke);
2433}
2434
2435void IntrinsicCodeGeneratorMIPS64::VisitMathCbrt(HInvoke* invoke) {
2436 GenFPToFPCall(invoke, codegen_, kQuickCbrt);
2437}
2438
2439// static double java.lang.Math.cosh(double x)
2440void IntrinsicLocationsBuilderMIPS64::VisitMathCosh(HInvoke* invoke) {
2441 CreateFPToFPCallLocations(arena_, invoke);
2442}
2443
2444void IntrinsicCodeGeneratorMIPS64::VisitMathCosh(HInvoke* invoke) {
2445 GenFPToFPCall(invoke, codegen_, kQuickCosh);
2446}
2447
2448// static double java.lang.Math.exp(double a)
2449void IntrinsicLocationsBuilderMIPS64::VisitMathExp(HInvoke* invoke) {
2450 CreateFPToFPCallLocations(arena_, invoke);
2451}
2452
2453void IntrinsicCodeGeneratorMIPS64::VisitMathExp(HInvoke* invoke) {
2454 GenFPToFPCall(invoke, codegen_, kQuickExp);
2455}
2456
2457// static double java.lang.Math.expm1(double x)
2458void IntrinsicLocationsBuilderMIPS64::VisitMathExpm1(HInvoke* invoke) {
2459 CreateFPToFPCallLocations(arena_, invoke);
2460}
2461
2462void IntrinsicCodeGeneratorMIPS64::VisitMathExpm1(HInvoke* invoke) {
2463 GenFPToFPCall(invoke, codegen_, kQuickExpm1);
2464}
2465
2466// static double java.lang.Math.hypot(double x, double y)
2467void IntrinsicLocationsBuilderMIPS64::VisitMathHypot(HInvoke* invoke) {
2468 CreateFPFPToFPCallLocations(arena_, invoke);
2469}
2470
2471void IntrinsicCodeGeneratorMIPS64::VisitMathHypot(HInvoke* invoke) {
2472 GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
2473}
2474
2475// static double java.lang.Math.log(double a)
2476void IntrinsicLocationsBuilderMIPS64::VisitMathLog(HInvoke* invoke) {
2477 CreateFPToFPCallLocations(arena_, invoke);
2478}
2479
2480void IntrinsicCodeGeneratorMIPS64::VisitMathLog(HInvoke* invoke) {
2481 GenFPToFPCall(invoke, codegen_, kQuickLog);
2482}
2483
2484// static double java.lang.Math.log10(double x)
2485void IntrinsicLocationsBuilderMIPS64::VisitMathLog10(HInvoke* invoke) {
2486 CreateFPToFPCallLocations(arena_, invoke);
2487}
2488
2489void IntrinsicCodeGeneratorMIPS64::VisitMathLog10(HInvoke* invoke) {
2490 GenFPToFPCall(invoke, codegen_, kQuickLog10);
2491}
2492
2493// static double java.lang.Math.nextAfter(double start, double direction)
2494void IntrinsicLocationsBuilderMIPS64::VisitMathNextAfter(HInvoke* invoke) {
2495 CreateFPFPToFPCallLocations(arena_, invoke);
2496}
2497
2498void IntrinsicCodeGeneratorMIPS64::VisitMathNextAfter(HInvoke* invoke) {
2499 GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
2500}
2501
2502// static double java.lang.Math.sinh(double x)
2503void IntrinsicLocationsBuilderMIPS64::VisitMathSinh(HInvoke* invoke) {
2504 CreateFPToFPCallLocations(arena_, invoke);
2505}
2506
2507void IntrinsicCodeGeneratorMIPS64::VisitMathSinh(HInvoke* invoke) {
2508 GenFPToFPCall(invoke, codegen_, kQuickSinh);
2509}
2510
2511// static double java.lang.Math.tan(double a)
2512void IntrinsicLocationsBuilderMIPS64::VisitMathTan(HInvoke* invoke) {
2513 CreateFPToFPCallLocations(arena_, invoke);
2514}
2515
2516void IntrinsicCodeGeneratorMIPS64::VisitMathTan(HInvoke* invoke) {
2517 GenFPToFPCall(invoke, codegen_, kQuickTan);
2518}
2519
2520// static double java.lang.Math.tanh(double x)
2521void IntrinsicLocationsBuilderMIPS64::VisitMathTanh(HInvoke* invoke) {
2522 CreateFPToFPCallLocations(arena_, invoke);
2523}
2524
2525void IntrinsicCodeGeneratorMIPS64::VisitMathTanh(HInvoke* invoke) {
2526 GenFPToFPCall(invoke, codegen_, kQuickTanh);
2527}
2528
Chris Larsen5633ce72017-04-10 15:47:40 -07002529// long java.lang.Integer.valueOf(long)
2530void IntrinsicLocationsBuilderMIPS64::VisitIntegerValueOf(HInvoke* invoke) {
2531 InvokeRuntimeCallingConvention calling_convention;
2532 IntrinsicVisitor::ComputeIntegerValueOfLocations(
2533 invoke,
2534 codegen_,
2535 calling_convention.GetReturnLocation(Primitive::kPrimNot),
2536 Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2537}
2538
2539void IntrinsicCodeGeneratorMIPS64::VisitIntegerValueOf(HInvoke* invoke) {
2540 IntrinsicVisitor::IntegerValueOfInfo info = IntrinsicVisitor::ComputeIntegerValueOfInfo();
2541 LocationSummary* locations = invoke->GetLocations();
2542 Mips64Assembler* assembler = GetAssembler();
2543 InstructionCodeGeneratorMIPS64* icodegen =
2544 down_cast<InstructionCodeGeneratorMIPS64*>(codegen_->GetInstructionVisitor());
2545
2546 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
2547 InvokeRuntimeCallingConvention calling_convention;
2548 if (invoke->InputAt(0)->IsConstant()) {
2549 int32_t value = invoke->InputAt(0)->AsIntConstant()->GetValue();
2550 if (value >= info.low && value <= info.high) {
2551 // Just embed the j.l.Integer in the code.
2552 ScopedObjectAccess soa(Thread::Current());
2553 mirror::Object* boxed = info.cache->Get(value + (-info.low));
2554 DCHECK(boxed != nullptr && Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(boxed));
2555 uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(boxed));
2556 __ LoadConst64(out, address);
2557 } else {
2558 // Allocate and initialize a new j.l.Integer.
2559 // TODO: If we JIT, we could allocate the j.l.Integer now, and store it in the
2560 // JIT object table.
2561 uint32_t address =
2562 dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
2563 __ LoadConst64(calling_convention.GetRegisterAt(0), address);
2564 codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
2565 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
2566 __ StoreConstToOffset(kStoreWord, value, out, info.value_offset, TMP);
2567 // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
2568 // one.
2569 icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2570 }
2571 } else {
2572 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
2573 Mips64Label allocate, done;
2574 int32_t count = static_cast<uint32_t>(info.high) - info.low + 1;
2575
2576 // Is (info.low <= in) && (in <= info.high)?
2577 __ Addiu32(out, in, -info.low);
2578 // As unsigned quantities is out < (info.high - info.low + 1)?
2579 __ LoadConst32(AT, count);
2580 // Branch if out >= (info.high - info.low + 1).
2581 // This means that "in" is outside of the range [info.low, info.high].
2582 __ Bgeuc(out, AT, &allocate);
2583
2584 // If the value is within the bounds, load the j.l.Integer directly from the array.
2585 uint32_t data_offset = mirror::Array::DataOffset(kHeapReferenceSize).Uint32Value();
2586 uint32_t address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.cache));
2587 __ LoadConst64(TMP, data_offset + address);
2588 __ Dlsa(out, out, TMP, TIMES_4);
2589 __ Lwu(out, out, 0);
2590 __ MaybeUnpoisonHeapReference(out);
2591 __ Bc(&done);
2592
2593 __ Bind(&allocate);
2594 // Otherwise allocate and initialize a new j.l.Integer.
2595 address = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(info.integer));
2596 __ LoadConst64(calling_convention.GetRegisterAt(0), address);
2597 codegen_->InvokeRuntime(kQuickAllocObjectInitialized, invoke, invoke->GetDexPc());
2598 CheckEntrypointTypes<kQuickAllocObjectWithChecks, void*, mirror::Class*>();
2599 __ StoreToOffset(kStoreWord, in, out, info.value_offset);
2600 // `value` is a final field :-( Ideally, we'd merge this memory barrier with the allocation
2601 // one.
2602 icodegen->GenerateMemoryBarrier(MemBarrierKind::kStoreStore);
2603 __ Bind(&done);
2604 }
2605}
2606
Aart Bik2f9fcc92016-03-01 15:16:54 -08002607UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
Aart Bik2f9fcc92016-03-01 15:16:54 -08002608UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
Aart Bik3f67e692016-01-15 14:35:12 -08002609
Aart Bikff7d89c2016-11-07 08:49:28 -08002610UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf);
2611UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter);
Aart Bik71bf7b42016-11-16 10:17:46 -08002612UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferAppend);
2613UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferLength);
2614UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferToString);
2615UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderAppend);
2616UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderLength);
2617UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderToString);
Aart Bikff7d89c2016-11-07 08:49:28 -08002618
Aart Bik0e54c012016-03-04 12:08:31 -08002619// 1.8.
2620UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddInt)
2621UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddLong)
2622UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetInt)
2623UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetLong)
2624UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetObject)
Aart Bik0e54c012016-03-04 12:08:31 -08002625
Nicolas Geoffray365719c2017-03-08 13:11:50 +00002626UNIMPLEMENTED_INTRINSIC(MIPS64, ThreadInterrupted)
2627
Aart Bik2f9fcc92016-03-01 15:16:54 -08002628UNREACHABLE_INTRINSICS(MIPS64)
Chris Larsen3039e382015-08-26 07:54:08 -07002629
2630#undef __
2631
2632} // namespace mips64
2633} // namespace art