intrinsics_arm.cc revision e401d146407d61eeb99f8d6176b2ac13c4df1e33
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_arm.h" 18 19#include "arch/arm/instruction_set_features_arm.h" 20#include "art_method.h" 21#include "code_generator_arm.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/arm/assembler_arm.h" 28 29namespace art { 30 31namespace arm { 32 33ArmAssembler* IntrinsicCodeGeneratorARM::GetAssembler() { 34 return codegen_->GetAssembler(); 35} 36 37ArenaAllocator* IntrinsicCodeGeneratorARM::GetAllocator() { 38 return codegen_->GetGraph()->GetArena(); 39} 40 41#define __ codegen->GetAssembler()-> 42 43static void MoveFromReturnRegister(Location trg, Primitive::Type type, CodeGeneratorARM* codegen) { 44 if (!trg.IsValid()) { 45 DCHECK(type == Primitive::kPrimVoid); 46 return; 47 } 48 49 DCHECK_NE(type, Primitive::kPrimVoid); 50 51 if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) { 52 if (type == Primitive::kPrimLong) { 53 Register trg_reg_lo = trg.AsRegisterPairLow<Register>(); 54 Register trg_reg_hi = trg.AsRegisterPairHigh<Register>(); 55 Register res_reg_lo = R0; 56 Register res_reg_hi = R1; 57 if (trg_reg_lo != res_reg_hi) { 58 if (trg_reg_lo != res_reg_lo) { 59 __ mov(trg_reg_lo, ShifterOperand(res_reg_lo)); 60 __ mov(trg_reg_hi, ShifterOperand(res_reg_hi)); 61 } else { 62 DCHECK_EQ(trg_reg_lo + 1, trg_reg_hi); 63 } 64 } else { 65 __ mov(trg_reg_hi, ShifterOperand(res_reg_hi)); 66 __ mov(trg_reg_lo, ShifterOperand(res_reg_lo)); 67 } 68 } else { 69 Register trg_reg = trg.AsRegister<Register>(); 70 Register res_reg = R0; 71 if (trg_reg != res_reg) { 72 __ mov(trg_reg, ShifterOperand(res_reg)); 73 } 74 } 75 } else { 76 UNIMPLEMENTED(FATAL) << "Floating-point return."; 77 } 78} 79 80static void MoveArguments(HInvoke* invoke, CodeGeneratorARM* codegen) { 81 InvokeDexCallingConventionVisitorARM calling_convention_visitor; 82 IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor); 83} 84 85// Slow-path for fallback (calling the managed code to handle the intrinsic) in an intrinsified 86// call. This will copy the arguments into the positions for a regular call. 87// 88// Note: The actual parameters are required to be in the locations given by the invoke's location 89// summary. If an intrinsic modifies those locations before a slowpath call, they must be 90// restored! 91class IntrinsicSlowPathARM : public SlowPathCodeARM { 92 public: 93 explicit IntrinsicSlowPathARM(HInvoke* invoke) : invoke_(invoke) { } 94 95 void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE { 96 CodeGeneratorARM* codegen = down_cast<CodeGeneratorARM*>(codegen_in); 97 __ Bind(GetEntryLabel()); 98 99 SaveLiveRegisters(codegen, invoke_->GetLocations()); 100 101 MoveArguments(invoke_, codegen); 102 103 if (invoke_->IsInvokeStaticOrDirect()) { 104 codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), kArtMethodRegister); 105 RecordPcInfo(codegen, invoke_, invoke_->GetDexPc()); 106 } else { 107 UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented"; 108 UNREACHABLE(); 109 } 110 111 // Copy the result back to the expected output. 112 Location out = invoke_->GetLocations()->Out(); 113 if (out.IsValid()) { 114 DCHECK(out.IsRegister()); // TODO: Replace this when we support output in memory. 115 DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg())); 116 MoveFromReturnRegister(out, invoke_->GetType(), codegen); 117 } 118 119 RestoreLiveRegisters(codegen, invoke_->GetLocations()); 120 __ b(GetExitLabel()); 121 } 122 123 private: 124 // The instruction where this slow path is happening. 125 HInvoke* const invoke_; 126 127 DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathARM); 128}; 129 130#undef __ 131 132bool IntrinsicLocationsBuilderARM::TryDispatch(HInvoke* invoke) { 133 Dispatch(invoke); 134 LocationSummary* res = invoke->GetLocations(); 135 return res != nullptr && res->Intrinsified(); 136} 137 138#define __ assembler-> 139 140static void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 141 LocationSummary* locations = new (arena) LocationSummary(invoke, 142 LocationSummary::kNoCall, 143 kIntrinsified); 144 locations->SetInAt(0, Location::RequiresFpuRegister()); 145 locations->SetOut(Location::RequiresRegister()); 146} 147 148static void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { 149 LocationSummary* locations = new (arena) LocationSummary(invoke, 150 LocationSummary::kNoCall, 151 kIntrinsified); 152 locations->SetInAt(0, Location::RequiresRegister()); 153 locations->SetOut(Location::RequiresFpuRegister()); 154} 155 156static void MoveFPToInt(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 157 Location input = locations->InAt(0); 158 Location output = locations->Out(); 159 if (is64bit) { 160 __ vmovrrd(output.AsRegisterPairLow<Register>(), 161 output.AsRegisterPairHigh<Register>(), 162 FromLowSToD(input.AsFpuRegisterPairLow<SRegister>())); 163 } else { 164 __ vmovrs(output.AsRegister<Register>(), input.AsFpuRegister<SRegister>()); 165 } 166} 167 168static void MoveIntToFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 169 Location input = locations->InAt(0); 170 Location output = locations->Out(); 171 if (is64bit) { 172 __ vmovdrr(FromLowSToD(output.AsFpuRegisterPairLow<SRegister>()), 173 input.AsRegisterPairLow<Register>(), 174 input.AsRegisterPairHigh<Register>()); 175 } else { 176 __ vmovsr(output.AsFpuRegister<SRegister>(), input.AsRegister<Register>()); 177 } 178} 179 180void IntrinsicLocationsBuilderARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { 181 CreateFPToIntLocations(arena_, invoke); 182} 183void IntrinsicLocationsBuilderARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) { 184 CreateIntToFPLocations(arena_, invoke); 185} 186 187void IntrinsicCodeGeneratorARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { 188 MoveFPToInt(invoke->GetLocations(), true, GetAssembler()); 189} 190void IntrinsicCodeGeneratorARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) { 191 MoveIntToFP(invoke->GetLocations(), true, GetAssembler()); 192} 193 194void IntrinsicLocationsBuilderARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { 195 CreateFPToIntLocations(arena_, invoke); 196} 197void IntrinsicLocationsBuilderARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { 198 CreateIntToFPLocations(arena_, invoke); 199} 200 201void IntrinsicCodeGeneratorARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { 202 MoveFPToInt(invoke->GetLocations(), false, GetAssembler()); 203} 204void IntrinsicCodeGeneratorARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { 205 MoveIntToFP(invoke->GetLocations(), false, GetAssembler()); 206} 207 208static void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 209 LocationSummary* locations = new (arena) LocationSummary(invoke, 210 LocationSummary::kNoCall, 211 kIntrinsified); 212 locations->SetInAt(0, Location::RequiresRegister()); 213 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 214} 215 216static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { 217 LocationSummary* locations = new (arena) LocationSummary(invoke, 218 LocationSummary::kNoCall, 219 kIntrinsified); 220 locations->SetInAt(0, Location::RequiresFpuRegister()); 221 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 222} 223 224static void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 225 Location in = locations->InAt(0); 226 Location out = locations->Out(); 227 228 if (is64bit) { 229 __ vabsd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 230 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 231 } else { 232 __ vabss(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>()); 233 } 234} 235 236void IntrinsicLocationsBuilderARM::VisitMathAbsDouble(HInvoke* invoke) { 237 CreateFPToFPLocations(arena_, invoke); 238} 239 240void IntrinsicCodeGeneratorARM::VisitMathAbsDouble(HInvoke* invoke) { 241 MathAbsFP(invoke->GetLocations(), true, GetAssembler()); 242} 243 244void IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) { 245 CreateFPToFPLocations(arena_, invoke); 246} 247 248void IntrinsicCodeGeneratorARM::VisitMathAbsFloat(HInvoke* invoke) { 249 MathAbsFP(invoke->GetLocations(), false, GetAssembler()); 250} 251 252static void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) { 253 LocationSummary* locations = new (arena) LocationSummary(invoke, 254 LocationSummary::kNoCall, 255 kIntrinsified); 256 locations->SetInAt(0, Location::RequiresRegister()); 257 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 258 259 locations->AddTemp(Location::RequiresRegister()); 260} 261 262static void GenAbsInteger(LocationSummary* locations, 263 bool is64bit, 264 ArmAssembler* assembler) { 265 Location in = locations->InAt(0); 266 Location output = locations->Out(); 267 268 Register mask = locations->GetTemp(0).AsRegister<Register>(); 269 270 if (is64bit) { 271 Register in_reg_lo = in.AsRegisterPairLow<Register>(); 272 Register in_reg_hi = in.AsRegisterPairHigh<Register>(); 273 Register out_reg_lo = output.AsRegisterPairLow<Register>(); 274 Register out_reg_hi = output.AsRegisterPairHigh<Register>(); 275 276 DCHECK_NE(out_reg_lo, in_reg_hi) << "Diagonal overlap unexpected."; 277 278 __ Asr(mask, in_reg_hi, 31); 279 __ adds(out_reg_lo, in_reg_lo, ShifterOperand(mask)); 280 __ adc(out_reg_hi, in_reg_hi, ShifterOperand(mask)); 281 __ eor(out_reg_lo, mask, ShifterOperand(out_reg_lo)); 282 __ eor(out_reg_hi, mask, ShifterOperand(out_reg_hi)); 283 } else { 284 Register in_reg = in.AsRegister<Register>(); 285 Register out_reg = output.AsRegister<Register>(); 286 287 __ Asr(mask, in_reg, 31); 288 __ add(out_reg, in_reg, ShifterOperand(mask)); 289 __ eor(out_reg, mask, ShifterOperand(out_reg)); 290 } 291} 292 293void IntrinsicLocationsBuilderARM::VisitMathAbsInt(HInvoke* invoke) { 294 CreateIntToIntPlusTemp(arena_, invoke); 295} 296 297void IntrinsicCodeGeneratorARM::VisitMathAbsInt(HInvoke* invoke) { 298 GenAbsInteger(invoke->GetLocations(), false, GetAssembler()); 299} 300 301 302void IntrinsicLocationsBuilderARM::VisitMathAbsLong(HInvoke* invoke) { 303 CreateIntToIntPlusTemp(arena_, invoke); 304} 305 306void IntrinsicCodeGeneratorARM::VisitMathAbsLong(HInvoke* invoke) { 307 GenAbsInteger(invoke->GetLocations(), true, GetAssembler()); 308} 309 310static void GenMinMax(LocationSummary* locations, 311 bool is_min, 312 ArmAssembler* assembler) { 313 Register op1 = locations->InAt(0).AsRegister<Register>(); 314 Register op2 = locations->InAt(1).AsRegister<Register>(); 315 Register out = locations->Out().AsRegister<Register>(); 316 317 __ cmp(op1, ShifterOperand(op2)); 318 319 __ it((is_min) ? Condition::LT : Condition::GT, kItElse); 320 __ mov(out, ShifterOperand(op1), is_min ? Condition::LT : Condition::GT); 321 __ mov(out, ShifterOperand(op2), is_min ? Condition::GE : Condition::LE); 322} 323 324static void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 325 LocationSummary* locations = new (arena) LocationSummary(invoke, 326 LocationSummary::kNoCall, 327 kIntrinsified); 328 locations->SetInAt(0, Location::RequiresRegister()); 329 locations->SetInAt(1, Location::RequiresRegister()); 330 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 331} 332 333void IntrinsicLocationsBuilderARM::VisitMathMinIntInt(HInvoke* invoke) { 334 CreateIntIntToIntLocations(arena_, invoke); 335} 336 337void IntrinsicCodeGeneratorARM::VisitMathMinIntInt(HInvoke* invoke) { 338 GenMinMax(invoke->GetLocations(), true, GetAssembler()); 339} 340 341void IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) { 342 CreateIntIntToIntLocations(arena_, invoke); 343} 344 345void IntrinsicCodeGeneratorARM::VisitMathMaxIntInt(HInvoke* invoke) { 346 GenMinMax(invoke->GetLocations(), false, GetAssembler()); 347} 348 349void IntrinsicLocationsBuilderARM::VisitMathSqrt(HInvoke* invoke) { 350 CreateFPToFPLocations(arena_, invoke); 351} 352 353void IntrinsicCodeGeneratorARM::VisitMathSqrt(HInvoke* invoke) { 354 LocationSummary* locations = invoke->GetLocations(); 355 ArmAssembler* assembler = GetAssembler(); 356 __ vsqrtd(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()), 357 FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>())); 358} 359 360void IntrinsicLocationsBuilderARM::VisitMemoryPeekByte(HInvoke* invoke) { 361 CreateIntToIntLocations(arena_, invoke); 362} 363 364void IntrinsicCodeGeneratorARM::VisitMemoryPeekByte(HInvoke* invoke) { 365 ArmAssembler* assembler = GetAssembler(); 366 // Ignore upper 4B of long address. 367 __ ldrsb(invoke->GetLocations()->Out().AsRegister<Register>(), 368 Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 369} 370 371void IntrinsicLocationsBuilderARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 372 CreateIntToIntLocations(arena_, invoke); 373} 374 375void IntrinsicCodeGeneratorARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 376 ArmAssembler* assembler = GetAssembler(); 377 // Ignore upper 4B of long address. 378 __ ldr(invoke->GetLocations()->Out().AsRegister<Register>(), 379 Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 380} 381 382void IntrinsicLocationsBuilderARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 383 CreateIntToIntLocations(arena_, invoke); 384} 385 386void IntrinsicCodeGeneratorARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 387 ArmAssembler* assembler = GetAssembler(); 388 // Ignore upper 4B of long address. 389 Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 390 // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 391 // exception. So we can't use ldrd as addr may be unaligned. 392 Register lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>(); 393 Register hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>(); 394 if (addr == lo) { 395 __ ldr(hi, Address(addr, 4)); 396 __ ldr(lo, Address(addr, 0)); 397 } else { 398 __ ldr(lo, Address(addr, 0)); 399 __ ldr(hi, Address(addr, 4)); 400 } 401} 402 403void IntrinsicLocationsBuilderARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 404 CreateIntToIntLocations(arena_, invoke); 405} 406 407void IntrinsicCodeGeneratorARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 408 ArmAssembler* assembler = GetAssembler(); 409 // Ignore upper 4B of long address. 410 __ ldrsh(invoke->GetLocations()->Out().AsRegister<Register>(), 411 Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 412} 413 414static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) { 415 LocationSummary* locations = new (arena) LocationSummary(invoke, 416 LocationSummary::kNoCall, 417 kIntrinsified); 418 locations->SetInAt(0, Location::RequiresRegister()); 419 locations->SetInAt(1, Location::RequiresRegister()); 420} 421 422void IntrinsicLocationsBuilderARM::VisitMemoryPokeByte(HInvoke* invoke) { 423 CreateIntIntToVoidLocations(arena_, invoke); 424} 425 426void IntrinsicCodeGeneratorARM::VisitMemoryPokeByte(HInvoke* invoke) { 427 ArmAssembler* assembler = GetAssembler(); 428 __ strb(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 429 Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 430} 431 432void IntrinsicLocationsBuilderARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 433 CreateIntIntToVoidLocations(arena_, invoke); 434} 435 436void IntrinsicCodeGeneratorARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 437 ArmAssembler* assembler = GetAssembler(); 438 __ str(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 439 Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 440} 441 442void IntrinsicLocationsBuilderARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 443 CreateIntIntToVoidLocations(arena_, invoke); 444} 445 446void IntrinsicCodeGeneratorARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 447 ArmAssembler* assembler = GetAssembler(); 448 // Ignore upper 4B of long address. 449 Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 450 // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 451 // exception. So we can't use ldrd as addr may be unaligned. 452 __ str(invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>(), Address(addr, 0)); 453 __ str(invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>(), Address(addr, 4)); 454} 455 456void IntrinsicLocationsBuilderARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 457 CreateIntIntToVoidLocations(arena_, invoke); 458} 459 460void IntrinsicCodeGeneratorARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 461 ArmAssembler* assembler = GetAssembler(); 462 __ strh(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 463 Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 464} 465 466void IntrinsicLocationsBuilderARM::VisitThreadCurrentThread(HInvoke* invoke) { 467 LocationSummary* locations = new (arena_) LocationSummary(invoke, 468 LocationSummary::kNoCall, 469 kIntrinsified); 470 locations->SetOut(Location::RequiresRegister()); 471} 472 473void IntrinsicCodeGeneratorARM::VisitThreadCurrentThread(HInvoke* invoke) { 474 ArmAssembler* assembler = GetAssembler(); 475 __ LoadFromOffset(kLoadWord, 476 invoke->GetLocations()->Out().AsRegister<Register>(), 477 TR, 478 Thread::PeerOffset<kArmPointerSize>().Int32Value()); 479} 480 481static void GenUnsafeGet(HInvoke* invoke, 482 Primitive::Type type, 483 bool is_volatile, 484 CodeGeneratorARM* codegen) { 485 LocationSummary* locations = invoke->GetLocations(); 486 DCHECK((type == Primitive::kPrimInt) || 487 (type == Primitive::kPrimLong) || 488 (type == Primitive::kPrimNot)); 489 ArmAssembler* assembler = codegen->GetAssembler(); 490 Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 491 Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Long offset, lo part only. 492 493 if (type == Primitive::kPrimLong) { 494 Register trg_lo = locations->Out().AsRegisterPairLow<Register>(); 495 __ add(IP, base, ShifterOperand(offset)); 496 if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 497 Register trg_hi = locations->Out().AsRegisterPairHigh<Register>(); 498 __ ldrexd(trg_lo, trg_hi, IP); 499 } else { 500 __ ldrd(trg_lo, Address(IP)); 501 } 502 } else { 503 Register trg = locations->Out().AsRegister<Register>(); 504 __ ldr(trg, Address(base, offset)); 505 } 506 507 if (is_volatile) { 508 __ dmb(ISH); 509 } 510} 511 512static void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 513 LocationSummary* locations = new (arena) LocationSummary(invoke, 514 LocationSummary::kNoCall, 515 kIntrinsified); 516 locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 517 locations->SetInAt(1, Location::RequiresRegister()); 518 locations->SetInAt(2, Location::RequiresRegister()); 519 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 520} 521 522void IntrinsicLocationsBuilderARM::VisitUnsafeGet(HInvoke* invoke) { 523 CreateIntIntIntToIntLocations(arena_, invoke); 524} 525void IntrinsicLocationsBuilderARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 526 CreateIntIntIntToIntLocations(arena_, invoke); 527} 528void IntrinsicLocationsBuilderARM::VisitUnsafeGetLong(HInvoke* invoke) { 529 CreateIntIntIntToIntLocations(arena_, invoke); 530} 531void IntrinsicLocationsBuilderARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 532 CreateIntIntIntToIntLocations(arena_, invoke); 533} 534void IntrinsicLocationsBuilderARM::VisitUnsafeGetObject(HInvoke* invoke) { 535 CreateIntIntIntToIntLocations(arena_, invoke); 536} 537void IntrinsicLocationsBuilderARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 538 CreateIntIntIntToIntLocations(arena_, invoke); 539} 540 541void IntrinsicCodeGeneratorARM::VisitUnsafeGet(HInvoke* invoke) { 542 GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_); 543} 544void IntrinsicCodeGeneratorARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 545 GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_); 546} 547void IntrinsicCodeGeneratorARM::VisitUnsafeGetLong(HInvoke* invoke) { 548 GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_); 549} 550void IntrinsicCodeGeneratorARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 551 GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_); 552} 553void IntrinsicCodeGeneratorARM::VisitUnsafeGetObject(HInvoke* invoke) { 554 GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_); 555} 556void IntrinsicCodeGeneratorARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 557 GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_); 558} 559 560static void CreateIntIntIntIntToVoid(ArenaAllocator* arena, 561 const ArmInstructionSetFeatures& features, 562 Primitive::Type type, 563 bool is_volatile, 564 HInvoke* invoke) { 565 LocationSummary* locations = new (arena) LocationSummary(invoke, 566 LocationSummary::kNoCall, 567 kIntrinsified); 568 locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 569 locations->SetInAt(1, Location::RequiresRegister()); 570 locations->SetInAt(2, Location::RequiresRegister()); 571 locations->SetInAt(3, Location::RequiresRegister()); 572 573 if (type == Primitive::kPrimLong) { 574 // Potentially need temps for ldrexd-strexd loop. 575 if (is_volatile && !features.HasAtomicLdrdAndStrd()) { 576 locations->AddTemp(Location::RequiresRegister()); // Temp_lo. 577 locations->AddTemp(Location::RequiresRegister()); // Temp_hi. 578 } 579 } else if (type == Primitive::kPrimNot) { 580 // Temps for card-marking. 581 locations->AddTemp(Location::RequiresRegister()); // Temp. 582 locations->AddTemp(Location::RequiresRegister()); // Card. 583 } 584} 585 586void IntrinsicLocationsBuilderARM::VisitUnsafePut(HInvoke* invoke) { 587 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke); 588} 589void IntrinsicLocationsBuilderARM::VisitUnsafePutOrdered(HInvoke* invoke) { 590 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke); 591} 592void IntrinsicLocationsBuilderARM::VisitUnsafePutVolatile(HInvoke* invoke) { 593 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, true, invoke); 594} 595void IntrinsicLocationsBuilderARM::VisitUnsafePutObject(HInvoke* invoke) { 596 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke); 597} 598void IntrinsicLocationsBuilderARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 599 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke); 600} 601void IntrinsicLocationsBuilderARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 602 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, true, invoke); 603} 604void IntrinsicLocationsBuilderARM::VisitUnsafePutLong(HInvoke* invoke) { 605 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke); 606} 607void IntrinsicLocationsBuilderARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 608 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke); 609} 610void IntrinsicLocationsBuilderARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 611 CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, true, invoke); 612} 613 614static void GenUnsafePut(LocationSummary* locations, 615 Primitive::Type type, 616 bool is_volatile, 617 bool is_ordered, 618 CodeGeneratorARM* codegen) { 619 ArmAssembler* assembler = codegen->GetAssembler(); 620 621 Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 622 Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Long offset, lo part only. 623 Register value; 624 625 if (is_volatile || is_ordered) { 626 __ dmb(ISH); 627 } 628 629 if (type == Primitive::kPrimLong) { 630 Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>(); 631 value = value_lo; 632 if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 633 Register temp_lo = locations->GetTemp(0).AsRegister<Register>(); 634 Register temp_hi = locations->GetTemp(1).AsRegister<Register>(); 635 Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>(); 636 637 __ add(IP, base, ShifterOperand(offset)); 638 Label loop_head; 639 __ Bind(&loop_head); 640 __ ldrexd(temp_lo, temp_hi, IP); 641 __ strexd(temp_lo, value_lo, value_hi, IP); 642 __ cmp(temp_lo, ShifterOperand(0)); 643 __ b(&loop_head, NE); 644 } else { 645 __ add(IP, base, ShifterOperand(offset)); 646 __ strd(value_lo, Address(IP)); 647 } 648 } else { 649 value = locations->InAt(3).AsRegister<Register>(); 650 __ str(value, Address(base, offset)); 651 } 652 653 if (is_volatile) { 654 __ dmb(ISH); 655 } 656 657 if (type == Primitive::kPrimNot) { 658 Register temp = locations->GetTemp(0).AsRegister<Register>(); 659 Register card = locations->GetTemp(1).AsRegister<Register>(); 660 bool value_can_be_null = true; // TODO: Worth finding out this information? 661 codegen->MarkGCCard(temp, card, base, value, value_can_be_null); 662 } 663} 664 665void IntrinsicCodeGeneratorARM::VisitUnsafePut(HInvoke* invoke) { 666 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, false, codegen_); 667} 668void IntrinsicCodeGeneratorARM::VisitUnsafePutOrdered(HInvoke* invoke) { 669 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, true, codegen_); 670} 671void IntrinsicCodeGeneratorARM::VisitUnsafePutVolatile(HInvoke* invoke) { 672 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, false, codegen_); 673} 674void IntrinsicCodeGeneratorARM::VisitUnsafePutObject(HInvoke* invoke) { 675 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, false, codegen_); 676} 677void IntrinsicCodeGeneratorARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 678 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, true, codegen_); 679} 680void IntrinsicCodeGeneratorARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 681 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, false, codegen_); 682} 683void IntrinsicCodeGeneratorARM::VisitUnsafePutLong(HInvoke* invoke) { 684 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, false, codegen_); 685} 686void IntrinsicCodeGeneratorARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 687 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, true, codegen_); 688} 689void IntrinsicCodeGeneratorARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 690 GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, false, codegen_); 691} 692 693static void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, 694 HInvoke* invoke) { 695 LocationSummary* locations = new (arena) LocationSummary(invoke, 696 LocationSummary::kNoCall, 697 kIntrinsified); 698 locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 699 locations->SetInAt(1, Location::RequiresRegister()); 700 locations->SetInAt(2, Location::RequiresRegister()); 701 locations->SetInAt(3, Location::RequiresRegister()); 702 locations->SetInAt(4, Location::RequiresRegister()); 703 704 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 705 706 locations->AddTemp(Location::RequiresRegister()); // Pointer. 707 locations->AddTemp(Location::RequiresRegister()); // Temp 1. 708 locations->AddTemp(Location::RequiresRegister()); // Temp 2. 709} 710 711static void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) { 712 DCHECK_NE(type, Primitive::kPrimLong); 713 714 ArmAssembler* assembler = codegen->GetAssembler(); 715 716 Register out = locations->Out().AsRegister<Register>(); // Boolean result. 717 718 Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 719 Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Offset (discard high 4B). 720 Register expected_lo = locations->InAt(3).AsRegister<Register>(); // Expected. 721 Register value_lo = locations->InAt(4).AsRegister<Register>(); // Value. 722 723 Register tmp_ptr = locations->GetTemp(0).AsRegister<Register>(); // Pointer to actual memory. 724 Register tmp_lo = locations->GetTemp(1).AsRegister<Register>(); // Value in memory. 725 726 if (type == Primitive::kPrimNot) { 727 // Mark card for object assuming new value is stored. Worst case we will mark an unchanged 728 // object and scan the receiver at the next GC for nothing. 729 bool value_can_be_null = true; // TODO: Worth finding out this information? 730 codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null); 731 } 732 733 // Prevent reordering with prior memory operations. 734 __ dmb(ISH); 735 736 __ add(tmp_ptr, base, ShifterOperand(offset)); 737 738 // do { 739 // tmp = [r_ptr] - expected; 740 // } while (tmp == 0 && failure([r_ptr] <- r_new_value)); 741 // result = tmp != 0; 742 743 Label loop_head; 744 __ Bind(&loop_head); 745 746 __ ldrex(tmp_lo, tmp_ptr); 747 748 __ subs(tmp_lo, tmp_lo, ShifterOperand(expected_lo)); 749 750 __ it(EQ, ItState::kItT); 751 __ strex(tmp_lo, value_lo, tmp_ptr, EQ); 752 __ cmp(tmp_lo, ShifterOperand(1), EQ); 753 754 __ b(&loop_head, EQ); 755 756 __ dmb(ISH); 757 758 __ rsbs(out, tmp_lo, ShifterOperand(1)); 759 __ it(CC); 760 __ mov(out, ShifterOperand(0), CC); 761} 762 763void IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) { 764 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 765} 766void IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) { 767 CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 768} 769void IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) { 770 GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_); 771} 772void IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) { 773 GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_); 774} 775 776void IntrinsicLocationsBuilderARM::VisitStringCharAt(HInvoke* invoke) { 777 LocationSummary* locations = new (arena_) LocationSummary(invoke, 778 LocationSummary::kCallOnSlowPath, 779 kIntrinsified); 780 locations->SetInAt(0, Location::RequiresRegister()); 781 locations->SetInAt(1, Location::RequiresRegister()); 782 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 783 784 locations->AddTemp(Location::RequiresRegister()); 785 locations->AddTemp(Location::RequiresRegister()); 786} 787 788void IntrinsicCodeGeneratorARM::VisitStringCharAt(HInvoke* invoke) { 789 ArmAssembler* assembler = GetAssembler(); 790 LocationSummary* locations = invoke->GetLocations(); 791 792 // Location of reference to data array 793 const MemberOffset value_offset = mirror::String::ValueOffset(); 794 // Location of count 795 const MemberOffset count_offset = mirror::String::CountOffset(); 796 797 Register obj = locations->InAt(0).AsRegister<Register>(); // String object pointer. 798 Register idx = locations->InAt(1).AsRegister<Register>(); // Index of character. 799 Register out = locations->Out().AsRegister<Register>(); // Result character. 800 801 Register temp = locations->GetTemp(0).AsRegister<Register>(); 802 Register array_temp = locations->GetTemp(1).AsRegister<Register>(); 803 804 // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth 805 // the cost. 806 // TODO: For simplicity, the index parameter is requested in a register, so different from Quick 807 // we will not optimize the code for constants (which would save a register). 808 809 SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 810 codegen_->AddSlowPath(slow_path); 811 812 __ ldr(temp, Address(obj, count_offset.Int32Value())); // temp = str.length. 813 codegen_->MaybeRecordImplicitNullCheck(invoke); 814 __ cmp(idx, ShifterOperand(temp)); 815 __ b(slow_path->GetEntryLabel(), CS); 816 817 __ add(array_temp, obj, ShifterOperand(value_offset.Int32Value())); // array_temp := str.value. 818 819 // Load the value. 820 __ ldrh(out, Address(array_temp, idx, LSL, 1)); // out := array_temp[idx]. 821 822 __ Bind(slow_path->GetExitLabel()); 823} 824 825void IntrinsicLocationsBuilderARM::VisitStringCompareTo(HInvoke* invoke) { 826 // The inputs plus one temp. 827 LocationSummary* locations = new (arena_) LocationSummary(invoke, 828 LocationSummary::kCall, 829 kIntrinsified); 830 InvokeRuntimeCallingConvention calling_convention; 831 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 832 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 833 locations->SetOut(Location::RegisterLocation(R0)); 834} 835 836void IntrinsicCodeGeneratorARM::VisitStringCompareTo(HInvoke* invoke) { 837 ArmAssembler* assembler = GetAssembler(); 838 LocationSummary* locations = invoke->GetLocations(); 839 840 // Note that the null check must have been done earlier. 841 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 842 843 Register argument = locations->InAt(1).AsRegister<Register>(); 844 __ cmp(argument, ShifterOperand(0)); 845 SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 846 codegen_->AddSlowPath(slow_path); 847 __ b(slow_path->GetEntryLabel(), EQ); 848 849 __ LoadFromOffset( 850 kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pStringCompareTo).Int32Value()); 851 __ blx(LR); 852 __ Bind(slow_path->GetExitLabel()); 853} 854 855static void GenerateVisitStringIndexOf(HInvoke* invoke, 856 ArmAssembler* assembler, 857 CodeGeneratorARM* codegen, 858 ArenaAllocator* allocator, 859 bool start_at_zero) { 860 LocationSummary* locations = invoke->GetLocations(); 861 Register tmp_reg = locations->GetTemp(0).AsRegister<Register>(); 862 863 // Note that the null check must have been done earlier. 864 DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 865 866 // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically, 867 // or directly dispatch if we have a constant. 868 SlowPathCodeARM* slow_path = nullptr; 869 if (invoke->InputAt(1)->IsIntConstant()) { 870 if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) > 871 std::numeric_limits<uint16_t>::max()) { 872 // Always needs the slow-path. We could directly dispatch to it, but this case should be 873 // rare, so for simplicity just put the full slow-path down and branch unconditionally. 874 slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 875 codegen->AddSlowPath(slow_path); 876 __ b(slow_path->GetEntryLabel()); 877 __ Bind(slow_path->GetExitLabel()); 878 return; 879 } 880 } else { 881 Register char_reg = locations->InAt(1).AsRegister<Register>(); 882 __ LoadImmediate(tmp_reg, std::numeric_limits<uint16_t>::max()); 883 __ cmp(char_reg, ShifterOperand(tmp_reg)); 884 slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 885 codegen->AddSlowPath(slow_path); 886 __ b(slow_path->GetEntryLabel(), HI); 887 } 888 889 if (start_at_zero) { 890 DCHECK_EQ(tmp_reg, R2); 891 // Start-index = 0. 892 __ LoadImmediate(tmp_reg, 0); 893 } 894 895 __ LoadFromOffset(kLoadWord, LR, TR, 896 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value()); 897 __ blx(LR); 898 899 if (slow_path != nullptr) { 900 __ Bind(slow_path->GetExitLabel()); 901 } 902} 903 904void IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) { 905 LocationSummary* locations = new (arena_) LocationSummary(invoke, 906 LocationSummary::kCall, 907 kIntrinsified); 908 // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 909 // best to align the inputs accordingly. 910 InvokeRuntimeCallingConvention calling_convention; 911 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 912 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 913 locations->SetOut(Location::RegisterLocation(R0)); 914 915 // Need a temp for slow-path codepoint compare, and need to send start-index=0. 916 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 917} 918 919void IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) { 920 GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), true); 921} 922 923void IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) { 924 LocationSummary* locations = new (arena_) LocationSummary(invoke, 925 LocationSummary::kCall, 926 kIntrinsified); 927 // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 928 // best to align the inputs accordingly. 929 InvokeRuntimeCallingConvention calling_convention; 930 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 931 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 932 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 933 locations->SetOut(Location::RegisterLocation(R0)); 934 935 // Need a temp for slow-path codepoint compare. 936 locations->AddTemp(Location::RequiresRegister()); 937} 938 939void IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) { 940 GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), false); 941} 942 943void IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 944 LocationSummary* locations = new (arena_) LocationSummary(invoke, 945 LocationSummary::kCall, 946 kIntrinsified); 947 InvokeRuntimeCallingConvention calling_convention; 948 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 949 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 950 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 951 locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3))); 952 locations->SetOut(Location::RegisterLocation(R0)); 953} 954 955void IntrinsicCodeGeneratorARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 956 ArmAssembler* assembler = GetAssembler(); 957 LocationSummary* locations = invoke->GetLocations(); 958 959 Register byte_array = locations->InAt(0).AsRegister<Register>(); 960 __ cmp(byte_array, ShifterOperand(0)); 961 SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 962 codegen_->AddSlowPath(slow_path); 963 __ b(slow_path->GetEntryLabel(), EQ); 964 965 __ LoadFromOffset( 966 kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromBytes).Int32Value()); 967 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 968 __ blx(LR); 969 __ Bind(slow_path->GetExitLabel()); 970} 971 972void IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) { 973 LocationSummary* locations = new (arena_) LocationSummary(invoke, 974 LocationSummary::kCall, 975 kIntrinsified); 976 InvokeRuntimeCallingConvention calling_convention; 977 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 978 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 979 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 980 locations->SetOut(Location::RegisterLocation(R0)); 981} 982 983void IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) { 984 ArmAssembler* assembler = GetAssembler(); 985 986 __ LoadFromOffset( 987 kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value()); 988 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 989 __ blx(LR); 990} 991 992void IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) { 993 LocationSummary* locations = new (arena_) LocationSummary(invoke, 994 LocationSummary::kCall, 995 kIntrinsified); 996 InvokeRuntimeCallingConvention calling_convention; 997 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 998 locations->SetOut(Location::RegisterLocation(R0)); 999} 1000 1001void IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) { 1002 ArmAssembler* assembler = GetAssembler(); 1003 LocationSummary* locations = invoke->GetLocations(); 1004 1005 Register string_to_copy = locations->InAt(0).AsRegister<Register>(); 1006 __ cmp(string_to_copy, ShifterOperand(0)); 1007 SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1008 codegen_->AddSlowPath(slow_path); 1009 __ b(slow_path->GetEntryLabel(), EQ); 1010 1011 __ LoadFromOffset(kLoadWord, 1012 LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromString).Int32Value()); 1013 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1014 __ blx(LR); 1015 __ Bind(slow_path->GetExitLabel()); 1016} 1017 1018// Unimplemented intrinsics. 1019 1020#define UNIMPLEMENTED_INTRINSIC(Name) \ 1021void IntrinsicLocationsBuilderARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 1022} \ 1023void IntrinsicCodeGeneratorARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 1024} 1025 1026UNIMPLEMENTED_INTRINSIC(IntegerReverse) 1027UNIMPLEMENTED_INTRINSIC(IntegerReverseBytes) 1028UNIMPLEMENTED_INTRINSIC(LongReverse) 1029UNIMPLEMENTED_INTRINSIC(LongReverseBytes) 1030UNIMPLEMENTED_INTRINSIC(ShortReverseBytes) 1031UNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble) 1032UNIMPLEMENTED_INTRINSIC(MathMinFloatFloat) 1033UNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble) 1034UNIMPLEMENTED_INTRINSIC(MathMaxFloatFloat) 1035UNIMPLEMENTED_INTRINSIC(MathMinLongLong) 1036UNIMPLEMENTED_INTRINSIC(MathMaxLongLong) 1037UNIMPLEMENTED_INTRINSIC(MathCeil) // Could be done by changing rounding mode, maybe? 1038UNIMPLEMENTED_INTRINSIC(MathFloor) // Could be done by changing rounding mode, maybe? 1039UNIMPLEMENTED_INTRINSIC(MathRint) 1040UNIMPLEMENTED_INTRINSIC(MathRoundDouble) // Could be done by changing rounding mode, maybe? 1041UNIMPLEMENTED_INTRINSIC(MathRoundFloat) // Could be done by changing rounding mode, maybe? 1042UNIMPLEMENTED_INTRINSIC(UnsafeCASLong) // High register pressure. 1043UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) 1044UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) 1045UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) 1046 1047} // namespace arm 1048} // namespace art 1049