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