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