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