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