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