1 /*
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"
25 #include "mirror/string.h"
26 #include "thread.h"
27 #include "utils/mips64/assembler_mips64.h"
28 #include "utils/mips64/constants_mips64.h"
29
30 namespace art {
31
32 namespace mips64 {
33
IntrinsicLocationsBuilderMIPS64(CodeGeneratorMIPS64 * codegen)34 IntrinsicLocationsBuilderMIPS64::IntrinsicLocationsBuilderMIPS64(CodeGeneratorMIPS64* codegen)
35 : arena_(codegen->GetGraph()->GetArena()) {
36 }
37
GetAssembler()38 Mips64Assembler* IntrinsicCodeGeneratorMIPS64::GetAssembler() {
39 return reinterpret_cast<Mips64Assembler*>(codegen_->GetAssembler());
40 }
41
GetAllocator()42 ArenaAllocator* IntrinsicCodeGeneratorMIPS64::GetAllocator() {
43 return codegen_->GetGraph()->GetArena();
44 }
45
46 #define __ codegen->GetAssembler()->
47
MoveFromReturnRegister(Location trg,Primitive::Type type,CodeGeneratorMIPS64 * codegen)48 static void MoveFromReturnRegister(Location trg,
49 Primitive::Type type,
50 CodeGeneratorMIPS64* codegen) {
51 if (!trg.IsValid()) {
52 DCHECK_EQ(type, Primitive::kPrimVoid);
53 return;
54 }
55
56 DCHECK_NE(type, Primitive::kPrimVoid);
57
58 if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
59 GpuRegister trg_reg = trg.AsRegister<GpuRegister>();
60 if (trg_reg != V0) {
61 __ Move(V0, trg_reg);
62 }
63 } else {
64 FpuRegister trg_reg = trg.AsFpuRegister<FpuRegister>();
65 if (trg_reg != F0) {
66 if (type == Primitive::kPrimFloat) {
67 __ MovS(F0, trg_reg);
68 } else {
69 __ MovD(F0, trg_reg);
70 }
71 }
72 }
73 }
74
MoveArguments(HInvoke * invoke,CodeGeneratorMIPS64 * codegen)75 static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS64* codegen) {
76 InvokeDexCallingConventionVisitorMIPS64 calling_convention_visitor;
77 IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
78 }
79
80 // Slow-path for fallback (calling the managed code to handle the
81 // intrinsic) in an intrinsified call. This will copy the arguments
82 // into the positions for a regular call.
83 //
84 // Note: The actual parameters are required to be in the locations
85 // given by the invoke's location summary. If an intrinsic
86 // modifies those locations before a slowpath call, they must be
87 // restored!
88 class IntrinsicSlowPathMIPS64 : public SlowPathCodeMIPS64 {
89 public:
IntrinsicSlowPathMIPS64(HInvoke * invoke)90 explicit IntrinsicSlowPathMIPS64(HInvoke* invoke)
91 : SlowPathCodeMIPS64(invoke), invoke_(invoke) { }
92
EmitNativeCode(CodeGenerator * codegen_in)93 void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
94 CodeGeneratorMIPS64* codegen = down_cast<CodeGeneratorMIPS64*>(codegen_in);
95
96 __ Bind(GetEntryLabel());
97
98 SaveLiveRegisters(codegen, invoke_->GetLocations());
99
100 MoveArguments(invoke_, codegen);
101
102 if (invoke_->IsInvokeStaticOrDirect()) {
103 codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
104 Location::RegisterLocation(A0));
105 } else {
106 codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0));
107 }
108 codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
109
110 // Copy the result back to the expected output.
111 Location out = invoke_->GetLocations()->Out();
112 if (out.IsValid()) {
113 DCHECK(out.IsRegister()); // TODO: Replace this when we support output in memory.
114 DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
115 MoveFromReturnRegister(out, invoke_->GetType(), codegen);
116 }
117
118 RestoreLiveRegisters(codegen, invoke_->GetLocations());
119 __ Bc(GetExitLabel());
120 }
121
GetDescription() const122 const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS64"; }
123
124 private:
125 // The instruction where this slow path is happening.
126 HInvoke* const invoke_;
127
128 DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS64);
129 };
130
131 #undef __
132
TryDispatch(HInvoke * invoke)133 bool IntrinsicLocationsBuilderMIPS64::TryDispatch(HInvoke* invoke) {
134 Dispatch(invoke);
135 LocationSummary* res = invoke->GetLocations();
136 return res != nullptr && res->Intrinsified();
137 }
138
139 #define __ assembler->
140
CreateFPToIntLocations(ArenaAllocator * arena,HInvoke * invoke)141 static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
142 LocationSummary* locations = new (arena) LocationSummary(invoke,
143 LocationSummary::kNoCall,
144 kIntrinsified);
145 locations->SetInAt(0, Location::RequiresFpuRegister());
146 locations->SetOut(Location::RequiresRegister());
147 }
148
MoveFPToInt(LocationSummary * locations,bool is64bit,Mips64Assembler * assembler)149 static void MoveFPToInt(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
150 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
151 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
152
153 if (is64bit) {
154 __ Dmfc1(out, in);
155 } else {
156 __ Mfc1(out, in);
157 }
158 }
159
160 // long java.lang.Double.doubleToRawLongBits(double)
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)161 void IntrinsicLocationsBuilderMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
162 CreateFPToIntLocations(arena_, invoke);
163 }
164
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)165 void IntrinsicCodeGeneratorMIPS64::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
166 MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
167 }
168
169 // int java.lang.Float.floatToRawIntBits(float)
VisitFloatFloatToRawIntBits(HInvoke * invoke)170 void IntrinsicLocationsBuilderMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
171 CreateFPToIntLocations(arena_, invoke);
172 }
173
VisitFloatFloatToRawIntBits(HInvoke * invoke)174 void IntrinsicCodeGeneratorMIPS64::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
175 MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
176 }
177
CreateIntToFPLocations(ArenaAllocator * arena,HInvoke * invoke)178 static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
179 LocationSummary* locations = new (arena) LocationSummary(invoke,
180 LocationSummary::kNoCall,
181 kIntrinsified);
182 locations->SetInAt(0, Location::RequiresRegister());
183 locations->SetOut(Location::RequiresFpuRegister());
184 }
185
MoveIntToFP(LocationSummary * locations,bool is64bit,Mips64Assembler * assembler)186 static void MoveIntToFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
187 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
188 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
189
190 if (is64bit) {
191 __ Dmtc1(in, out);
192 } else {
193 __ Mtc1(in, out);
194 }
195 }
196
197 // double java.lang.Double.longBitsToDouble(long)
VisitDoubleLongBitsToDouble(HInvoke * invoke)198 void IntrinsicLocationsBuilderMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
199 CreateIntToFPLocations(arena_, invoke);
200 }
201
VisitDoubleLongBitsToDouble(HInvoke * invoke)202 void IntrinsicCodeGeneratorMIPS64::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
203 MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
204 }
205
206 // float java.lang.Float.intBitsToFloat(int)
VisitFloatIntBitsToFloat(HInvoke * invoke)207 void IntrinsicLocationsBuilderMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
208 CreateIntToFPLocations(arena_, invoke);
209 }
210
VisitFloatIntBitsToFloat(HInvoke * invoke)211 void IntrinsicCodeGeneratorMIPS64::VisitFloatIntBitsToFloat(HInvoke* invoke) {
212 MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
213 }
214
CreateIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke)215 static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
216 LocationSummary* locations = new (arena) LocationSummary(invoke,
217 LocationSummary::kNoCall,
218 kIntrinsified);
219 locations->SetInAt(0, Location::RequiresRegister());
220 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
221 }
222
GenReverseBytes(LocationSummary * locations,Primitive::Type type,Mips64Assembler * assembler)223 static void GenReverseBytes(LocationSummary* locations,
224 Primitive::Type type,
225 Mips64Assembler* assembler) {
226 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
227 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
228
229 switch (type) {
230 case Primitive::kPrimShort:
231 __ Dsbh(out, in);
232 __ Seh(out, out);
233 break;
234 case Primitive::kPrimInt:
235 __ Rotr(out, in, 16);
236 __ Wsbh(out, out);
237 break;
238 case Primitive::kPrimLong:
239 __ Dsbh(out, in);
240 __ Dshd(out, out);
241 break;
242 default:
243 LOG(FATAL) << "Unexpected size for reverse-bytes: " << type;
244 UNREACHABLE();
245 }
246 }
247
248 // int java.lang.Integer.reverseBytes(int)
VisitIntegerReverseBytes(HInvoke * invoke)249 void IntrinsicLocationsBuilderMIPS64::VisitIntegerReverseBytes(HInvoke* invoke) {
250 CreateIntToIntLocations(arena_, invoke);
251 }
252
VisitIntegerReverseBytes(HInvoke * invoke)253 void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverseBytes(HInvoke* invoke) {
254 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
255 }
256
257 // long java.lang.Long.reverseBytes(long)
VisitLongReverseBytes(HInvoke * invoke)258 void IntrinsicLocationsBuilderMIPS64::VisitLongReverseBytes(HInvoke* invoke) {
259 CreateIntToIntLocations(arena_, invoke);
260 }
261
VisitLongReverseBytes(HInvoke * invoke)262 void IntrinsicCodeGeneratorMIPS64::VisitLongReverseBytes(HInvoke* invoke) {
263 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
264 }
265
266 // short java.lang.Short.reverseBytes(short)
VisitShortReverseBytes(HInvoke * invoke)267 void IntrinsicLocationsBuilderMIPS64::VisitShortReverseBytes(HInvoke* invoke) {
268 CreateIntToIntLocations(arena_, invoke);
269 }
270
VisitShortReverseBytes(HInvoke * invoke)271 void IntrinsicCodeGeneratorMIPS64::VisitShortReverseBytes(HInvoke* invoke) {
272 GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
273 }
274
GenNumberOfLeadingZeroes(LocationSummary * locations,bool is64bit,Mips64Assembler * assembler)275 static void GenNumberOfLeadingZeroes(LocationSummary* locations,
276 bool is64bit,
277 Mips64Assembler* assembler) {
278 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
279 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
280
281 if (is64bit) {
282 __ Dclz(out, in);
283 } else {
284 __ Clz(out, in);
285 }
286 }
287
288 // int java.lang.Integer.numberOfLeadingZeros(int i)
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)289 void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
290 CreateIntToIntLocations(arena_, invoke);
291 }
292
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)293 void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
294 GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
295 }
296
297 // int java.lang.Long.numberOfLeadingZeros(long i)
VisitLongNumberOfLeadingZeros(HInvoke * invoke)298 void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
299 CreateIntToIntLocations(arena_, invoke);
300 }
301
VisitLongNumberOfLeadingZeros(HInvoke * invoke)302 void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
303 GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
304 }
305
GenNumberOfTrailingZeroes(LocationSummary * locations,bool is64bit,Mips64Assembler * assembler)306 static void GenNumberOfTrailingZeroes(LocationSummary* locations,
307 bool is64bit,
308 Mips64Assembler* assembler) {
309 Location in = locations->InAt(0);
310 Location out = locations->Out();
311
312 if (is64bit) {
313 __ Dsbh(out.AsRegister<GpuRegister>(), in.AsRegister<GpuRegister>());
314 __ Dshd(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
315 __ Dbitswap(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
316 __ Dclz(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
317 } else {
318 __ Rotr(out.AsRegister<GpuRegister>(), in.AsRegister<GpuRegister>(), 16);
319 __ Wsbh(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
320 __ Bitswap(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
321 __ Clz(out.AsRegister<GpuRegister>(), out.AsRegister<GpuRegister>());
322 }
323 }
324
325 // int java.lang.Integer.numberOfTrailingZeros(int i)
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)326 void IntrinsicLocationsBuilderMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
327 CreateIntToIntLocations(arena_, invoke);
328 }
329
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)330 void IntrinsicCodeGeneratorMIPS64::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
331 GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
332 }
333
334 // int java.lang.Long.numberOfTrailingZeros(long i)
VisitLongNumberOfTrailingZeros(HInvoke * invoke)335 void IntrinsicLocationsBuilderMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
336 CreateIntToIntLocations(arena_, invoke);
337 }
338
VisitLongNumberOfTrailingZeros(HInvoke * invoke)339 void IntrinsicCodeGeneratorMIPS64::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
340 GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
341 }
342
GenReverse(LocationSummary * locations,Primitive::Type type,Mips64Assembler * assembler)343 static void GenReverse(LocationSummary* locations,
344 Primitive::Type type,
345 Mips64Assembler* assembler) {
346 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
347
348 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
349 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
350
351 if (type == Primitive::kPrimInt) {
352 __ Rotr(out, in, 16);
353 __ Wsbh(out, out);
354 __ Bitswap(out, out);
355 } else {
356 __ Dsbh(out, in);
357 __ Dshd(out, out);
358 __ Dbitswap(out, out);
359 }
360 }
361
362 // int java.lang.Integer.reverse(int)
VisitIntegerReverse(HInvoke * invoke)363 void IntrinsicLocationsBuilderMIPS64::VisitIntegerReverse(HInvoke* invoke) {
364 CreateIntToIntLocations(arena_, invoke);
365 }
366
VisitIntegerReverse(HInvoke * invoke)367 void IntrinsicCodeGeneratorMIPS64::VisitIntegerReverse(HInvoke* invoke) {
368 GenReverse(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
369 }
370
371 // long java.lang.Long.reverse(long)
VisitLongReverse(HInvoke * invoke)372 void IntrinsicLocationsBuilderMIPS64::VisitLongReverse(HInvoke* invoke) {
373 CreateIntToIntLocations(arena_, invoke);
374 }
375
VisitLongReverse(HInvoke * invoke)376 void IntrinsicCodeGeneratorMIPS64::VisitLongReverse(HInvoke* invoke) {
377 GenReverse(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
378 }
379
CreateFPToFPLocations(ArenaAllocator * arena,HInvoke * invoke)380 static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
381 LocationSummary* locations = new (arena) LocationSummary(invoke,
382 LocationSummary::kNoCall,
383 kIntrinsified);
384 locations->SetInAt(0, Location::RequiresFpuRegister());
385 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
386 }
387
GenBitCount(LocationSummary * locations,const Primitive::Type type,Mips64Assembler * assembler)388 static void GenBitCount(LocationSummary* locations,
389 const Primitive::Type type,
390 Mips64Assembler* assembler) {
391 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
392 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
393
394 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
395
396 // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
397 //
398 // A generalization of the best bit counting method to integers of
399 // bit-widths up to 128 (parameterized by type T) is this:
400 //
401 // v = v - ((v >> 1) & (T)~(T)0/3); // temp
402 // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); // temp
403 // v = (v + (v >> 4)) & (T)~(T)0/255*15; // temp
404 // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; // count
405 //
406 // For comparison, for 32-bit quantities, this algorithm can be executed
407 // using 20 MIPS instructions (the calls to LoadConst32() generate two
408 // machine instructions each for the values being used in this algorithm).
409 // A(n unrolled) loop-based algorithm requires 25 instructions.
410 //
411 // For a 64-bit operand this can be performed in 24 instructions compared
412 // to a(n unrolled) loop based algorithm which requires 38 instructions.
413 //
414 // There are algorithms which are faster in the cases where very few
415 // bits are set but the algorithm here attempts to minimize the total
416 // number of instructions executed even when a large number of bits
417 // are set.
418
419 if (type == Primitive::kPrimInt) {
420 __ Srl(TMP, in, 1);
421 __ LoadConst32(AT, 0x55555555);
422 __ And(TMP, TMP, AT);
423 __ Subu(TMP, in, TMP);
424 __ LoadConst32(AT, 0x33333333);
425 __ And(out, TMP, AT);
426 __ Srl(TMP, TMP, 2);
427 __ And(TMP, TMP, AT);
428 __ Addu(TMP, out, TMP);
429 __ Srl(out, TMP, 4);
430 __ Addu(out, out, TMP);
431 __ LoadConst32(AT, 0x0F0F0F0F);
432 __ And(out, out, AT);
433 __ LoadConst32(TMP, 0x01010101);
434 __ MulR6(out, out, TMP);
435 __ Srl(out, out, 24);
436 } else if (type == Primitive::kPrimLong) {
437 __ Dsrl(TMP, in, 1);
438 __ LoadConst64(AT, 0x5555555555555555L);
439 __ And(TMP, TMP, AT);
440 __ Dsubu(TMP, in, TMP);
441 __ LoadConst64(AT, 0x3333333333333333L);
442 __ And(out, TMP, AT);
443 __ Dsrl(TMP, TMP, 2);
444 __ And(TMP, TMP, AT);
445 __ Daddu(TMP, out, TMP);
446 __ Dsrl(out, TMP, 4);
447 __ Daddu(out, out, TMP);
448 __ LoadConst64(AT, 0x0F0F0F0F0F0F0F0FL);
449 __ And(out, out, AT);
450 __ LoadConst64(TMP, 0x0101010101010101L);
451 __ Dmul(out, out, TMP);
452 __ Dsrl32(out, out, 24);
453 }
454 }
455
456 // int java.lang.Integer.bitCount(int)
VisitIntegerBitCount(HInvoke * invoke)457 void IntrinsicLocationsBuilderMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
458 CreateIntToIntLocations(arena_, invoke);
459 }
460
VisitIntegerBitCount(HInvoke * invoke)461 void IntrinsicCodeGeneratorMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
462 GenBitCount(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
463 }
464
465 // int java.lang.Long.bitCount(long)
VisitLongBitCount(HInvoke * invoke)466 void IntrinsicLocationsBuilderMIPS64::VisitLongBitCount(HInvoke* invoke) {
467 CreateIntToIntLocations(arena_, invoke);
468 }
469
VisitLongBitCount(HInvoke * invoke)470 void IntrinsicCodeGeneratorMIPS64::VisitLongBitCount(HInvoke* invoke) {
471 GenBitCount(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
472 }
473
MathAbsFP(LocationSummary * locations,bool is64bit,Mips64Assembler * assembler)474 static void MathAbsFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
475 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
476 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
477
478 if (is64bit) {
479 __ AbsD(out, in);
480 } else {
481 __ AbsS(out, in);
482 }
483 }
484
485 // double java.lang.Math.abs(double)
VisitMathAbsDouble(HInvoke * invoke)486 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsDouble(HInvoke* invoke) {
487 CreateFPToFPLocations(arena_, invoke);
488 }
489
VisitMathAbsDouble(HInvoke * invoke)490 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsDouble(HInvoke* invoke) {
491 MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
492 }
493
494 // float java.lang.Math.abs(float)
VisitMathAbsFloat(HInvoke * invoke)495 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsFloat(HInvoke* invoke) {
496 CreateFPToFPLocations(arena_, invoke);
497 }
498
VisitMathAbsFloat(HInvoke * invoke)499 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsFloat(HInvoke* invoke) {
500 MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
501 }
502
CreateIntToInt(ArenaAllocator * arena,HInvoke * invoke)503 static void CreateIntToInt(ArenaAllocator* arena, HInvoke* invoke) {
504 LocationSummary* locations = new (arena) LocationSummary(invoke,
505 LocationSummary::kNoCall,
506 kIntrinsified);
507 locations->SetInAt(0, Location::RequiresRegister());
508 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
509 }
510
GenAbsInteger(LocationSummary * locations,bool is64bit,Mips64Assembler * assembler)511 static void GenAbsInteger(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
512 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
513 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
514
515 if (is64bit) {
516 __ Dsra32(AT, in, 31);
517 __ Xor(out, in, AT);
518 __ Dsubu(out, out, AT);
519 } else {
520 __ Sra(AT, in, 31);
521 __ Xor(out, in, AT);
522 __ Subu(out, out, AT);
523 }
524 }
525
526 // int java.lang.Math.abs(int)
VisitMathAbsInt(HInvoke * invoke)527 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsInt(HInvoke* invoke) {
528 CreateIntToInt(arena_, invoke);
529 }
530
VisitMathAbsInt(HInvoke * invoke)531 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsInt(HInvoke* invoke) {
532 GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
533 }
534
535 // long java.lang.Math.abs(long)
VisitMathAbsLong(HInvoke * invoke)536 void IntrinsicLocationsBuilderMIPS64::VisitMathAbsLong(HInvoke* invoke) {
537 CreateIntToInt(arena_, invoke);
538 }
539
VisitMathAbsLong(HInvoke * invoke)540 void IntrinsicCodeGeneratorMIPS64::VisitMathAbsLong(HInvoke* invoke) {
541 GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
542 }
543
GenMinMaxFP(LocationSummary * locations,bool is_min,Primitive::Type type,Mips64Assembler * assembler)544 static void GenMinMaxFP(LocationSummary* locations,
545 bool is_min,
546 Primitive::Type type,
547 Mips64Assembler* assembler) {
548 FpuRegister a = locations->InAt(0).AsFpuRegister<FpuRegister>();
549 FpuRegister b = locations->InAt(1).AsFpuRegister<FpuRegister>();
550 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
551
552 Mips64Label noNaNs;
553 Mips64Label done;
554 FpuRegister ftmp = ((out != a) && (out != b)) ? out : FTMP;
555
556 // When Java computes min/max it prefers a NaN to a number; the
557 // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of
558 // the inputs is a NaN and the other is a valid number, the MIPS
559 // instruction will return the number; Java wants the NaN value
560 // returned. This is why there is extra logic preceding the use of
561 // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
562 // NaN, return the NaN, otherwise return the min/max.
563 if (type == Primitive::kPrimDouble) {
564 __ CmpUnD(FTMP, a, b);
565 __ Bc1eqz(FTMP, &noNaNs);
566
567 // One of the inputs is a NaN
568 __ CmpEqD(ftmp, a, a);
569 // If a == a then b is the NaN, otherwise a is the NaN.
570 __ SelD(ftmp, a, b);
571
572 if (ftmp != out) {
573 __ MovD(out, ftmp);
574 }
575
576 __ Bc(&done);
577
578 __ Bind(&noNaNs);
579
580 if (is_min) {
581 __ MinD(out, a, b);
582 } else {
583 __ MaxD(out, a, b);
584 }
585 } else {
586 DCHECK_EQ(type, Primitive::kPrimFloat);
587 __ CmpUnS(FTMP, a, b);
588 __ Bc1eqz(FTMP, &noNaNs);
589
590 // One of the inputs is a NaN
591 __ CmpEqS(ftmp, a, a);
592 // If a == a then b is the NaN, otherwise a is the NaN.
593 __ SelS(ftmp, a, b);
594
595 if (ftmp != out) {
596 __ MovS(out, ftmp);
597 }
598
599 __ Bc(&done);
600
601 __ Bind(&noNaNs);
602
603 if (is_min) {
604 __ MinS(out, a, b);
605 } else {
606 __ MaxS(out, a, b);
607 }
608 }
609
610 __ Bind(&done);
611 }
612
CreateFPFPToFPLocations(ArenaAllocator * arena,HInvoke * invoke)613 static void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
614 LocationSummary* locations = new (arena) LocationSummary(invoke,
615 LocationSummary::kNoCall,
616 kIntrinsified);
617 locations->SetInAt(0, Location::RequiresFpuRegister());
618 locations->SetInAt(1, Location::RequiresFpuRegister());
619 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
620 }
621
622 // double java.lang.Math.min(double, double)
VisitMathMinDoubleDouble(HInvoke * invoke)623 void IntrinsicLocationsBuilderMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) {
624 CreateFPFPToFPLocations(arena_, invoke);
625 }
626
VisitMathMinDoubleDouble(HInvoke * invoke)627 void IntrinsicCodeGeneratorMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) {
628 GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, Primitive::kPrimDouble, GetAssembler());
629 }
630
631 // float java.lang.Math.min(float, float)
VisitMathMinFloatFloat(HInvoke * invoke)632 void IntrinsicLocationsBuilderMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) {
633 CreateFPFPToFPLocations(arena_, invoke);
634 }
635
VisitMathMinFloatFloat(HInvoke * invoke)636 void IntrinsicCodeGeneratorMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) {
637 GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, Primitive::kPrimFloat, GetAssembler());
638 }
639
640 // double java.lang.Math.max(double, double)
VisitMathMaxDoubleDouble(HInvoke * invoke)641 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
642 CreateFPFPToFPLocations(arena_, invoke);
643 }
644
VisitMathMaxDoubleDouble(HInvoke * invoke)645 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) {
646 GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, Primitive::kPrimDouble, GetAssembler());
647 }
648
649 // float java.lang.Math.max(float, float)
VisitMathMaxFloatFloat(HInvoke * invoke)650 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) {
651 CreateFPFPToFPLocations(arena_, invoke);
652 }
653
VisitMathMaxFloatFloat(HInvoke * invoke)654 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) {
655 GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, Primitive::kPrimFloat, GetAssembler());
656 }
657
GenMinMax(LocationSummary * locations,bool is_min,Mips64Assembler * assembler)658 static void GenMinMax(LocationSummary* locations,
659 bool is_min,
660 Mips64Assembler* assembler) {
661 GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
662 GpuRegister rhs = locations->InAt(1).AsRegister<GpuRegister>();
663 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
664
665 if (lhs == rhs) {
666 if (out != lhs) {
667 __ Move(out, lhs);
668 }
669 } else {
670 // Some architectures, such as ARM and MIPS (prior to r6), have a
671 // conditional move instruction which only changes the target
672 // (output) register if the condition is true (MIPS prior to r6 had
673 // MOVF, MOVT, and MOVZ). The SELEQZ and SELNEZ instructions always
674 // change the target (output) register. If the condition is true the
675 // output register gets the contents of the "rs" register; otherwise,
676 // the output register is set to zero. One consequence of this is
677 // that to implement something like "rd = c==0 ? rs : rt" MIPS64r6
678 // needs to use a pair of SELEQZ/SELNEZ instructions. After
679 // executing this pair of instructions one of the output registers
680 // from the pair will necessarily contain zero. Then the code ORs the
681 // output registers from the SELEQZ/SELNEZ instructions to get the
682 // final result.
683 //
684 // The initial test to see if the output register is same as the
685 // first input register is needed to make sure that value in the
686 // first input register isn't clobbered before we've finished
687 // computing the output value. The logic in the corresponding else
688 // clause performs the same task but makes sure the second input
689 // register isn't clobbered in the event that it's the same register
690 // as the output register; the else clause also handles the case
691 // where the output register is distinct from both the first, and the
692 // second input registers.
693 if (out == lhs) {
694 __ Slt(AT, rhs, lhs);
695 if (is_min) {
696 __ Seleqz(out, lhs, AT);
697 __ Selnez(AT, rhs, AT);
698 } else {
699 __ Selnez(out, lhs, AT);
700 __ Seleqz(AT, rhs, AT);
701 }
702 } else {
703 __ Slt(AT, lhs, rhs);
704 if (is_min) {
705 __ Seleqz(out, rhs, AT);
706 __ Selnez(AT, lhs, AT);
707 } else {
708 __ Selnez(out, rhs, AT);
709 __ Seleqz(AT, lhs, AT);
710 }
711 }
712 __ Or(out, out, AT);
713 }
714 }
715
CreateIntIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke)716 static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
717 LocationSummary* locations = new (arena) LocationSummary(invoke,
718 LocationSummary::kNoCall,
719 kIntrinsified);
720 locations->SetInAt(0, Location::RequiresRegister());
721 locations->SetInAt(1, Location::RequiresRegister());
722 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
723 }
724
725 // int java.lang.Math.min(int, int)
VisitMathMinIntInt(HInvoke * invoke)726 void IntrinsicLocationsBuilderMIPS64::VisitMathMinIntInt(HInvoke* invoke) {
727 CreateIntIntToIntLocations(arena_, invoke);
728 }
729
VisitMathMinIntInt(HInvoke * invoke)730 void IntrinsicCodeGeneratorMIPS64::VisitMathMinIntInt(HInvoke* invoke) {
731 GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler());
732 }
733
734 // long java.lang.Math.min(long, long)
VisitMathMinLongLong(HInvoke * invoke)735 void IntrinsicLocationsBuilderMIPS64::VisitMathMinLongLong(HInvoke* invoke) {
736 CreateIntIntToIntLocations(arena_, invoke);
737 }
738
VisitMathMinLongLong(HInvoke * invoke)739 void IntrinsicCodeGeneratorMIPS64::VisitMathMinLongLong(HInvoke* invoke) {
740 GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler());
741 }
742
743 // int java.lang.Math.max(int, int)
VisitMathMaxIntInt(HInvoke * invoke)744 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxIntInt(HInvoke* invoke) {
745 CreateIntIntToIntLocations(arena_, invoke);
746 }
747
VisitMathMaxIntInt(HInvoke * invoke)748 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxIntInt(HInvoke* invoke) {
749 GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler());
750 }
751
752 // long java.lang.Math.max(long, long)
VisitMathMaxLongLong(HInvoke * invoke)753 void IntrinsicLocationsBuilderMIPS64::VisitMathMaxLongLong(HInvoke* invoke) {
754 CreateIntIntToIntLocations(arena_, invoke);
755 }
756
VisitMathMaxLongLong(HInvoke * invoke)757 void IntrinsicCodeGeneratorMIPS64::VisitMathMaxLongLong(HInvoke* invoke) {
758 GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler());
759 }
760
761 // double java.lang.Math.sqrt(double)
VisitMathSqrt(HInvoke * invoke)762 void IntrinsicLocationsBuilderMIPS64::VisitMathSqrt(HInvoke* invoke) {
763 CreateFPToFPLocations(arena_, invoke);
764 }
765
VisitMathSqrt(HInvoke * invoke)766 void IntrinsicCodeGeneratorMIPS64::VisitMathSqrt(HInvoke* invoke) {
767 LocationSummary* locations = invoke->GetLocations();
768 Mips64Assembler* assembler = GetAssembler();
769 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
770 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
771
772 __ SqrtD(out, in);
773 }
774
CreateFPToFP(ArenaAllocator * arena,HInvoke * invoke,Location::OutputOverlap overlaps=Location::kOutputOverlap)775 static void CreateFPToFP(ArenaAllocator* arena,
776 HInvoke* invoke,
777 Location::OutputOverlap overlaps = Location::kOutputOverlap) {
778 LocationSummary* locations = new (arena) LocationSummary(invoke,
779 LocationSummary::kNoCall,
780 kIntrinsified);
781 locations->SetInAt(0, Location::RequiresFpuRegister());
782 locations->SetOut(Location::RequiresFpuRegister(), overlaps);
783 }
784
785 // double java.lang.Math.rint(double)
VisitMathRint(HInvoke * invoke)786 void IntrinsicLocationsBuilderMIPS64::VisitMathRint(HInvoke* invoke) {
787 CreateFPToFP(arena_, invoke, Location::kNoOutputOverlap);
788 }
789
VisitMathRint(HInvoke * invoke)790 void IntrinsicCodeGeneratorMIPS64::VisitMathRint(HInvoke* invoke) {
791 LocationSummary* locations = invoke->GetLocations();
792 Mips64Assembler* assembler = GetAssembler();
793 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
794 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
795
796 __ RintD(out, in);
797 }
798
799 // double java.lang.Math.floor(double)
VisitMathFloor(HInvoke * invoke)800 void IntrinsicLocationsBuilderMIPS64::VisitMathFloor(HInvoke* invoke) {
801 CreateFPToFP(arena_, invoke);
802 }
803
804 const constexpr uint16_t kFPLeaveUnchanged = kPositiveZero |
805 kPositiveInfinity |
806 kNegativeZero |
807 kNegativeInfinity |
808 kQuietNaN |
809 kSignalingNaN;
810
811 enum FloatRoundingMode {
812 kFloor,
813 kCeil,
814 };
815
GenRoundingMode(LocationSummary * locations,FloatRoundingMode mode,Mips64Assembler * assembler)816 static void GenRoundingMode(LocationSummary* locations,
817 FloatRoundingMode mode,
818 Mips64Assembler* assembler) {
819 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
820 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
821
822 DCHECK_NE(in, out);
823
824 Mips64Label done;
825
826 // double floor/ceil(double in) {
827 // if in.isNaN || in.isInfinite || in.isZero {
828 // return in;
829 // }
830 __ ClassD(out, in);
831 __ Dmfc1(AT, out);
832 __ Andi(AT, AT, kFPLeaveUnchanged); // +0.0 | +Inf | -0.0 | -Inf | qNaN | sNaN
833 __ MovD(out, in);
834 __ Bnezc(AT, &done);
835
836 // Long outLong = floor/ceil(in);
837 // if (outLong == Long.MAX_VALUE) || (outLong == Long.MIN_VALUE) {
838 // // floor()/ceil() has almost certainly returned a value
839 // // which can't be successfully represented as a signed
840 // // 64-bit number. Java expects that the input value will
841 // // be returned in these cases.
842 // // There is also a small probability that floor(in)/ceil(in)
843 // // correctly truncates/rounds up the input value to
844 // // Long.MAX_VALUE or Long.MIN_VALUE. In these cases, this
845 // // exception handling code still does the correct thing.
846 // return in;
847 // }
848 if (mode == kFloor) {
849 __ FloorLD(out, in);
850 } else if (mode == kCeil) {
851 __ CeilLD(out, in);
852 }
853 __ Dmfc1(AT, out);
854 __ MovD(out, in);
855 __ Daddiu(TMP, AT, 1);
856 __ Dati(TMP, 0x8000); // TMP = AT + 0x8000 0000 0000 0001
857 // or AT - 0x7FFF FFFF FFFF FFFF.
858 // IOW, TMP = 1 if AT = Long.MIN_VALUE
859 // or TMP = 0 if AT = Long.MAX_VALUE.
860 __ Dsrl(TMP, TMP, 1); // TMP = 0 if AT = Long.MIN_VALUE
861 // or AT = Long.MAX_VALUE.
862 __ Beqzc(TMP, &done);
863
864 // double out = outLong;
865 // return out;
866 __ Dmtc1(AT, out);
867 __ Cvtdl(out, out);
868 __ Bind(&done);
869 // }
870 }
871
VisitMathFloor(HInvoke * invoke)872 void IntrinsicCodeGeneratorMIPS64::VisitMathFloor(HInvoke* invoke) {
873 GenRoundingMode(invoke->GetLocations(), kFloor, GetAssembler());
874 }
875
876 // double java.lang.Math.ceil(double)
VisitMathCeil(HInvoke * invoke)877 void IntrinsicLocationsBuilderMIPS64::VisitMathCeil(HInvoke* invoke) {
878 CreateFPToFP(arena_, invoke);
879 }
880
VisitMathCeil(HInvoke * invoke)881 void IntrinsicCodeGeneratorMIPS64::VisitMathCeil(HInvoke* invoke) {
882 GenRoundingMode(invoke->GetLocations(), kCeil, GetAssembler());
883 }
884
GenRound(LocationSummary * locations,Mips64Assembler * assembler,Primitive::Type type)885 static void GenRound(LocationSummary* locations, Mips64Assembler* assembler, Primitive::Type type) {
886 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
887 FpuRegister half = locations->GetTemp(0).AsFpuRegister<FpuRegister>();
888 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
889
890 DCHECK(type == Primitive::kPrimFloat || type == Primitive::kPrimDouble);
891
892 Mips64Label done;
893 Mips64Label finite;
894 Mips64Label add;
895
896 // if (in.isNaN) {
897 // return 0;
898 // }
899 //
900 // out = floor(in);
901 //
902 // /*
903 // * TODO: Amend this code when emulator FCSR.NAN2008=1 bug is fixed.
904 // *
905 // * Starting with MIPSR6, which always sets FCSR.NAN2008=1, negative
906 // * numbers which are too large to be represented in a 32-/64-bit
907 // * signed integer will be processed by floor.X.Y to output
908 // * Integer.MIN_VALUE/Long.MIN_VALUE, and will no longer be
909 // * processed by this "if" statement.
910 // *
911 // * However, this bug in the 64-bit MIPS emulator causes the
912 // * behavior of floor.X.Y to be the same as pre-R6 implementations
913 // * of MIPS64. When that bug is fixed this logic should be amended.
914 // */
915 // if (out == MAX_VALUE) {
916 // TMP = (in < 0.0) ? 1 : 0;
917 // /*
918 // * If TMP is 1, then adding it to out will wrap its value from
919 // * MAX_VALUE to MIN_VALUE.
920 // */
921 // return out += TMP;
922 // }
923 //
924 // /*
925 // * For negative values not handled by the previous "if" statement the
926 // * test here will correctly set the value of TMP.
927 // */
928 // TMP = ((in - out) >= 0.5) ? 1 : 0;
929 // return out += TMP;
930
931 // Test for NaN.
932 if (type == Primitive::kPrimDouble) {
933 __ CmpUnD(FTMP, in, in);
934 } else {
935 __ CmpUnS(FTMP, in, in);
936 }
937
938 // Return zero for NaN.
939 __ Move(out, ZERO);
940 __ Bc1nez(FTMP, &done);
941
942 // out = floor(in);
943 if (type == Primitive::kPrimDouble) {
944 __ FloorLD(FTMP, in);
945 __ Dmfc1(out, FTMP);
946 } else {
947 __ FloorWS(FTMP, in);
948 __ Mfc1(out, FTMP);
949 }
950
951 // TMP = (out = java.lang.Integer.MAX_VALUE) ? 1 : 0;
952 if (type == Primitive::kPrimDouble) {
953 __ LoadConst64(AT, std::numeric_limits<int64_t>::max());
954 } else {
955 __ LoadConst32(AT, std::numeric_limits<int32_t>::max());
956 }
957 __ Bnec(AT, out, &finite);
958
959 if (type == Primitive::kPrimDouble) {
960 __ Dmtc1(ZERO, FTMP);
961 __ CmpLtD(FTMP, in, FTMP);
962 __ Dmfc1(AT, FTMP);
963 } else {
964 __ Mtc1(ZERO, FTMP);
965 __ CmpLtS(FTMP, in, FTMP);
966 __ Mfc1(AT, FTMP);
967 }
968
969 __ Bc(&add);
970
971 __ Bind(&finite);
972
973 // TMP = (0.5 <= (in - out)) ? -1 : 0;
974 if (type == Primitive::kPrimDouble) {
975 __ Cvtdl(FTMP, FTMP); // Convert output of floor.l.d back to "double".
976 __ LoadConst64(AT, bit_cast<int64_t, double>(0.5));
977 __ SubD(FTMP, in, FTMP);
978 __ Dmtc1(AT, half);
979 __ CmpLeD(FTMP, half, FTMP);
980 __ Dmfc1(AT, FTMP);
981 } else {
982 __ Cvtsw(FTMP, FTMP); // Convert output of floor.w.s back to "float".
983 __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
984 __ SubS(FTMP, in, FTMP);
985 __ Mtc1(AT, half);
986 __ CmpLeS(FTMP, half, FTMP);
987 __ Mfc1(AT, FTMP);
988 }
989
990 __ Bind(&add);
991
992 // Return out -= TMP.
993 if (type == Primitive::kPrimDouble) {
994 __ Dsubu(out, out, AT);
995 } else {
996 __ Subu(out, out, AT);
997 }
998
999 __ Bind(&done);
1000 }
1001
1002 // int java.lang.Math.round(float)
VisitMathRoundFloat(HInvoke * invoke)1003 void IntrinsicLocationsBuilderMIPS64::VisitMathRoundFloat(HInvoke* invoke) {
1004 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1005 LocationSummary::kNoCall,
1006 kIntrinsified);
1007 locations->SetInAt(0, Location::RequiresFpuRegister());
1008 locations->AddTemp(Location::RequiresFpuRegister());
1009 locations->SetOut(Location::RequiresRegister());
1010 }
1011
VisitMathRoundFloat(HInvoke * invoke)1012 void IntrinsicCodeGeneratorMIPS64::VisitMathRoundFloat(HInvoke* invoke) {
1013 GenRound(invoke->GetLocations(), GetAssembler(), Primitive::kPrimFloat);
1014 }
1015
1016 // long java.lang.Math.round(double)
VisitMathRoundDouble(HInvoke * invoke)1017 void IntrinsicLocationsBuilderMIPS64::VisitMathRoundDouble(HInvoke* invoke) {
1018 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1019 LocationSummary::kNoCall,
1020 kIntrinsified);
1021 locations->SetInAt(0, Location::RequiresFpuRegister());
1022 locations->AddTemp(Location::RequiresFpuRegister());
1023 locations->SetOut(Location::RequiresRegister());
1024 }
1025
VisitMathRoundDouble(HInvoke * invoke)1026 void IntrinsicCodeGeneratorMIPS64::VisitMathRoundDouble(HInvoke* invoke) {
1027 GenRound(invoke->GetLocations(), GetAssembler(), Primitive::kPrimDouble);
1028 }
1029
1030 // byte libcore.io.Memory.peekByte(long address)
VisitMemoryPeekByte(HInvoke * invoke)1031 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekByte(HInvoke* invoke) {
1032 CreateIntToIntLocations(arena_, invoke);
1033 }
1034
VisitMemoryPeekByte(HInvoke * invoke)1035 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekByte(HInvoke* invoke) {
1036 Mips64Assembler* assembler = GetAssembler();
1037 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1038 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1039
1040 __ Lb(out, adr, 0);
1041 }
1042
1043 // short libcore.io.Memory.peekShort(long address)
VisitMemoryPeekShortNative(HInvoke * invoke)1044 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekShortNative(HInvoke* invoke) {
1045 CreateIntToIntLocations(arena_, invoke);
1046 }
1047
VisitMemoryPeekShortNative(HInvoke * invoke)1048 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekShortNative(HInvoke* invoke) {
1049 Mips64Assembler* assembler = GetAssembler();
1050 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1051 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1052
1053 __ Lh(out, adr, 0);
1054 }
1055
1056 // int libcore.io.Memory.peekInt(long address)
VisitMemoryPeekIntNative(HInvoke * invoke)1057 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekIntNative(HInvoke* invoke) {
1058 CreateIntToIntLocations(arena_, invoke);
1059 }
1060
VisitMemoryPeekIntNative(HInvoke * invoke)1061 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekIntNative(HInvoke* invoke) {
1062 Mips64Assembler* assembler = GetAssembler();
1063 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1064 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1065
1066 __ Lw(out, adr, 0);
1067 }
1068
1069 // long libcore.io.Memory.peekLong(long address)
VisitMemoryPeekLongNative(HInvoke * invoke)1070 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPeekLongNative(HInvoke* invoke) {
1071 CreateIntToIntLocations(arena_, invoke);
1072 }
1073
VisitMemoryPeekLongNative(HInvoke * invoke)1074 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPeekLongNative(HInvoke* invoke) {
1075 Mips64Assembler* assembler = GetAssembler();
1076 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1077 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1078
1079 __ Ld(out, adr, 0);
1080 }
1081
CreateIntIntToVoidLocations(ArenaAllocator * arena,HInvoke * invoke)1082 static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
1083 LocationSummary* locations = new (arena) LocationSummary(invoke,
1084 LocationSummary::kNoCall,
1085 kIntrinsified);
1086 locations->SetInAt(0, Location::RequiresRegister());
1087 locations->SetInAt(1, Location::RequiresRegister());
1088 }
1089
1090 // void libcore.io.Memory.pokeByte(long address, byte value)
VisitMemoryPokeByte(HInvoke * invoke)1091 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeByte(HInvoke* invoke) {
1092 CreateIntIntToVoidLocations(arena_, invoke);
1093 }
1094
VisitMemoryPokeByte(HInvoke * invoke)1095 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeByte(HInvoke* invoke) {
1096 Mips64Assembler* assembler = GetAssembler();
1097 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1098 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1099
1100 __ Sb(val, adr, 0);
1101 }
1102
1103 // void libcore.io.Memory.pokeShort(long address, short value)
VisitMemoryPokeShortNative(HInvoke * invoke)1104 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeShortNative(HInvoke* invoke) {
1105 CreateIntIntToVoidLocations(arena_, invoke);
1106 }
1107
VisitMemoryPokeShortNative(HInvoke * invoke)1108 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeShortNative(HInvoke* invoke) {
1109 Mips64Assembler* assembler = GetAssembler();
1110 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1111 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1112
1113 __ Sh(val, adr, 0);
1114 }
1115
1116 // void libcore.io.Memory.pokeInt(long address, int value)
VisitMemoryPokeIntNative(HInvoke * invoke)1117 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeIntNative(HInvoke* invoke) {
1118 CreateIntIntToVoidLocations(arena_, invoke);
1119 }
1120
VisitMemoryPokeIntNative(HInvoke * invoke)1121 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeIntNative(HInvoke* invoke) {
1122 Mips64Assembler* assembler = GetAssembler();
1123 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1124 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1125
1126 __ Sw(val, adr, 00);
1127 }
1128
1129 // void libcore.io.Memory.pokeLong(long address, long value)
VisitMemoryPokeLongNative(HInvoke * invoke)1130 void IntrinsicLocationsBuilderMIPS64::VisitMemoryPokeLongNative(HInvoke* invoke) {
1131 CreateIntIntToVoidLocations(arena_, invoke);
1132 }
1133
VisitMemoryPokeLongNative(HInvoke * invoke)1134 void IntrinsicCodeGeneratorMIPS64::VisitMemoryPokeLongNative(HInvoke* invoke) {
1135 Mips64Assembler* assembler = GetAssembler();
1136 GpuRegister adr = invoke->GetLocations()->InAt(0).AsRegister<GpuRegister>();
1137 GpuRegister val = invoke->GetLocations()->InAt(1).AsRegister<GpuRegister>();
1138
1139 __ Sd(val, adr, 0);
1140 }
1141
1142 // Thread java.lang.Thread.currentThread()
VisitThreadCurrentThread(HInvoke * invoke)1143 void IntrinsicLocationsBuilderMIPS64::VisitThreadCurrentThread(HInvoke* invoke) {
1144 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1145 LocationSummary::kNoCall,
1146 kIntrinsified);
1147 locations->SetOut(Location::RequiresRegister());
1148 }
1149
VisitThreadCurrentThread(HInvoke * invoke)1150 void IntrinsicCodeGeneratorMIPS64::VisitThreadCurrentThread(HInvoke* invoke) {
1151 Mips64Assembler* assembler = GetAssembler();
1152 GpuRegister out = invoke->GetLocations()->Out().AsRegister<GpuRegister>();
1153
1154 __ LoadFromOffset(kLoadUnsignedWord,
1155 out,
1156 TR,
1157 Thread::PeerOffset<kMips64PointerSize>().Int32Value());
1158 }
1159
CreateIntIntIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke,Primitive::Type type)1160 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
1161 HInvoke* invoke,
1162 Primitive::Type type) {
1163 bool can_call = kEmitCompilerReadBarrier &&
1164 (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
1165 invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
1166 LocationSummary* locations = new (arena) LocationSummary(invoke,
1167 (can_call
1168 ? LocationSummary::kCallOnSlowPath
1169 : LocationSummary::kNoCall),
1170 kIntrinsified);
1171 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1172 locations->SetInAt(1, Location::RequiresRegister());
1173 locations->SetInAt(2, Location::RequiresRegister());
1174 locations->SetOut(Location::RequiresRegister(),
1175 (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
1176 if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1177 // We need a temporary register for the read barrier marking slow
1178 // path in InstructionCodeGeneratorMIPS64::GenerateReferenceLoadWithBakerReadBarrier.
1179 locations->AddTemp(Location::RequiresRegister());
1180 }
1181 }
1182
1183 // Note that the caller must supply a properly aligned memory address.
1184 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
GenUnsafeGet(HInvoke * invoke,Primitive::Type type,bool is_volatile,CodeGeneratorMIPS64 * codegen)1185 static void GenUnsafeGet(HInvoke* invoke,
1186 Primitive::Type type,
1187 bool is_volatile,
1188 CodeGeneratorMIPS64* codegen) {
1189 LocationSummary* locations = invoke->GetLocations();
1190 DCHECK((type == Primitive::kPrimInt) ||
1191 (type == Primitive::kPrimLong) ||
1192 (type == Primitive::kPrimNot)) << type;
1193 Mips64Assembler* assembler = codegen->GetAssembler();
1194 // Target register.
1195 Location trg_loc = locations->Out();
1196 GpuRegister trg = trg_loc.AsRegister<GpuRegister>();
1197 // Object pointer.
1198 Location base_loc = locations->InAt(1);
1199 GpuRegister base = base_loc.AsRegister<GpuRegister>();
1200 // Long offset.
1201 Location offset_loc = locations->InAt(2);
1202 GpuRegister offset = offset_loc.AsRegister<GpuRegister>();
1203
1204 if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == Primitive::kPrimNot))) {
1205 __ Daddu(TMP, base, offset);
1206 }
1207
1208 switch (type) {
1209 case Primitive::kPrimLong:
1210 __ Ld(trg, TMP, 0);
1211 if (is_volatile) {
1212 __ Sync(0);
1213 }
1214 break;
1215
1216 case Primitive::kPrimInt:
1217 __ Lw(trg, TMP, 0);
1218 if (is_volatile) {
1219 __ Sync(0);
1220 }
1221 break;
1222
1223 case Primitive::kPrimNot:
1224 if (kEmitCompilerReadBarrier) {
1225 if (kUseBakerReadBarrier) {
1226 Location temp = locations->GetTemp(0);
1227 codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
1228 trg_loc,
1229 base,
1230 /* offset */ 0U,
1231 /* index */ offset_loc,
1232 TIMES_1,
1233 temp,
1234 /* needs_null_check */ false);
1235 if (is_volatile) {
1236 __ Sync(0);
1237 }
1238 } else {
1239 __ Lwu(trg, TMP, 0);
1240 if (is_volatile) {
1241 __ Sync(0);
1242 }
1243 codegen->GenerateReadBarrierSlow(invoke,
1244 trg_loc,
1245 trg_loc,
1246 base_loc,
1247 /* offset */ 0U,
1248 /* index */ offset_loc);
1249 }
1250 } else {
1251 __ Lwu(trg, TMP, 0);
1252 if (is_volatile) {
1253 __ Sync(0);
1254 }
1255 __ MaybeUnpoisonHeapReference(trg);
1256 }
1257 break;
1258
1259 default:
1260 LOG(FATAL) << "Unsupported op size " << type;
1261 UNREACHABLE();
1262 }
1263 }
1264
1265 // int sun.misc.Unsafe.getInt(Object o, long offset)
VisitUnsafeGet(HInvoke * invoke)1266 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGet(HInvoke* invoke) {
1267 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
1268 }
1269
VisitUnsafeGet(HInvoke * invoke)1270 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGet(HInvoke* invoke) {
1271 GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
1272 }
1273
1274 // int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
VisitUnsafeGetVolatile(HInvoke * invoke)1275 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
1276 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
1277 }
1278
VisitUnsafeGetVolatile(HInvoke * invoke)1279 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetVolatile(HInvoke* invoke) {
1280 GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
1281 }
1282
1283 // long sun.misc.Unsafe.getLong(Object o, long offset)
VisitUnsafeGetLong(HInvoke * invoke)1284 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
1285 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
1286 }
1287
VisitUnsafeGetLong(HInvoke * invoke)1288 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLong(HInvoke* invoke) {
1289 GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
1290 }
1291
1292 // long sun.misc.Unsafe.getLongVolatile(Object o, long offset)
VisitUnsafeGetLongVolatile(HInvoke * invoke)1293 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1294 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
1295 }
1296
VisitUnsafeGetLongVolatile(HInvoke * invoke)1297 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1298 GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
1299 }
1300
1301 // Object sun.misc.Unsafe.getObject(Object o, long offset)
VisitUnsafeGetObject(HInvoke * invoke)1302 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
1303 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
1304 }
1305
VisitUnsafeGetObject(HInvoke * invoke)1306 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObject(HInvoke* invoke) {
1307 GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
1308 }
1309
1310 // Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
VisitUnsafeGetObjectVolatile(HInvoke * invoke)1311 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1312 CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
1313 }
1314
VisitUnsafeGetObjectVolatile(HInvoke * invoke)1315 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1316 GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
1317 }
1318
CreateIntIntIntIntToVoid(ArenaAllocator * arena,HInvoke * invoke)1319 static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, HInvoke* invoke) {
1320 LocationSummary* locations = new (arena) LocationSummary(invoke,
1321 LocationSummary::kNoCall,
1322 kIntrinsified);
1323 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1324 locations->SetInAt(1, Location::RequiresRegister());
1325 locations->SetInAt(2, Location::RequiresRegister());
1326 locations->SetInAt(3, Location::RequiresRegister());
1327 }
1328
1329 // Note that the caller must supply a properly aligned memory address.
1330 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
GenUnsafePut(LocationSummary * locations,Primitive::Type type,bool is_volatile,bool is_ordered,CodeGeneratorMIPS64 * codegen)1331 static void GenUnsafePut(LocationSummary* locations,
1332 Primitive::Type type,
1333 bool is_volatile,
1334 bool is_ordered,
1335 CodeGeneratorMIPS64* codegen) {
1336 DCHECK((type == Primitive::kPrimInt) ||
1337 (type == Primitive::kPrimLong) ||
1338 (type == Primitive::kPrimNot));
1339 Mips64Assembler* assembler = codegen->GetAssembler();
1340 // Object pointer.
1341 GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
1342 // Long offset.
1343 GpuRegister offset = locations->InAt(2).AsRegister<GpuRegister>();
1344 GpuRegister value = locations->InAt(3).AsRegister<GpuRegister>();
1345
1346 __ Daddu(TMP, base, offset);
1347 if (is_volatile || is_ordered) {
1348 __ Sync(0);
1349 }
1350 switch (type) {
1351 case Primitive::kPrimInt:
1352 case Primitive::kPrimNot:
1353 if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1354 __ PoisonHeapReference(AT, value);
1355 __ Sw(AT, TMP, 0);
1356 } else {
1357 __ Sw(value, TMP, 0);
1358 }
1359 break;
1360
1361 case Primitive::kPrimLong:
1362 __ Sd(value, TMP, 0);
1363 break;
1364
1365 default:
1366 LOG(FATAL) << "Unsupported op size " << type;
1367 UNREACHABLE();
1368 }
1369 if (is_volatile) {
1370 __ Sync(0);
1371 }
1372
1373 if (type == Primitive::kPrimNot) {
1374 bool value_can_be_null = true; // TODO: Worth finding out this information?
1375 codegen->MarkGCCard(base, value, value_can_be_null);
1376 }
1377 }
1378
1379 // void sun.misc.Unsafe.putInt(Object o, long offset, int x)
VisitUnsafePut(HInvoke * invoke)1380 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePut(HInvoke* invoke) {
1381 CreateIntIntIntIntToVoid(arena_, invoke);
1382 }
1383
VisitUnsafePut(HInvoke * invoke)1384 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePut(HInvoke* invoke) {
1385 GenUnsafePut(invoke->GetLocations(),
1386 Primitive::kPrimInt,
1387 /* is_volatile */ false,
1388 /* is_ordered */ false,
1389 codegen_);
1390 }
1391
1392 // void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x)
VisitUnsafePutOrdered(HInvoke * invoke)1393 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) {
1394 CreateIntIntIntIntToVoid(arena_, invoke);
1395 }
1396
VisitUnsafePutOrdered(HInvoke * invoke)1397 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutOrdered(HInvoke* invoke) {
1398 GenUnsafePut(invoke->GetLocations(),
1399 Primitive::kPrimInt,
1400 /* is_volatile */ false,
1401 /* is_ordered */ true,
1402 codegen_);
1403 }
1404
1405 // void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x)
VisitUnsafePutVolatile(HInvoke * invoke)1406 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) {
1407 CreateIntIntIntIntToVoid(arena_, invoke);
1408 }
1409
VisitUnsafePutVolatile(HInvoke * invoke)1410 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutVolatile(HInvoke* invoke) {
1411 GenUnsafePut(invoke->GetLocations(),
1412 Primitive::kPrimInt,
1413 /* is_volatile */ true,
1414 /* is_ordered */ false,
1415 codegen_);
1416 }
1417
1418 // void sun.misc.Unsafe.putObject(Object o, long offset, Object x)
VisitUnsafePutObject(HInvoke * invoke)1419 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObject(HInvoke* invoke) {
1420 CreateIntIntIntIntToVoid(arena_, invoke);
1421 }
1422
VisitUnsafePutObject(HInvoke * invoke)1423 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObject(HInvoke* invoke) {
1424 GenUnsafePut(invoke->GetLocations(),
1425 Primitive::kPrimNot,
1426 /* is_volatile */ false,
1427 /* is_ordered */ false,
1428 codegen_);
1429 }
1430
1431 // void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x)
VisitUnsafePutObjectOrdered(HInvoke * invoke)1432 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1433 CreateIntIntIntIntToVoid(arena_, invoke);
1434 }
1435
VisitUnsafePutObjectOrdered(HInvoke * invoke)1436 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1437 GenUnsafePut(invoke->GetLocations(),
1438 Primitive::kPrimNot,
1439 /* is_volatile */ false,
1440 /* is_ordered */ true,
1441 codegen_);
1442 }
1443
1444 // void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x)
VisitUnsafePutObjectVolatile(HInvoke * invoke)1445 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1446 CreateIntIntIntIntToVoid(arena_, invoke);
1447 }
1448
VisitUnsafePutObjectVolatile(HInvoke * invoke)1449 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1450 GenUnsafePut(invoke->GetLocations(),
1451 Primitive::kPrimNot,
1452 /* is_volatile */ true,
1453 /* is_ordered */ false,
1454 codegen_);
1455 }
1456
1457 // void sun.misc.Unsafe.putLong(Object o, long offset, long x)
VisitUnsafePutLong(HInvoke * invoke)1458 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLong(HInvoke* invoke) {
1459 CreateIntIntIntIntToVoid(arena_, invoke);
1460 }
1461
VisitUnsafePutLong(HInvoke * invoke)1462 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLong(HInvoke* invoke) {
1463 GenUnsafePut(invoke->GetLocations(),
1464 Primitive::kPrimLong,
1465 /* is_volatile */ false,
1466 /* is_ordered */ false,
1467 codegen_);
1468 }
1469
1470 // void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x)
VisitUnsafePutLongOrdered(HInvoke * invoke)1471 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1472 CreateIntIntIntIntToVoid(arena_, invoke);
1473 }
1474
VisitUnsafePutLongOrdered(HInvoke * invoke)1475 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1476 GenUnsafePut(invoke->GetLocations(),
1477 Primitive::kPrimLong,
1478 /* is_volatile */ false,
1479 /* is_ordered */ true,
1480 codegen_);
1481 }
1482
1483 // void sun.misc.Unsafe.putLongVolatile(Object o, long offset, long x)
VisitUnsafePutLongVolatile(HInvoke * invoke)1484 void IntrinsicLocationsBuilderMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1485 CreateIntIntIntIntToVoid(arena_, invoke);
1486 }
1487
VisitUnsafePutLongVolatile(HInvoke * invoke)1488 void IntrinsicCodeGeneratorMIPS64::VisitUnsafePutLongVolatile(HInvoke* invoke) {
1489 GenUnsafePut(invoke->GetLocations(),
1490 Primitive::kPrimLong,
1491 /* is_volatile */ true,
1492 /* is_ordered */ false,
1493 codegen_);
1494 }
1495
CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator * arena,HInvoke * invoke)1496 static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, HInvoke* invoke) {
1497 bool can_call = kEmitCompilerReadBarrier &&
1498 kUseBakerReadBarrier &&
1499 (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
1500 LocationSummary* locations = new (arena) LocationSummary(invoke,
1501 (can_call
1502 ? LocationSummary::kCallOnSlowPath
1503 : LocationSummary::kNoCall),
1504 kIntrinsified);
1505 locations->SetInAt(0, Location::NoLocation()); // Unused receiver.
1506 locations->SetInAt(1, Location::RequiresRegister());
1507 locations->SetInAt(2, Location::RequiresRegister());
1508 locations->SetInAt(3, Location::RequiresRegister());
1509 locations->SetInAt(4, Location::RequiresRegister());
1510 locations->SetOut(Location::RequiresRegister());
1511
1512 // Temporary register used in CAS by (Baker) read barrier.
1513 if (can_call) {
1514 locations->AddTemp(Location::RequiresRegister());
1515 }
1516 }
1517
1518 // Note that the caller must supply a properly aligned memory address.
1519 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
GenCas(HInvoke * invoke,Primitive::Type type,CodeGeneratorMIPS64 * codegen)1520 static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorMIPS64* codegen) {
1521 Mips64Assembler* assembler = codegen->GetAssembler();
1522 LocationSummary* locations = invoke->GetLocations();
1523 GpuRegister base = locations->InAt(1).AsRegister<GpuRegister>();
1524 Location offset_loc = locations->InAt(2);
1525 GpuRegister offset = offset_loc.AsRegister<GpuRegister>();
1526 GpuRegister expected = locations->InAt(3).AsRegister<GpuRegister>();
1527 GpuRegister value = locations->InAt(4).AsRegister<GpuRegister>();
1528 Location out_loc = locations->Out();
1529 GpuRegister out = out_loc.AsRegister<GpuRegister>();
1530
1531 DCHECK_NE(base, out);
1532 DCHECK_NE(offset, out);
1533 DCHECK_NE(expected, out);
1534
1535 if (type == Primitive::kPrimNot) {
1536 // The only read barrier implementation supporting the
1537 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1538 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1539
1540 // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
1541 // object and scan the receiver at the next GC for nothing.
1542 bool value_can_be_null = true; // TODO: Worth finding out this information?
1543 codegen->MarkGCCard(base, value, value_can_be_null);
1544
1545 if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1546 Location temp = locations->GetTemp(0);
1547 // Need to make sure the reference stored in the field is a to-space
1548 // one before attempting the CAS or the CAS could fail incorrectly.
1549 codegen->GenerateReferenceLoadWithBakerReadBarrier(
1550 invoke,
1551 out_loc, // Unused, used only as a "temporary" within the read barrier.
1552 base,
1553 /* offset */ 0u,
1554 /* index */ offset_loc,
1555 ScaleFactor::TIMES_1,
1556 temp,
1557 /* needs_null_check */ false,
1558 /* always_update_field */ true);
1559 }
1560 }
1561
1562 Mips64Label loop_head, exit_loop;
1563 __ Daddu(TMP, base, offset);
1564
1565 if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1566 __ PoisonHeapReference(expected);
1567 // Do not poison `value`, if it is the same register as
1568 // `expected`, which has just been poisoned.
1569 if (value != expected) {
1570 __ PoisonHeapReference(value);
1571 }
1572 }
1573
1574 // do {
1575 // tmp_value = [tmp_ptr] - expected;
1576 // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
1577 // result = tmp_value != 0;
1578
1579 __ Sync(0);
1580 __ Bind(&loop_head);
1581 if (type == Primitive::kPrimLong) {
1582 __ Lld(out, TMP);
1583 } else {
1584 // Note: We will need a read barrier here, when read barrier
1585 // support is added to the MIPS64 back end.
1586 __ Ll(out, TMP);
1587 if (type == Primitive::kPrimNot) {
1588 // The LL instruction sign-extends the 32-bit value, but
1589 // 32-bit references must be zero-extended. Zero-extend `out`.
1590 __ Dext(out, out, 0, 32);
1591 }
1592 }
1593 __ Dsubu(out, out, expected); // If we didn't get the 'expected'
1594 __ Sltiu(out, out, 1); // value, set 'out' to false, and
1595 __ Beqzc(out, &exit_loop); // return.
1596 __ Move(out, value); // Use 'out' for the 'store conditional' instruction.
1597 // If we use 'value' directly, we would lose 'value'
1598 // in the case that the store fails. Whether the
1599 // store succeeds, or fails, it will load the
1600 // correct Boolean value into the 'out' register.
1601 if (type == Primitive::kPrimLong) {
1602 __ Scd(out, TMP);
1603 } else {
1604 __ Sc(out, TMP);
1605 }
1606 __ Beqzc(out, &loop_head); // If we couldn't do the read-modify-write
1607 // cycle atomically then retry.
1608 __ Bind(&exit_loop);
1609 __ Sync(0);
1610
1611 if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1612 __ UnpoisonHeapReference(expected);
1613 // Do not unpoison `value`, if it is the same register as
1614 // `expected`, which has just been unpoisoned.
1615 if (value != expected) {
1616 __ UnpoisonHeapReference(value);
1617 }
1618 }
1619 }
1620
1621 // boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
VisitUnsafeCASInt(HInvoke * invoke)1622 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASInt(HInvoke* invoke) {
1623 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
1624 }
1625
VisitUnsafeCASInt(HInvoke * invoke)1626 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASInt(HInvoke* invoke) {
1627 GenCas(invoke, Primitive::kPrimInt, codegen_);
1628 }
1629
1630 // boolean sun.misc.Unsafe.compareAndSwapLong(Object o, long offset, long expected, long x)
VisitUnsafeCASLong(HInvoke * invoke)1631 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASLong(HInvoke* invoke) {
1632 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
1633 }
1634
VisitUnsafeCASLong(HInvoke * invoke)1635 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASLong(HInvoke* invoke) {
1636 GenCas(invoke, Primitive::kPrimLong, codegen_);
1637 }
1638
1639 // boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
VisitUnsafeCASObject(HInvoke * invoke)1640 void IntrinsicLocationsBuilderMIPS64::VisitUnsafeCASObject(HInvoke* invoke) {
1641 // The only read barrier implementation supporting the
1642 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1643 if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) {
1644 return;
1645 }
1646
1647 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
1648 }
1649
VisitUnsafeCASObject(HInvoke * invoke)1650 void IntrinsicCodeGeneratorMIPS64::VisitUnsafeCASObject(HInvoke* invoke) {
1651 // The only read barrier implementation supporting the
1652 // UnsafeCASObject intrinsic is the Baker-style read barriers.
1653 DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1654
1655 GenCas(invoke, Primitive::kPrimNot, codegen_);
1656 }
1657
1658 // int java.lang.String.compareTo(String anotherString)
VisitStringCompareTo(HInvoke * invoke)1659 void IntrinsicLocationsBuilderMIPS64::VisitStringCompareTo(HInvoke* invoke) {
1660 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1661 LocationSummary::kCallOnMainAndSlowPath,
1662 kIntrinsified);
1663 InvokeRuntimeCallingConvention calling_convention;
1664 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1665 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1666 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1667 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1668 }
1669
VisitStringCompareTo(HInvoke * invoke)1670 void IntrinsicCodeGeneratorMIPS64::VisitStringCompareTo(HInvoke* invoke) {
1671 Mips64Assembler* assembler = GetAssembler();
1672 LocationSummary* locations = invoke->GetLocations();
1673
1674 // Note that the null check must have been done earlier.
1675 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1676
1677 GpuRegister argument = locations->InAt(1).AsRegister<GpuRegister>();
1678 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
1679 codegen_->AddSlowPath(slow_path);
1680 __ Beqzc(argument, slow_path->GetEntryLabel());
1681
1682 codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
1683 __ Bind(slow_path->GetExitLabel());
1684 }
1685
1686 // boolean java.lang.String.equals(Object anObject)
VisitStringEquals(HInvoke * invoke)1687 void IntrinsicLocationsBuilderMIPS64::VisitStringEquals(HInvoke* invoke) {
1688 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1689 LocationSummary::kNoCall,
1690 kIntrinsified);
1691 locations->SetInAt(0, Location::RequiresRegister());
1692 locations->SetInAt(1, Location::RequiresRegister());
1693 locations->SetOut(Location::RequiresRegister());
1694
1695 // Temporary registers to store lengths of strings and for calculations.
1696 locations->AddTemp(Location::RequiresRegister());
1697 locations->AddTemp(Location::RequiresRegister());
1698 locations->AddTemp(Location::RequiresRegister());
1699 }
1700
VisitStringEquals(HInvoke * invoke)1701 void IntrinsicCodeGeneratorMIPS64::VisitStringEquals(HInvoke* invoke) {
1702 Mips64Assembler* assembler = GetAssembler();
1703 LocationSummary* locations = invoke->GetLocations();
1704
1705 GpuRegister str = locations->InAt(0).AsRegister<GpuRegister>();
1706 GpuRegister arg = locations->InAt(1).AsRegister<GpuRegister>();
1707 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
1708
1709 GpuRegister temp1 = locations->GetTemp(0).AsRegister<GpuRegister>();
1710 GpuRegister temp2 = locations->GetTemp(1).AsRegister<GpuRegister>();
1711 GpuRegister temp3 = locations->GetTemp(2).AsRegister<GpuRegister>();
1712
1713 Mips64Label loop;
1714 Mips64Label end;
1715 Mips64Label return_true;
1716 Mips64Label return_false;
1717
1718 // Get offsets of count, value, and class fields within a string object.
1719 const int32_t count_offset = mirror::String::CountOffset().Int32Value();
1720 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
1721 const int32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1722
1723 // Note that the null check must have been done earlier.
1724 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1725
1726 // If the register containing the pointer to "this", and the register
1727 // containing the pointer to "anObject" are the same register then
1728 // "this", and "anObject" are the same object and we can
1729 // short-circuit the logic to a true result.
1730 if (str == arg) {
1731 __ LoadConst64(out, 1);
1732 return;
1733 }
1734
1735 StringEqualsOptimizations optimizations(invoke);
1736 if (!optimizations.GetArgumentNotNull()) {
1737 // Check if input is null, return false if it is.
1738 __ Beqzc(arg, &return_false);
1739 }
1740
1741 // Reference equality check, return true if same reference.
1742 __ Beqc(str, arg, &return_true);
1743
1744 if (!optimizations.GetArgumentIsString()) {
1745 // Instanceof check for the argument by comparing class fields.
1746 // All string objects must have the same type since String cannot be subclassed.
1747 // Receiver must be a string object, so its class field is equal to all strings' class fields.
1748 // If the argument is a string object, its class field must be equal to receiver's class field.
1749 __ Lw(temp1, str, class_offset);
1750 __ Lw(temp2, arg, class_offset);
1751 __ Bnec(temp1, temp2, &return_false);
1752 }
1753
1754 // Load `count` fields of this and argument strings.
1755 __ Lw(temp1, str, count_offset);
1756 __ Lw(temp2, arg, count_offset);
1757 // Check if `count` fields are equal, return false if they're not.
1758 // Also compares the compression style, if differs return false.
1759 __ Bnec(temp1, temp2, &return_false);
1760 // Return true if both strings are empty. Even with string compression `count == 0` means empty.
1761 static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
1762 "Expecting 0=compressed, 1=uncompressed");
1763 __ Beqzc(temp1, &return_true);
1764
1765 // Don't overwrite input registers
1766 __ Move(TMP, str);
1767 __ Move(temp3, arg);
1768
1769 // Assertions that must hold in order to compare strings 8 bytes at a time.
1770 DCHECK_ALIGNED(value_offset, 8);
1771 static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
1772
1773 if (mirror::kUseStringCompression) {
1774 // For string compression, calculate the number of bytes to compare (not chars).
1775 __ Dext(temp2, temp1, 0, 1); // Extract compression flag.
1776 __ Srl(temp1, temp1, 1); // Extract length.
1777 __ Sllv(temp1, temp1, temp2); // Double the byte count if uncompressed.
1778 }
1779
1780 // Loop to compare strings 8 bytes at a time starting at the beginning of the string.
1781 // Ok to do this because strings are zero-padded to kObjectAlignment.
1782 __ Bind(&loop);
1783 __ Ld(out, TMP, value_offset);
1784 __ Ld(temp2, temp3, value_offset);
1785 __ Bnec(out, temp2, &return_false);
1786 __ Daddiu(TMP, TMP, 8);
1787 __ Daddiu(temp3, temp3, 8);
1788 // With string compression, we have compared 8 bytes, otherwise 4 chars.
1789 __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -8 : -4);
1790 __ Bgtzc(temp1, &loop);
1791
1792 // Return true and exit the function.
1793 // If loop does not result in returning false, we return true.
1794 __ Bind(&return_true);
1795 __ LoadConst64(out, 1);
1796 __ Bc(&end);
1797
1798 // Return false and exit the function.
1799 __ Bind(&return_false);
1800 __ LoadConst64(out, 0);
1801 __ Bind(&end);
1802 }
1803
GenerateStringIndexOf(HInvoke * invoke,Mips64Assembler * assembler,CodeGeneratorMIPS64 * codegen,ArenaAllocator * allocator,bool start_at_zero)1804 static void GenerateStringIndexOf(HInvoke* invoke,
1805 Mips64Assembler* assembler,
1806 CodeGeneratorMIPS64* codegen,
1807 ArenaAllocator* allocator,
1808 bool start_at_zero) {
1809 LocationSummary* locations = invoke->GetLocations();
1810 GpuRegister tmp_reg = start_at_zero ? locations->GetTemp(0).AsRegister<GpuRegister>() : TMP;
1811
1812 // Note that the null check must have been done earlier.
1813 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1814
1815 // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
1816 // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
1817 SlowPathCodeMIPS64* slow_path = nullptr;
1818 HInstruction* code_point = invoke->InputAt(1);
1819 if (code_point->IsIntConstant()) {
1820 if (!IsUint<16>(code_point->AsIntConstant()->GetValue())) {
1821 // Always needs the slow-path. We could directly dispatch to it,
1822 // but this case should be rare, so for simplicity just put the
1823 // full slow-path down and branch unconditionally.
1824 slow_path = new (allocator) IntrinsicSlowPathMIPS64(invoke);
1825 codegen->AddSlowPath(slow_path);
1826 __ Bc(slow_path->GetEntryLabel());
1827 __ Bind(slow_path->GetExitLabel());
1828 return;
1829 }
1830 } else if (code_point->GetType() != Primitive::kPrimChar) {
1831 GpuRegister char_reg = locations->InAt(1).AsRegister<GpuRegister>();
1832 __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
1833 slow_path = new (allocator) IntrinsicSlowPathMIPS64(invoke);
1834 codegen->AddSlowPath(slow_path);
1835 __ Bltuc(tmp_reg, char_reg, slow_path->GetEntryLabel()); // UTF-16 required
1836 }
1837
1838 if (start_at_zero) {
1839 DCHECK_EQ(tmp_reg, A2);
1840 // Start-index = 0.
1841 __ Clear(tmp_reg);
1842 }
1843
1844 codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
1845 CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>();
1846
1847 if (slow_path != nullptr) {
1848 __ Bind(slow_path->GetExitLabel());
1849 }
1850 }
1851
1852 // int java.lang.String.indexOf(int ch)
VisitStringIndexOf(HInvoke * invoke)1853 void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOf(HInvoke* invoke) {
1854 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1855 LocationSummary::kCallOnMainAndSlowPath,
1856 kIntrinsified);
1857 // We have a hand-crafted assembly stub that follows the runtime
1858 // calling convention. So it's best to align the inputs accordingly.
1859 InvokeRuntimeCallingConvention calling_convention;
1860 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1861 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1862 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1863 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1864
1865 // Need a temp for slow-path codepoint compare, and need to send start-index=0.
1866 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1867 }
1868
VisitStringIndexOf(HInvoke * invoke)1869 void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOf(HInvoke* invoke) {
1870 GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true);
1871 }
1872
1873 // int java.lang.String.indexOf(int ch, int fromIndex)
VisitStringIndexOfAfter(HInvoke * invoke)1874 void IntrinsicLocationsBuilderMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
1875 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1876 LocationSummary::kCallOnMainAndSlowPath,
1877 kIntrinsified);
1878 // We have a hand-crafted assembly stub that follows the runtime
1879 // calling convention. So it's best to align the inputs accordingly.
1880 InvokeRuntimeCallingConvention calling_convention;
1881 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1882 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1883 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1884 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1885 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1886 }
1887
VisitStringIndexOfAfter(HInvoke * invoke)1888 void IntrinsicCodeGeneratorMIPS64::VisitStringIndexOfAfter(HInvoke* invoke) {
1889 GenerateStringIndexOf(
1890 invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false);
1891 }
1892
1893 // java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
VisitStringNewStringFromBytes(HInvoke * invoke)1894 void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
1895 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1896 LocationSummary::kCallOnMainAndSlowPath,
1897 kIntrinsified);
1898 InvokeRuntimeCallingConvention calling_convention;
1899 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1900 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1901 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1902 locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
1903 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1904 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1905 }
1906
VisitStringNewStringFromBytes(HInvoke * invoke)1907 void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromBytes(HInvoke* invoke) {
1908 Mips64Assembler* assembler = GetAssembler();
1909 LocationSummary* locations = invoke->GetLocations();
1910
1911 GpuRegister byte_array = locations->InAt(0).AsRegister<GpuRegister>();
1912 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
1913 codegen_->AddSlowPath(slow_path);
1914 __ Beqzc(byte_array, slow_path->GetEntryLabel());
1915
1916 codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
1917 CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
1918 __ Bind(slow_path->GetExitLabel());
1919 }
1920
1921 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
VisitStringNewStringFromChars(HInvoke * invoke)1922 void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) {
1923 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1924 LocationSummary::kCallOnMainOnly,
1925 kIntrinsified);
1926 InvokeRuntimeCallingConvention calling_convention;
1927 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1928 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1929 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1930 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1931 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1932 }
1933
VisitStringNewStringFromChars(HInvoke * invoke)1934 void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromChars(HInvoke* invoke) {
1935 // No need to emit code checking whether `locations->InAt(2)` is a null
1936 // pointer, as callers of the native method
1937 //
1938 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1939 //
1940 // all include a null check on `data` before calling that method.
1941 codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
1942 CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
1943 }
1944
1945 // java.lang.StringFactory.newStringFromString(String toCopy)
VisitStringNewStringFromString(HInvoke * invoke)1946 void IntrinsicLocationsBuilderMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
1947 LocationSummary* locations = new (arena_) LocationSummary(invoke,
1948 LocationSummary::kCallOnMainAndSlowPath,
1949 kIntrinsified);
1950 InvokeRuntimeCallingConvention calling_convention;
1951 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1952 Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
1953 locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<GpuRegister>()));
1954 }
1955
VisitStringNewStringFromString(HInvoke * invoke)1956 void IntrinsicCodeGeneratorMIPS64::VisitStringNewStringFromString(HInvoke* invoke) {
1957 Mips64Assembler* assembler = GetAssembler();
1958 LocationSummary* locations = invoke->GetLocations();
1959
1960 GpuRegister string_to_copy = locations->InAt(0).AsRegister<GpuRegister>();
1961 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
1962 codegen_->AddSlowPath(slow_path);
1963 __ Beqzc(string_to_copy, slow_path->GetEntryLabel());
1964
1965 codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc(), slow_path);
1966 CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
1967 __ Bind(slow_path->GetExitLabel());
1968 }
1969
GenIsInfinite(LocationSummary * locations,bool is64bit,Mips64Assembler * assembler)1970 static void GenIsInfinite(LocationSummary* locations,
1971 bool is64bit,
1972 Mips64Assembler* assembler) {
1973 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
1974 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
1975
1976 if (is64bit) {
1977 __ ClassD(FTMP, in);
1978 } else {
1979 __ ClassS(FTMP, in);
1980 }
1981 __ Mfc1(out, FTMP);
1982 __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
1983 __ Sltu(out, ZERO, out);
1984 }
1985
1986 // boolean java.lang.Float.isInfinite(float)
VisitFloatIsInfinite(HInvoke * invoke)1987 void IntrinsicLocationsBuilderMIPS64::VisitFloatIsInfinite(HInvoke* invoke) {
1988 CreateFPToIntLocations(arena_, invoke);
1989 }
1990
VisitFloatIsInfinite(HInvoke * invoke)1991 void IntrinsicCodeGeneratorMIPS64::VisitFloatIsInfinite(HInvoke* invoke) {
1992 GenIsInfinite(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
1993 }
1994
1995 // boolean java.lang.Double.isInfinite(double)
VisitDoubleIsInfinite(HInvoke * invoke)1996 void IntrinsicLocationsBuilderMIPS64::VisitDoubleIsInfinite(HInvoke* invoke) {
1997 CreateFPToIntLocations(arena_, invoke);
1998 }
1999
VisitDoubleIsInfinite(HInvoke * invoke)2000 void IntrinsicCodeGeneratorMIPS64::VisitDoubleIsInfinite(HInvoke* invoke) {
2001 GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
2002 }
2003
2004 // void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
VisitStringGetCharsNoCheck(HInvoke * invoke)2005 void IntrinsicLocationsBuilderMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2006 LocationSummary* locations = new (arena_) LocationSummary(invoke,
2007 LocationSummary::kNoCall,
2008 kIntrinsified);
2009 locations->SetInAt(0, Location::RequiresRegister());
2010 locations->SetInAt(1, Location::RequiresRegister());
2011 locations->SetInAt(2, Location::RequiresRegister());
2012 locations->SetInAt(3, Location::RequiresRegister());
2013 locations->SetInAt(4, Location::RequiresRegister());
2014
2015 locations->AddTemp(Location::RequiresRegister());
2016 locations->AddTemp(Location::RequiresRegister());
2017 locations->AddTemp(Location::RequiresRegister());
2018 }
2019
VisitStringGetCharsNoCheck(HInvoke * invoke)2020 void IntrinsicCodeGeneratorMIPS64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2021 Mips64Assembler* assembler = GetAssembler();
2022 LocationSummary* locations = invoke->GetLocations();
2023
2024 // Check assumption that sizeof(Char) is 2 (used in scaling below).
2025 const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
2026 DCHECK_EQ(char_size, 2u);
2027 const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
2028
2029 GpuRegister srcObj = locations->InAt(0).AsRegister<GpuRegister>();
2030 GpuRegister srcBegin = locations->InAt(1).AsRegister<GpuRegister>();
2031 GpuRegister srcEnd = locations->InAt(2).AsRegister<GpuRegister>();
2032 GpuRegister dstObj = locations->InAt(3).AsRegister<GpuRegister>();
2033 GpuRegister dstBegin = locations->InAt(4).AsRegister<GpuRegister>();
2034
2035 GpuRegister dstPtr = locations->GetTemp(0).AsRegister<GpuRegister>();
2036 GpuRegister srcPtr = locations->GetTemp(1).AsRegister<GpuRegister>();
2037 GpuRegister numChrs = locations->GetTemp(2).AsRegister<GpuRegister>();
2038
2039 Mips64Label done;
2040 Mips64Label loop;
2041
2042 // Location of data in char array buffer.
2043 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2044
2045 // Get offset of value field within a string object.
2046 const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
2047
2048 __ Beqc(srcEnd, srcBegin, &done); // No characters to move.
2049
2050 // Calculate number of characters to be copied.
2051 __ Dsubu(numChrs, srcEnd, srcBegin);
2052
2053 // Calculate destination address.
2054 __ Daddiu(dstPtr, dstObj, data_offset);
2055 __ Dlsa(dstPtr, dstBegin, dstPtr, char_shift);
2056
2057 if (mirror::kUseStringCompression) {
2058 Mips64Label uncompressed_copy, compressed_loop;
2059 const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2060 // Load count field and extract compression flag.
2061 __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset);
2062 __ Dext(TMP, TMP, 0, 1);
2063
2064 // If string is uncompressed, use uncompressed path.
2065 __ Bnezc(TMP, &uncompressed_copy);
2066
2067 // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
2068 __ Daddu(srcPtr, srcObj, srcBegin);
2069 __ Bind(&compressed_loop);
2070 __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset);
2071 __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0);
2072 __ Daddiu(numChrs, numChrs, -1);
2073 __ Daddiu(srcPtr, srcPtr, 1);
2074 __ Daddiu(dstPtr, dstPtr, 2);
2075 __ Bnezc(numChrs, &compressed_loop);
2076
2077 __ Bc(&done);
2078 __ Bind(&uncompressed_copy);
2079 }
2080
2081 // Calculate source address.
2082 __ Daddiu(srcPtr, srcObj, value_offset);
2083 __ Dlsa(srcPtr, srcBegin, srcPtr, char_shift);
2084
2085 __ Bind(&loop);
2086 __ Lh(AT, srcPtr, 0);
2087 __ Daddiu(numChrs, numChrs, -1);
2088 __ Daddiu(srcPtr, srcPtr, char_size);
2089 __ Sh(AT, dstPtr, 0);
2090 __ Daddiu(dstPtr, dstPtr, char_size);
2091 __ Bnezc(numChrs, &loop);
2092
2093 __ Bind(&done);
2094 }
2095
2096 // static void java.lang.System.arraycopy(Object src, int srcPos,
2097 // Object dest, int destPos,
2098 // int length)
VisitSystemArrayCopyChar(HInvoke * invoke)2099 void IntrinsicLocationsBuilderMIPS64::VisitSystemArrayCopyChar(HInvoke* invoke) {
2100 HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
2101 HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
2102 HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
2103
2104 // As long as we are checking, we might as well check to see if the src and dest
2105 // positions are >= 0.
2106 if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
2107 (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
2108 // We will have to fail anyways.
2109 return;
2110 }
2111
2112 // And since we are already checking, check the length too.
2113 if (length != nullptr) {
2114 int32_t len = length->GetValue();
2115 if (len < 0) {
2116 // Just call as normal.
2117 return;
2118 }
2119 }
2120
2121 // Okay, it is safe to generate inline code.
2122 LocationSummary* locations =
2123 new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
2124 // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
2125 locations->SetInAt(0, Location::RequiresRegister());
2126 locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
2127 locations->SetInAt(2, Location::RequiresRegister());
2128 locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
2129 locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
2130
2131 locations->AddTemp(Location::RequiresRegister());
2132 locations->AddTemp(Location::RequiresRegister());
2133 locations->AddTemp(Location::RequiresRegister());
2134 }
2135
2136 // Utility routine to verify that "length(input) - pos >= length"
EnoughItems(Mips64Assembler * assembler,GpuRegister length_input_minus_pos,Location length,SlowPathCodeMIPS64 * slow_path)2137 static void EnoughItems(Mips64Assembler* assembler,
2138 GpuRegister length_input_minus_pos,
2139 Location length,
2140 SlowPathCodeMIPS64* slow_path) {
2141 if (length.IsConstant()) {
2142 int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
2143
2144 if (IsInt<16>(length_constant)) {
2145 __ Slti(TMP, length_input_minus_pos, length_constant);
2146 __ Bnezc(TMP, slow_path->GetEntryLabel());
2147 } else {
2148 __ LoadConst32(TMP, length_constant);
2149 __ Bltc(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
2150 }
2151 } else {
2152 __ Bltc(length_input_minus_pos, length.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
2153 }
2154 }
2155
CheckPosition(Mips64Assembler * assembler,Location pos,GpuRegister input,Location length,SlowPathCodeMIPS64 * slow_path,bool length_is_input_length=false)2156 static void CheckPosition(Mips64Assembler* assembler,
2157 Location pos,
2158 GpuRegister input,
2159 Location length,
2160 SlowPathCodeMIPS64* slow_path,
2161 bool length_is_input_length = false) {
2162 // Where is the length in the Array?
2163 const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
2164
2165 // Calculate length(input) - pos.
2166 if (pos.IsConstant()) {
2167 int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
2168 if (pos_const == 0) {
2169 if (!length_is_input_length) {
2170 // Check that length(input) >= length.
2171 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2172 EnoughItems(assembler, AT, length, slow_path);
2173 }
2174 } else {
2175 // Check that (length(input) - pos) >= zero.
2176 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2177 DCHECK_GT(pos_const, 0);
2178 __ Addiu32(AT, AT, -pos_const);
2179 __ Bltzc(AT, slow_path->GetEntryLabel());
2180
2181 // Verify that (length(input) - pos) >= length.
2182 EnoughItems(assembler, AT, length, slow_path);
2183 }
2184 } else if (length_is_input_length) {
2185 // The only way the copy can succeed is if pos is zero.
2186 GpuRegister pos_reg = pos.AsRegister<GpuRegister>();
2187 __ Bnezc(pos_reg, slow_path->GetEntryLabel());
2188 } else {
2189 // Verify that pos >= 0.
2190 GpuRegister pos_reg = pos.AsRegister<GpuRegister>();
2191 __ Bltzc(pos_reg, slow_path->GetEntryLabel());
2192
2193 // Check that (length(input) - pos) >= zero.
2194 __ LoadFromOffset(kLoadWord, AT, input, length_offset);
2195 __ Subu(AT, AT, pos_reg);
2196 __ Bltzc(AT, slow_path->GetEntryLabel());
2197
2198 // Verify that (length(input) - pos) >= length.
2199 EnoughItems(assembler, AT, length, slow_path);
2200 }
2201 }
2202
VisitSystemArrayCopyChar(HInvoke * invoke)2203 void IntrinsicCodeGeneratorMIPS64::VisitSystemArrayCopyChar(HInvoke* invoke) {
2204 Mips64Assembler* assembler = GetAssembler();
2205 LocationSummary* locations = invoke->GetLocations();
2206
2207 GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
2208 Location src_pos = locations->InAt(1);
2209 GpuRegister dest = locations->InAt(2).AsRegister<GpuRegister>();
2210 Location dest_pos = locations->InAt(3);
2211 Location length = locations->InAt(4);
2212
2213 Mips64Label loop;
2214
2215 GpuRegister dest_base = locations->GetTemp(0).AsRegister<GpuRegister>();
2216 GpuRegister src_base = locations->GetTemp(1).AsRegister<GpuRegister>();
2217 GpuRegister count = locations->GetTemp(2).AsRegister<GpuRegister>();
2218
2219 SlowPathCodeMIPS64* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS64(invoke);
2220 codegen_->AddSlowPath(slow_path);
2221
2222 // Bail out if the source and destination are the same (to handle overlap).
2223 __ Beqc(src, dest, slow_path->GetEntryLabel());
2224
2225 // Bail out if the source is null.
2226 __ Beqzc(src, slow_path->GetEntryLabel());
2227
2228 // Bail out if the destination is null.
2229 __ Beqzc(dest, slow_path->GetEntryLabel());
2230
2231 // Load length into register for count.
2232 if (length.IsConstant()) {
2233 __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
2234 } else {
2235 // If the length is negative, bail out.
2236 // We have already checked in the LocationsBuilder for the constant case.
2237 __ Bltzc(length.AsRegister<GpuRegister>(), slow_path->GetEntryLabel());
2238
2239 __ Move(count, length.AsRegister<GpuRegister>());
2240 }
2241
2242 // Validity checks: source.
2243 CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
2244
2245 // Validity checks: dest.
2246 CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
2247
2248 // If count is zero, we're done.
2249 __ Beqzc(count, slow_path->GetExitLabel());
2250
2251 // Okay, everything checks out. Finally time to do the copy.
2252 // Check assumption that sizeof(Char) is 2 (used in scaling below).
2253 const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
2254 DCHECK_EQ(char_size, 2u);
2255
2256 const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
2257
2258 const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2259
2260 // Calculate source and destination addresses.
2261 if (src_pos.IsConstant()) {
2262 int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
2263
2264 __ Daddiu64(src_base, src, data_offset + char_size * src_pos_const, TMP);
2265 } else {
2266 __ Daddiu64(src_base, src, data_offset, TMP);
2267 __ Dlsa(src_base, src_pos.AsRegister<GpuRegister>(), src_base, char_shift);
2268 }
2269 if (dest_pos.IsConstant()) {
2270 int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
2271
2272 __ Daddiu64(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
2273 } else {
2274 __ Daddiu64(dest_base, dest, data_offset, TMP);
2275 __ Dlsa(dest_base, dest_pos.AsRegister<GpuRegister>(), dest_base, char_shift);
2276 }
2277
2278 __ Bind(&loop);
2279 __ Lh(TMP, src_base, 0);
2280 __ Daddiu(src_base, src_base, char_size);
2281 __ Daddiu(count, count, -1);
2282 __ Sh(TMP, dest_base, 0);
2283 __ Daddiu(dest_base, dest_base, char_size);
2284 __ Bnezc(count, &loop);
2285
2286 __ Bind(slow_path->GetExitLabel());
2287 }
2288
GenHighestOneBit(LocationSummary * locations,Primitive::Type type,Mips64Assembler * assembler)2289 static void GenHighestOneBit(LocationSummary* locations,
2290 Primitive::Type type,
2291 Mips64Assembler* assembler) {
2292 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << PrettyDescriptor(type);
2293
2294 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
2295 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
2296
2297 if (type == Primitive::kPrimLong) {
2298 __ Dclz(TMP, in);
2299 __ LoadConst64(AT, INT64_C(0x8000000000000000));
2300 __ Dsrlv(AT, AT, TMP);
2301 } else {
2302 __ Clz(TMP, in);
2303 __ LoadConst32(AT, 0x80000000);
2304 __ Srlv(AT, AT, TMP);
2305 }
2306 // For either value of "type", when "in" is zero, "out" should also
2307 // be zero. Without this extra "and" operation, when "in" is zero,
2308 // "out" would be either Integer.MIN_VALUE, or Long.MIN_VALUE because
2309 // the MIPS logical shift operations "dsrlv", and "srlv" don't use
2310 // the shift amount (TMP) directly; they use either (TMP % 64) or
2311 // (TMP % 32), respectively.
2312 __ And(out, AT, in);
2313 }
2314
2315 // int java.lang.Integer.highestOneBit(int)
VisitIntegerHighestOneBit(HInvoke * invoke)2316 void IntrinsicLocationsBuilderMIPS64::VisitIntegerHighestOneBit(HInvoke* invoke) {
2317 CreateIntToIntLocations(arena_, invoke);
2318 }
2319
VisitIntegerHighestOneBit(HInvoke * invoke)2320 void IntrinsicCodeGeneratorMIPS64::VisitIntegerHighestOneBit(HInvoke* invoke) {
2321 GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
2322 }
2323
2324 // long java.lang.Long.highestOneBit(long)
VisitLongHighestOneBit(HInvoke * invoke)2325 void IntrinsicLocationsBuilderMIPS64::VisitLongHighestOneBit(HInvoke* invoke) {
2326 CreateIntToIntLocations(arena_, invoke);
2327 }
2328
VisitLongHighestOneBit(HInvoke * invoke)2329 void IntrinsicCodeGeneratorMIPS64::VisitLongHighestOneBit(HInvoke* invoke) {
2330 GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
2331 }
2332
GenLowestOneBit(LocationSummary * locations,Primitive::Type type,Mips64Assembler * assembler)2333 static void GenLowestOneBit(LocationSummary* locations,
2334 Primitive::Type type,
2335 Mips64Assembler* assembler) {
2336 DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong) << PrettyDescriptor(type);
2337
2338 GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
2339 GpuRegister out = locations->Out().AsRegister<GpuRegister>();
2340
2341 if (type == Primitive::kPrimLong) {
2342 __ Dsubu(TMP, ZERO, in);
2343 } else {
2344 __ Subu(TMP, ZERO, in);
2345 }
2346 __ And(out, TMP, in);
2347 }
2348
2349 // int java.lang.Integer.lowestOneBit(int)
VisitIntegerLowestOneBit(HInvoke * invoke)2350 void IntrinsicLocationsBuilderMIPS64::VisitIntegerLowestOneBit(HInvoke* invoke) {
2351 CreateIntToIntLocations(arena_, invoke);
2352 }
2353
VisitIntegerLowestOneBit(HInvoke * invoke)2354 void IntrinsicCodeGeneratorMIPS64::VisitIntegerLowestOneBit(HInvoke* invoke) {
2355 GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
2356 }
2357
2358 // long java.lang.Long.lowestOneBit(long)
VisitLongLowestOneBit(HInvoke * invoke)2359 void IntrinsicLocationsBuilderMIPS64::VisitLongLowestOneBit(HInvoke* invoke) {
2360 CreateIntToIntLocations(arena_, invoke);
2361 }
2362
VisitLongLowestOneBit(HInvoke * invoke)2363 void IntrinsicCodeGeneratorMIPS64::VisitLongLowestOneBit(HInvoke* invoke) {
2364 GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
2365 }
2366
CreateFPToFPCallLocations(ArenaAllocator * arena,HInvoke * invoke)2367 static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
2368 LocationSummary* locations = new (arena) LocationSummary(invoke,
2369 LocationSummary::kCallOnMainOnly,
2370 kIntrinsified);
2371 InvokeRuntimeCallingConvention calling_convention;
2372
2373 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2374 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
2375 }
2376
CreateFPFPToFPCallLocations(ArenaAllocator * arena,HInvoke * invoke)2377 static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
2378 LocationSummary* locations = new (arena) LocationSummary(invoke,
2379 LocationSummary::kCallOnMainOnly,
2380 kIntrinsified);
2381 InvokeRuntimeCallingConvention calling_convention;
2382
2383 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2384 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2385 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
2386 }
2387
GenFPToFPCall(HInvoke * invoke,CodeGeneratorMIPS64 * codegen,QuickEntrypointEnum entry)2388 static void GenFPToFPCall(HInvoke* invoke,
2389 CodeGeneratorMIPS64* codegen,
2390 QuickEntrypointEnum entry) {
2391 LocationSummary* locations = invoke->GetLocations();
2392 FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
2393 DCHECK_EQ(in, F12);
2394 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
2395 DCHECK_EQ(out, F0);
2396
2397 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2398 }
2399
GenFPFPToFPCall(HInvoke * invoke,CodeGeneratorMIPS64 * codegen,QuickEntrypointEnum entry)2400 static void GenFPFPToFPCall(HInvoke* invoke,
2401 CodeGeneratorMIPS64* codegen,
2402 QuickEntrypointEnum entry) {
2403 LocationSummary* locations = invoke->GetLocations();
2404 FpuRegister in0 = locations->InAt(0).AsFpuRegister<FpuRegister>();
2405 DCHECK_EQ(in0, F12);
2406 FpuRegister in1 = locations->InAt(1).AsFpuRegister<FpuRegister>();
2407 DCHECK_EQ(in1, F13);
2408 FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
2409 DCHECK_EQ(out, F0);
2410
2411 codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2412 }
2413
2414 // static double java.lang.Math.cos(double a)
VisitMathCos(HInvoke * invoke)2415 void IntrinsicLocationsBuilderMIPS64::VisitMathCos(HInvoke* invoke) {
2416 CreateFPToFPCallLocations(arena_, invoke);
2417 }
2418
VisitMathCos(HInvoke * invoke)2419 void IntrinsicCodeGeneratorMIPS64::VisitMathCos(HInvoke* invoke) {
2420 GenFPToFPCall(invoke, codegen_, kQuickCos);
2421 }
2422
2423 // static double java.lang.Math.sin(double a)
VisitMathSin(HInvoke * invoke)2424 void IntrinsicLocationsBuilderMIPS64::VisitMathSin(HInvoke* invoke) {
2425 CreateFPToFPCallLocations(arena_, invoke);
2426 }
2427
VisitMathSin(HInvoke * invoke)2428 void IntrinsicCodeGeneratorMIPS64::VisitMathSin(HInvoke* invoke) {
2429 GenFPToFPCall(invoke, codegen_, kQuickSin);
2430 }
2431
2432 // static double java.lang.Math.acos(double a)
VisitMathAcos(HInvoke * invoke)2433 void IntrinsicLocationsBuilderMIPS64::VisitMathAcos(HInvoke* invoke) {
2434 CreateFPToFPCallLocations(arena_, invoke);
2435 }
2436
VisitMathAcos(HInvoke * invoke)2437 void IntrinsicCodeGeneratorMIPS64::VisitMathAcos(HInvoke* invoke) {
2438 GenFPToFPCall(invoke, codegen_, kQuickAcos);
2439 }
2440
2441 // static double java.lang.Math.asin(double a)
VisitMathAsin(HInvoke * invoke)2442 void IntrinsicLocationsBuilderMIPS64::VisitMathAsin(HInvoke* invoke) {
2443 CreateFPToFPCallLocations(arena_, invoke);
2444 }
2445
VisitMathAsin(HInvoke * invoke)2446 void IntrinsicCodeGeneratorMIPS64::VisitMathAsin(HInvoke* invoke) {
2447 GenFPToFPCall(invoke, codegen_, kQuickAsin);
2448 }
2449
2450 // static double java.lang.Math.atan(double a)
VisitMathAtan(HInvoke * invoke)2451 void IntrinsicLocationsBuilderMIPS64::VisitMathAtan(HInvoke* invoke) {
2452 CreateFPToFPCallLocations(arena_, invoke);
2453 }
2454
VisitMathAtan(HInvoke * invoke)2455 void IntrinsicCodeGeneratorMIPS64::VisitMathAtan(HInvoke* invoke) {
2456 GenFPToFPCall(invoke, codegen_, kQuickAtan);
2457 }
2458
2459 // static double java.lang.Math.atan2(double y, double x)
VisitMathAtan2(HInvoke * invoke)2460 void IntrinsicLocationsBuilderMIPS64::VisitMathAtan2(HInvoke* invoke) {
2461 CreateFPFPToFPCallLocations(arena_, invoke);
2462 }
2463
VisitMathAtan2(HInvoke * invoke)2464 void IntrinsicCodeGeneratorMIPS64::VisitMathAtan2(HInvoke* invoke) {
2465 GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
2466 }
2467
2468 // static double java.lang.Math.cbrt(double a)
VisitMathCbrt(HInvoke * invoke)2469 void IntrinsicLocationsBuilderMIPS64::VisitMathCbrt(HInvoke* invoke) {
2470 CreateFPToFPCallLocations(arena_, invoke);
2471 }
2472
VisitMathCbrt(HInvoke * invoke)2473 void IntrinsicCodeGeneratorMIPS64::VisitMathCbrt(HInvoke* invoke) {
2474 GenFPToFPCall(invoke, codegen_, kQuickCbrt);
2475 }
2476
2477 // static double java.lang.Math.cosh(double x)
VisitMathCosh(HInvoke * invoke)2478 void IntrinsicLocationsBuilderMIPS64::VisitMathCosh(HInvoke* invoke) {
2479 CreateFPToFPCallLocations(arena_, invoke);
2480 }
2481
VisitMathCosh(HInvoke * invoke)2482 void IntrinsicCodeGeneratorMIPS64::VisitMathCosh(HInvoke* invoke) {
2483 GenFPToFPCall(invoke, codegen_, kQuickCosh);
2484 }
2485
2486 // static double java.lang.Math.exp(double a)
VisitMathExp(HInvoke * invoke)2487 void IntrinsicLocationsBuilderMIPS64::VisitMathExp(HInvoke* invoke) {
2488 CreateFPToFPCallLocations(arena_, invoke);
2489 }
2490
VisitMathExp(HInvoke * invoke)2491 void IntrinsicCodeGeneratorMIPS64::VisitMathExp(HInvoke* invoke) {
2492 GenFPToFPCall(invoke, codegen_, kQuickExp);
2493 }
2494
2495 // static double java.lang.Math.expm1(double x)
VisitMathExpm1(HInvoke * invoke)2496 void IntrinsicLocationsBuilderMIPS64::VisitMathExpm1(HInvoke* invoke) {
2497 CreateFPToFPCallLocations(arena_, invoke);
2498 }
2499
VisitMathExpm1(HInvoke * invoke)2500 void IntrinsicCodeGeneratorMIPS64::VisitMathExpm1(HInvoke* invoke) {
2501 GenFPToFPCall(invoke, codegen_, kQuickExpm1);
2502 }
2503
2504 // static double java.lang.Math.hypot(double x, double y)
VisitMathHypot(HInvoke * invoke)2505 void IntrinsicLocationsBuilderMIPS64::VisitMathHypot(HInvoke* invoke) {
2506 CreateFPFPToFPCallLocations(arena_, invoke);
2507 }
2508
VisitMathHypot(HInvoke * invoke)2509 void IntrinsicCodeGeneratorMIPS64::VisitMathHypot(HInvoke* invoke) {
2510 GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
2511 }
2512
2513 // static double java.lang.Math.log(double a)
VisitMathLog(HInvoke * invoke)2514 void IntrinsicLocationsBuilderMIPS64::VisitMathLog(HInvoke* invoke) {
2515 CreateFPToFPCallLocations(arena_, invoke);
2516 }
2517
VisitMathLog(HInvoke * invoke)2518 void IntrinsicCodeGeneratorMIPS64::VisitMathLog(HInvoke* invoke) {
2519 GenFPToFPCall(invoke, codegen_, kQuickLog);
2520 }
2521
2522 // static double java.lang.Math.log10(double x)
VisitMathLog10(HInvoke * invoke)2523 void IntrinsicLocationsBuilderMIPS64::VisitMathLog10(HInvoke* invoke) {
2524 CreateFPToFPCallLocations(arena_, invoke);
2525 }
2526
VisitMathLog10(HInvoke * invoke)2527 void IntrinsicCodeGeneratorMIPS64::VisitMathLog10(HInvoke* invoke) {
2528 GenFPToFPCall(invoke, codegen_, kQuickLog10);
2529 }
2530
2531 // static double java.lang.Math.nextAfter(double start, double direction)
VisitMathNextAfter(HInvoke * invoke)2532 void IntrinsicLocationsBuilderMIPS64::VisitMathNextAfter(HInvoke* invoke) {
2533 CreateFPFPToFPCallLocations(arena_, invoke);
2534 }
2535
VisitMathNextAfter(HInvoke * invoke)2536 void IntrinsicCodeGeneratorMIPS64::VisitMathNextAfter(HInvoke* invoke) {
2537 GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
2538 }
2539
2540 // static double java.lang.Math.sinh(double x)
VisitMathSinh(HInvoke * invoke)2541 void IntrinsicLocationsBuilderMIPS64::VisitMathSinh(HInvoke* invoke) {
2542 CreateFPToFPCallLocations(arena_, invoke);
2543 }
2544
VisitMathSinh(HInvoke * invoke)2545 void IntrinsicCodeGeneratorMIPS64::VisitMathSinh(HInvoke* invoke) {
2546 GenFPToFPCall(invoke, codegen_, kQuickSinh);
2547 }
2548
2549 // static double java.lang.Math.tan(double a)
VisitMathTan(HInvoke * invoke)2550 void IntrinsicLocationsBuilderMIPS64::VisitMathTan(HInvoke* invoke) {
2551 CreateFPToFPCallLocations(arena_, invoke);
2552 }
2553
VisitMathTan(HInvoke * invoke)2554 void IntrinsicCodeGeneratorMIPS64::VisitMathTan(HInvoke* invoke) {
2555 GenFPToFPCall(invoke, codegen_, kQuickTan);
2556 }
2557
2558 // static double java.lang.Math.tanh(double x)
VisitMathTanh(HInvoke * invoke)2559 void IntrinsicLocationsBuilderMIPS64::VisitMathTanh(HInvoke* invoke) {
2560 CreateFPToFPCallLocations(arena_, invoke);
2561 }
2562
VisitMathTanh(HInvoke * invoke)2563 void IntrinsicCodeGeneratorMIPS64::VisitMathTanh(HInvoke* invoke) {
2564 GenFPToFPCall(invoke, codegen_, kQuickTanh);
2565 }
2566
2567 UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
2568 UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
2569
2570 UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf);
2571 UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter);
2572 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferAppend);
2573 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferLength);
2574 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBufferToString);
2575 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderAppend);
2576 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderLength);
2577 UNIMPLEMENTED_INTRINSIC(MIPS64, StringBuilderToString);
2578
2579 // 1.8.
2580 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddInt)
2581 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndAddLong)
2582 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetInt)
2583 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetLong)
2584 UNIMPLEMENTED_INTRINSIC(MIPS64, UnsafeGetAndSetObject)
2585
2586 UNIMPLEMENTED_INTRINSIC(MIPS64, IntegerValueOf)
2587
2588 UNREACHABLE_INTRINSICS(MIPS64)
2589
2590 #undef __
2591
2592 } // namespace mips64
2593 } // namespace art
2594