• 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_mips.h"
18 
19 #include "arch/mips/instruction_set_features_mips.h"
20 #include "art_method.h"
21 #include "code_generator_mips.h"
22 #include "entrypoints/quick/quick_entrypoints.h"
23 #include "intrinsics.h"
24 #include "mirror/array-inl.h"
25 #include "mirror/string.h"
26 #include "thread.h"
27 #include "utils/mips/assembler_mips.h"
28 #include "utils/mips/constants_mips.h"
29 
30 namespace art {
31 
32 namespace mips {
33 
IntrinsicLocationsBuilderMIPS(CodeGeneratorMIPS * codegen)34 IntrinsicLocationsBuilderMIPS::IntrinsicLocationsBuilderMIPS(CodeGeneratorMIPS* codegen)
35   : arena_(codegen->GetGraph()->GetArena()) {
36 }
37 
GetAssembler()38 MipsAssembler* IntrinsicCodeGeneratorMIPS::GetAssembler() {
39   return reinterpret_cast<MipsAssembler*>(codegen_->GetAssembler());
40 }
41 
GetAllocator()42 ArenaAllocator* IntrinsicCodeGeneratorMIPS::GetAllocator() {
43   return codegen_->GetGraph()->GetArena();
44 }
45 
IsR2OrNewer() const46 inline bool IntrinsicCodeGeneratorMIPS::IsR2OrNewer() const {
47   return codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
48 }
49 
IsR6() const50 inline bool IntrinsicCodeGeneratorMIPS::IsR6() const {
51   return codegen_->GetInstructionSetFeatures().IsR6();
52 }
53 
Is32BitFPU() const54 inline bool IntrinsicCodeGeneratorMIPS::Is32BitFPU() const {
55   return codegen_->GetInstructionSetFeatures().Is32BitFloatingPoint();
56 }
57 
58 #define __ codegen->GetAssembler()->
59 
MoveFromReturnRegister(Location trg,Primitive::Type type,CodeGeneratorMIPS * codegen)60 static void MoveFromReturnRegister(Location trg,
61                                    Primitive::Type type,
62                                    CodeGeneratorMIPS* codegen) {
63   if (!trg.IsValid()) {
64     DCHECK_EQ(type, Primitive::kPrimVoid);
65     return;
66   }
67 
68   DCHECK_NE(type, Primitive::kPrimVoid);
69 
70   if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
71     Register trg_reg = trg.AsRegister<Register>();
72     if (trg_reg != V0) {
73       __ Move(V0, trg_reg);
74     }
75   } else {
76     FRegister trg_reg = trg.AsFpuRegister<FRegister>();
77     if (trg_reg != F0) {
78       if (type == Primitive::kPrimFloat) {
79         __ MovS(F0, trg_reg);
80       } else {
81         __ MovD(F0, trg_reg);
82       }
83     }
84   }
85 }
86 
MoveArguments(HInvoke * invoke,CodeGeneratorMIPS * codegen)87 static void MoveArguments(HInvoke* invoke, CodeGeneratorMIPS* codegen) {
88   InvokeDexCallingConventionVisitorMIPS calling_convention_visitor;
89   IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
90 }
91 
92 // Slow-path for fallback (calling the managed code to handle the
93 // intrinsic) in an intrinsified call. This will copy the arguments
94 // into the positions for a regular call.
95 //
96 // Note: The actual parameters are required to be in the locations
97 //       given by the invoke's location summary. If an intrinsic
98 //       modifies those locations before a slowpath call, they must be
99 //       restored!
100 class IntrinsicSlowPathMIPS : public SlowPathCodeMIPS {
101  public:
IntrinsicSlowPathMIPS(HInvoke * invoke)102   explicit IntrinsicSlowPathMIPS(HInvoke* invoke) : SlowPathCodeMIPS(invoke), invoke_(invoke) { }
103 
EmitNativeCode(CodeGenerator * codegen_in)104   void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
105     CodeGeneratorMIPS* codegen = down_cast<CodeGeneratorMIPS*>(codegen_in);
106 
107     __ Bind(GetEntryLabel());
108 
109     SaveLiveRegisters(codegen, invoke_->GetLocations());
110 
111     MoveArguments(invoke_, codegen);
112 
113     if (invoke_->IsInvokeStaticOrDirect()) {
114       codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
115                                           Location::RegisterLocation(A0));
116     } else {
117       codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(A0));
118     }
119     codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
120 
121     // Copy the result back to the expected output.
122     Location out = invoke_->GetLocations()->Out();
123     if (out.IsValid()) {
124       DCHECK(out.IsRegister());  // TODO: Replace this when we support output in memory.
125       DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
126       MoveFromReturnRegister(out, invoke_->GetType(), codegen);
127     }
128 
129     RestoreLiveRegisters(codegen, invoke_->GetLocations());
130     __ B(GetExitLabel());
131   }
132 
GetDescription() const133   const char* GetDescription() const OVERRIDE { return "IntrinsicSlowPathMIPS"; }
134 
135  private:
136   // The instruction where this slow path is happening.
137   HInvoke* const invoke_;
138 
139   DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathMIPS);
140 };
141 
142 #undef __
143 
TryDispatch(HInvoke * invoke)144 bool IntrinsicLocationsBuilderMIPS::TryDispatch(HInvoke* invoke) {
145   Dispatch(invoke);
146   LocationSummary* res = invoke->GetLocations();
147   return res != nullptr && res->Intrinsified();
148 }
149 
150 #define __ assembler->
151 
CreateFPToIntLocations(ArenaAllocator * arena,HInvoke * invoke)152 static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
153   LocationSummary* locations = new (arena) LocationSummary(invoke,
154                                                            LocationSummary::kNoCall,
155                                                            kIntrinsified);
156   locations->SetInAt(0, Location::RequiresFpuRegister());
157   locations->SetOut(Location::RequiresRegister());
158 }
159 
MoveFPToInt(LocationSummary * locations,bool is64bit,MipsAssembler * assembler)160 static void MoveFPToInt(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
161   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
162 
163   if (is64bit) {
164     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
165     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
166 
167     __ Mfc1(out_lo, in);
168     __ MoveFromFpuHigh(out_hi, in);
169   } else {
170     Register out = locations->Out().AsRegister<Register>();
171 
172     __ Mfc1(out, in);
173   }
174 }
175 
176 // long java.lang.Double.doubleToRawLongBits(double)
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)177 void IntrinsicLocationsBuilderMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
178   CreateFPToIntLocations(arena_, invoke);
179 }
180 
VisitDoubleDoubleToRawLongBits(HInvoke * invoke)181 void IntrinsicCodeGeneratorMIPS::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
182   MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
183 }
184 
185 // int java.lang.Float.floatToRawIntBits(float)
VisitFloatFloatToRawIntBits(HInvoke * invoke)186 void IntrinsicLocationsBuilderMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
187   CreateFPToIntLocations(arena_, invoke);
188 }
189 
VisitFloatFloatToRawIntBits(HInvoke * invoke)190 void IntrinsicCodeGeneratorMIPS::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
191   MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
192 }
193 
CreateIntToFPLocations(ArenaAllocator * arena,HInvoke * invoke)194 static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
195   LocationSummary* locations = new (arena) LocationSummary(invoke,
196                                                            LocationSummary::kNoCall,
197                                                            kIntrinsified);
198   locations->SetInAt(0, Location::RequiresRegister());
199   locations->SetOut(Location::RequiresFpuRegister());
200 }
201 
MoveIntToFP(LocationSummary * locations,bool is64bit,MipsAssembler * assembler)202 static void MoveIntToFP(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
203   FRegister out = locations->Out().AsFpuRegister<FRegister>();
204 
205   if (is64bit) {
206     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
207     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
208 
209     __ Mtc1(in_lo, out);
210     __ MoveToFpuHigh(in_hi, out);
211   } else {
212     Register in = locations->InAt(0).AsRegister<Register>();
213 
214     __ Mtc1(in, out);
215   }
216 }
217 
218 // double java.lang.Double.longBitsToDouble(long)
VisitDoubleLongBitsToDouble(HInvoke * invoke)219 void IntrinsicLocationsBuilderMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
220   CreateIntToFPLocations(arena_, invoke);
221 }
222 
VisitDoubleLongBitsToDouble(HInvoke * invoke)223 void IntrinsicCodeGeneratorMIPS::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
224   MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
225 }
226 
227 // float java.lang.Float.intBitsToFloat(int)
VisitFloatIntBitsToFloat(HInvoke * invoke)228 void IntrinsicLocationsBuilderMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) {
229   CreateIntToFPLocations(arena_, invoke);
230 }
231 
VisitFloatIntBitsToFloat(HInvoke * invoke)232 void IntrinsicCodeGeneratorMIPS::VisitFloatIntBitsToFloat(HInvoke* invoke) {
233   MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
234 }
235 
CreateIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke,Location::OutputOverlap overlaps=Location::kNoOutputOverlap)236 static void CreateIntToIntLocations(ArenaAllocator* arena,
237                                     HInvoke* invoke,
238                                     Location::OutputOverlap overlaps = Location::kNoOutputOverlap) {
239   LocationSummary* locations = new (arena) LocationSummary(invoke,
240                                                            LocationSummary::kNoCall,
241                                                            kIntrinsified);
242   locations->SetInAt(0, Location::RequiresRegister());
243   locations->SetOut(Location::RequiresRegister(), overlaps);
244 }
245 
GenReverse(LocationSummary * locations,Primitive::Type type,bool isR2OrNewer,bool isR6,bool reverseBits,MipsAssembler * assembler)246 static void GenReverse(LocationSummary* locations,
247                        Primitive::Type type,
248                        bool isR2OrNewer,
249                        bool isR6,
250                        bool reverseBits,
251                        MipsAssembler* assembler) {
252   DCHECK(type == Primitive::kPrimShort ||
253          type == Primitive::kPrimInt ||
254          type == Primitive::kPrimLong);
255   DCHECK(type != Primitive::kPrimShort || !reverseBits);
256 
257   if (type == Primitive::kPrimShort) {
258     Register in = locations->InAt(0).AsRegister<Register>();
259     Register out = locations->Out().AsRegister<Register>();
260 
261     if (isR2OrNewer) {
262       __ Wsbh(out, in);
263       __ Seh(out, out);
264     } else {
265       __ Sll(TMP, in, 24);
266       __ Sra(TMP, TMP, 16);
267       __ Sll(out, in, 16);
268       __ Srl(out, out, 24);
269       __ Or(out, out, TMP);
270     }
271   } else if (type == Primitive::kPrimInt) {
272     Register in = locations->InAt(0).AsRegister<Register>();
273     Register out = locations->Out().AsRegister<Register>();
274 
275     if (isR2OrNewer) {
276       __ Rotr(out, in, 16);
277       __ Wsbh(out, out);
278     } else {
279       // MIPS32r1
280       // __ Rotr(out, in, 16);
281       __ Sll(TMP, in, 16);
282       __ Srl(out, in, 16);
283       __ Or(out, out, TMP);
284       // __ Wsbh(out, out);
285       __ LoadConst32(AT, 0x00FF00FF);
286       __ And(TMP, out, AT);
287       __ Sll(TMP, TMP, 8);
288       __ Srl(out, out, 8);
289       __ And(out, out, AT);
290       __ Or(out, out, TMP);
291     }
292     if (reverseBits) {
293       if (isR6) {
294         __ Bitswap(out, out);
295       } else {
296         __ LoadConst32(AT, 0x0F0F0F0F);
297         __ And(TMP, out, AT);
298         __ Sll(TMP, TMP, 4);
299         __ Srl(out, out, 4);
300         __ And(out, out, AT);
301         __ Or(out, TMP, out);
302         __ LoadConst32(AT, 0x33333333);
303         __ And(TMP, out, AT);
304         __ Sll(TMP, TMP, 2);
305         __ Srl(out, out, 2);
306         __ And(out, out, AT);
307         __ Or(out, TMP, out);
308         __ LoadConst32(AT, 0x55555555);
309         __ And(TMP, out, AT);
310         __ Sll(TMP, TMP, 1);
311         __ Srl(out, out, 1);
312         __ And(out, out, AT);
313         __ Or(out, TMP, out);
314       }
315     }
316   } else if (type == Primitive::kPrimLong) {
317     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
318     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
319     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
320     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
321 
322     if (isR2OrNewer) {
323       __ Rotr(AT, in_hi, 16);
324       __ Rotr(TMP, in_lo, 16);
325       __ Wsbh(out_lo, AT);
326       __ Wsbh(out_hi, TMP);
327     } else {
328       // When calling CreateIntToIntLocations() we promised that the
329       // use of the out_lo/out_hi wouldn't overlap with the use of
330       // in_lo/in_hi. Be very careful not to write to out_lo/out_hi
331       // until we're completely done reading from in_lo/in_hi.
332       // __ Rotr(TMP, in_lo, 16);
333       __ Sll(TMP, in_lo, 16);
334       __ Srl(AT, in_lo, 16);
335       __ Or(TMP, TMP, AT);             // Hold in TMP until it's safe
336                                        // to write to out_hi.
337       // __ Rotr(out_lo, in_hi, 16);
338       __ Sll(AT, in_hi, 16);
339       __ Srl(out_lo, in_hi, 16);        // Here we are finally done reading
340                                         // from in_lo/in_hi so it's okay to
341                                         // write to out_lo/out_hi.
342       __ Or(out_lo, out_lo, AT);
343       // __ Wsbh(out_hi, out_hi);
344       __ LoadConst32(AT, 0x00FF00FF);
345       __ And(out_hi, TMP, AT);
346       __ Sll(out_hi, out_hi, 8);
347       __ Srl(TMP, TMP, 8);
348       __ And(TMP, TMP, AT);
349       __ Or(out_hi, out_hi, TMP);
350       // __ Wsbh(out_lo, out_lo);
351       __ And(TMP, out_lo, AT);  // AT already holds the correct mask value
352       __ Sll(TMP, TMP, 8);
353       __ Srl(out_lo, out_lo, 8);
354       __ And(out_lo, out_lo, AT);
355       __ Or(out_lo, out_lo, TMP);
356     }
357     if (reverseBits) {
358       if (isR6) {
359         __ Bitswap(out_hi, out_hi);
360         __ Bitswap(out_lo, out_lo);
361       } else {
362         __ LoadConst32(AT, 0x0F0F0F0F);
363         __ And(TMP, out_hi, AT);
364         __ Sll(TMP, TMP, 4);
365         __ Srl(out_hi, out_hi, 4);
366         __ And(out_hi, out_hi, AT);
367         __ Or(out_hi, TMP, out_hi);
368         __ And(TMP, out_lo, AT);
369         __ Sll(TMP, TMP, 4);
370         __ Srl(out_lo, out_lo, 4);
371         __ And(out_lo, out_lo, AT);
372         __ Or(out_lo, TMP, out_lo);
373         __ LoadConst32(AT, 0x33333333);
374         __ And(TMP, out_hi, AT);
375         __ Sll(TMP, TMP, 2);
376         __ Srl(out_hi, out_hi, 2);
377         __ And(out_hi, out_hi, AT);
378         __ Or(out_hi, TMP, out_hi);
379         __ And(TMP, out_lo, AT);
380         __ Sll(TMP, TMP, 2);
381         __ Srl(out_lo, out_lo, 2);
382         __ And(out_lo, out_lo, AT);
383         __ Or(out_lo, TMP, out_lo);
384         __ LoadConst32(AT, 0x55555555);
385         __ And(TMP, out_hi, AT);
386         __ Sll(TMP, TMP, 1);
387         __ Srl(out_hi, out_hi, 1);
388         __ And(out_hi, out_hi, AT);
389         __ Or(out_hi, TMP, out_hi);
390         __ And(TMP, out_lo, AT);
391         __ Sll(TMP, TMP, 1);
392         __ Srl(out_lo, out_lo, 1);
393         __ And(out_lo, out_lo, AT);
394         __ Or(out_lo, TMP, out_lo);
395       }
396     }
397   }
398 }
399 
400 // int java.lang.Integer.reverseBytes(int)
VisitIntegerReverseBytes(HInvoke * invoke)401 void IntrinsicLocationsBuilderMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
402   CreateIntToIntLocations(arena_, invoke);
403 }
404 
VisitIntegerReverseBytes(HInvoke * invoke)405 void IntrinsicCodeGeneratorMIPS::VisitIntegerReverseBytes(HInvoke* invoke) {
406   GenReverse(invoke->GetLocations(),
407              Primitive::kPrimInt,
408              IsR2OrNewer(),
409              IsR6(),
410              /* reverseBits */ false,
411              GetAssembler());
412 }
413 
414 // long java.lang.Long.reverseBytes(long)
VisitLongReverseBytes(HInvoke * invoke)415 void IntrinsicLocationsBuilderMIPS::VisitLongReverseBytes(HInvoke* invoke) {
416   CreateIntToIntLocations(arena_, invoke);
417 }
418 
VisitLongReverseBytes(HInvoke * invoke)419 void IntrinsicCodeGeneratorMIPS::VisitLongReverseBytes(HInvoke* invoke) {
420   GenReverse(invoke->GetLocations(),
421              Primitive::kPrimLong,
422              IsR2OrNewer(),
423              IsR6(),
424              /* reverseBits */ false,
425              GetAssembler());
426 }
427 
428 // short java.lang.Short.reverseBytes(short)
VisitShortReverseBytes(HInvoke * invoke)429 void IntrinsicLocationsBuilderMIPS::VisitShortReverseBytes(HInvoke* invoke) {
430   CreateIntToIntLocations(arena_, invoke);
431 }
432 
VisitShortReverseBytes(HInvoke * invoke)433 void IntrinsicCodeGeneratorMIPS::VisitShortReverseBytes(HInvoke* invoke) {
434   GenReverse(invoke->GetLocations(),
435              Primitive::kPrimShort,
436              IsR2OrNewer(),
437              IsR6(),
438              /* reverseBits */ false,
439              GetAssembler());
440 }
441 
GenNumberOfLeadingZeroes(LocationSummary * locations,bool is64bit,bool isR6,MipsAssembler * assembler)442 static void GenNumberOfLeadingZeroes(LocationSummary* locations,
443                                      bool is64bit,
444                                      bool isR6,
445                                      MipsAssembler* assembler) {
446   Register out = locations->Out().AsRegister<Register>();
447   if (is64bit) {
448     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
449     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
450 
451     if (isR6) {
452       __ ClzR6(AT, in_hi);
453       __ ClzR6(TMP, in_lo);
454       __ Seleqz(TMP, TMP, in_hi);
455     } else {
456       __ ClzR2(AT, in_hi);
457       __ ClzR2(TMP, in_lo);
458       __ Movn(TMP, ZERO, in_hi);
459     }
460     __ Addu(out, AT, TMP);
461   } else {
462     Register in = locations->InAt(0).AsRegister<Register>();
463 
464     if (isR6) {
465       __ ClzR6(out, in);
466     } else {
467       __ ClzR2(out, in);
468     }
469   }
470 }
471 
472 // int java.lang.Integer.numberOfLeadingZeros(int i)
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)473 void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
474   CreateIntToIntLocations(arena_, invoke);
475 }
476 
VisitIntegerNumberOfLeadingZeros(HInvoke * invoke)477 void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
478   GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ false, IsR6(), GetAssembler());
479 }
480 
481 // int java.lang.Long.numberOfLeadingZeros(long i)
VisitLongNumberOfLeadingZeros(HInvoke * invoke)482 void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
483   CreateIntToIntLocations(arena_, invoke);
484 }
485 
VisitLongNumberOfLeadingZeros(HInvoke * invoke)486 void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
487   GenNumberOfLeadingZeroes(invoke->GetLocations(), /* is64bit */ true, IsR6(), GetAssembler());
488 }
489 
GenNumberOfTrailingZeroes(LocationSummary * locations,bool is64bit,bool isR6,MipsAssembler * assembler)490 static void GenNumberOfTrailingZeroes(LocationSummary* locations,
491                                       bool is64bit,
492                                       bool isR6,
493                                       MipsAssembler* assembler) {
494   Register out = locations->Out().AsRegister<Register>();
495   Register in_lo;
496   Register in;
497 
498   if (is64bit) {
499     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
500 
501     in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
502 
503     // If in_lo is zero then count the number of trailing zeroes in in_hi;
504     // otherwise count the number of trailing zeroes in in_lo.
505     // out = in_lo ? in_lo : in_hi;
506     if (isR6) {
507       __ Seleqz(out, in_hi, in_lo);
508       __ Selnez(TMP, in_lo, in_lo);
509       __ Or(out, out, TMP);
510     } else {
511       __ Movz(out, in_hi, in_lo);
512       __ Movn(out, in_lo, in_lo);
513     }
514 
515     in = out;
516   } else {
517     in = locations->InAt(0).AsRegister<Register>();
518     // Give in_lo a dummy value to keep the compiler from complaining.
519     // Since we only get here in the 32-bit case, this value will never
520     // be used.
521     in_lo = in;
522   }
523 
524   if (isR6) {
525     // We don't have an instruction to count the number of trailing zeroes.
526     // Start by flipping the bits end-for-end so we can count the number of
527     // leading zeroes instead.
528     __ Rotr(out, in, 16);
529     __ Wsbh(out, out);
530     __ Bitswap(out, out);
531     __ ClzR6(out, out);
532   } else {
533     // Convert trailing zeroes to trailing ones, and bits to their left
534     // to zeroes.
535     __ Addiu(TMP, in, -1);
536     __ Xor(out, TMP, in);
537     __ And(out, out, TMP);
538     // Count number of leading zeroes.
539     __ ClzR2(out, out);
540     // Subtract number of leading zeroes from 32 to get number of trailing ones.
541     // Remember that the trailing ones were formerly trailing zeroes.
542     __ LoadConst32(TMP, 32);
543     __ Subu(out, TMP, out);
544   }
545 
546   if (is64bit) {
547     // If in_lo is zero, then we counted the number of trailing zeroes in in_hi so we must add the
548     // number of trailing zeroes in in_lo (32) to get the correct final count
549     __ LoadConst32(TMP, 32);
550     if (isR6) {
551       __ Seleqz(TMP, TMP, in_lo);
552     } else {
553       __ Movn(TMP, ZERO, in_lo);
554     }
555     __ Addu(out, out, TMP);
556   }
557 }
558 
559 // int java.lang.Integer.numberOfTrailingZeros(int i)
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)560 void IntrinsicLocationsBuilderMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
561   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
562 }
563 
VisitIntegerNumberOfTrailingZeros(HInvoke * invoke)564 void IntrinsicCodeGeneratorMIPS::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
565   GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ false, IsR6(), GetAssembler());
566 }
567 
568 // int java.lang.Long.numberOfTrailingZeros(long i)
VisitLongNumberOfTrailingZeros(HInvoke * invoke)569 void IntrinsicLocationsBuilderMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
570   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
571 }
572 
VisitLongNumberOfTrailingZeros(HInvoke * invoke)573 void IntrinsicCodeGeneratorMIPS::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
574   GenNumberOfTrailingZeroes(invoke->GetLocations(), /* is64bit */ true, IsR6(), GetAssembler());
575 }
576 
577 // int java.lang.Integer.reverse(int)
VisitIntegerReverse(HInvoke * invoke)578 void IntrinsicLocationsBuilderMIPS::VisitIntegerReverse(HInvoke* invoke) {
579   CreateIntToIntLocations(arena_, invoke);
580 }
581 
VisitIntegerReverse(HInvoke * invoke)582 void IntrinsicCodeGeneratorMIPS::VisitIntegerReverse(HInvoke* invoke) {
583   GenReverse(invoke->GetLocations(),
584              Primitive::kPrimInt,
585              IsR2OrNewer(),
586              IsR6(),
587              /* reverseBits */ true,
588              GetAssembler());
589 }
590 
591 // long java.lang.Long.reverse(long)
VisitLongReverse(HInvoke * invoke)592 void IntrinsicLocationsBuilderMIPS::VisitLongReverse(HInvoke* invoke) {
593   CreateIntToIntLocations(arena_, invoke);
594 }
595 
VisitLongReverse(HInvoke * invoke)596 void IntrinsicCodeGeneratorMIPS::VisitLongReverse(HInvoke* invoke) {
597   GenReverse(invoke->GetLocations(),
598              Primitive::kPrimLong,
599              IsR2OrNewer(),
600              IsR6(),
601              /* reverseBits */ true,
602              GetAssembler());
603 }
604 
CreateFPToFPLocations(ArenaAllocator * arena,HInvoke * invoke)605 static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
606   LocationSummary* locations = new (arena) LocationSummary(invoke,
607                                                            LocationSummary::kNoCall,
608                                                            kIntrinsified);
609   locations->SetInAt(0, Location::RequiresFpuRegister());
610   locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
611 }
612 
GenBitCount(LocationSummary * locations,Primitive::Type type,bool isR6,MipsAssembler * assembler)613 static void GenBitCount(LocationSummary* locations,
614                         Primitive::Type type,
615                         bool isR6,
616                         MipsAssembler* assembler) {
617   Register out = locations->Out().AsRegister<Register>();
618 
619   // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
620   //
621   // A generalization of the best bit counting method to integers of
622   // bit-widths up to 128 (parameterized by type T) is this:
623   //
624   // v = v - ((v >> 1) & (T)~(T)0/3);                           // temp
625   // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);      // temp
626   // v = (v + (v >> 4)) & (T)~(T)0/255*15;                      // temp
627   // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; // count
628   //
629   // For comparison, for 32-bit quantities, this algorithm can be executed
630   // using 20 MIPS instructions (the calls to LoadConst32() generate two
631   // machine instructions each for the values being used in this algorithm).
632   // A(n unrolled) loop-based algorithm required 25 instructions.
633   //
634   // For 64-bit quantities, this algorithm gets executed twice, (once
635   // for in_lo, and again for in_hi), but saves a few instructions
636   // because the mask values only have to be loaded once.  Using this
637   // algorithm the count for a 64-bit operand can be performed in 29
638   // instructions compared to a loop-based algorithm which required 47
639   // instructions.
640 
641   if (type == Primitive::kPrimInt) {
642     Register in = locations->InAt(0).AsRegister<Register>();
643 
644     __ Srl(TMP, in, 1);
645     __ LoadConst32(AT, 0x55555555);
646     __ And(TMP, TMP, AT);
647     __ Subu(TMP, in, TMP);
648     __ LoadConst32(AT, 0x33333333);
649     __ And(out, TMP, AT);
650     __ Srl(TMP, TMP, 2);
651     __ And(TMP, TMP, AT);
652     __ Addu(TMP, out, TMP);
653     __ Srl(out, TMP, 4);
654     __ Addu(out, out, TMP);
655     __ LoadConst32(AT, 0x0F0F0F0F);
656     __ And(out, out, AT);
657     __ LoadConst32(TMP, 0x01010101);
658     if (isR6) {
659       __ MulR6(out, out, TMP);
660     } else {
661       __ MulR2(out, out, TMP);
662     }
663     __ Srl(out, out, 24);
664   } else {
665     DCHECK_EQ(type, Primitive::kPrimLong);
666     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
667     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
668     Register tmp_hi = locations->GetTemp(0).AsRegister<Register>();
669     Register out_hi = locations->GetTemp(1).AsRegister<Register>();
670     Register tmp_lo = TMP;
671     Register out_lo = out;
672 
673     __ Srl(tmp_lo, in_lo, 1);
674     __ Srl(tmp_hi, in_hi, 1);
675 
676     __ LoadConst32(AT, 0x55555555);
677 
678     __ And(tmp_lo, tmp_lo, AT);
679     __ Subu(tmp_lo, in_lo, tmp_lo);
680 
681     __ And(tmp_hi, tmp_hi, AT);
682     __ Subu(tmp_hi, in_hi, tmp_hi);
683 
684     __ LoadConst32(AT, 0x33333333);
685 
686     __ And(out_lo, tmp_lo, AT);
687     __ Srl(tmp_lo, tmp_lo, 2);
688     __ And(tmp_lo, tmp_lo, AT);
689     __ Addu(tmp_lo, out_lo, tmp_lo);
690 
691     __ And(out_hi, tmp_hi, AT);
692     __ Srl(tmp_hi, tmp_hi, 2);
693     __ And(tmp_hi, tmp_hi, AT);
694     __ Addu(tmp_hi, out_hi, tmp_hi);
695 
696     // Here we deviate from the original algorithm a bit. We've reached
697     // the stage where the bitfields holding the subtotals are large
698     // enough to hold the combined subtotals for both the low word, and
699     // the high word. This means that we can add the subtotals for the
700     // the high, and low words into a single word, and compute the final
701     // result for both the high, and low words using fewer instructions.
702     __ LoadConst32(AT, 0x0F0F0F0F);
703 
704     __ Addu(TMP, tmp_hi, tmp_lo);
705 
706     __ Srl(out, TMP, 4);
707     __ And(out, out, AT);
708     __ And(TMP, TMP, AT);
709     __ Addu(out, out, TMP);
710 
711     __ LoadConst32(AT, 0x01010101);
712 
713     if (isR6) {
714       __ MulR6(out, out, AT);
715     } else {
716       __ MulR2(out, out, AT);
717     }
718 
719     __ Srl(out, out, 24);
720   }
721 }
722 
723 // int java.lang.Integer.bitCount(int)
VisitIntegerBitCount(HInvoke * invoke)724 void IntrinsicLocationsBuilderMIPS::VisitIntegerBitCount(HInvoke* invoke) {
725   CreateIntToIntLocations(arena_, invoke);
726 }
727 
VisitIntegerBitCount(HInvoke * invoke)728 void IntrinsicCodeGeneratorMIPS::VisitIntegerBitCount(HInvoke* invoke) {
729   GenBitCount(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
730 }
731 
732 // int java.lang.Long.bitCount(int)
VisitLongBitCount(HInvoke * invoke)733 void IntrinsicLocationsBuilderMIPS::VisitLongBitCount(HInvoke* invoke) {
734   LocationSummary* locations = new (arena_) LocationSummary(invoke,
735                                                             LocationSummary::kNoCall,
736                                                             kIntrinsified);
737   locations->SetInAt(0, Location::RequiresRegister());
738   locations->SetOut(Location::RequiresRegister());
739   locations->AddTemp(Location::RequiresRegister());
740   locations->AddTemp(Location::RequiresRegister());
741 }
742 
VisitLongBitCount(HInvoke * invoke)743 void IntrinsicCodeGeneratorMIPS::VisitLongBitCount(HInvoke* invoke) {
744   GenBitCount(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
745 }
746 
MathAbsFP(LocationSummary * locations,bool is64bit,bool isR2OrNewer,bool isR6,MipsAssembler * assembler)747 static void MathAbsFP(LocationSummary* locations,
748                       bool is64bit,
749                       bool isR2OrNewer,
750                       bool isR6,
751                       MipsAssembler* assembler) {
752   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
753   FRegister out = locations->Out().AsFpuRegister<FRegister>();
754 
755   // Note, as a "quality of implementation", rather than pure "spec compliance", we require that
756   // Math.abs() clears the sign bit (but changes nothing else) for all numbers, including NaN
757   // (signaling NaN may become quiet though).
758   //
759   // The ABS.fmt instructions (abs.s and abs.d) do exactly that when NAN2008=1 (R6). For this case,
760   // both regular floating point numbers and NAN values are treated alike, only the sign bit is
761   // affected by this instruction.
762   // But when NAN2008=0 (R2 and before), the ABS.fmt instructions can't be used. For this case, any
763   // NaN operand signals invalid operation. This means that other bits (not just sign bit) might be
764   // changed when doing abs(NaN). Because of that, we clear sign bit in a different way.
765   if (isR6) {
766     if (is64bit) {
767       __ AbsD(out, in);
768     } else {
769       __ AbsS(out, in);
770     }
771   } else {
772     if (is64bit) {
773       if (in != out) {
774         __ MovD(out, in);
775       }
776       __ MoveFromFpuHigh(TMP, in);
777       // ins instruction is not available for R1.
778       if (isR2OrNewer) {
779         __ Ins(TMP, ZERO, 31, 1);
780       } else {
781         __ Sll(TMP, TMP, 1);
782         __ Srl(TMP, TMP, 1);
783       }
784       __ MoveToFpuHigh(TMP, out);
785     } else {
786       __ Mfc1(TMP, in);
787       // ins instruction is not available for R1.
788       if (isR2OrNewer) {
789         __ Ins(TMP, ZERO, 31, 1);
790       } else {
791         __ Sll(TMP, TMP, 1);
792         __ Srl(TMP, TMP, 1);
793       }
794       __ Mtc1(TMP, out);
795     }
796   }
797 }
798 
799 // double java.lang.Math.abs(double)
VisitMathAbsDouble(HInvoke * invoke)800 void IntrinsicLocationsBuilderMIPS::VisitMathAbsDouble(HInvoke* invoke) {
801   CreateFPToFPLocations(arena_, invoke);
802 }
803 
VisitMathAbsDouble(HInvoke * invoke)804 void IntrinsicCodeGeneratorMIPS::VisitMathAbsDouble(HInvoke* invoke) {
805   MathAbsFP(invoke->GetLocations(), /* is64bit */ true, IsR2OrNewer(), IsR6(), GetAssembler());
806 }
807 
808 // float java.lang.Math.abs(float)
VisitMathAbsFloat(HInvoke * invoke)809 void IntrinsicLocationsBuilderMIPS::VisitMathAbsFloat(HInvoke* invoke) {
810   CreateFPToFPLocations(arena_, invoke);
811 }
812 
VisitMathAbsFloat(HInvoke * invoke)813 void IntrinsicCodeGeneratorMIPS::VisitMathAbsFloat(HInvoke* invoke) {
814   MathAbsFP(invoke->GetLocations(), /* is64bit */ false, IsR2OrNewer(), IsR6(), GetAssembler());
815 }
816 
GenAbsInteger(LocationSummary * locations,bool is64bit,MipsAssembler * assembler)817 static void GenAbsInteger(LocationSummary* locations, bool is64bit, MipsAssembler* assembler) {
818   if (is64bit) {
819     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
820     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
821     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
822     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
823 
824     // The comments in this section show the analogous operations which would
825     // be performed if we had 64-bit registers "in", and "out".
826     // __ Dsra32(AT, in, 31);
827     __ Sra(AT, in_hi, 31);
828     // __ Xor(out, in, AT);
829     __ Xor(TMP, in_lo, AT);
830     __ Xor(out_hi, in_hi, AT);
831     // __ Dsubu(out, out, AT);
832     __ Subu(out_lo, TMP, AT);
833     __ Sltu(TMP, out_lo, TMP);
834     __ Addu(out_hi, out_hi, TMP);
835   } else {
836     Register in = locations->InAt(0).AsRegister<Register>();
837     Register out = locations->Out().AsRegister<Register>();
838 
839     __ Sra(AT, in, 31);
840     __ Xor(out, in, AT);
841     __ Subu(out, out, AT);
842   }
843 }
844 
845 // int java.lang.Math.abs(int)
VisitMathAbsInt(HInvoke * invoke)846 void IntrinsicLocationsBuilderMIPS::VisitMathAbsInt(HInvoke* invoke) {
847   CreateIntToIntLocations(arena_, invoke);
848 }
849 
VisitMathAbsInt(HInvoke * invoke)850 void IntrinsicCodeGeneratorMIPS::VisitMathAbsInt(HInvoke* invoke) {
851   GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
852 }
853 
854 // long java.lang.Math.abs(long)
VisitMathAbsLong(HInvoke * invoke)855 void IntrinsicLocationsBuilderMIPS::VisitMathAbsLong(HInvoke* invoke) {
856   CreateIntToIntLocations(arena_, invoke);
857 }
858 
VisitMathAbsLong(HInvoke * invoke)859 void IntrinsicCodeGeneratorMIPS::VisitMathAbsLong(HInvoke* invoke) {
860   GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
861 }
862 
GenMinMaxFP(LocationSummary * locations,bool is_min,Primitive::Type type,bool is_R6,MipsAssembler * assembler)863 static void GenMinMaxFP(LocationSummary* locations,
864                         bool is_min,
865                         Primitive::Type type,
866                         bool is_R6,
867                         MipsAssembler* assembler) {
868   FRegister out = locations->Out().AsFpuRegister<FRegister>();
869   FRegister a = locations->InAt(0).AsFpuRegister<FRegister>();
870   FRegister b = locations->InAt(1).AsFpuRegister<FRegister>();
871 
872   if (is_R6) {
873     MipsLabel noNaNs;
874     MipsLabel done;
875     FRegister ftmp = ((out != a) && (out != b)) ? out : FTMP;
876 
877     // When Java computes min/max it prefers a NaN to a number; the
878     // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of
879     // the inputs is a NaN and the other is a valid number, the MIPS
880     // instruction will return the number; Java wants the NaN value
881     // returned. This is why there is extra logic preceding the use of
882     // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a
883     // NaN, return the NaN, otherwise return the min/max.
884     if (type == Primitive::kPrimDouble) {
885       __ CmpUnD(FTMP, a, b);
886       __ Bc1eqz(FTMP, &noNaNs);
887 
888       // One of the inputs is a NaN
889       __ CmpEqD(ftmp, a, a);
890       // If a == a then b is the NaN, otherwise a is the NaN.
891       __ SelD(ftmp, a, b);
892 
893       if (ftmp != out) {
894         __ MovD(out, ftmp);
895       }
896 
897       __ B(&done);
898 
899       __ Bind(&noNaNs);
900 
901       if (is_min) {
902         __ MinD(out, a, b);
903       } else {
904         __ MaxD(out, a, b);
905       }
906     } else {
907       DCHECK_EQ(type, Primitive::kPrimFloat);
908       __ CmpUnS(FTMP, a, b);
909       __ Bc1eqz(FTMP, &noNaNs);
910 
911       // One of the inputs is a NaN
912       __ CmpEqS(ftmp, a, a);
913       // If a == a then b is the NaN, otherwise a is the NaN.
914       __ SelS(ftmp, a, b);
915 
916       if (ftmp != out) {
917         __ MovS(out, ftmp);
918       }
919 
920       __ B(&done);
921 
922       __ Bind(&noNaNs);
923 
924       if (is_min) {
925         __ MinS(out, a, b);
926       } else {
927         __ MaxS(out, a, b);
928       }
929     }
930 
931     __ Bind(&done);
932   } else {
933     MipsLabel ordered;
934     MipsLabel compare;
935     MipsLabel select;
936     MipsLabel done;
937 
938     if (type == Primitive::kPrimDouble) {
939       __ CunD(a, b);
940     } else {
941       DCHECK_EQ(type, Primitive::kPrimFloat);
942       __ CunS(a, b);
943     }
944     __ Bc1f(&ordered);
945 
946     // a or b (or both) is a NaN. Return one, which is a NaN.
947     if (type == Primitive::kPrimDouble) {
948       __ CeqD(b, b);
949     } else {
950       __ CeqS(b, b);
951     }
952     __ B(&select);
953 
954     __ Bind(&ordered);
955 
956     // Neither is a NaN.
957     // a == b? (-0.0 compares equal with +0.0)
958     // If equal, handle zeroes, else compare further.
959     if (type == Primitive::kPrimDouble) {
960       __ CeqD(a, b);
961     } else {
962       __ CeqS(a, b);
963     }
964     __ Bc1f(&compare);
965 
966     // a == b either bit for bit or one is -0.0 and the other is +0.0.
967     if (type == Primitive::kPrimDouble) {
968       __ MoveFromFpuHigh(TMP, a);
969       __ MoveFromFpuHigh(AT, b);
970     } else {
971       __ Mfc1(TMP, a);
972       __ Mfc1(AT, b);
973     }
974 
975     if (is_min) {
976       // -0.0 prevails over +0.0.
977       __ Or(TMP, TMP, AT);
978     } else {
979       // +0.0 prevails over -0.0.
980       __ And(TMP, TMP, AT);
981     }
982 
983     if (type == Primitive::kPrimDouble) {
984       __ Mfc1(AT, a);
985       __ Mtc1(AT, out);
986       __ MoveToFpuHigh(TMP, out);
987     } else {
988       __ Mtc1(TMP, out);
989     }
990     __ B(&done);
991 
992     __ Bind(&compare);
993 
994     if (type == Primitive::kPrimDouble) {
995       if (is_min) {
996         // return (a <= b) ? a : b;
997         __ ColeD(a, b);
998       } else {
999         // return (a >= b) ? a : b;
1000         __ ColeD(b, a);  // b <= a
1001       }
1002     } else {
1003       if (is_min) {
1004         // return (a <= b) ? a : b;
1005         __ ColeS(a, b);
1006       } else {
1007         // return (a >= b) ? a : b;
1008         __ ColeS(b, a);  // b <= a
1009       }
1010     }
1011 
1012     __ Bind(&select);
1013 
1014     if (type == Primitive::kPrimDouble) {
1015       __ MovtD(out, a);
1016       __ MovfD(out, b);
1017     } else {
1018       __ MovtS(out, a);
1019       __ MovfS(out, b);
1020     }
1021 
1022     __ Bind(&done);
1023   }
1024 }
1025 
CreateFPFPToFPLocations(ArenaAllocator * arena,HInvoke * invoke)1026 static void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
1027   LocationSummary* locations = new (arena) LocationSummary(invoke,
1028                                                            LocationSummary::kNoCall,
1029                                                            kIntrinsified);
1030   locations->SetInAt(0, Location::RequiresFpuRegister());
1031   locations->SetInAt(1, Location::RequiresFpuRegister());
1032   locations->SetOut(Location::RequiresFpuRegister(), Location::kOutputOverlap);
1033 }
1034 
1035 // double java.lang.Math.min(double, double)
VisitMathMinDoubleDouble(HInvoke * invoke)1036 void IntrinsicLocationsBuilderMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) {
1037   CreateFPFPToFPLocations(arena_, invoke);
1038 }
1039 
VisitMathMinDoubleDouble(HInvoke * invoke)1040 void IntrinsicCodeGeneratorMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) {
1041   GenMinMaxFP(invoke->GetLocations(),
1042               /* is_min */ true,
1043               Primitive::kPrimDouble,
1044               IsR6(),
1045               GetAssembler());
1046 }
1047 
1048 // float java.lang.Math.min(float, float)
VisitMathMinFloatFloat(HInvoke * invoke)1049 void IntrinsicLocationsBuilderMIPS::VisitMathMinFloatFloat(HInvoke* invoke) {
1050   CreateFPFPToFPLocations(arena_, invoke);
1051 }
1052 
VisitMathMinFloatFloat(HInvoke * invoke)1053 void IntrinsicCodeGeneratorMIPS::VisitMathMinFloatFloat(HInvoke* invoke) {
1054   GenMinMaxFP(invoke->GetLocations(),
1055               /* is_min */ true,
1056               Primitive::kPrimFloat,
1057               IsR6(),
1058               GetAssembler());
1059 }
1060 
1061 // double java.lang.Math.max(double, double)
VisitMathMaxDoubleDouble(HInvoke * invoke)1062 void IntrinsicLocationsBuilderMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) {
1063   CreateFPFPToFPLocations(arena_, invoke);
1064 }
1065 
VisitMathMaxDoubleDouble(HInvoke * invoke)1066 void IntrinsicCodeGeneratorMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) {
1067   GenMinMaxFP(invoke->GetLocations(),
1068               /* is_min */ false,
1069               Primitive::kPrimDouble,
1070               IsR6(),
1071               GetAssembler());
1072 }
1073 
1074 // float java.lang.Math.max(float, float)
VisitMathMaxFloatFloat(HInvoke * invoke)1075 void IntrinsicLocationsBuilderMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) {
1076   CreateFPFPToFPLocations(arena_, invoke);
1077 }
1078 
VisitMathMaxFloatFloat(HInvoke * invoke)1079 void IntrinsicCodeGeneratorMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) {
1080   GenMinMaxFP(invoke->GetLocations(),
1081               /* is_min */ false,
1082               Primitive::kPrimFloat,
1083               IsR6(),
1084               GetAssembler());
1085 }
1086 
CreateIntIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke)1087 static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
1088   LocationSummary* locations = new (arena) LocationSummary(invoke,
1089                                                            LocationSummary::kNoCall,
1090                                                            kIntrinsified);
1091   locations->SetInAt(0, Location::RequiresRegister());
1092   locations->SetInAt(1, Location::RequiresRegister());
1093   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1094 }
1095 
GenMinMax(LocationSummary * locations,bool is_min,Primitive::Type type,bool is_R6,MipsAssembler * assembler)1096 static void GenMinMax(LocationSummary* locations,
1097                       bool is_min,
1098                       Primitive::Type type,
1099                       bool is_R6,
1100                       MipsAssembler* assembler) {
1101   if (is_R6) {
1102     // Some architectures, such as ARM and MIPS (prior to r6), have a
1103     // conditional move instruction which only changes the target
1104     // (output) register if the condition is true (MIPS prior to r6 had
1105     // MOVF, MOVT, MOVN, and MOVZ). The SELEQZ and SELNEZ instructions
1106     // always change the target (output) register.  If the condition is
1107     // true the output register gets the contents of the "rs" register;
1108     // otherwise, the output register is set to zero. One consequence
1109     // of this is that to implement something like "rd = c==0 ? rs : rt"
1110     // MIPS64r6 needs to use a pair of SELEQZ/SELNEZ instructions.
1111     // After executing this pair of instructions one of the output
1112     // registers from the pair will necessarily contain zero. Then the
1113     // code ORs the output registers from the SELEQZ/SELNEZ instructions
1114     // to get the final result.
1115     //
1116     // The initial test to see if the output register is same as the
1117     // first input register is needed to make sure that value in the
1118     // first input register isn't clobbered before we've finished
1119     // computing the output value. The logic in the corresponding else
1120     // clause performs the same task but makes sure the second input
1121     // register isn't clobbered in the event that it's the same register
1122     // as the output register; the else clause also handles the case
1123     // where the output register is distinct from both the first, and the
1124     // second input registers.
1125     if (type == Primitive::kPrimLong) {
1126       Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
1127       Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
1128       Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
1129       Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
1130       Register out_lo = locations->Out().AsRegisterPairLow<Register>();
1131       Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
1132 
1133       MipsLabel compare_done;
1134 
1135       if (a_lo == b_lo) {
1136         if (out_lo != a_lo) {
1137           __ Move(out_lo, a_lo);
1138           __ Move(out_hi, a_hi);
1139         }
1140       } else {
1141         __ Slt(TMP, b_hi, a_hi);
1142         __ Bne(b_hi, a_hi, &compare_done);
1143 
1144         __ Sltu(TMP, b_lo, a_lo);
1145 
1146         __ Bind(&compare_done);
1147 
1148         if (is_min) {
1149           __ Seleqz(AT, a_lo, TMP);
1150           __ Selnez(out_lo, b_lo, TMP);  // Safe even if out_lo == a_lo/b_lo
1151                                          // because at this point we're
1152                                          // done using a_lo/b_lo.
1153         } else {
1154           __ Selnez(AT, a_lo, TMP);
1155           __ Seleqz(out_lo, b_lo, TMP);  // ditto
1156         }
1157         __ Or(out_lo, out_lo, AT);
1158         if (is_min) {
1159           __ Seleqz(AT, a_hi, TMP);
1160           __ Selnez(out_hi, b_hi, TMP);  // ditto but for out_hi & a_hi/b_hi
1161         } else {
1162           __ Selnez(AT, a_hi, TMP);
1163           __ Seleqz(out_hi, b_hi, TMP);  // ditto but for out_hi & a_hi/b_hi
1164         }
1165         __ Or(out_hi, out_hi, AT);
1166       }
1167     } else {
1168       DCHECK_EQ(type, Primitive::kPrimInt);
1169       Register a = locations->InAt(0).AsRegister<Register>();
1170       Register b = locations->InAt(1).AsRegister<Register>();
1171       Register out = locations->Out().AsRegister<Register>();
1172 
1173       if (a == b) {
1174         if (out != a) {
1175           __ Move(out, a);
1176         }
1177       } else {
1178         __ Slt(AT, b, a);
1179         if (is_min) {
1180           __ Seleqz(TMP, a, AT);
1181           __ Selnez(AT, b, AT);
1182         } else {
1183           __ Selnez(TMP, a, AT);
1184           __ Seleqz(AT, b, AT);
1185         }
1186         __ Or(out, TMP, AT);
1187       }
1188     }
1189   } else {
1190     if (type == Primitive::kPrimLong) {
1191       Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>();
1192       Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
1193       Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>();
1194       Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>();
1195       Register out_lo = locations->Out().AsRegisterPairLow<Register>();
1196       Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
1197 
1198       MipsLabel compare_done;
1199 
1200       if (a_lo == b_lo) {
1201         if (out_lo != a_lo) {
1202           __ Move(out_lo, a_lo);
1203           __ Move(out_hi, a_hi);
1204         }
1205       } else {
1206         __ Slt(TMP, a_hi, b_hi);
1207         __ Bne(a_hi, b_hi, &compare_done);
1208 
1209         __ Sltu(TMP, a_lo, b_lo);
1210 
1211         __ Bind(&compare_done);
1212 
1213         if (is_min) {
1214           if (out_lo != a_lo) {
1215             __ Movn(out_hi, a_hi, TMP);
1216             __ Movn(out_lo, a_lo, TMP);
1217           }
1218           if (out_lo != b_lo) {
1219             __ Movz(out_hi, b_hi, TMP);
1220             __ Movz(out_lo, b_lo, TMP);
1221           }
1222         } else {
1223           if (out_lo != a_lo) {
1224             __ Movz(out_hi, a_hi, TMP);
1225             __ Movz(out_lo, a_lo, TMP);
1226           }
1227           if (out_lo != b_lo) {
1228             __ Movn(out_hi, b_hi, TMP);
1229             __ Movn(out_lo, b_lo, TMP);
1230           }
1231         }
1232       }
1233     } else {
1234       DCHECK_EQ(type, Primitive::kPrimInt);
1235       Register a = locations->InAt(0).AsRegister<Register>();
1236       Register b = locations->InAt(1).AsRegister<Register>();
1237       Register out = locations->Out().AsRegister<Register>();
1238 
1239       if (a == b) {
1240         if (out != a) {
1241           __ Move(out, a);
1242         }
1243       } else {
1244         __ Slt(AT, a, b);
1245         if (is_min) {
1246           if (out != a) {
1247             __ Movn(out, a, AT);
1248           }
1249           if (out != b) {
1250             __ Movz(out, b, AT);
1251           }
1252         } else {
1253           if (out != a) {
1254             __ Movz(out, a, AT);
1255           }
1256           if (out != b) {
1257             __ Movn(out, b, AT);
1258           }
1259         }
1260       }
1261     }
1262   }
1263 }
1264 
1265 // int java.lang.Math.min(int, int)
VisitMathMinIntInt(HInvoke * invoke)1266 void IntrinsicLocationsBuilderMIPS::VisitMathMinIntInt(HInvoke* invoke) {
1267   CreateIntIntToIntLocations(arena_, invoke);
1268 }
1269 
VisitMathMinIntInt(HInvoke * invoke)1270 void IntrinsicCodeGeneratorMIPS::VisitMathMinIntInt(HInvoke* invoke) {
1271   GenMinMax(invoke->GetLocations(),
1272             /* is_min */ true,
1273             Primitive::kPrimInt,
1274             IsR6(),
1275             GetAssembler());
1276 }
1277 
1278 // long java.lang.Math.min(long, long)
VisitMathMinLongLong(HInvoke * invoke)1279 void IntrinsicLocationsBuilderMIPS::VisitMathMinLongLong(HInvoke* invoke) {
1280   CreateIntIntToIntLocations(arena_, invoke);
1281 }
1282 
VisitMathMinLongLong(HInvoke * invoke)1283 void IntrinsicCodeGeneratorMIPS::VisitMathMinLongLong(HInvoke* invoke) {
1284   GenMinMax(invoke->GetLocations(),
1285             /* is_min */ true,
1286             Primitive::kPrimLong,
1287             IsR6(),
1288             GetAssembler());
1289 }
1290 
1291 // int java.lang.Math.max(int, int)
VisitMathMaxIntInt(HInvoke * invoke)1292 void IntrinsicLocationsBuilderMIPS::VisitMathMaxIntInt(HInvoke* invoke) {
1293   CreateIntIntToIntLocations(arena_, invoke);
1294 }
1295 
VisitMathMaxIntInt(HInvoke * invoke)1296 void IntrinsicCodeGeneratorMIPS::VisitMathMaxIntInt(HInvoke* invoke) {
1297   GenMinMax(invoke->GetLocations(),
1298             /* is_min */ false,
1299             Primitive::kPrimInt,
1300             IsR6(),
1301             GetAssembler());
1302 }
1303 
1304 // long java.lang.Math.max(long, long)
VisitMathMaxLongLong(HInvoke * invoke)1305 void IntrinsicLocationsBuilderMIPS::VisitMathMaxLongLong(HInvoke* invoke) {
1306   CreateIntIntToIntLocations(arena_, invoke);
1307 }
1308 
VisitMathMaxLongLong(HInvoke * invoke)1309 void IntrinsicCodeGeneratorMIPS::VisitMathMaxLongLong(HInvoke* invoke) {
1310   GenMinMax(invoke->GetLocations(),
1311             /* is_min */ false,
1312             Primitive::kPrimLong,
1313             IsR6(),
1314             GetAssembler());
1315 }
1316 
1317 // double java.lang.Math.sqrt(double)
VisitMathSqrt(HInvoke * invoke)1318 void IntrinsicLocationsBuilderMIPS::VisitMathSqrt(HInvoke* invoke) {
1319   CreateFPToFPLocations(arena_, invoke);
1320 }
1321 
VisitMathSqrt(HInvoke * invoke)1322 void IntrinsicCodeGeneratorMIPS::VisitMathSqrt(HInvoke* invoke) {
1323   LocationSummary* locations = invoke->GetLocations();
1324   MipsAssembler* assembler = GetAssembler();
1325   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
1326   FRegister out = locations->Out().AsFpuRegister<FRegister>();
1327 
1328   __ SqrtD(out, in);
1329 }
1330 
1331 // byte libcore.io.Memory.peekByte(long address)
VisitMemoryPeekByte(HInvoke * invoke)1332 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
1333   CreateIntToIntLocations(arena_, invoke);
1334 }
1335 
VisitMemoryPeekByte(HInvoke * invoke)1336 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekByte(HInvoke* invoke) {
1337   MipsAssembler* assembler = GetAssembler();
1338   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1339   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1340 
1341   __ Lb(out, adr, 0);
1342 }
1343 
1344 // short libcore.io.Memory.peekShort(long address)
VisitMemoryPeekShortNative(HInvoke * invoke)1345 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
1346   CreateIntToIntLocations(arena_, invoke);
1347 }
1348 
VisitMemoryPeekShortNative(HInvoke * invoke)1349 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekShortNative(HInvoke* invoke) {
1350   MipsAssembler* assembler = GetAssembler();
1351   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1352   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1353 
1354   if (IsR6()) {
1355     __ Lh(out, adr, 0);
1356   } else if (IsR2OrNewer()) {
1357     // Unlike for words, there are no lhl/lhr instructions to load
1358     // unaligned halfwords so the code loads individual bytes, in case
1359     // the address isn't halfword-aligned, and assembles them into a
1360     // signed halfword.
1361     __ Lb(AT, adr, 1);   // This byte must be sign-extended.
1362     __ Lb(out, adr, 0);  // This byte can be either sign-extended, or
1363                          // zero-extended because the following
1364                          // instruction overwrites the sign bits.
1365     __ Ins(out, AT, 8, 24);
1366   } else {
1367     __ Lbu(AT, adr, 0);  // This byte must be zero-extended.  If it's not
1368                          // the "or" instruction below will destroy the upper
1369                          // 24 bits of the final result.
1370     __ Lb(out, adr, 1);  // This byte must be sign-extended.
1371     __ Sll(out, out, 8);
1372     __ Or(out, out, AT);
1373   }
1374 }
1375 
1376 // int libcore.io.Memory.peekInt(long address)
VisitMemoryPeekIntNative(HInvoke * invoke)1377 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
1378   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
1379 }
1380 
VisitMemoryPeekIntNative(HInvoke * invoke)1381 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekIntNative(HInvoke* invoke) {
1382   MipsAssembler* assembler = GetAssembler();
1383   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1384   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1385 
1386   if (IsR6()) {
1387     __ Lw(out, adr, 0);
1388   } else {
1389     __ Lwr(out, adr, 0);
1390     __ Lwl(out, adr, 3);
1391   }
1392 }
1393 
1394 // long libcore.io.Memory.peekLong(long address)
VisitMemoryPeekLongNative(HInvoke * invoke)1395 void IntrinsicLocationsBuilderMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
1396   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
1397 }
1398 
VisitMemoryPeekLongNative(HInvoke * invoke)1399 void IntrinsicCodeGeneratorMIPS::VisitMemoryPeekLongNative(HInvoke* invoke) {
1400   MipsAssembler* assembler = GetAssembler();
1401   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1402   Register out_lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>();
1403   Register out_hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>();
1404 
1405   if (IsR6()) {
1406     __ Lw(out_lo, adr, 0);
1407     __ Lw(out_hi, adr, 4);
1408   } else {
1409     __ Lwr(out_lo, adr, 0);
1410     __ Lwl(out_lo, adr, 3);
1411     __ Lwr(out_hi, adr, 4);
1412     __ Lwl(out_hi, adr, 7);
1413   }
1414 }
1415 
CreateIntIntToVoidLocations(ArenaAllocator * arena,HInvoke * invoke)1416 static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
1417   LocationSummary* locations = new (arena) LocationSummary(invoke,
1418                                                            LocationSummary::kNoCall,
1419                                                            kIntrinsified);
1420   locations->SetInAt(0, Location::RequiresRegister());
1421   locations->SetInAt(1, Location::RequiresRegister());
1422 }
1423 
1424 // void libcore.io.Memory.pokeByte(long address, byte value)
VisitMemoryPokeByte(HInvoke * invoke)1425 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
1426   CreateIntIntToVoidLocations(arena_, invoke);
1427 }
1428 
VisitMemoryPokeByte(HInvoke * invoke)1429 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeByte(HInvoke* invoke) {
1430   MipsAssembler* assembler = GetAssembler();
1431   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1432   Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
1433 
1434   __ Sb(val, adr, 0);
1435 }
1436 
1437 // void libcore.io.Memory.pokeShort(long address, short value)
VisitMemoryPokeShortNative(HInvoke * invoke)1438 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
1439   CreateIntIntToVoidLocations(arena_, invoke);
1440 }
1441 
VisitMemoryPokeShortNative(HInvoke * invoke)1442 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeShortNative(HInvoke* invoke) {
1443   MipsAssembler* assembler = GetAssembler();
1444   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1445   Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
1446 
1447   if (IsR6()) {
1448     __ Sh(val, adr, 0);
1449   } else {
1450     // Unlike for words, there are no shl/shr instructions to store
1451     // unaligned halfwords so the code stores individual bytes, in case
1452     // the address isn't halfword-aligned.
1453     __ Sb(val, adr, 0);
1454     __ Srl(AT, val, 8);
1455     __ Sb(AT, adr, 1);
1456   }
1457 }
1458 
1459 // void libcore.io.Memory.pokeInt(long address, int value)
VisitMemoryPokeIntNative(HInvoke * invoke)1460 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
1461   CreateIntIntToVoidLocations(arena_, invoke);
1462 }
1463 
VisitMemoryPokeIntNative(HInvoke * invoke)1464 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeIntNative(HInvoke* invoke) {
1465   MipsAssembler* assembler = GetAssembler();
1466   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1467   Register val = invoke->GetLocations()->InAt(1).AsRegister<Register>();
1468 
1469   if (IsR6()) {
1470     __ Sw(val, adr, 0);
1471   } else {
1472     __ Swr(val, adr, 0);
1473     __ Swl(val, adr, 3);
1474   }
1475 }
1476 
1477 // void libcore.io.Memory.pokeLong(long address, long value)
VisitMemoryPokeLongNative(HInvoke * invoke)1478 void IntrinsicLocationsBuilderMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
1479   CreateIntIntToVoidLocations(arena_, invoke);
1480 }
1481 
VisitMemoryPokeLongNative(HInvoke * invoke)1482 void IntrinsicCodeGeneratorMIPS::VisitMemoryPokeLongNative(HInvoke* invoke) {
1483   MipsAssembler* assembler = GetAssembler();
1484   Register adr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
1485   Register val_lo = invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>();
1486   Register val_hi = invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>();
1487 
1488   if (IsR6()) {
1489     __ Sw(val_lo, adr, 0);
1490     __ Sw(val_hi, adr, 4);
1491   } else {
1492     __ Swr(val_lo, adr, 0);
1493     __ Swl(val_lo, adr, 3);
1494     __ Swr(val_hi, adr, 4);
1495     __ Swl(val_hi, adr, 7);
1496   }
1497 }
1498 
1499 // Thread java.lang.Thread.currentThread()
VisitThreadCurrentThread(HInvoke * invoke)1500 void IntrinsicLocationsBuilderMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
1501   LocationSummary* locations = new (arena_) LocationSummary(invoke,
1502                                                             LocationSummary::kNoCall,
1503                                                             kIntrinsified);
1504   locations->SetOut(Location::RequiresRegister());
1505 }
1506 
VisitThreadCurrentThread(HInvoke * invoke)1507 void IntrinsicCodeGeneratorMIPS::VisitThreadCurrentThread(HInvoke* invoke) {
1508   MipsAssembler* assembler = GetAssembler();
1509   Register out = invoke->GetLocations()->Out().AsRegister<Register>();
1510 
1511   __ LoadFromOffset(kLoadWord,
1512                     out,
1513                     TR,
1514                     Thread::PeerOffset<kMipsPointerSize>().Int32Value());
1515 }
1516 
CreateIntIntIntToIntLocations(ArenaAllocator * arena,HInvoke * invoke,Primitive::Type type)1517 static void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
1518                                           HInvoke* invoke,
1519                                           Primitive::Type type) {
1520   bool can_call = kEmitCompilerReadBarrier &&
1521       (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
1522        invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
1523   LocationSummary* locations = new (arena) LocationSummary(invoke,
1524                                                            (can_call
1525                                                                 ? LocationSummary::kCallOnSlowPath
1526                                                                 : LocationSummary::kNoCall),
1527                                                            kIntrinsified);
1528   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1529   locations->SetInAt(1, Location::RequiresRegister());
1530   locations->SetInAt(2, Location::RequiresRegister());
1531   locations->SetOut(Location::RequiresRegister(),
1532                     (can_call ? Location::kOutputOverlap : Location::kNoOutputOverlap));
1533   if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1534     // We need a temporary register for the read barrier marking slow
1535     // path in InstructionCodeGeneratorMIPS::GenerateReferenceLoadWithBakerReadBarrier.
1536     locations->AddTemp(Location::RequiresRegister());
1537   }
1538 }
1539 
1540 // Note that the caller must supply a properly aligned memory address.
1541 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
GenUnsafeGet(HInvoke * invoke,Primitive::Type type,bool is_volatile,bool is_R6,CodeGeneratorMIPS * codegen)1542 static void GenUnsafeGet(HInvoke* invoke,
1543                          Primitive::Type type,
1544                          bool is_volatile,
1545                          bool is_R6,
1546                          CodeGeneratorMIPS* codegen) {
1547   LocationSummary* locations = invoke->GetLocations();
1548   DCHECK((type == Primitive::kPrimInt) ||
1549          (type == Primitive::kPrimLong) ||
1550          (type == Primitive::kPrimNot)) << type;
1551   MipsAssembler* assembler = codegen->GetAssembler();
1552   // Target register.
1553   Location trg_loc = locations->Out();
1554   // Object pointer.
1555   Location base_loc = locations->InAt(1);
1556   Register base = base_loc.AsRegister<Register>();
1557   // The "offset" argument is passed as a "long". Since this code is for
1558   // a 32-bit processor, we can only use 32-bit addresses, so we only
1559   // need the low 32-bits of offset.
1560   Location offset_loc = locations->InAt(2);
1561   Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
1562 
1563   if (!(kEmitCompilerReadBarrier && kUseBakerReadBarrier && (type == Primitive::kPrimNot))) {
1564     __ Addu(TMP, base, offset_lo);
1565   }
1566 
1567   switch (type) {
1568     case Primitive::kPrimLong: {
1569       Register trg_lo = trg_loc.AsRegisterPairLow<Register>();
1570       Register trg_hi = trg_loc.AsRegisterPairHigh<Register>();
1571       CHECK(!is_volatile);  // TODO: support atomic 8-byte volatile loads.
1572       if (is_R6) {
1573         __ Lw(trg_lo, TMP, 0);
1574         __ Lw(trg_hi, TMP, 4);
1575       } else {
1576         __ Lwr(trg_lo, TMP, 0);
1577         __ Lwl(trg_lo, TMP, 3);
1578         __ Lwr(trg_hi, TMP, 4);
1579         __ Lwl(trg_hi, TMP, 7);
1580       }
1581       break;
1582     }
1583 
1584     case Primitive::kPrimInt: {
1585       Register trg = trg_loc.AsRegister<Register>();
1586       if (is_R6) {
1587         __ Lw(trg, TMP, 0);
1588       } else {
1589         __ Lwr(trg, TMP, 0);
1590         __ Lwl(trg, TMP, 3);
1591       }
1592       if (is_volatile) {
1593         __ Sync(0);
1594       }
1595       break;
1596     }
1597 
1598     case Primitive::kPrimNot: {
1599       Register trg = trg_loc.AsRegister<Register>();
1600       if (kEmitCompilerReadBarrier) {
1601         if (kUseBakerReadBarrier) {
1602           Location temp = locations->GetTemp(0);
1603           codegen->GenerateReferenceLoadWithBakerReadBarrier(invoke,
1604                                                              trg_loc,
1605                                                              base,
1606                                                              /* offset */ 0U,
1607                                                              /* index */ offset_loc,
1608                                                              TIMES_1,
1609                                                              temp,
1610                                                              /* needs_null_check */ false);
1611           if (is_volatile) {
1612             __ Sync(0);
1613           }
1614         } else {
1615           if (is_R6) {
1616             __ Lw(trg, TMP, 0);
1617           } else {
1618             __ Lwr(trg, TMP, 0);
1619             __ Lwl(trg, TMP, 3);
1620           }
1621           if (is_volatile) {
1622             __ Sync(0);
1623           }
1624           codegen->GenerateReadBarrierSlow(invoke,
1625                                            trg_loc,
1626                                            trg_loc,
1627                                            base_loc,
1628                                            /* offset */ 0U,
1629                                            /* index */ offset_loc);
1630         }
1631       } else {
1632         if (is_R6) {
1633           __ Lw(trg, TMP, 0);
1634         } else {
1635           __ Lwr(trg, TMP, 0);
1636           __ Lwl(trg, TMP, 3);
1637         }
1638         if (is_volatile) {
1639           __ Sync(0);
1640         }
1641         __ MaybeUnpoisonHeapReference(trg);
1642       }
1643       break;
1644     }
1645 
1646     default:
1647       LOG(FATAL) << "Unexpected type " << type;
1648       UNREACHABLE();
1649   }
1650 }
1651 
1652 // int sun.misc.Unsafe.getInt(Object o, long offset)
VisitUnsafeGet(HInvoke * invoke)1653 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGet(HInvoke* invoke) {
1654   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
1655 }
1656 
VisitUnsafeGet(HInvoke * invoke)1657 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGet(HInvoke* invoke) {
1658   GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, IsR6(), codegen_);
1659 }
1660 
1661 // int sun.misc.Unsafe.getIntVolatile(Object o, long offset)
VisitUnsafeGetVolatile(HInvoke * invoke)1662 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
1663   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt);
1664 }
1665 
VisitUnsafeGetVolatile(HInvoke * invoke)1666 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetVolatile(HInvoke* invoke) {
1667   GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, IsR6(), codegen_);
1668 }
1669 
1670 // long sun.misc.Unsafe.getLong(Object o, long offset)
VisitUnsafeGetLong(HInvoke * invoke)1671 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
1672   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong);
1673 }
1674 
VisitUnsafeGetLong(HInvoke * invoke)1675 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetLong(HInvoke* invoke) {
1676   GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, IsR6(), codegen_);
1677 }
1678 
1679 // Object sun.misc.Unsafe.getObject(Object o, long offset)
VisitUnsafeGetObject(HInvoke * invoke)1680 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
1681   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
1682 }
1683 
VisitUnsafeGetObject(HInvoke * invoke)1684 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObject(HInvoke* invoke) {
1685   GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, IsR6(), codegen_);
1686 }
1687 
1688 // Object sun.misc.Unsafe.getObjectVolatile(Object o, long offset)
VisitUnsafeGetObjectVolatile(HInvoke * invoke)1689 void IntrinsicLocationsBuilderMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1690   CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot);
1691 }
1692 
VisitUnsafeGetObjectVolatile(HInvoke * invoke)1693 void IntrinsicCodeGeneratorMIPS::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1694   GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, IsR6(), codegen_);
1695 }
1696 
CreateIntIntIntIntToVoidLocations(ArenaAllocator * arena,HInvoke * invoke)1697 static void CreateIntIntIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
1698   LocationSummary* locations = new (arena) LocationSummary(invoke,
1699                                                            LocationSummary::kNoCall,
1700                                                            kIntrinsified);
1701   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1702   locations->SetInAt(1, Location::RequiresRegister());
1703   locations->SetInAt(2, Location::RequiresRegister());
1704   locations->SetInAt(3, Location::RequiresRegister());
1705 }
1706 
1707 // Note that the caller must supply a properly aligned memory address.
1708 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
GenUnsafePut(LocationSummary * locations,Primitive::Type type,bool is_volatile,bool is_ordered,bool is_R6,CodeGeneratorMIPS * codegen)1709 static void GenUnsafePut(LocationSummary* locations,
1710                          Primitive::Type type,
1711                          bool is_volatile,
1712                          bool is_ordered,
1713                          bool is_R6,
1714                          CodeGeneratorMIPS* codegen) {
1715   DCHECK((type == Primitive::kPrimInt) ||
1716          (type == Primitive::kPrimLong) ||
1717          (type == Primitive::kPrimNot)) << type;
1718   MipsAssembler* assembler = codegen->GetAssembler();
1719   // Object pointer.
1720   Register base = locations->InAt(1).AsRegister<Register>();
1721   // The "offset" argument is passed as a "long", i.e., it's 64-bits in
1722   // size. Since this code is for a 32-bit processor, we can only use
1723   // 32-bit addresses, so we only need the low 32-bits of offset.
1724   Register offset_lo = locations->InAt(2).AsRegisterPairLow<Register>();
1725 
1726   __ Addu(TMP, base, offset_lo);
1727   if (is_volatile || is_ordered) {
1728     __ Sync(0);
1729   }
1730   if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
1731     Register value = locations->InAt(3).AsRegister<Register>();
1732 
1733     if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1734       __ PoisonHeapReference(AT, value);
1735       value = AT;
1736     }
1737 
1738     if (is_R6) {
1739       __ Sw(value, TMP, 0);
1740     } else {
1741       __ Swr(value, TMP, 0);
1742       __ Swl(value, TMP, 3);
1743     }
1744   } else {
1745     Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>();
1746     Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>();
1747     CHECK(!is_volatile);  // TODO: support atomic 8-byte volatile stores.
1748     if (is_R6) {
1749       __ Sw(value_lo, TMP, 0);
1750       __ Sw(value_hi, TMP, 4);
1751     } else {
1752       __ Swr(value_lo, TMP, 0);
1753       __ Swl(value_lo, TMP, 3);
1754       __ Swr(value_hi, TMP, 4);
1755       __ Swl(value_hi, TMP, 7);
1756     }
1757   }
1758 
1759   if (is_volatile) {
1760     __ Sync(0);
1761   }
1762 
1763   if (type == Primitive::kPrimNot) {
1764     bool value_can_be_null = true;  // TODO: Worth finding out this information?
1765     codegen->MarkGCCard(base, locations->InAt(3).AsRegister<Register>(), value_can_be_null);
1766   }
1767 }
1768 
1769 // void sun.misc.Unsafe.putInt(Object o, long offset, int x)
VisitUnsafePut(HInvoke * invoke)1770 void IntrinsicLocationsBuilderMIPS::VisitUnsafePut(HInvoke* invoke) {
1771   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1772 }
1773 
VisitUnsafePut(HInvoke * invoke)1774 void IntrinsicCodeGeneratorMIPS::VisitUnsafePut(HInvoke* invoke) {
1775   GenUnsafePut(invoke->GetLocations(),
1776                Primitive::kPrimInt,
1777                /* is_volatile */ false,
1778                /* is_ordered */ false,
1779                IsR6(),
1780                codegen_);
1781 }
1782 
1783 // void sun.misc.Unsafe.putOrderedInt(Object o, long offset, int x)
VisitUnsafePutOrdered(HInvoke * invoke)1784 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
1785   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1786 }
1787 
VisitUnsafePutOrdered(HInvoke * invoke)1788 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutOrdered(HInvoke* invoke) {
1789   GenUnsafePut(invoke->GetLocations(),
1790                Primitive::kPrimInt,
1791                /* is_volatile */ false,
1792                /* is_ordered */ true,
1793                IsR6(),
1794                codegen_);
1795 }
1796 
1797 // void sun.misc.Unsafe.putIntVolatile(Object o, long offset, int x)
VisitUnsafePutVolatile(HInvoke * invoke)1798 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
1799   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1800 }
1801 
VisitUnsafePutVolatile(HInvoke * invoke)1802 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutVolatile(HInvoke* invoke) {
1803   GenUnsafePut(invoke->GetLocations(),
1804                Primitive::kPrimInt,
1805                /* is_volatile */ true,
1806                /* is_ordered */ false,
1807                IsR6(),
1808                codegen_);
1809 }
1810 
1811 // void sun.misc.Unsafe.putObject(Object o, long offset, Object x)
VisitUnsafePutObject(HInvoke * invoke)1812 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObject(HInvoke* invoke) {
1813   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1814 }
1815 
VisitUnsafePutObject(HInvoke * invoke)1816 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObject(HInvoke* invoke) {
1817   GenUnsafePut(invoke->GetLocations(),
1818                Primitive::kPrimNot,
1819                /* is_volatile */ false,
1820                /* is_ordered */ false,
1821                IsR6(),
1822                codegen_);
1823 }
1824 
1825 // void sun.misc.Unsafe.putOrderedObject(Object o, long offset, Object x)
VisitUnsafePutObjectOrdered(HInvoke * invoke)1826 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1827   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1828 }
1829 
VisitUnsafePutObjectOrdered(HInvoke * invoke)1830 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
1831   GenUnsafePut(invoke->GetLocations(),
1832                Primitive::kPrimNot,
1833                /* is_volatile */ false,
1834                /* is_ordered */ true,
1835                IsR6(),
1836                codegen_);
1837 }
1838 
1839 // void sun.misc.Unsafe.putObjectVolatile(Object o, long offset, Object x)
VisitUnsafePutObjectVolatile(HInvoke * invoke)1840 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1841   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1842 }
1843 
VisitUnsafePutObjectVolatile(HInvoke * invoke)1844 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
1845   GenUnsafePut(invoke->GetLocations(),
1846                Primitive::kPrimNot,
1847                /* is_volatile */ true,
1848                /* is_ordered */ false,
1849                IsR6(),
1850                codegen_);
1851 }
1852 
1853 // void sun.misc.Unsafe.putLong(Object o, long offset, long x)
VisitUnsafePutLong(HInvoke * invoke)1854 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLong(HInvoke* invoke) {
1855   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1856 }
1857 
VisitUnsafePutLong(HInvoke * invoke)1858 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLong(HInvoke* invoke) {
1859   GenUnsafePut(invoke->GetLocations(),
1860                Primitive::kPrimLong,
1861                /* is_volatile */ false,
1862                /* is_ordered */ false,
1863                IsR6(),
1864                codegen_);
1865 }
1866 
1867 // void sun.misc.Unsafe.putOrderedLong(Object o, long offset, long x)
VisitUnsafePutLongOrdered(HInvoke * invoke)1868 void IntrinsicLocationsBuilderMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1869   CreateIntIntIntIntToVoidLocations(arena_, invoke);
1870 }
1871 
VisitUnsafePutLongOrdered(HInvoke * invoke)1872 void IntrinsicCodeGeneratorMIPS::VisitUnsafePutLongOrdered(HInvoke* invoke) {
1873   GenUnsafePut(invoke->GetLocations(),
1874                Primitive::kPrimLong,
1875                /* is_volatile */ false,
1876                /* is_ordered */ true,
1877                IsR6(),
1878                codegen_);
1879 }
1880 
CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator * arena,HInvoke * invoke)1881 static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, HInvoke* invoke) {
1882   bool can_call = kEmitCompilerReadBarrier &&
1883       kUseBakerReadBarrier &&
1884       (invoke->GetIntrinsic() == Intrinsics::kUnsafeCASObject);
1885   LocationSummary* locations = new (arena) LocationSummary(invoke,
1886                                                            (can_call
1887                                                                 ? LocationSummary::kCallOnSlowPath
1888                                                                 : LocationSummary::kNoCall),
1889                                                            kIntrinsified);
1890   locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
1891   locations->SetInAt(1, Location::RequiresRegister());
1892   locations->SetInAt(2, Location::RequiresRegister());
1893   locations->SetInAt(3, Location::RequiresRegister());
1894   locations->SetInAt(4, Location::RequiresRegister());
1895   locations->SetOut(Location::RequiresRegister());
1896 
1897   // Temporary register used in CAS by (Baker) read barrier.
1898   if (can_call) {
1899     locations->AddTemp(Location::RequiresRegister());
1900   }
1901 }
1902 
1903 // Note that the caller must supply a properly aligned memory address.
1904 // If they do not, the behavior is undefined (atomicity not guaranteed, exception may occur).
GenCas(HInvoke * invoke,Primitive::Type type,CodeGeneratorMIPS * codegen)1905 static void GenCas(HInvoke* invoke, Primitive::Type type, CodeGeneratorMIPS* codegen) {
1906   MipsAssembler* assembler = codegen->GetAssembler();
1907   LocationSummary* locations = invoke->GetLocations();
1908   bool isR6 = codegen->GetInstructionSetFeatures().IsR6();
1909   Register base = locations->InAt(1).AsRegister<Register>();
1910   Location offset_loc = locations->InAt(2);
1911   Register offset_lo = offset_loc.AsRegisterPairLow<Register>();
1912   Register expected = locations->InAt(3).AsRegister<Register>();
1913   Register value = locations->InAt(4).AsRegister<Register>();
1914   Location out_loc = locations->Out();
1915   Register out = out_loc.AsRegister<Register>();
1916 
1917   DCHECK_NE(base, out);
1918   DCHECK_NE(offset_lo, out);
1919   DCHECK_NE(expected, out);
1920 
1921   if (type == Primitive::kPrimNot) {
1922     // The only read barrier implementation supporting the
1923     // UnsafeCASObject intrinsic is the Baker-style read barriers.
1924     DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
1925 
1926     // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
1927     // object and scan the receiver at the next GC for nothing.
1928     bool value_can_be_null = true;  // TODO: Worth finding out this information?
1929     codegen->MarkGCCard(base, value, value_can_be_null);
1930 
1931     if (kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
1932       Location temp = locations->GetTemp(0);
1933       // Need to make sure the reference stored in the field is a to-space
1934       // one before attempting the CAS or the CAS could fail incorrectly.
1935       codegen->GenerateReferenceLoadWithBakerReadBarrier(
1936           invoke,
1937           out_loc,  // Unused, used only as a "temporary" within the read barrier.
1938           base,
1939           /* offset */ 0u,
1940           /* index */ offset_loc,
1941           ScaleFactor::TIMES_1,
1942           temp,
1943           /* needs_null_check */ false,
1944           /* always_update_field */ true);
1945     }
1946   }
1947 
1948   MipsLabel loop_head, exit_loop;
1949   __ Addu(TMP, base, offset_lo);
1950 
1951   if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
1952     __ PoisonHeapReference(expected);
1953     // Do not poison `value`, if it is the same register as
1954     // `expected`, which has just been poisoned.
1955     if (value != expected) {
1956       __ PoisonHeapReference(value);
1957     }
1958   }
1959 
1960   // do {
1961   //   tmp_value = [tmp_ptr] - expected;
1962   // } while (tmp_value == 0 && failure([tmp_ptr] <- r_new_value));
1963   // result = tmp_value != 0;
1964 
1965   __ Sync(0);
1966   __ Bind(&loop_head);
1967   if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
1968     if (isR6) {
1969       __ LlR6(out, TMP);
1970     } else {
1971       __ LlR2(out, TMP);
1972     }
1973   } else {
1974     LOG(FATAL) << "Unsupported op size " << type;
1975     UNREACHABLE();
1976   }
1977   __ Subu(out, out, expected);          // If we didn't get the 'expected'
1978   __ Sltiu(out, out, 1);                // value, set 'out' to false, and
1979   __ Beqz(out, &exit_loop);             // return.
1980   __ Move(out, value);  // Use 'out' for the 'store conditional' instruction.
1981                         // If we use 'value' directly, we would lose 'value'
1982                         // in the case that the store fails.  Whether the
1983                         // store succeeds, or fails, it will load the
1984                         // correct Boolean value into the 'out' register.
1985   // This test isn't really necessary. We only support Primitive::kPrimInt,
1986   // Primitive::kPrimNot, and we already verified that we're working on one
1987   // of those two types. It's left here in case the code needs to support
1988   // other types in the future.
1989   if ((type == Primitive::kPrimInt) || (type == Primitive::kPrimNot)) {
1990     if (isR6) {
1991       __ ScR6(out, TMP);
1992     } else {
1993       __ ScR2(out, TMP);
1994     }
1995   }
1996   __ Beqz(out, &loop_head);     // If we couldn't do the read-modify-write
1997                                 // cycle atomically then retry.
1998   __ Bind(&exit_loop);
1999   __ Sync(0);
2000 
2001   if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
2002     __ UnpoisonHeapReference(expected);
2003     // Do not unpoison `value`, if it is the same register as
2004     // `expected`, which has just been unpoisoned.
2005     if (value != expected) {
2006       __ UnpoisonHeapReference(value);
2007     }
2008   }
2009 }
2010 
2011 // boolean sun.misc.Unsafe.compareAndSwapInt(Object o, long offset, int expected, int x)
VisitUnsafeCASInt(HInvoke * invoke)2012 void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
2013   CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
2014 }
2015 
VisitUnsafeCASInt(HInvoke * invoke)2016 void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASInt(HInvoke* invoke) {
2017   GenCas(invoke, Primitive::kPrimInt, codegen_);
2018 }
2019 
2020 // boolean sun.misc.Unsafe.compareAndSwapObject(Object o, long offset, Object expected, Object x)
VisitUnsafeCASObject(HInvoke * invoke)2021 void IntrinsicLocationsBuilderMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
2022   // The only read barrier implementation supporting the
2023   // UnsafeCASObject intrinsic is the Baker-style read barriers.
2024   if (kEmitCompilerReadBarrier && !kUseBakerReadBarrier) {
2025     return;
2026   }
2027 
2028   CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
2029 }
2030 
VisitUnsafeCASObject(HInvoke * invoke)2031 void IntrinsicCodeGeneratorMIPS::VisitUnsafeCASObject(HInvoke* invoke) {
2032   // The only read barrier implementation supporting the
2033   // UnsafeCASObject intrinsic is the Baker-style read barriers.
2034   DCHECK(!kEmitCompilerReadBarrier || kUseBakerReadBarrier);
2035 
2036   GenCas(invoke, Primitive::kPrimNot, codegen_);
2037 }
2038 
2039 // int java.lang.String.compareTo(String anotherString)
VisitStringCompareTo(HInvoke * invoke)2040 void IntrinsicLocationsBuilderMIPS::VisitStringCompareTo(HInvoke* invoke) {
2041   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2042                                                             LocationSummary::kCallOnMainAndSlowPath,
2043                                                             kIntrinsified);
2044   InvokeRuntimeCallingConvention calling_convention;
2045   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2046   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2047   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
2048   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2049 }
2050 
VisitStringCompareTo(HInvoke * invoke)2051 void IntrinsicCodeGeneratorMIPS::VisitStringCompareTo(HInvoke* invoke) {
2052   MipsAssembler* assembler = GetAssembler();
2053   LocationSummary* locations = invoke->GetLocations();
2054 
2055   // Note that the null check must have been done earlier.
2056   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2057 
2058   Register argument = locations->InAt(1).AsRegister<Register>();
2059   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
2060   codegen_->AddSlowPath(slow_path);
2061   __ Beqz(argument, slow_path->GetEntryLabel());
2062   codegen_->InvokeRuntime(kQuickStringCompareTo, invoke, invoke->GetDexPc(), slow_path);
2063   __ Bind(slow_path->GetExitLabel());
2064 }
2065 
2066 // boolean java.lang.String.equals(Object anObject)
VisitStringEquals(HInvoke * invoke)2067 void IntrinsicLocationsBuilderMIPS::VisitStringEquals(HInvoke* invoke) {
2068   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2069                                                             LocationSummary::kNoCall,
2070                                                             kIntrinsified);
2071   locations->SetInAt(0, Location::RequiresRegister());
2072   locations->SetInAt(1, Location::RequiresRegister());
2073   locations->SetOut(Location::RequiresRegister());
2074 
2075   // Temporary registers to store lengths of strings and for calculations.
2076   locations->AddTemp(Location::RequiresRegister());
2077   locations->AddTemp(Location::RequiresRegister());
2078   locations->AddTemp(Location::RequiresRegister());
2079 }
2080 
VisitStringEquals(HInvoke * invoke)2081 void IntrinsicCodeGeneratorMIPS::VisitStringEquals(HInvoke* invoke) {
2082   MipsAssembler* assembler = GetAssembler();
2083   LocationSummary* locations = invoke->GetLocations();
2084 
2085   Register str = locations->InAt(0).AsRegister<Register>();
2086   Register arg = locations->InAt(1).AsRegister<Register>();
2087   Register out = locations->Out().AsRegister<Register>();
2088 
2089   Register temp1 = locations->GetTemp(0).AsRegister<Register>();
2090   Register temp2 = locations->GetTemp(1).AsRegister<Register>();
2091   Register temp3 = locations->GetTemp(2).AsRegister<Register>();
2092 
2093   MipsLabel loop;
2094   MipsLabel end;
2095   MipsLabel return_true;
2096   MipsLabel return_false;
2097 
2098   // Get offsets of count, value, and class fields within a string object.
2099   const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2100   const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
2101   const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
2102 
2103   // Note that the null check must have been done earlier.
2104   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2105 
2106   // If the register containing the pointer to "this", and the register
2107   // containing the pointer to "anObject" are the same register then
2108   // "this", and "anObject" are the same object and we can
2109   // short-circuit the logic to a true result.
2110   if (str == arg) {
2111     __ LoadConst32(out, 1);
2112     return;
2113   }
2114   StringEqualsOptimizations optimizations(invoke);
2115   if (!optimizations.GetArgumentNotNull()) {
2116     // Check if input is null, return false if it is.
2117     __ Beqz(arg, &return_false);
2118   }
2119 
2120   // Reference equality check, return true if same reference.
2121   __ Beq(str, arg, &return_true);
2122 
2123   if (!optimizations.GetArgumentIsString()) {
2124     // Instanceof check for the argument by comparing class fields.
2125     // All string objects must have the same type since String cannot be subclassed.
2126     // Receiver must be a string object, so its class field is equal to all strings' class fields.
2127     // If the argument is a string object, its class field must be equal to receiver's class field.
2128     __ Lw(temp1, str, class_offset);
2129     __ Lw(temp2, arg, class_offset);
2130     __ Bne(temp1, temp2, &return_false);
2131   }
2132 
2133   // Load `count` fields of this and argument strings.
2134   __ Lw(temp1, str, count_offset);
2135   __ Lw(temp2, arg, count_offset);
2136   // Check if `count` fields are equal, return false if they're not.
2137   // Also compares the compression style, if differs return false.
2138   __ Bne(temp1, temp2, &return_false);
2139   // Return true if both strings are empty. Even with string compression `count == 0` means empty.
2140   static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
2141                 "Expecting 0=compressed, 1=uncompressed");
2142   __ Beqz(temp1, &return_true);
2143 
2144   // Don't overwrite input registers
2145   __ Move(TMP, str);
2146   __ Move(temp3, arg);
2147 
2148   // Assertions that must hold in order to compare strings 4 bytes at a time.
2149   DCHECK_ALIGNED(value_offset, 4);
2150   static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
2151 
2152   // For string compression, calculate the number of bytes to compare (not chars).
2153   if (mirror::kUseStringCompression) {
2154     // Extract compression flag.
2155     if (IsR2OrNewer()) {
2156       __ Ext(temp2, temp1, 0, 1);
2157     } else {
2158       __ Sll(temp2, temp1, 31);
2159       __ Srl(temp2, temp2, 31);
2160     }
2161     __ Srl(temp1, temp1, 1);             // Extract length.
2162     __ Sllv(temp1, temp1, temp2);        // Double the byte count if uncompressed.
2163   }
2164 
2165   // Loop to compare strings 4 bytes at a time starting at the beginning of the string.
2166   // Ok to do this because strings are zero-padded to kObjectAlignment.
2167   __ Bind(&loop);
2168   __ Lw(out, TMP, value_offset);
2169   __ Lw(temp2, temp3, value_offset);
2170   __ Bne(out, temp2, &return_false);
2171   __ Addiu(TMP, TMP, 4);
2172   __ Addiu(temp3, temp3, 4);
2173   // With string compression, we have compared 4 bytes, otherwise 2 chars.
2174   __ Addiu(temp1, temp1, mirror::kUseStringCompression ? -4 : -2);
2175   __ Bgtz(temp1, &loop);
2176 
2177   // Return true and exit the function.
2178   // If loop does not result in returning false, we return true.
2179   __ Bind(&return_true);
2180   __ LoadConst32(out, 1);
2181   __ B(&end);
2182 
2183   // Return false and exit the function.
2184   __ Bind(&return_false);
2185   __ LoadConst32(out, 0);
2186   __ Bind(&end);
2187 }
2188 
GenerateStringIndexOf(HInvoke * invoke,bool start_at_zero,MipsAssembler * assembler,CodeGeneratorMIPS * codegen,ArenaAllocator * allocator)2189 static void GenerateStringIndexOf(HInvoke* invoke,
2190                                   bool start_at_zero,
2191                                   MipsAssembler* assembler,
2192                                   CodeGeneratorMIPS* codegen,
2193                                   ArenaAllocator* allocator) {
2194   LocationSummary* locations = invoke->GetLocations();
2195   Register tmp_reg = start_at_zero ? locations->GetTemp(0).AsRegister<Register>() : TMP;
2196 
2197   // Note that the null check must have been done earlier.
2198   DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
2199 
2200   // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
2201   // or directly dispatch for a large constant, or omit slow-path for a small constant or a char.
2202   SlowPathCodeMIPS* slow_path = nullptr;
2203   HInstruction* code_point = invoke->InputAt(1);
2204   if (code_point->IsIntConstant()) {
2205     if (!IsUint<16>(code_point->AsIntConstant()->GetValue())) {
2206       // Always needs the slow-path. We could directly dispatch to it,
2207       // but this case should be rare, so for simplicity just put the
2208       // full slow-path down and branch unconditionally.
2209       slow_path = new (allocator) IntrinsicSlowPathMIPS(invoke);
2210       codegen->AddSlowPath(slow_path);
2211       __ B(slow_path->GetEntryLabel());
2212       __ Bind(slow_path->GetExitLabel());
2213       return;
2214     }
2215   } else if (code_point->GetType() != Primitive::kPrimChar) {
2216     Register char_reg = locations->InAt(1).AsRegister<Register>();
2217     // The "bltu" conditional branch tests to see if the character value
2218     // fits in a valid 16-bit (MIPS halfword) value. If it doesn't then
2219     // the character being searched for, if it exists in the string, is
2220     // encoded using UTF-16 and stored in the string as two (16-bit)
2221     // halfwords. Currently the assembly code used to implement this
2222     // intrinsic doesn't support searching for a character stored as
2223     // two halfwords so we fallback to using the generic implementation
2224     // of indexOf().
2225     __ LoadConst32(tmp_reg, std::numeric_limits<uint16_t>::max());
2226     slow_path = new (allocator) IntrinsicSlowPathMIPS(invoke);
2227     codegen->AddSlowPath(slow_path);
2228     __ Bltu(tmp_reg, char_reg, slow_path->GetEntryLabel());
2229   }
2230 
2231   if (start_at_zero) {
2232     DCHECK_EQ(tmp_reg, A2);
2233     // Start-index = 0.
2234     __ Clear(tmp_reg);
2235   }
2236 
2237   codegen->InvokeRuntime(kQuickIndexOf, invoke, invoke->GetDexPc(), slow_path);
2238   if (slow_path != nullptr) {
2239     __ Bind(slow_path->GetExitLabel());
2240   }
2241 }
2242 
2243 // int java.lang.String.indexOf(int ch)
VisitStringIndexOf(HInvoke * invoke)2244 void IntrinsicLocationsBuilderMIPS::VisitStringIndexOf(HInvoke* invoke) {
2245   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2246                                                             LocationSummary::kCallOnMainAndSlowPath,
2247                                                             kIntrinsified);
2248   // We have a hand-crafted assembly stub that follows the runtime
2249   // calling convention. So it's best to align the inputs accordingly.
2250   InvokeRuntimeCallingConvention calling_convention;
2251   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2252   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2253   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
2254   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2255 
2256   // Need a temp for slow-path codepoint compare, and need to send start-index=0.
2257   locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2258 }
2259 
VisitStringIndexOf(HInvoke * invoke)2260 void IntrinsicCodeGeneratorMIPS::VisitStringIndexOf(HInvoke* invoke) {
2261   GenerateStringIndexOf(invoke,
2262                         /* start_at_zero */ true,
2263                         GetAssembler(),
2264                         codegen_,
2265                         GetAllocator());
2266 }
2267 
2268 // int java.lang.String.indexOf(int ch, int fromIndex)
VisitStringIndexOfAfter(HInvoke * invoke)2269 void IntrinsicLocationsBuilderMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
2270   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2271                                                             LocationSummary::kCallOnMainAndSlowPath,
2272                                                             kIntrinsified);
2273   // We have a hand-crafted assembly stub that follows the runtime
2274   // calling convention. So it's best to align the inputs accordingly.
2275   InvokeRuntimeCallingConvention calling_convention;
2276   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2277   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2278   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2279   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
2280   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2281 
2282   // Need a temp for slow-path codepoint compare.
2283   locations->AddTemp(Location::RequiresRegister());
2284 }
2285 
VisitStringIndexOfAfter(HInvoke * invoke)2286 void IntrinsicCodeGeneratorMIPS::VisitStringIndexOfAfter(HInvoke* invoke) {
2287   GenerateStringIndexOf(invoke,
2288                         /* start_at_zero */ false,
2289                         GetAssembler(),
2290                         codegen_,
2291                         GetAllocator());
2292 }
2293 
2294 // java.lang.StringFactory.newStringFromBytes(byte[] data, int high, int offset, int byteCount)
VisitStringNewStringFromBytes(HInvoke * invoke)2295 void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
2296   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2297                                                             LocationSummary::kCallOnMainAndSlowPath,
2298                                                             kIntrinsified);
2299   InvokeRuntimeCallingConvention calling_convention;
2300   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2301   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2302   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2303   locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
2304   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
2305   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2306 }
2307 
VisitStringNewStringFromBytes(HInvoke * invoke)2308 void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromBytes(HInvoke* invoke) {
2309   MipsAssembler* assembler = GetAssembler();
2310   LocationSummary* locations = invoke->GetLocations();
2311 
2312   Register byte_array = locations->InAt(0).AsRegister<Register>();
2313   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
2314   codegen_->AddSlowPath(slow_path);
2315   __ Beqz(byte_array, slow_path->GetEntryLabel());
2316   codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path);
2317   __ Bind(slow_path->GetExitLabel());
2318 }
2319 
2320 // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
VisitStringNewStringFromChars(HInvoke * invoke)2321 void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
2322   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2323                                                             LocationSummary::kCallOnMainOnly,
2324                                                             kIntrinsified);
2325   InvokeRuntimeCallingConvention calling_convention;
2326   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2327   locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
2328   locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2329   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
2330   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2331 }
2332 
VisitStringNewStringFromChars(HInvoke * invoke)2333 void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromChars(HInvoke* invoke) {
2334   // No need to emit code checking whether `locations->InAt(2)` is a null
2335   // pointer, as callers of the native method
2336   //
2337   //   java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
2338   //
2339   // all include a null check on `data` before calling that method.
2340   codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc());
2341 }
2342 
2343 // java.lang.StringFactory.newStringFromString(String toCopy)
VisitStringNewStringFromString(HInvoke * invoke)2344 void IntrinsicLocationsBuilderMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
2345   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2346                                                             LocationSummary::kCallOnMainAndSlowPath,
2347                                                             kIntrinsified);
2348   InvokeRuntimeCallingConvention calling_convention;
2349   locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2350   Location outLocation = calling_convention.GetReturnLocation(Primitive::kPrimInt);
2351   locations->SetOut(Location::RegisterLocation(outLocation.AsRegister<Register>()));
2352 }
2353 
VisitStringNewStringFromString(HInvoke * invoke)2354 void IntrinsicCodeGeneratorMIPS::VisitStringNewStringFromString(HInvoke* invoke) {
2355   MipsAssembler* assembler = GetAssembler();
2356   LocationSummary* locations = invoke->GetLocations();
2357 
2358   Register string_to_copy = locations->InAt(0).AsRegister<Register>();
2359   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
2360   codegen_->AddSlowPath(slow_path);
2361   __ Beqz(string_to_copy, slow_path->GetEntryLabel());
2362   codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc());
2363   __ Bind(slow_path->GetExitLabel());
2364 }
2365 
GenIsInfinite(LocationSummary * locations,const Primitive::Type type,const bool isR6,MipsAssembler * assembler)2366 static void GenIsInfinite(LocationSummary* locations,
2367                           const Primitive::Type type,
2368                           const bool isR6,
2369                           MipsAssembler* assembler) {
2370   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
2371   Register out = locations->Out().AsRegister<Register>();
2372 
2373   DCHECK(type == Primitive::kPrimFloat || type == Primitive::kPrimDouble);
2374 
2375   if (isR6) {
2376     if (type == Primitive::kPrimDouble) {
2377         __ ClassD(FTMP, in);
2378     } else {
2379         __ ClassS(FTMP, in);
2380     }
2381     __ Mfc1(out, FTMP);
2382     __ Andi(out, out, kPositiveInfinity | kNegativeInfinity);
2383     __ Sltu(out, ZERO, out);
2384   } else {
2385     // If one, or more, of the exponent bits is zero, then the number can't be infinite.
2386     if (type == Primitive::kPrimDouble) {
2387       __ MoveFromFpuHigh(TMP, in);
2388       __ LoadConst32(AT, High32Bits(kPositiveInfinityDouble));
2389     } else {
2390       __ Mfc1(TMP, in);
2391       __ LoadConst32(AT, kPositiveInfinityFloat);
2392     }
2393     __ Xor(TMP, TMP, AT);
2394 
2395     __ Sll(TMP, TMP, 1);
2396 
2397     if (type == Primitive::kPrimDouble) {
2398       __ Mfc1(AT, in);
2399       __ Or(TMP, TMP, AT);
2400     }
2401     // If any of the significand bits are one, then the number is not infinite.
2402     __ Sltiu(out, TMP, 1);
2403   }
2404 }
2405 
2406 // boolean java.lang.Float.isInfinite(float)
VisitFloatIsInfinite(HInvoke * invoke)2407 void IntrinsicLocationsBuilderMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
2408   CreateFPToIntLocations(arena_, invoke);
2409 }
2410 
VisitFloatIsInfinite(HInvoke * invoke)2411 void IntrinsicCodeGeneratorMIPS::VisitFloatIsInfinite(HInvoke* invoke) {
2412   GenIsInfinite(invoke->GetLocations(), Primitive::kPrimFloat, IsR6(), GetAssembler());
2413 }
2414 
2415 // boolean java.lang.Double.isInfinite(double)
VisitDoubleIsInfinite(HInvoke * invoke)2416 void IntrinsicLocationsBuilderMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
2417   CreateFPToIntLocations(arena_, invoke);
2418 }
2419 
VisitDoubleIsInfinite(HInvoke * invoke)2420 void IntrinsicCodeGeneratorMIPS::VisitDoubleIsInfinite(HInvoke* invoke) {
2421   GenIsInfinite(invoke->GetLocations(), Primitive::kPrimDouble, IsR6(), GetAssembler());
2422 }
2423 
GenHighestOneBit(LocationSummary * locations,const Primitive::Type type,bool isR6,MipsAssembler * assembler)2424 static void GenHighestOneBit(LocationSummary* locations,
2425                              const Primitive::Type type,
2426                              bool isR6,
2427                              MipsAssembler* assembler) {
2428   DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
2429 
2430   if (type == Primitive::kPrimLong) {
2431     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
2432     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
2433     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
2434     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
2435 
2436     if (isR6) {
2437       __ ClzR6(TMP, in_hi);
2438     } else {
2439       __ ClzR2(TMP, in_hi);
2440     }
2441     __ LoadConst32(AT, 0x80000000);
2442     __ Srlv(out_hi, AT, TMP);
2443     __ And(out_hi, out_hi, in_hi);
2444     if (isR6) {
2445       __ ClzR6(TMP, in_lo);
2446     } else {
2447       __ ClzR2(TMP, in_lo);
2448     }
2449     __ Srlv(out_lo, AT, TMP);
2450     __ And(out_lo, out_lo, in_lo);
2451     if (isR6) {
2452       __ Seleqz(out_lo, out_lo, out_hi);
2453     } else {
2454       __ Movn(out_lo, ZERO, out_hi);
2455     }
2456   } else {
2457     Register in = locations->InAt(0).AsRegister<Register>();
2458     Register out = locations->Out().AsRegister<Register>();
2459 
2460     if (isR6) {
2461       __ ClzR6(TMP, in);
2462     } else {
2463       __ ClzR2(TMP, in);
2464     }
2465     __ LoadConst32(AT, 0x80000000);
2466     __ Srlv(AT, AT, TMP);  // Srlv shifts in the range of [0;31] bits (lower 5 bits of arg).
2467     __ And(out, AT, in);   // So this is required for 0 (=shift by 32).
2468   }
2469 }
2470 
2471 // int java.lang.Integer.highestOneBit(int)
VisitIntegerHighestOneBit(HInvoke * invoke)2472 void IntrinsicLocationsBuilderMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
2473   CreateIntToIntLocations(arena_, invoke);
2474 }
2475 
VisitIntegerHighestOneBit(HInvoke * invoke)2476 void IntrinsicCodeGeneratorMIPS::VisitIntegerHighestOneBit(HInvoke* invoke) {
2477   GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
2478 }
2479 
2480 // long java.lang.Long.highestOneBit(long)
VisitLongHighestOneBit(HInvoke * invoke)2481 void IntrinsicLocationsBuilderMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
2482   CreateIntToIntLocations(arena_, invoke, Location::kOutputOverlap);
2483 }
2484 
VisitLongHighestOneBit(HInvoke * invoke)2485 void IntrinsicCodeGeneratorMIPS::VisitLongHighestOneBit(HInvoke* invoke) {
2486   GenHighestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
2487 }
2488 
GenLowestOneBit(LocationSummary * locations,const Primitive::Type type,bool isR6,MipsAssembler * assembler)2489 static void GenLowestOneBit(LocationSummary* locations,
2490                             const Primitive::Type type,
2491                             bool isR6,
2492                             MipsAssembler* assembler) {
2493   DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
2494 
2495   if (type == Primitive::kPrimLong) {
2496     Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>();
2497     Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>();
2498     Register out_lo = locations->Out().AsRegisterPairLow<Register>();
2499     Register out_hi = locations->Out().AsRegisterPairHigh<Register>();
2500 
2501     __ Subu(TMP, ZERO, in_lo);
2502     __ And(out_lo, TMP, in_lo);
2503     __ Subu(TMP, ZERO, in_hi);
2504     __ And(out_hi, TMP, in_hi);
2505     if (isR6) {
2506       __ Seleqz(out_hi, out_hi, out_lo);
2507     } else {
2508       __ Movn(out_hi, ZERO, out_lo);
2509     }
2510   } else {
2511     Register in = locations->InAt(0).AsRegister<Register>();
2512     Register out = locations->Out().AsRegister<Register>();
2513 
2514     __ Subu(TMP, ZERO, in);
2515     __ And(out, TMP, in);
2516   }
2517 }
2518 
2519 // int java.lang.Integer.lowestOneBit(int)
VisitIntegerLowestOneBit(HInvoke * invoke)2520 void IntrinsicLocationsBuilderMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
2521   CreateIntToIntLocations(arena_, invoke);
2522 }
2523 
VisitIntegerLowestOneBit(HInvoke * invoke)2524 void IntrinsicCodeGeneratorMIPS::VisitIntegerLowestOneBit(HInvoke* invoke) {
2525   GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimInt, IsR6(), GetAssembler());
2526 }
2527 
2528 // long java.lang.Long.lowestOneBit(long)
VisitLongLowestOneBit(HInvoke * invoke)2529 void IntrinsicLocationsBuilderMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
2530   CreateIntToIntLocations(arena_, invoke);
2531 }
2532 
VisitLongLowestOneBit(HInvoke * invoke)2533 void IntrinsicCodeGeneratorMIPS::VisitLongLowestOneBit(HInvoke* invoke) {
2534   GenLowestOneBit(invoke->GetLocations(), Primitive::kPrimLong, IsR6(), GetAssembler());
2535 }
2536 
2537 // int java.lang.Math.round(float)
VisitMathRoundFloat(HInvoke * invoke)2538 void IntrinsicLocationsBuilderMIPS::VisitMathRoundFloat(HInvoke* invoke) {
2539   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2540                                                            LocationSummary::kNoCall,
2541                                                            kIntrinsified);
2542   locations->SetInAt(0, Location::RequiresFpuRegister());
2543   locations->AddTemp(Location::RequiresFpuRegister());
2544   locations->SetOut(Location::RequiresRegister());
2545 }
2546 
VisitMathRoundFloat(HInvoke * invoke)2547 void IntrinsicCodeGeneratorMIPS::VisitMathRoundFloat(HInvoke* invoke) {
2548   LocationSummary* locations = invoke->GetLocations();
2549   MipsAssembler* assembler = GetAssembler();
2550   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
2551   FRegister half = locations->GetTemp(0).AsFpuRegister<FRegister>();
2552   Register out = locations->Out().AsRegister<Register>();
2553 
2554   MipsLabel done;
2555   MipsLabel finite;
2556   MipsLabel add;
2557 
2558   // if (in.isNaN) {
2559   //   return 0;
2560   // }
2561   //
2562   // out = floor.w.s(in);
2563   //
2564   // /*
2565   //  * This "if" statement is only needed for the pre-R6 version of floor.w.s
2566   //  * which outputs Integer.MAX_VALUE for negative numbers with magnitudes
2567   //  * too large to fit in a 32-bit integer.
2568   //  *
2569   //  * Starting with MIPSR6, which always sets FCSR.NAN2008=1, negative
2570   //  * numbers which are too large to be represented in a 32-bit signed
2571   //  * integer will be processed by floor.w.s to output Integer.MIN_VALUE,
2572   //  * and will no longer be processed by this "if" statement.
2573   //  */
2574   // if (out == Integer.MAX_VALUE) {
2575   //   TMP = (in < 0.0f) ? 1 : 0;
2576   //   /*
2577   //    * If TMP is 1, then adding it to out will wrap its value from
2578   //    * Integer.MAX_VALUE to Integer.MIN_VALUE.
2579   //    */
2580   //   return out += TMP;
2581   // }
2582   //
2583   // /*
2584   //  * For negative values not handled by the previous "if" statement the
2585   //  * test here will correctly set the value of TMP.
2586   //  */
2587   // TMP = ((in - out) >= 0.5f) ? 1 : 0;
2588   // return out += TMP;
2589 
2590   // Test for NaN.
2591   if (IsR6()) {
2592     __ CmpUnS(FTMP, in, in);
2593   } else {
2594     __ CunS(in, in);
2595   }
2596 
2597   // Return zero for NaN.
2598   __ Move(out, ZERO);
2599   if (IsR6()) {
2600     __ Bc1nez(FTMP, &done);
2601   } else {
2602     __ Bc1t(&done);
2603   }
2604 
2605   // out = floor(in);
2606   __ FloorWS(FTMP, in);
2607   __ Mfc1(out, FTMP);
2608 
2609   if (!IsR6()) {
2610     __ LoadConst32(TMP, -1);
2611   }
2612 
2613   // TMP = (out = java.lang.Integer.MAX_VALUE) ? -1 : 0;
2614   __ LoadConst32(AT, std::numeric_limits<int32_t>::max());
2615   __ Bne(AT, out, &finite);
2616 
2617   __ Mtc1(ZERO, FTMP);
2618   if (IsR6()) {
2619     __ CmpLtS(FTMP, in, FTMP);
2620     __ Mfc1(TMP, FTMP);
2621   } else {
2622     __ ColtS(in, FTMP);
2623   }
2624 
2625   __ B(&add);
2626 
2627   __ Bind(&finite);
2628 
2629   // TMP = (0.5f <= (in - out)) ? -1 : 0;
2630   __ Cvtsw(FTMP, FTMP);  // Convert output of floor.w.s back to "float".
2631   __ LoadConst32(AT, bit_cast<int32_t, float>(0.5f));
2632   __ SubS(FTMP, in, FTMP);
2633   __ Mtc1(AT, half);
2634   if (IsR6()) {
2635     __ CmpLeS(FTMP, half, FTMP);
2636     __ Mfc1(TMP, FTMP);
2637   } else {
2638     __ ColeS(half, FTMP);
2639   }
2640 
2641   __ Bind(&add);
2642 
2643   if (!IsR6()) {
2644     __ Movf(TMP, ZERO);
2645   }
2646 
2647   // Return out -= TMP.
2648   __ Subu(out, out, TMP);
2649 
2650   __ Bind(&done);
2651 }
2652 
2653 // void java.lang.String.getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
VisitStringGetCharsNoCheck(HInvoke * invoke)2654 void IntrinsicLocationsBuilderMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2655   LocationSummary* locations = new (arena_) LocationSummary(invoke,
2656                                                             LocationSummary::kNoCall,
2657                                                             kIntrinsified);
2658   locations->SetInAt(0, Location::RequiresRegister());
2659   locations->SetInAt(1, Location::RequiresRegister());
2660   locations->SetInAt(2, Location::RequiresRegister());
2661   locations->SetInAt(3, Location::RequiresRegister());
2662   locations->SetInAt(4, Location::RequiresRegister());
2663 
2664   locations->AddTemp(Location::RequiresRegister());
2665   locations->AddTemp(Location::RequiresRegister());
2666   locations->AddTemp(Location::RequiresRegister());
2667 }
2668 
VisitStringGetCharsNoCheck(HInvoke * invoke)2669 void IntrinsicCodeGeneratorMIPS::VisitStringGetCharsNoCheck(HInvoke* invoke) {
2670   MipsAssembler* assembler = GetAssembler();
2671   LocationSummary* locations = invoke->GetLocations();
2672 
2673   // Check assumption that sizeof(Char) is 2 (used in scaling below).
2674   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
2675   DCHECK_EQ(char_size, 2u);
2676   const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
2677 
2678   Register srcObj = locations->InAt(0).AsRegister<Register>();
2679   Register srcBegin = locations->InAt(1).AsRegister<Register>();
2680   Register srcEnd = locations->InAt(2).AsRegister<Register>();
2681   Register dstObj = locations->InAt(3).AsRegister<Register>();
2682   Register dstBegin = locations->InAt(4).AsRegister<Register>();
2683 
2684   Register dstPtr = locations->GetTemp(0).AsRegister<Register>();
2685   Register srcPtr = locations->GetTemp(1).AsRegister<Register>();
2686   Register numChrs = locations->GetTemp(2).AsRegister<Register>();
2687 
2688   MipsLabel done;
2689   MipsLabel loop;
2690 
2691   // Location of data in char array buffer.
2692   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
2693 
2694   // Get offset of value field within a string object.
2695   const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
2696 
2697   __ Beq(srcEnd, srcBegin, &done);  // No characters to move.
2698 
2699   // Calculate number of characters to be copied.
2700   __ Subu(numChrs, srcEnd, srcBegin);
2701 
2702   // Calculate destination address.
2703   __ Addiu(dstPtr, dstObj, data_offset);
2704   __ ShiftAndAdd(dstPtr, dstBegin, dstPtr, char_shift);
2705 
2706   if (mirror::kUseStringCompression) {
2707     MipsLabel uncompressed_copy, compressed_loop;
2708     const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
2709     // Load count field and extract compression flag.
2710     __ LoadFromOffset(kLoadWord, TMP, srcObj, count_offset);
2711     __ Sll(TMP, TMP, 31);
2712 
2713     // If string is uncompressed, use uncompressed path.
2714     __ Bnez(TMP, &uncompressed_copy);
2715 
2716     // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
2717     __ Addu(srcPtr, srcObj, srcBegin);
2718     __ Bind(&compressed_loop);
2719     __ LoadFromOffset(kLoadUnsignedByte, TMP, srcPtr, value_offset);
2720     __ StoreToOffset(kStoreHalfword, TMP, dstPtr, 0);
2721     __ Addiu(numChrs, numChrs, -1);
2722     __ Addiu(srcPtr, srcPtr, 1);
2723     __ Addiu(dstPtr, dstPtr, 2);
2724     __ Bnez(numChrs, &compressed_loop);
2725 
2726     __ B(&done);
2727     __ Bind(&uncompressed_copy);
2728   }
2729 
2730   // Calculate source address.
2731   __ Addiu(srcPtr, srcObj, value_offset);
2732   __ ShiftAndAdd(srcPtr, srcBegin, srcPtr, char_shift);
2733 
2734   __ Bind(&loop);
2735   __ Lh(AT, srcPtr, 0);
2736   __ Addiu(numChrs, numChrs, -1);
2737   __ Addiu(srcPtr, srcPtr, char_size);
2738   __ Sh(AT, dstPtr, 0);
2739   __ Addiu(dstPtr, dstPtr, char_size);
2740   __ Bnez(numChrs, &loop);
2741 
2742   __ Bind(&done);
2743 }
2744 
CreateFPToFPCallLocations(ArenaAllocator * arena,HInvoke * invoke)2745 static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
2746   LocationSummary* locations = new (arena) LocationSummary(invoke,
2747                                                            LocationSummary::kCallOnMainOnly,
2748                                                            kIntrinsified);
2749   InvokeRuntimeCallingConvention calling_convention;
2750 
2751   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2752   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
2753 }
2754 
CreateFPFPToFPCallLocations(ArenaAllocator * arena,HInvoke * invoke)2755 static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
2756   LocationSummary* locations = new (arena) LocationSummary(invoke,
2757                                                            LocationSummary::kCallOnMainOnly,
2758                                                            kIntrinsified);
2759   InvokeRuntimeCallingConvention calling_convention;
2760 
2761   locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
2762   locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
2763   locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimDouble));
2764 }
2765 
GenFPToFPCall(HInvoke * invoke,CodeGeneratorMIPS * codegen,QuickEntrypointEnum entry)2766 static void GenFPToFPCall(HInvoke* invoke, CodeGeneratorMIPS* codegen, QuickEntrypointEnum entry) {
2767   LocationSummary* locations = invoke->GetLocations();
2768   FRegister in = locations->InAt(0).AsFpuRegister<FRegister>();
2769   DCHECK_EQ(in, F12);
2770   FRegister out = locations->Out().AsFpuRegister<FRegister>();
2771   DCHECK_EQ(out, F0);
2772 
2773   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2774 }
2775 
GenFPFPToFPCall(HInvoke * invoke,CodeGeneratorMIPS * codegen,QuickEntrypointEnum entry)2776 static void GenFPFPToFPCall(HInvoke* invoke,
2777                             CodeGeneratorMIPS* codegen,
2778                             QuickEntrypointEnum entry) {
2779   LocationSummary* locations = invoke->GetLocations();
2780   FRegister in0 = locations->InAt(0).AsFpuRegister<FRegister>();
2781   DCHECK_EQ(in0, F12);
2782   FRegister in1 = locations->InAt(1).AsFpuRegister<FRegister>();
2783   DCHECK_EQ(in1, F14);
2784   FRegister out = locations->Out().AsFpuRegister<FRegister>();
2785   DCHECK_EQ(out, F0);
2786 
2787   codegen->InvokeRuntime(entry, invoke, invoke->GetDexPc());
2788 }
2789 
2790 // static double java.lang.Math.cos(double a)
VisitMathCos(HInvoke * invoke)2791 void IntrinsicLocationsBuilderMIPS::VisitMathCos(HInvoke* invoke) {
2792   CreateFPToFPCallLocations(arena_, invoke);
2793 }
2794 
VisitMathCos(HInvoke * invoke)2795 void IntrinsicCodeGeneratorMIPS::VisitMathCos(HInvoke* invoke) {
2796   GenFPToFPCall(invoke, codegen_, kQuickCos);
2797 }
2798 
2799 // static double java.lang.Math.sin(double a)
VisitMathSin(HInvoke * invoke)2800 void IntrinsicLocationsBuilderMIPS::VisitMathSin(HInvoke* invoke) {
2801   CreateFPToFPCallLocations(arena_, invoke);
2802 }
2803 
VisitMathSin(HInvoke * invoke)2804 void IntrinsicCodeGeneratorMIPS::VisitMathSin(HInvoke* invoke) {
2805   GenFPToFPCall(invoke, codegen_, kQuickSin);
2806 }
2807 
2808 // static double java.lang.Math.acos(double a)
VisitMathAcos(HInvoke * invoke)2809 void IntrinsicLocationsBuilderMIPS::VisitMathAcos(HInvoke* invoke) {
2810   CreateFPToFPCallLocations(arena_, invoke);
2811 }
2812 
VisitMathAcos(HInvoke * invoke)2813 void IntrinsicCodeGeneratorMIPS::VisitMathAcos(HInvoke* invoke) {
2814   GenFPToFPCall(invoke, codegen_, kQuickAcos);
2815 }
2816 
2817 // static double java.lang.Math.asin(double a)
VisitMathAsin(HInvoke * invoke)2818 void IntrinsicLocationsBuilderMIPS::VisitMathAsin(HInvoke* invoke) {
2819   CreateFPToFPCallLocations(arena_, invoke);
2820 }
2821 
VisitMathAsin(HInvoke * invoke)2822 void IntrinsicCodeGeneratorMIPS::VisitMathAsin(HInvoke* invoke) {
2823   GenFPToFPCall(invoke, codegen_, kQuickAsin);
2824 }
2825 
2826 // static double java.lang.Math.atan(double a)
VisitMathAtan(HInvoke * invoke)2827 void IntrinsicLocationsBuilderMIPS::VisitMathAtan(HInvoke* invoke) {
2828   CreateFPToFPCallLocations(arena_, invoke);
2829 }
2830 
VisitMathAtan(HInvoke * invoke)2831 void IntrinsicCodeGeneratorMIPS::VisitMathAtan(HInvoke* invoke) {
2832   GenFPToFPCall(invoke, codegen_, kQuickAtan);
2833 }
2834 
2835 // static double java.lang.Math.atan2(double y, double x)
VisitMathAtan2(HInvoke * invoke)2836 void IntrinsicLocationsBuilderMIPS::VisitMathAtan2(HInvoke* invoke) {
2837   CreateFPFPToFPCallLocations(arena_, invoke);
2838 }
2839 
VisitMathAtan2(HInvoke * invoke)2840 void IntrinsicCodeGeneratorMIPS::VisitMathAtan2(HInvoke* invoke) {
2841   GenFPFPToFPCall(invoke, codegen_, kQuickAtan2);
2842 }
2843 
2844 // static double java.lang.Math.cbrt(double a)
VisitMathCbrt(HInvoke * invoke)2845 void IntrinsicLocationsBuilderMIPS::VisitMathCbrt(HInvoke* invoke) {
2846   CreateFPToFPCallLocations(arena_, invoke);
2847 }
2848 
VisitMathCbrt(HInvoke * invoke)2849 void IntrinsicCodeGeneratorMIPS::VisitMathCbrt(HInvoke* invoke) {
2850   GenFPToFPCall(invoke, codegen_, kQuickCbrt);
2851 }
2852 
2853 // static double java.lang.Math.cosh(double x)
VisitMathCosh(HInvoke * invoke)2854 void IntrinsicLocationsBuilderMIPS::VisitMathCosh(HInvoke* invoke) {
2855   CreateFPToFPCallLocations(arena_, invoke);
2856 }
2857 
VisitMathCosh(HInvoke * invoke)2858 void IntrinsicCodeGeneratorMIPS::VisitMathCosh(HInvoke* invoke) {
2859   GenFPToFPCall(invoke, codegen_, kQuickCosh);
2860 }
2861 
2862 // static double java.lang.Math.exp(double a)
VisitMathExp(HInvoke * invoke)2863 void IntrinsicLocationsBuilderMIPS::VisitMathExp(HInvoke* invoke) {
2864   CreateFPToFPCallLocations(arena_, invoke);
2865 }
2866 
VisitMathExp(HInvoke * invoke)2867 void IntrinsicCodeGeneratorMIPS::VisitMathExp(HInvoke* invoke) {
2868   GenFPToFPCall(invoke, codegen_, kQuickExp);
2869 }
2870 
2871 // static double java.lang.Math.expm1(double x)
VisitMathExpm1(HInvoke * invoke)2872 void IntrinsicLocationsBuilderMIPS::VisitMathExpm1(HInvoke* invoke) {
2873   CreateFPToFPCallLocations(arena_, invoke);
2874 }
2875 
VisitMathExpm1(HInvoke * invoke)2876 void IntrinsicCodeGeneratorMIPS::VisitMathExpm1(HInvoke* invoke) {
2877   GenFPToFPCall(invoke, codegen_, kQuickExpm1);
2878 }
2879 
2880 // static double java.lang.Math.hypot(double x, double y)
VisitMathHypot(HInvoke * invoke)2881 void IntrinsicLocationsBuilderMIPS::VisitMathHypot(HInvoke* invoke) {
2882   CreateFPFPToFPCallLocations(arena_, invoke);
2883 }
2884 
VisitMathHypot(HInvoke * invoke)2885 void IntrinsicCodeGeneratorMIPS::VisitMathHypot(HInvoke* invoke) {
2886   GenFPFPToFPCall(invoke, codegen_, kQuickHypot);
2887 }
2888 
2889 // static double java.lang.Math.log(double a)
VisitMathLog(HInvoke * invoke)2890 void IntrinsicLocationsBuilderMIPS::VisitMathLog(HInvoke* invoke) {
2891   CreateFPToFPCallLocations(arena_, invoke);
2892 }
2893 
VisitMathLog(HInvoke * invoke)2894 void IntrinsicCodeGeneratorMIPS::VisitMathLog(HInvoke* invoke) {
2895   GenFPToFPCall(invoke, codegen_, kQuickLog);
2896 }
2897 
2898 // static double java.lang.Math.log10(double x)
VisitMathLog10(HInvoke * invoke)2899 void IntrinsicLocationsBuilderMIPS::VisitMathLog10(HInvoke* invoke) {
2900   CreateFPToFPCallLocations(arena_, invoke);
2901 }
2902 
VisitMathLog10(HInvoke * invoke)2903 void IntrinsicCodeGeneratorMIPS::VisitMathLog10(HInvoke* invoke) {
2904   GenFPToFPCall(invoke, codegen_, kQuickLog10);
2905 }
2906 
2907 // static double java.lang.Math.nextAfter(double start, double direction)
VisitMathNextAfter(HInvoke * invoke)2908 void IntrinsicLocationsBuilderMIPS::VisitMathNextAfter(HInvoke* invoke) {
2909   CreateFPFPToFPCallLocations(arena_, invoke);
2910 }
2911 
VisitMathNextAfter(HInvoke * invoke)2912 void IntrinsicCodeGeneratorMIPS::VisitMathNextAfter(HInvoke* invoke) {
2913   GenFPFPToFPCall(invoke, codegen_, kQuickNextAfter);
2914 }
2915 
2916 // static double java.lang.Math.sinh(double x)
VisitMathSinh(HInvoke * invoke)2917 void IntrinsicLocationsBuilderMIPS::VisitMathSinh(HInvoke* invoke) {
2918   CreateFPToFPCallLocations(arena_, invoke);
2919 }
2920 
VisitMathSinh(HInvoke * invoke)2921 void IntrinsicCodeGeneratorMIPS::VisitMathSinh(HInvoke* invoke) {
2922   GenFPToFPCall(invoke, codegen_, kQuickSinh);
2923 }
2924 
2925 // static double java.lang.Math.tan(double a)
VisitMathTan(HInvoke * invoke)2926 void IntrinsicLocationsBuilderMIPS::VisitMathTan(HInvoke* invoke) {
2927   CreateFPToFPCallLocations(arena_, invoke);
2928 }
2929 
VisitMathTan(HInvoke * invoke)2930 void IntrinsicCodeGeneratorMIPS::VisitMathTan(HInvoke* invoke) {
2931   GenFPToFPCall(invoke, codegen_, kQuickTan);
2932 }
2933 
2934 // static double java.lang.Math.tanh(double x)
VisitMathTanh(HInvoke * invoke)2935 void IntrinsicLocationsBuilderMIPS::VisitMathTanh(HInvoke* invoke) {
2936   CreateFPToFPCallLocations(arena_, invoke);
2937 }
2938 
VisitMathTanh(HInvoke * invoke)2939 void IntrinsicCodeGeneratorMIPS::VisitMathTanh(HInvoke* invoke) {
2940   GenFPToFPCall(invoke, codegen_, kQuickTanh);
2941 }
2942 
2943 // static void java.lang.System.arraycopy(Object src, int srcPos,
2944 //                                        Object dest, int destPos,
2945 //                                        int length)
VisitSystemArrayCopyChar(HInvoke * invoke)2946 void IntrinsicLocationsBuilderMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
2947   HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
2948   HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
2949   HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
2950 
2951   // As long as we are checking, we might as well check to see if the src and dest
2952   // positions are >= 0.
2953   if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
2954       (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
2955     // We will have to fail anyways.
2956     return;
2957   }
2958 
2959   // And since we are already checking, check the length too.
2960   if (length != nullptr) {
2961     int32_t len = length->GetValue();
2962     if (len < 0) {
2963       // Just call as normal.
2964       return;
2965     }
2966   }
2967 
2968   // Okay, it is safe to generate inline code.
2969   LocationSummary* locations =
2970       new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
2971   // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
2972   locations->SetInAt(0, Location::RequiresRegister());
2973   locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
2974   locations->SetInAt(2, Location::RequiresRegister());
2975   locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
2976   locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
2977 
2978   locations->AddTemp(Location::RequiresRegister());
2979   locations->AddTemp(Location::RequiresRegister());
2980   locations->AddTemp(Location::RequiresRegister());
2981 }
2982 
2983 // Utility routine to verify that "length(input) - pos >= length"
EnoughItems(MipsAssembler * assembler,Register length_input_minus_pos,Location length,SlowPathCodeMIPS * slow_path)2984 static void EnoughItems(MipsAssembler* assembler,
2985                         Register length_input_minus_pos,
2986                         Location length,
2987                         SlowPathCodeMIPS* slow_path) {
2988   if (length.IsConstant()) {
2989     int32_t length_constant = length.GetConstant()->AsIntConstant()->GetValue();
2990 
2991     if (IsInt<16>(length_constant)) {
2992       __ Slti(TMP, length_input_minus_pos, length_constant);
2993       __ Bnez(TMP, slow_path->GetEntryLabel());
2994     } else {
2995       __ LoadConst32(TMP, length_constant);
2996       __ Blt(length_input_minus_pos, TMP, slow_path->GetEntryLabel());
2997     }
2998   } else {
2999     __ Blt(length_input_minus_pos, length.AsRegister<Register>(), slow_path->GetEntryLabel());
3000   }
3001 }
3002 
CheckPosition(MipsAssembler * assembler,Location pos,Register input,Location length,SlowPathCodeMIPS * slow_path,bool length_is_input_length=false)3003 static void CheckPosition(MipsAssembler* assembler,
3004                           Location pos,
3005                           Register input,
3006                           Location length,
3007                           SlowPathCodeMIPS* slow_path,
3008                           bool length_is_input_length = false) {
3009   // Where is the length in the Array?
3010   const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
3011 
3012   // Calculate length(input) - pos.
3013   if (pos.IsConstant()) {
3014     int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
3015     if (pos_const == 0) {
3016       if (!length_is_input_length) {
3017         // Check that length(input) >= length.
3018         __ LoadFromOffset(kLoadWord, AT, input, length_offset);
3019         EnoughItems(assembler, AT, length, slow_path);
3020       }
3021     } else {
3022       // Check that (length(input) - pos) >= zero.
3023       __ LoadFromOffset(kLoadWord, AT, input, length_offset);
3024       DCHECK_GT(pos_const, 0);
3025       __ Addiu32(AT, AT, -pos_const, TMP);
3026       __ Bltz(AT, slow_path->GetEntryLabel());
3027 
3028       // Verify that (length(input) - pos) >= length.
3029       EnoughItems(assembler, AT, length, slow_path);
3030     }
3031   } else if (length_is_input_length) {
3032     // The only way the copy can succeed is if pos is zero.
3033     Register pos_reg = pos.AsRegister<Register>();
3034     __ Bnez(pos_reg, slow_path->GetEntryLabel());
3035   } else {
3036     // Verify that pos >= 0.
3037     Register pos_reg = pos.AsRegister<Register>();
3038     __ Bltz(pos_reg, slow_path->GetEntryLabel());
3039 
3040     // Check that (length(input) - pos) >= zero.
3041     __ LoadFromOffset(kLoadWord, AT, input, length_offset);
3042     __ Subu(AT, AT, pos_reg);
3043     __ Bltz(AT, slow_path->GetEntryLabel());
3044 
3045     // Verify that (length(input) - pos) >= length.
3046     EnoughItems(assembler, AT, length, slow_path);
3047   }
3048 }
3049 
VisitSystemArrayCopyChar(HInvoke * invoke)3050 void IntrinsicCodeGeneratorMIPS::VisitSystemArrayCopyChar(HInvoke* invoke) {
3051   MipsAssembler* assembler = GetAssembler();
3052   LocationSummary* locations = invoke->GetLocations();
3053 
3054   Register src = locations->InAt(0).AsRegister<Register>();
3055   Location src_pos = locations->InAt(1);
3056   Register dest = locations->InAt(2).AsRegister<Register>();
3057   Location dest_pos = locations->InAt(3);
3058   Location length = locations->InAt(4);
3059 
3060   MipsLabel loop;
3061 
3062   Register dest_base = locations->GetTemp(0).AsRegister<Register>();
3063   Register src_base = locations->GetTemp(1).AsRegister<Register>();
3064   Register count = locations->GetTemp(2).AsRegister<Register>();
3065 
3066   SlowPathCodeMIPS* slow_path = new (GetAllocator()) IntrinsicSlowPathMIPS(invoke);
3067   codegen_->AddSlowPath(slow_path);
3068 
3069   // Bail out if the source and destination are the same (to handle overlap).
3070   __ Beq(src, dest, slow_path->GetEntryLabel());
3071 
3072   // Bail out if the source is null.
3073   __ Beqz(src, slow_path->GetEntryLabel());
3074 
3075   // Bail out if the destination is null.
3076   __ Beqz(dest, slow_path->GetEntryLabel());
3077 
3078   // Load length into register for count.
3079   if (length.IsConstant()) {
3080     __ LoadConst32(count, length.GetConstant()->AsIntConstant()->GetValue());
3081   } else {
3082     // If the length is negative, bail out.
3083     // We have already checked in the LocationsBuilder for the constant case.
3084     __ Bltz(length.AsRegister<Register>(), slow_path->GetEntryLabel());
3085 
3086     __ Move(count, length.AsRegister<Register>());
3087   }
3088 
3089   // Validity checks: source.
3090   CheckPosition(assembler, src_pos, src, Location::RegisterLocation(count), slow_path);
3091 
3092   // Validity checks: dest.
3093   CheckPosition(assembler, dest_pos, dest, Location::RegisterLocation(count), slow_path);
3094 
3095   // If count is zero, we're done.
3096   __ Beqz(count, slow_path->GetExitLabel());
3097 
3098   // Okay, everything checks out.  Finally time to do the copy.
3099   // Check assumption that sizeof(Char) is 2 (used in scaling below).
3100   const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
3101   DCHECK_EQ(char_size, 2u);
3102 
3103   const size_t char_shift = Primitive::ComponentSizeShift(Primitive::kPrimChar);
3104 
3105   const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
3106 
3107   // Calculate source and destination addresses.
3108   if (src_pos.IsConstant()) {
3109     int32_t src_pos_const = src_pos.GetConstant()->AsIntConstant()->GetValue();
3110 
3111     __ Addiu32(src_base, src, data_offset + char_size * src_pos_const, TMP);
3112   } else {
3113     __ Addiu32(src_base, src, data_offset, TMP);
3114     __ ShiftAndAdd(src_base, src_pos.AsRegister<Register>(), src_base, char_shift);
3115   }
3116   if (dest_pos.IsConstant()) {
3117     int32_t dest_pos_const = dest_pos.GetConstant()->AsIntConstant()->GetValue();
3118 
3119     __ Addiu32(dest_base, dest, data_offset + char_size * dest_pos_const, TMP);
3120   } else {
3121     __ Addiu32(dest_base, dest, data_offset, TMP);
3122     __ ShiftAndAdd(dest_base, dest_pos.AsRegister<Register>(), dest_base, char_shift);
3123   }
3124 
3125   __ Bind(&loop);
3126   __ Lh(TMP, src_base, 0);
3127   __ Addiu(src_base, src_base, char_size);
3128   __ Addiu(count, count, -1);
3129   __ Sh(TMP, dest_base, 0);
3130   __ Addiu(dest_base, dest_base, char_size);
3131   __ Bnez(count, &loop);
3132 
3133   __ Bind(slow_path->GetExitLabel());
3134 }
3135 
3136 // Unimplemented intrinsics.
3137 
3138 UNIMPLEMENTED_INTRINSIC(MIPS, MathCeil)
3139 UNIMPLEMENTED_INTRINSIC(MIPS, MathFloor)
3140 UNIMPLEMENTED_INTRINSIC(MIPS, MathRint)
3141 UNIMPLEMENTED_INTRINSIC(MIPS, MathRoundDouble)
3142 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetLongVolatile);
3143 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafePutLongVolatile);
3144 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeCASLong)
3145 
3146 UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
3147 UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
3148 
3149 UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
3150 UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
3151 UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend);
3152 UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferLength);
3153 UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferToString);
3154 UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderAppend);
3155 UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderLength);
3156 UNIMPLEMENTED_INTRINSIC(MIPS, StringBuilderToString);
3157 
3158 // 1.8.
3159 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddInt)
3160 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndAddLong)
3161 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetInt)
3162 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetLong)
3163 UNIMPLEMENTED_INTRINSIC(MIPS, UnsafeGetAndSetObject)
3164 
3165 UNIMPLEMENTED_INTRINSIC(MIPS, IntegerValueOf)
3166 
3167 UNREACHABLE_INTRINSICS(MIPS)
3168 
3169 #undef __
3170 
3171 }  // namespace mips
3172 }  // namespace art
3173