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