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