12bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe/* 22bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * Copyright (C) 2015 The Android Open Source Project 32bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * 42bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * Licensed under the Apache License, Version 2.0 (the "License"); 52bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * you may not use this file except in compliance with the License. 62bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * You may obtain a copy of the License at 72bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * 82bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * http://www.apache.org/licenses/LICENSE-2.0 92bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * 102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * Unless required by applicable law or agreed to in writing, software 112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * distributed under the License is distributed on an "AS IS" BASIS, 122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * See the License for the specific language governing permissions and 142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe * limitations under the License. 152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe */ 162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "intrinsics_arm.h" 182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "arch/arm/instruction_set_features_arm.h" 20e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier#include "art_method.h" 212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "code_generator_arm.h" 222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "entrypoints/quick/quick_entrypoints.h" 232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "intrinsics.h" 2485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "intrinsics_utils.h" 252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "mirror/array-inl.h" 262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "mirror/string.h" 272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "thread.h" 282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "utils/arm/assembler_arm.h" 292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampenamespace art { 312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampenamespace arm { 332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeArmAssembler* IntrinsicCodeGeneratorARM::GetAssembler() { 352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe return codegen_->GetAssembler(); 362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeArenaAllocator* IntrinsicCodeGeneratorARM::GetAllocator() { 392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe return codegen_->GetGraph()->GetArena(); 402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampeusing IntrinsicSlowPathARM = IntrinsicSlowPath<InvokeDexCallingConventionVisitorARM>; 432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampebool IntrinsicLocationsBuilderARM::TryDispatch(HInvoke* invoke) { 452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Dispatch(invoke); 462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* res = invoke->GetLocations(); 473b359c71f2fb784589be113206932e76807787bbRoland Levillain if (res == nullptr) { 483b359c71f2fb784589be113206932e76807787bbRoland Levillain return false; 493b359c71f2fb784589be113206932e76807787bbRoland Levillain } 503b359c71f2fb784589be113206932e76807787bbRoland Levillain if (kEmitCompilerReadBarrier && res->CanCall()) { 513b359c71f2fb784589be113206932e76807787bbRoland Levillain // Generating an intrinsic for this HInvoke may produce an 523b359c71f2fb784589be113206932e76807787bbRoland Levillain // IntrinsicSlowPathARM slow path. Currently this approach 533b359c71f2fb784589be113206932e76807787bbRoland Levillain // does not work when using read barriers, as the emitted 543b359c71f2fb784589be113206932e76807787bbRoland Levillain // calling sequence will make use of another slow path 553b359c71f2fb784589be113206932e76807787bbRoland Levillain // (ReadBarrierForRootSlowPathARM for HInvokeStaticOrDirect, 563b359c71f2fb784589be113206932e76807787bbRoland Levillain // ReadBarrierSlowPathARM for HInvokeVirtual). So we bail 573b359c71f2fb784589be113206932e76807787bbRoland Levillain // out in this case. 583b359c71f2fb784589be113206932e76807787bbRoland Levillain // 593b359c71f2fb784589be113206932e76807787bbRoland Levillain // TODO: Find a way to have intrinsics work with read barriers. 603b359c71f2fb784589be113206932e76807787bbRoland Levillain invoke->SetLocations(nullptr); 613b359c71f2fb784589be113206932e76807787bbRoland Levillain return false; 623b359c71f2fb784589be113206932e76807787bbRoland Levillain } 633b359c71f2fb784589be113206932e76807787bbRoland Levillain return res->Intrinsified(); 642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define __ assembler-> 672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresFpuRegister()); 732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister()); 742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { 772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresFpuRegister()); 822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MoveFPToInt(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location input = locations->InAt(0); 862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location output = locations->Out(); 872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovrrd(output.AsRegisterPairLow<Register>(), 892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe output.AsRegisterPairHigh<Register>(), 902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(input.AsFpuRegisterPairLow<SRegister>())); 912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovrs(output.AsRegister<Register>(), input.AsFpuRegister<SRegister>()); 932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MoveIntToFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location input = locations->InAt(0); 982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location output = locations->Out(); 992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 1002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovdrr(FromLowSToD(output.AsFpuRegisterPairLow<SRegister>()), 1012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe input.AsRegisterPairLow<Register>(), 1022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe input.AsRegisterPairHigh<Register>()); 1032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 1042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovsr(output.AsFpuRegister<SRegister>(), input.AsRegister<Register>()); 1052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 1062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { 1092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToIntLocations(arena_, invoke); 1102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) { 1122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToFPLocations(arena_, invoke); 1132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { 116bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); 1172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) { 119bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); 1202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { 1232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToIntLocations(arena_, invoke); 1242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { 1262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToFPLocations(arena_, invoke); 1272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { 130bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); 1312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { 133bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); 1342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 1372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 1382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 1392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 1402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 1412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { 1452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 1462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 1472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 1482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresFpuRegister()); 1492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 152611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingstatic void GenNumberOfLeadingZeros(LocationSummary* locations, 153611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Primitive::Type type, 154611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling ArmAssembler* assembler) { 155611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Location in = locations->InAt(0); 156611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Register out = locations->Out().AsRegister<Register>(); 157611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 158611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong)); 159611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 160611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling if (type == Primitive::kPrimLong) { 161611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Register in_reg_lo = in.AsRegisterPairLow<Register>(); 162611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Register in_reg_hi = in.AsRegisterPairHigh<Register>(); 163611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Label end; 164611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ clz(out, in_reg_hi); 165611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ CompareAndBranchIfNonZero(in_reg_hi, &end); 166611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ clz(out, in_reg_lo); 167611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ AddConstant(out, 32); 168611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ Bind(&end); 169611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling } else { 170611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ clz(out, in.AsRegister<Register>()); 171611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling } 172611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 173611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 174611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { 175611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling CreateIntToIntLocations(arena_, invoke); 176611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 177611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 178611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { 179611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler()); 180611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 181611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 182611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { 183611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 184611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling LocationSummary::kNoCall, 185611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling kIntrinsified); 186611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 187611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 188611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 189611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 190611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { 191611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler()); 192611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 193611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 1949ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingstatic void GenNumberOfTrailingZeros(LocationSummary* locations, 1959ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Primitive::Type type, 1969ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling ArmAssembler* assembler) { 1979ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong)); 1989ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 1999ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out = locations->Out().AsRegister<Register>(); 2009ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2019ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (type == Primitive::kPrimLong) { 2029ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); 2039ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); 2049ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Label end; 2059ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rbit(out, in_reg_lo); 2069ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ clz(out, out); 2079ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ CompareAndBranchIfNonZero(in_reg_lo, &end); 2089ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rbit(out, in_reg_hi); 2099ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ clz(out, out); 2109ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ AddConstant(out, 32); 2119ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Bind(&end); 2129ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 2139ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in = locations->InAt(0).AsRegister<Register>(); 2149ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rbit(out, in); 2159ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ clz(out, out); 2169ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2179ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2189ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2199ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { 2209ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 2219ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 2229ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 2239ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 2249ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2259ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2269ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2279ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { 2289ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler()); 2299ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2309ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2319ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { 2329ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 2339ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 2349ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 2359ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 2369ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 2379ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2389ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2399ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { 2409ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler()); 2419ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2429ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 2442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location in = locations->InAt(0); 2452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location out = locations->Out(); 2462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 2482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vabsd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 2492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 2502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 2512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vabss(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>()); 2522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 2532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 2542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsDouble(HInvoke* invoke) { 2562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 2572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 2582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsDouble(HInvoke* invoke) { 260bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); 2612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 2622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) { 2642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 2652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 2662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsFloat(HInvoke* invoke) { 268bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); 2692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 2702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) { 2722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 2732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 2742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 2752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 2762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 2792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 2802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenAbsInteger(LocationSummary* locations, 2822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is64bit, 2832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler) { 2842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location in = locations->InAt(0); 2852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location output = locations->Out(); 2862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register mask = locations->GetTemp(0).AsRegister<Register>(); 2882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 2902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg_lo = in.AsRegisterPairLow<Register>(); 2912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg_hi = in.AsRegisterPairHigh<Register>(); 2922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg_lo = output.AsRegisterPairLow<Register>(); 2932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg_hi = output.AsRegisterPairHigh<Register>(); 2942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK_NE(out_reg_lo, in_reg_hi) << "Diagonal overlap unexpected."; 2962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 2972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Asr(mask, in_reg_hi, 31); 2982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ adds(out_reg_lo, in_reg_lo, ShifterOperand(mask)); 2992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ adc(out_reg_hi, in_reg_hi, ShifterOperand(mask)); 3002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg_lo, mask, ShifterOperand(out_reg_lo)); 3012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg_hi, mask, ShifterOperand(out_reg_hi)); 3022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 3032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg = in.AsRegister<Register>(); 3042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg = output.AsRegister<Register>(); 3052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Asr(mask, in_reg, 31); 3072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(out_reg, in_reg, ShifterOperand(mask)); 3082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg, mask, ShifterOperand(out_reg)); 3092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 3102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsInt(HInvoke* invoke) { 3132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntPlusTemp(arena_, invoke); 3142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsInt(HInvoke* invoke) { 317bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); 3182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsLong(HInvoke* invoke) { 3222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntPlusTemp(arena_, invoke); 3232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsLong(HInvoke* invoke) { 326bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); 3272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenMinMax(LocationSummary* locations, 3302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_min, 3312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler) { 3322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register op1 = locations->InAt(0).AsRegister<Register>(); 3332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register op2 = locations->InAt(1).AsRegister<Register>(); 3342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); 3352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(op1, ShifterOperand(op2)); 3372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it((is_min) ? Condition::LT : Condition::GT, kItElse); 3392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(op1), is_min ? Condition::LT : Condition::GT); 3402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(op2), is_min ? Condition::GE : Condition::LE); 3412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 3442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 3452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 3462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 3472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 3482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 3492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMinIntInt(HInvoke* invoke) { 3532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToIntLocations(arena_, invoke); 3542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMinIntInt(HInvoke* invoke) { 357bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler()); 3582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) { 3612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToIntLocations(arena_, invoke); 3622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMaxIntInt(HInvoke* invoke) { 365bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler()); 3662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathSqrt(HInvoke* invoke) { 3692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 3702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathSqrt(HInvoke* invoke) { 3732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 3742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 3752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vsqrtd(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()), 3762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>())); 3772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekByte(HInvoke* invoke) { 3802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 3812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekByte(HInvoke* invoke) { 3842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 3852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 3862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrsb(invoke->GetLocations()->Out().AsRegister<Register>(), 3872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 3882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 3912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 3922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 3932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 3942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 3952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 3962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 3972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(invoke->GetLocations()->Out().AsRegister<Register>(), 3982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 3992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 4022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 4032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 4062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 4072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 4082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 4092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 4102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // exception. So we can't use ldrd as addr may be unaligned. 4112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>(); 4122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>(); 4132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (addr == lo) { 4142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(hi, Address(addr, 4)); 4152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(lo, Address(addr, 0)); 4162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 4172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(lo, Address(addr, 0)); 4182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(hi, Address(addr, 4)); 4192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 4202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 4232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 4242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 4272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 4282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 4292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrsh(invoke->GetLocations()->Out().AsRegister<Register>(), 4302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 4312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) { 4342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 4352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 4362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 4372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 4382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 4392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeByte(HInvoke* invoke) { 4422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 4432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeByte(HInvoke* invoke) { 4462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 4472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strb(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 4482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 4492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 4522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 4532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 4562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 4572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 4582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 4592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 4622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 4632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 4662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 4672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 4682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 4692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 4702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // exception. So we can't use ldrd as addr may be unaligned. 4712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>(), Address(addr, 0)); 4722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>(), Address(addr, 4)); 4732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 4762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 4772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 4802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 4812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strh(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 4822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 4832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitThreadCurrentThread(HInvoke* invoke) { 4862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 4872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 4882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 4892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister()); 4902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitThreadCurrentThread(HInvoke* invoke) { 4932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 4942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ LoadFromOffset(kLoadWord, 4952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe invoke->GetLocations()->Out().AsRegister<Register>(), 4962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe TR, 4972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Thread::PeerOffset<kArmPointerSize>().Int32Value()); 4982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafeGet(HInvoke* invoke, 5012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 5022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 5032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CodeGeneratorARM* codegen) { 5042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 5052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 5063b359c71f2fb784589be113206932e76807787bbRoland Levillain Location base_loc = locations->InAt(1); 5073b359c71f2fb784589be113206932e76807787bbRoland Levillain Register base = base_loc.AsRegister<Register>(); // Object pointer. 5083b359c71f2fb784589be113206932e76807787bbRoland Levillain Location offset_loc = locations->InAt(2); 5093b359c71f2fb784589be113206932e76807787bbRoland Levillain Register offset = offset_loc.AsRegisterPairLow<Register>(); // Long offset, lo part only. 5103b359c71f2fb784589be113206932e76807787bbRoland Levillain Location trg_loc = locations->Out(); 5112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 512c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain switch (type) { 513c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain case Primitive::kPrimInt: { 514c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain Register trg = trg_loc.AsRegister<Register>(); 515c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ ldr(trg, Address(base, offset)); 516c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (is_volatile) { 517c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ dmb(ISH); 518c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 519c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain break; 5202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 5212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 522c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain case Primitive::kPrimNot: { 523c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain Register trg = trg_loc.AsRegister<Register>(); 524c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (kEmitCompilerReadBarrier) { 525c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (kUseBakerReadBarrier) { 526c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain Location temp = locations->GetTemp(0); 527c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain codegen->GenerateArrayLoadWithBakerReadBarrier( 528c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain invoke, trg_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false); 529c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (is_volatile) { 530c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ dmb(ISH); 531c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 532c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } else { 533c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ ldr(trg, Address(base, offset)); 534c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (is_volatile) { 535c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ dmb(ISH); 536c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 537c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain codegen->GenerateReadBarrierSlow(invoke, trg_loc, trg_loc, base_loc, 0U, offset_loc); 538c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 539c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } else { 540c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ ldr(trg, Address(base, offset)); 541c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (is_volatile) { 542c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ dmb(ISH); 543c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 544c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ MaybeUnpoisonHeapReference(trg); 545c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 546c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain break; 547c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 548c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain 549c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain case Primitive::kPrimLong: { 550c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain Register trg_lo = trg_loc.AsRegisterPairLow<Register>(); 551c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ add(IP, base, ShifterOperand(offset)); 552c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 553c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain Register trg_hi = trg_loc.AsRegisterPairHigh<Register>(); 554c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ ldrexd(trg_lo, trg_hi, IP); 555c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } else { 556c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ ldrd(trg_lo, Address(IP)); 557c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 558c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (is_volatile) { 559c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain __ dmb(ISH); 560c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 561c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain break; 562c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 5634d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 564c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain default: 565c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain LOG(FATAL) << "Unexpected type " << type; 566c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain UNREACHABLE(); 5674d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 5682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 570c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillainstatic void CreateIntIntIntToIntLocations(ArenaAllocator* arena, 571c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain HInvoke* invoke, 572c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain Primitive::Type type) { 5733b359c71f2fb784589be113206932e76807787bbRoland Levillain bool can_call = kEmitCompilerReadBarrier && 5743b359c71f2fb784589be113206932e76807787bbRoland Levillain (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject || 5753b359c71f2fb784589be113206932e76807787bbRoland Levillain invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile); 5762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 5773b359c71f2fb784589be113206932e76807787bbRoland Levillain can_call ? 5783b359c71f2fb784589be113206932e76807787bbRoland Levillain LocationSummary::kCallOnSlowPath : 5793b359c71f2fb784589be113206932e76807787bbRoland Levillain LocationSummary::kNoCall, 5802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 5812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 5822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 5832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 5842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 585c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) { 586c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain // We need a temporary register for the read barrier marking slow 587c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain // path in InstructionCodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier. 588c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain locations->AddTemp(Location::RequiresRegister()); 589c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain } 5902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGet(HInvoke* invoke) { 593c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt); 5942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 596c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt); 5972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLong(HInvoke* invoke) { 599c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong); 6002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 602c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong); 6032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObject(HInvoke* invoke) { 605c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot); 6062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 608c928591f5b2c544751bb3fb26dc614d3c2e67befRoland Levillain CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot); 6092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGet(HInvoke* invoke) { 612bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_); 6132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 615bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_); 6162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLong(HInvoke* invoke) { 618bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_); 6192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 621bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_); 6222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObject(HInvoke* invoke) { 624bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_); 6252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 627bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_); 6282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntToVoid(ArenaAllocator* arena, 6312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const ArmInstructionSetFeatures& features, 6322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 6332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 6342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe HInvoke* invoke) { 6352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 6362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 6372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 6382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 6392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 6402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 6412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(3, Location::RequiresRegister()); 6422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 6442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Potentially need temps for ldrexd-strexd loop. 6452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !features.HasAtomicLdrdAndStrd()) { 6462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp_lo. 6472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp_hi. 6482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 6492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else if (type == Primitive::kPrimNot) { 6502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Temps for card-marking. 6512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp. 6522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Card. 6532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 6542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePut(HInvoke* invoke) { 657bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke); 6582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutOrdered(HInvoke* invoke) { 660bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke); 6612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutVolatile(HInvoke* invoke) { 663bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ true, invoke); 6642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObject(HInvoke* invoke) { 666bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke); 6672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 669bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke); 6702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 672bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ true, invoke); 6732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLong(HInvoke* invoke) { 675bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid( 676bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke); 6772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 679bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid( 680bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke); 6812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 683bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid( 684bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain arena_, features_, Primitive::kPrimLong, /* is_volatile */ true, invoke); 6852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafePut(LocationSummary* locations, 6882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 6892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 6902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_ordered, 6912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CodeGeneratorARM* codegen) { 6922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 6932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 6952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Long offset, lo part only. 6962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value; 6972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile || is_ordered) { 6992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 7002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 7032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>(); 7042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe value = value_lo; 7052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 7062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp_lo = locations->GetTemp(0).AsRegister<Register>(); 7072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp_hi = locations->GetTemp(1).AsRegister<Register>(); 7082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>(); 7092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 7112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Label loop_head; 7122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(&loop_head); 7132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrexd(temp_lo, temp_hi, IP); 7142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strexd(temp_lo, value_lo, value_hi, IP); 7152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(temp_lo, ShifterOperand(0)); 7162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(&loop_head, NE); 7172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 7182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 7192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strd(value_lo, Address(IP)); 7202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 7224d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain value = locations->InAt(3).AsRegister<Register>(); 7234d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain Register source = value; 7244d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 7254d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain Register temp = locations->GetTemp(0).AsRegister<Register>(); 7264d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ Mov(temp, value); 7274d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ PoisonHeapReference(temp); 7284d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain source = temp; 7294d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 7304d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ str(source, Address(base, offset)); 7312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile) { 7342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 7352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimNot) { 7382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp = locations->GetTemp(0).AsRegister<Register>(); 7392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register card = locations->GetTemp(1).AsRegister<Register>(); 74007276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray bool value_can_be_null = true; // TODO: Worth finding out this information? 74107276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray codegen->MarkGCCard(temp, card, base, value, value_can_be_null); 7422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePut(HInvoke* invoke) { 746bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 747bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimInt, 748bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 749bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 750bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 7512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutOrdered(HInvoke* invoke) { 753bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 754bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimInt, 755bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 756bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ true, 757bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 7582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutVolatile(HInvoke* invoke) { 760bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 761bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimInt, 762bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ true, 763bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 764bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 7652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObject(HInvoke* invoke) { 767bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 768bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimNot, 769bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 770bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 771bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 7722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 774bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 775bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimNot, 776bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 777bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ true, 778bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 7792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 781bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 782bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimNot, 783bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ true, 784bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 785bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 7862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLong(HInvoke* invoke) { 788bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 789bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimLong, 790bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 791bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 792bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 7932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 795bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 796bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimLong, 797bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 798bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ true, 799bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 8002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 802bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 803bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimLong, 804bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ true, 805bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 806bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 8072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, 8102e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain HInvoke* invoke, 8112e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain Primitive::Type type) { 8122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 8132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 8142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 8152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 8162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 8172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 8182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(3, Location::RequiresRegister()); 8192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(4, Location::RequiresRegister()); 8202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8212e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain // If heap poisoning is enabled, we don't want the unpoisoning 8222e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain // operations to potentially clobber the output. 8232e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain Location::OutputOverlap overlaps = (kPoisonHeapReferences && type == Primitive::kPrimNot) 8242e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain ? Location::kOutputOverlap 8252e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain : Location::kNoOutputOverlap; 8262e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain locations->SetOut(Location::RequiresRegister(), overlaps); 8272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Pointer. 8292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp 1. 8302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) { 8332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK_NE(type, Primitive::kPrimLong); 8342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 8362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Boolean result. 8382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 8402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Offset (discard high 4B). 8412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register expected_lo = locations->InAt(3).AsRegister<Register>(); // Expected. 8422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_lo = locations->InAt(4).AsRegister<Register>(); // Value. 8432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_ptr = locations->GetTemp(0).AsRegister<Register>(); // Pointer to actual memory. 8452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_lo = locations->GetTemp(1).AsRegister<Register>(); // Value in memory. 8462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimNot) { 8482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Mark card for object assuming new value is stored. Worst case we will mark an unchanged 8492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // object and scan the receiver at the next GC for nothing. 85007276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray bool value_can_be_null = true; // TODO: Worth finding out this information? 85107276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null); 8522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Prevent reordering with prior memory operations. 8554bedb3845ac33c95cb779987abd4e76a88b19989Roland Levillain // Emit a DMB ISH instruction instead of an DMB ISHST one, as the 8564bedb3845ac33c95cb779987abd4e76a88b19989Roland Levillain // latter allows a preceding load to be delayed past the STXR 8574bedb3845ac33c95cb779987abd4e76a88b19989Roland Levillain // instruction below. 8582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(tmp_ptr, base, ShifterOperand(offset)); 8612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8624d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 8634d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->PoisonHeapReference(expected_lo); 8642e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain if (value_lo == expected_lo) { 8652e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain // Do not poison `value_lo`, as it is the same register as 8662e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain // `expected_lo`, which has just been poisoned. 8672e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain } else { 8682e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain codegen->GetAssembler()->PoisonHeapReference(value_lo); 8692e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain } 8704d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 8714d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 8722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // do { 8732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // tmp = [r_ptr] - expected; 8742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // } while (tmp == 0 && failure([r_ptr] <- r_new_value)); 8752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // result = tmp != 0; 8762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Label loop_head; 8782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(&loop_head); 8792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 880391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // TODO: When `type == Primitive::kPrimNot`, add a read barrier for 881391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // the reference stored in the object before attempting the CAS, 882391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // similar to the one in the art::Unsafe_compareAndSwapObject JNI 883391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // implementation. 884391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // 885391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // Note that this code is not (yet) used when read barriers are 886391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // enabled (see IntrinsicLocationsBuilderARM::VisitUnsafeCASObject). 887391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier)); 8882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrex(tmp_lo, tmp_ptr); 8892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ subs(tmp_lo, tmp_lo, ShifterOperand(expected_lo)); 8912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(EQ, ItState::kItT); 8932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strex(tmp_lo, value_lo, tmp_ptr, EQ); 8942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(tmp_lo, ShifterOperand(1), EQ); 8952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(&loop_head, EQ); 8972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ rsbs(out, tmp_lo, ShifterOperand(1)); 9012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(CC); 9022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(0), CC); 9034d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 9044d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 9054d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(expected_lo); 9062e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain if (value_lo == expected_lo) { 9072e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain // Do not unpoison `value_lo`, as it is the same register as 9082e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain // `expected_lo`, which has just been unpoisoned. 9092e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain } else { 9102e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(value_lo); 9112e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain } 9124d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 9132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 915ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) { 9162e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimInt); 9172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 918ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) { 919391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // The UnsafeCASObject intrinsic is missing a read barrier, and 920391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // therefore sometimes does not work as expected (b/25883050). 921391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // Turn it off temporarily as a quick fix, until the read barrier is 922391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // implemented (see TODO in GenCAS below). 9233b359c71f2fb784589be113206932e76807787bbRoland Levillain // 9242e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain // TODO(rpl): Fix this issue and re-enable this intrinsic with read barriers. 9252e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain if (kEmitCompilerReadBarrier) { 926985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain return; 927985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain } 928985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain 9292e50ecb95ddf645595491438cf35e79b705ee366Roland Levillain CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke, Primitive::kPrimNot); 9302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) { 9322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_); 9332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) { 9352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_); 9362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringCharAt(HInvoke* invoke) { 9392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 9402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kCallOnSlowPath, 9412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 9422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 9432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 9442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 9452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 9472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 9482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringCharAt(HInvoke* invoke) { 9512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 9522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 9532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of reference to data array 9552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset value_offset = mirror::String::ValueOffset(); 9562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of count 9572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset count_offset = mirror::String::CountOffset(); 9582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register obj = locations->InAt(0).AsRegister<Register>(); // String object pointer. 9602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register idx = locations->InAt(1).AsRegister<Register>(); // Index of character. 9612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Result character. 9622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp = locations->GetTemp(0).AsRegister<Register>(); 9642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register array_temp = locations->GetTemp(1).AsRegister<Register>(); 9652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth 9672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // the cost. 9682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: For simplicity, the index parameter is requested in a register, so different from Quick 9692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // we will not optimize the code for constants (which would save a register). 9702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 97185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 9722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->AddSlowPath(slow_path); 9732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(temp, Address(obj, count_offset.Int32Value())); // temp = str.length. 9752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->MaybeRecordImplicitNullCheck(invoke); 9762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(idx, ShifterOperand(temp)); 9772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(slow_path->GetEntryLabel(), CS); 9782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 979848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ add(array_temp, obj, ShifterOperand(value_offset.Int32Value())); // array_temp := str.value. 9802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Load the value. 982848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ ldrh(out, Address(array_temp, idx, LSL, 1)); // out := array_temp[idx]. 9832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(slow_path->GetExitLabel()); 9852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 987d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitStringCompareTo(HInvoke* invoke) { 988d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray // The inputs plus one temp. 989d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = new (arena_) LocationSummary(invoke, 990d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary::kCall, 991d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kIntrinsified); 992d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray InvokeRuntimeCallingConvention calling_convention; 993d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 994d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 995d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetOut(Location::RegisterLocation(R0)); 996d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 997d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 998d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitStringCompareTo(HInvoke* invoke) { 999d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray ArmAssembler* assembler = GetAssembler(); 1000d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 1001d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1002512e04d1ea7fb33e3992715fe55be8a834d4a79cNicolas Geoffray // Note that the null check must have been done earlier. 1003641547a5f18ca2ea54469cceadcfef64f132e5e0Calin Juravle DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1004d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1005d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray Register argument = locations->InAt(1).AsRegister<Register>(); 1006d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ cmp(argument, ShifterOperand(0)); 100785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1008d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray codegen_->AddSlowPath(slow_path); 1009d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ b(slow_path->GetEntryLabel(), EQ); 1010d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1011d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ LoadFromOffset( 1012d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pStringCompareTo).Int32Value()); 1013d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ blx(LR); 1014d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ Bind(slow_path->GetExitLabel()); 1015d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 1016d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1017289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicLocationsBuilderARM::VisitStringEquals(HInvoke* invoke) { 1018289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = new (arena_) LocationSummary(invoke, 1019289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary::kNoCall, 1020289cd55808111d23c92f2739a096942a8049649aAgi Csaki kIntrinsified); 1021289cd55808111d23c92f2739a096942a8049649aAgi Csaki InvokeRuntimeCallingConvention calling_convention; 1022289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(0, Location::RequiresRegister()); 1023289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(1, Location::RequiresRegister()); 1024289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Temporary registers to store lengths of strings and for calculations. 1025289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Using instruction cbz requires a low register, so explicitly set a temp to be R0. 1026289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RegisterLocation(R0)); 1027289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1028289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1029289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1030289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetOut(Location::RequiresRegister()); 1031289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1032289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1033289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicCodeGeneratorARM::VisitStringEquals(HInvoke* invoke) { 1034289cd55808111d23c92f2739a096942a8049649aAgi Csaki ArmAssembler* assembler = GetAssembler(); 1035289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = invoke->GetLocations(); 1036289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1037289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register str = locations->InAt(0).AsRegister<Register>(); 1038289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register arg = locations->InAt(1).AsRegister<Register>(); 1039289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register out = locations->Out().AsRegister<Register>(); 1040289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1041289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp = locations->GetTemp(0).AsRegister<Register>(); 1042289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp1 = locations->GetTemp(1).AsRegister<Register>(); 1043289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp2 = locations->GetTemp(2).AsRegister<Register>(); 1044289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1045289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label loop; 1046289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label end; 1047289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_true; 1048289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_false; 1049289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1050289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Get offsets of count, value, and class fields within a string object. 1051289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); 1052289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); 1053289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value(); 1054289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1055289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Note that the null check must have been done earlier. 1056289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1057289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1058289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if input is null, return false if it is. 1059289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ CompareAndBranchIfZero(arg, &return_false); 1060289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1061289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Instanceof check for the argument by comparing class fields. 1062289cd55808111d23c92f2739a096942a8049649aAgi Csaki // All string objects must have the same type since String cannot be subclassed. 1063289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Receiver must be a string object, so its class field is equal to all strings' class fields. 1064289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If the argument is a string object, its class field must be equal to receiver's class field. 1065289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, class_offset)); 1066289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, class_offset)); 1067289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1068289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1069289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1070289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Load lengths of this and argument strings. 1071289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, count_offset)); 1072289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, count_offset)); 1073289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if lengths are equal, return false if they're not. 1074289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1075289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1076289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true if both strings are empty. 1077289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cbz(temp, &return_true); 1078289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1079289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Reference equality check, return true if same reference. 1080289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(str, ShifterOperand(arg)); 1081289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_true, EQ); 1082289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1083289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Assertions that must hold in order to compare strings 2 characters at a time. 1084289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK_ALIGNED(value_offset, 4); 1085289cd55808111d23c92f2739a096942a8049649aAgi Csaki static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded"); 1086289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1087289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(temp1, value_offset); 1088289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1089289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Loop to compare strings 2 characters at a time starting at the front of the string. 1090289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Ok to do this because strings with an odd length are zero-padded. 1091289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&loop); 1092289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(out, Address(str, temp1)); 1093289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp2, Address(arg, temp1)); 1094289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(out, ShifterOperand(temp2)); 1095289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1096289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ add(temp1, temp1, ShifterOperand(sizeof(uint32_t))); 1097a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ subs(temp, temp, ShifterOperand(sizeof(uint32_t) / sizeof(uint16_t))); 1098a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ b(&loop, GT); 1099289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1100289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true and exit the function. 1101289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If loop does not result in returning false, we return true. 1102289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_true); 1103289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 1); 1104289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&end); 1105289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1106289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return false and exit the function. 1107289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_false); 1108289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 0); 1109289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&end); 1110289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1111289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1112ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampestatic void GenerateVisitStringIndexOf(HInvoke* invoke, 1113ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArmAssembler* assembler, 1114ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe CodeGeneratorARM* codegen, 1115ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArenaAllocator* allocator, 1116ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe bool start_at_zero) { 1117ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 1118ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register tmp_reg = locations->GetTemp(0).AsRegister<Register>(); 1119ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1120ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Note that the null check must have been done earlier. 1121ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1122ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1123ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically, 1124ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // or directly dispatch if we have a constant. 112585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = nullptr; 1126ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (invoke->InputAt(1)->IsIntConstant()) { 1127ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) > 1128ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe std::numeric_limits<uint16_t>::max()) { 1129ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Always needs the slow-path. We could directly dispatch to it, but this case should be 1130ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // rare, so for simplicity just put the full slow-path down and branch unconditionally. 1131ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1132ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1133ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel()); 1134ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1135ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe return; 1136ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1137ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } else { 1138ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register char_reg = locations->InAt(1).AsRegister<Register>(); 1139ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, std::numeric_limits<uint16_t>::max()); 1140ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ cmp(char_reg, ShifterOperand(tmp_reg)); 1141ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1142ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1143ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel(), HI); 1144ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1145ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1146ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (start_at_zero) { 1147ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK_EQ(tmp_reg, R2); 1148ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Start-index = 0. 1149ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, 0); 1150ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1151ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1152ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadFromOffset(kLoadWord, LR, TR, 1153ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value()); 115442ad288254e660ad091d03fad8c8fbad1d34ec89Roland Levillain CheckEntrypointTypes<kQuickIndexOf, int32_t, void*, uint32_t, uint32_t>(); 1155ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ blx(LR); 1156ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1157ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (slow_path != nullptr) { 1158ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1159ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1160ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1161ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1162ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) { 1163ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1164ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1165ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1166ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1167ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1168ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1169ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1170ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1171ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1172ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1173ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare, and need to send start-index=0. 1174ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1175ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1176ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1177ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) { 1178bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenerateVisitStringIndexOf( 1179bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); 1180ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1181ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1182ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1183ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1184ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1185ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1186ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1187ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1188ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1189ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1190ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1191ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1192ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1193ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1194ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare. 1195ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 1196ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1197ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1198ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1199bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenerateVisitStringIndexOf( 1200bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); 1201ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1202ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1203848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1204848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1205848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1206848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1207848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1208848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1209848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1210848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1211848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3))); 1212848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1213848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1214848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1215848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1216848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1217848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1218848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1219848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register byte_array = locations->InAt(0).AsRegister<Register>(); 1220848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(byte_array, ShifterOperand(0)); 122185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1222848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1223848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1224848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1225848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1226848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromBytes).Int32Value()); 1227f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>(); 1228848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1229f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1230848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1231848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1232848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1233848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1234848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1235848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1236848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1237848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1238848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1239848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1240848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1241848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1242848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1243848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1244848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1245848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1246848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1247cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain // No need to emit code checking whether `locations->InAt(2)` is a null 1248cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain // pointer, as callers of the native method 1249cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain // 1250cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) 1251cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain // 1252cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain // all include a null check on `data` before calling that method. 1253848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1254848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value()); 1255f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>(); 1256848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1257f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1258848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1259848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1260848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) { 1261848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1262848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1263848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1264848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1265848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1266848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1267848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1268848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1269848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) { 1270848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1271848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1272848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1273848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register string_to_copy = locations->InAt(0).AsRegister<Register>(); 1274848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(string_to_copy, ShifterOperand(0)); 127585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1276848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1277848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1278848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1279848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset(kLoadWord, 1280848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromString).Int32Value()); 1281f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>(); 1282848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1283f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1284848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1285848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1286848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 12875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitSystemArrayCopy(HInvoke* invoke) { 12885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke); 12895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 12905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (locations == nullptr) { 12915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray return; 12925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 12935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 12945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant(); 12955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant(); 12965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* length = invoke->InputAt(4)->AsIntConstant(); 12975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 12985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(src_pos->GetValue())) { 12995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(1, Location::RequiresRegister()); 13005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(dest_pos->GetValue())) { 13025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(3, Location::RequiresRegister()); 13035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length != nullptr && !assembler_->ShifterOperandCanAlwaysHold(length->GetValue())) { 13055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(4, Location::RequiresRegister()); 13065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 13085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffraystatic void CheckPosition(ArmAssembler* assembler, 13105bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location pos, 13115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register input, 13125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location length, 13135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SlowPathCode* slow_path, 13145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register input_len, 13155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp, 13165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray bool length_is_input_length = false) { 13175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Where is the length in the Array? 13185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value(); 13195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (pos.IsConstant()) { 13215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue(); 13225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (pos_const == 0) { 13235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!length_is_input_length) { 13245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that length(input) >= length. 13255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp, input, length_offset); 13265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 13275bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 13285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 13305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that length(input) >= pos. 13355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, input_len, input, length_offset); 13365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ subs(temp, input_len, ShifterOperand(pos_const)); 13375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that (length(input) - pos) >= length. 13405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 13415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 13425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 13445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else if (length_is_input_length) { 13485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // The only way the copy can succeed is if pos is zero. 13495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register pos_reg = pos.AsRegister<Register>(); 13505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(pos_reg, slow_path->GetEntryLabel()); 13515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that pos >= 0. 13535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register pos_reg = pos.AsRegister<Register>(); 13545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(pos_reg, ShifterOperand(0)); 13555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that pos <= length(input). 13585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp, input, length_offset); 13595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ subs(temp, temp, ShifterOperand(pos_reg)); 13605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that (length(input) - pos) >= length. 13635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 13645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 13655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 13675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 13715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13723b359c71f2fb784589be113206932e76807787bbRoland Levillain// TODO: Implement read barriers in the SystemArrayCopy intrinsic. 13733b359c71f2fb784589be113206932e76807787bbRoland Levillain// Note that this code path is not used (yet) because we do not 13743b359c71f2fb784589be113206932e76807787bbRoland Levillain// intrinsify methods that can go into the IntrinsicSlowPathARM 13753b359c71f2fb784589be113206932e76807787bbRoland Levillain// slow path. 13765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) { 13775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray ArmAssembler* assembler = GetAssembler(); 13785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 13795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 13815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); 13825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); 13835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); 13845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register src = locations->InAt(0).AsRegister<Register>(); 13865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location src_pos = locations->InAt(1); 13875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register dest = locations->InAt(2).AsRegister<Register>(); 13885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location dest_pos = locations->InAt(3); 13895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location length = locations->InAt(4); 13905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp1 = locations->GetTemp(0).AsRegister<Register>(); 13915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp2 = locations->GetTemp(1).AsRegister<Register>(); 13925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp3 = locations->GetTemp(2).AsRegister<Register>(); 13935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 13955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray codegen_->AddSlowPath(slow_path); 13965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 1397ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain Label conditions_on_positions_validated; 13985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SystemArrayCopyOptimizations optimizations(invoke); 13995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // If source and destination are the same, we go to slow path if we need to do 14015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // forward copying. 14025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos.IsConstant()) { 14035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); 14045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 1405b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); 1406b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray if (optimizations.GetDestinationIsSource()) { 1407b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray // Checked when building locations. 1408b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray DCHECK_GE(src_pos_constant, dest_pos_constant); 1409b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray } else if (src_pos_constant < dest_pos_constant) { 1410b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray __ cmp(src, ShifterOperand(dest)); 1411b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray __ b(slow_path->GetEntryLabel(), EQ); 1412b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray } 1413b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray 14145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Checked when building locations. 14155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray DCHECK(!optimizations.GetDestinationIsSource() 14165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray || (src_pos_constant >= dest_pos.GetConstant()->AsIntConstant()->GetValue())); 14175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 1419b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray __ cmp(src, ShifterOperand(dest)); 1420ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain __ b(&conditions_on_positions_validated, NE); 14215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(dest_pos.AsRegister<Register>(), ShifterOperand(src_pos_constant)); 14235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), GT); 14245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 1427b198b013ae7bd2da85e007414fc028cd51a13883Nicolas Geoffray __ cmp(src, ShifterOperand(dest)); 1428ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain __ b(&conditions_on_positions_validated, NE); 14295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 14315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); 14325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos_constant)); 14335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos.AsRegister<Register>())); 14355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 1439ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain __ Bind(&conditions_on_positions_validated); 14405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetSourceIsNotNull()) { 14425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is null. 14435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(src, slow_path->GetEntryLabel()); 14445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) { 14475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is null. 14485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(dest, slow_path->GetEntryLabel()); 14495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // If the length is negative, bail out. 14525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // We have already checked in the LocationsBuilder for the constant case. 14535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!length.IsConstant() && 14545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetCountIsSourceLength() && 14555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetCountIsDestinationLength()) { 14565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(length.AsRegister<Register>(), ShifterOperand(0)); 14575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Validity checks: source. 14615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CheckPosition(assembler, 14625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray src_pos, 14635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray src, 14645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray length, 14655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray slow_path, 14665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp1, 14675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 14685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray optimizations.GetCountIsSourceLength()); 14695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Validity checks: dest. 14715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CheckPosition(assembler, 14725bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest_pos, 14735bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest, 14745bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray length, 14755bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray slow_path, 14765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp1, 14775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 14785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray optimizations.GetCountIsDestinationLength()); 14795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDoesNotNeedTypeCheck()) { 14815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check whether all elements of the source array are assignable to the component 14825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // type of the destination array. We do two checks: the classes are the same, 14835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // or the destination is Object[]. If none of these checks succeed, we go to the 14845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // slow path. 14855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, dest, class_offset); 14865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp2, src, class_offset); 14875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray bool did_unpoison = false; 14885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNonPrimitiveArray() || 14895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetSourceIsNonPrimitiveArray()) { 1490ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain // One or two of the references need to be unpoisoned. Unpoison them 14915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // both to make the identity check valid. 14925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 14935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp2); 14945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray did_unpoison = true; 14955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNonPrimitiveArray()) { 14985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is not a non primitive array. 1499ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain // /* HeapReference<Class> */ temp3 = temp1->component_type_ 15005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset); 15015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 15025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 15035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 15045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 15055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 15065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetSourceIsNonPrimitiveArray()) { 15095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is not a non primitive array. 1510ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain // /* HeapReference<Class> */ temp3 = temp2->component_type_ 15115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp2, component_offset); 15125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 15135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 15145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 15155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 15165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 15175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp2)); 15205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (optimizations.GetDestinationIsTypedObjectArray()) { 15225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label do_copy; 15235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&do_copy, EQ); 15245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!did_unpoison) { 15255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 15265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 1527ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain // /* HeapReference<Class> */ temp1 = temp1->component_type_ 15285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset); 15295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 1530ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain // /* HeapReference<Class> */ temp1 = temp1->super_class_ 15315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset); 15325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // No need to unpoison the result, we're comparing against null. 15335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel()); 15345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&do_copy); 15355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), NE); 15375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { 15395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); 15405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is not a non primitive array. 1541ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain // /* HeapReference<Class> */ temp1 = src->klass_ 15425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, src, class_offset); 15435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 1544ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain // /* HeapReference<Class> */ temp3 = temp1->component_type_ 15455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset); 15465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 15475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 15485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 15495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 15505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 15515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Compute base source address, base destination address, and end source address. 15545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t element_size = sizeof(int32_t); 15565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t offset = mirror::Array::DataOffset(element_size).Uint32Value(); 15575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos.IsConstant()) { 15585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); 15595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp1, src, element_size * constant + offset); 15605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp1, src, ShifterOperand(src_pos.AsRegister<Register>(), LSL, 2)); 15625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp1, offset); 15635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 15665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); 15675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp2, dest, element_size * constant + offset); 15685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp2, dest, ShifterOperand(dest_pos.AsRegister<Register>(), LSL, 2)); 15705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp2, offset); 15715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15725bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15735bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 15745bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = length.GetConstant()->AsIntConstant()->GetValue(); 15755bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp3, temp1, element_size * constant); 15765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp3, temp1, ShifterOperand(length.AsRegister<Register>(), LSL, 2)); 15785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Iterate over the arrays and do a raw copy of the objects. We don't need to 15815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // poison/unpoison, nor do any read barrier as the next uses of the destination 15825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // array will do it. 15835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label loop, done; 15845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp3)); 15855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&done, EQ); 15865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&loop); 15875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ ldr(IP, Address(temp1, element_size, Address::PostIndex)); 15885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ str(IP, Address(temp2, element_size, Address::PostIndex)); 15895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp3)); 15905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&loop, NE); 15915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&done); 15925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // We only need one card marking on the destination array. 15945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray codegen_->MarkGCCard(temp1, 15955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 15965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest, 15975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register(kNoRegister), 1598ebea3d2cce6aa34216502bb6b83d155d4c92e4ffRoland Levillain /* value_can_be_null */ false); 15995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(slow_path->GetExitLabel()); 16015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 16025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 1603d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovstatic void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) { 1604d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // If the graph is debuggable, all callee-saved floating-point registers are blocked by 1605d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // the code generator. Furthermore, the register allocator creates fixed live intervals 1606d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // for all caller-saved registers because we are doing a function call. As a result, if 1607d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // the input and output locations are unallocated, the register allocator runs out of 1608d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // registers and fails; however, a debuggable graph is not the common case. 1609d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov if (invoke->GetBlock()->GetGraph()->IsDebuggable()) { 1610d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov return; 1611d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov } 1612d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1613d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->GetNumberOfArguments(), 1U); 1614d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble); 1615d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble); 1616d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1617d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov LocationSummary* const locations = new (arena) LocationSummary(invoke, 1618d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov LocationSummary::kCall, 1619d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov kIntrinsified); 1620d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov const InvokeRuntimeCallingConvention calling_convention; 1621d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1622d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->SetInAt(0, Location::RequiresFpuRegister()); 1623d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->SetOut(Location::RequiresFpuRegister()); 1624d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // Native code uses the soft float ABI. 1625d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1626d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1627d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1628d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1629d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovstatic void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) { 1630d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // If the graph is debuggable, all callee-saved floating-point registers are blocked by 1631d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // the code generator. Furthermore, the register allocator creates fixed live intervals 1632d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // for all caller-saved registers because we are doing a function call. As a result, if 1633d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // the input and output locations are unallocated, the register allocator runs out of 1634d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // registers and fails; however, a debuggable graph is not the common case. 1635d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov if (invoke->GetBlock()->GetGraph()->IsDebuggable()) { 1636d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov return; 1637d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov } 1638d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1639d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->GetNumberOfArguments(), 2U); 1640d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble); 1641d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->InputAt(1)->GetType(), Primitive::kPrimDouble); 1642d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble); 1643d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1644d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov LocationSummary* const locations = new (arena) LocationSummary(invoke, 1645d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov LocationSummary::kCall, 1646d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov kIntrinsified); 1647d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov const InvokeRuntimeCallingConvention calling_convention; 1648d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1649d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->SetInAt(0, Location::RequiresFpuRegister()); 1650d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->SetInAt(1, Location::RequiresFpuRegister()); 1651d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->SetOut(Location::RequiresFpuRegister()); 1652d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // Native code uses the soft float ABI. 1653d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1654d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1655d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1656d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3))); 1657d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1658d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1659d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovstatic void GenFPToFPCall(HInvoke* invoke, 1660d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov ArmAssembler* assembler, 1661d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CodeGeneratorARM* codegen, 1662d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov QuickEntrypointEnum entry) { 1663d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov LocationSummary* const locations = invoke->GetLocations(); 1664d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov const InvokeRuntimeCallingConvention calling_convention; 1665d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1666d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->GetNumberOfArguments(), 1U); 1667d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(locations->WillCall() && locations->Intrinsified()); 1668d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0))); 1669d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1))); 1670d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1671d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value()); 1672d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // Native code uses the soft float ABI. 1673d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ vmovrrd(calling_convention.GetRegisterAt(0), 1674d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov calling_convention.GetRegisterAt(1), 1675d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>())); 1676d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ blx(LR); 1677d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov codegen->RecordPcInfo(invoke, invoke->GetDexPc()); 1678d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()), 1679d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov calling_convention.GetRegisterAt(0), 1680d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov calling_convention.GetRegisterAt(1)); 1681d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1682d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1683d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovstatic void GenFPFPToFPCall(HInvoke* invoke, 1684d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov ArmAssembler* assembler, 1685d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CodeGeneratorARM* codegen, 1686d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov QuickEntrypointEnum entry) { 1687d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov LocationSummary* const locations = invoke->GetLocations(); 1688d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov const InvokeRuntimeCallingConvention calling_convention; 1689d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1690d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK_EQ(invoke->GetNumberOfArguments(), 2U); 1691d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(locations->WillCall() && locations->Intrinsified()); 1692d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0))); 1693d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1))); 1694d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(2))); 1695d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(3))); 1696d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1697d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value()); 1698d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov // Native code uses the soft float ABI. 1699d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ vmovrrd(calling_convention.GetRegisterAt(0), 1700d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov calling_convention.GetRegisterAt(1), 1701d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>())); 1702d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ vmovrrd(calling_convention.GetRegisterAt(2), 1703d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov calling_convention.GetRegisterAt(3), 1704d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>())); 1705d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ blx(LR); 1706d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov codegen->RecordPcInfo(invoke, invoke->GetDexPc()); 1707d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()), 1708d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov calling_convention.GetRegisterAt(0), 1709d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov calling_convention.GetRegisterAt(1)); 1710d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1711d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1712d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathCos(HInvoke* invoke) { 1713d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1714d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1715d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1716d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathCos(HInvoke* invoke) { 1717d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCos); 1718d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1719d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1720d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathSin(HInvoke* invoke) { 1721d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1722d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1723d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1724d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathSin(HInvoke* invoke) { 1725d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSin); 1726d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1727d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1728d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathAcos(HInvoke* invoke) { 1729d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1730d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1731d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1732d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathAcos(HInvoke* invoke) { 1733d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAcos); 1734d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1735d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1736d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathAsin(HInvoke* invoke) { 1737d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1738d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1739d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1740d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathAsin(HInvoke* invoke) { 1741d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAsin); 1742d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1743d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1744d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathAtan(HInvoke* invoke) { 1745d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1746d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1747d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1748d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathAtan(HInvoke* invoke) { 1749d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan); 1750d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1751d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1752d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathCbrt(HInvoke* invoke) { 1753d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1754d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1755d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1756d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathCbrt(HInvoke* invoke) { 1757d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCbrt); 1758d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1759d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1760d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathCosh(HInvoke* invoke) { 1761d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1762d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1763d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1764d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathCosh(HInvoke* invoke) { 1765d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCosh); 1766d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1767d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1768d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathExp(HInvoke* invoke) { 1769d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1770d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1771d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1772d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathExp(HInvoke* invoke) { 1773d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExp); 1774d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1775d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1776d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathExpm1(HInvoke* invoke) { 1777d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1778d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1779d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1780d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathExpm1(HInvoke* invoke) { 1781d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExpm1); 1782d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1783d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1784d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathLog(HInvoke* invoke) { 1785d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1786d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1787d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1788d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathLog(HInvoke* invoke) { 1789d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog); 1790d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1791d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1792d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathLog10(HInvoke* invoke) { 1793d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1794d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1795d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1796d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathLog10(HInvoke* invoke) { 1797d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog10); 1798d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1799d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1800d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathSinh(HInvoke* invoke) { 1801d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1802d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1803d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1804d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathSinh(HInvoke* invoke) { 1805d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSinh); 1806d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1807d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1808d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathTan(HInvoke* invoke) { 1809d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1810d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1811d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1812d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathTan(HInvoke* invoke) { 1813d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTan); 1814d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1815d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1816d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathTanh(HInvoke* invoke) { 1817d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPToFPCallLocations(arena_, invoke); 1818d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1819d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1820d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathTanh(HInvoke* invoke) { 1821d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTanh); 1822d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1823d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1824d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathAtan2(HInvoke* invoke) { 1825d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPFPToFPCallLocations(arena_, invoke); 1826d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1827d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1828d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathAtan2(HInvoke* invoke) { 1829d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan2); 1830d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1831d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1832d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathHypot(HInvoke* invoke) { 1833d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPFPToFPCallLocations(arena_, invoke); 1834d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1835d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1836d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathHypot(HInvoke* invoke) { 1837d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickHypot); 1838d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1839d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1840d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicLocationsBuilderARM::VisitMathNextAfter(HInvoke* invoke) { 1841d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov CreateFPFPToFPCallLocations(arena_, invoke); 1842d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1843d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1844d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilovvoid IntrinsicCodeGeneratorARM::VisitMathNextAfter(HInvoke* invoke) { 1845d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickNextAfter); 1846d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov} 1847d70dc9d824b715475d7fb3900757dba2f4d67f50Anton Kirilov 1848c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicLocationsBuilderARM::VisitIntegerReverse(HInvoke* invoke) { 1849c257da7b0fb6737f65aba426add8831e45404755Artem Serov CreateIntToIntLocations(arena_, invoke); 1850c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1851c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1852c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicCodeGeneratorARM::VisitIntegerReverse(HInvoke* invoke) { 1853c257da7b0fb6737f65aba426add8831e45404755Artem Serov ArmAssembler* assembler = GetAssembler(); 1854c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary* locations = invoke->GetLocations(); 1855c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1856c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register out = locations->Out().AsRegister<Register>(); 1857c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register in = locations->InAt(0).AsRegister<Register>(); 1858c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1859c257da7b0fb6737f65aba426add8831e45404755Artem Serov __ rbit(out, in); 1860c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1861c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1862c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicLocationsBuilderARM::VisitLongReverse(HInvoke* invoke) { 1863c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary* locations = new (arena_) LocationSummary(invoke, 1864c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary::kNoCall, 1865c257da7b0fb6737f65aba426add8831e45404755Artem Serov kIntrinsified); 1866c257da7b0fb6737f65aba426add8831e45404755Artem Serov locations->SetInAt(0, Location::RequiresRegister()); 1867c257da7b0fb6737f65aba426add8831e45404755Artem Serov locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 1868c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1869c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1870c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicCodeGeneratorARM::VisitLongReverse(HInvoke* invoke) { 1871c257da7b0fb6737f65aba426add8831e45404755Artem Serov ArmAssembler* assembler = GetAssembler(); 1872c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary* locations = invoke->GetLocations(); 1873c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1874c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); 1875c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); 1876c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>(); 1877c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>(); 1878c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1879c257da7b0fb6737f65aba426add8831e45404755Artem Serov __ rbit(out_reg_lo, in_reg_hi); 1880c257da7b0fb6737f65aba426add8831e45404755Artem Serov __ rbit(out_reg_hi, in_reg_lo); 1881c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1882c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1883c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicLocationsBuilderARM::VisitIntegerReverseBytes(HInvoke* invoke) { 1884c257da7b0fb6737f65aba426add8831e45404755Artem Serov CreateIntToIntLocations(arena_, invoke); 1885c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1886c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1887c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicCodeGeneratorARM::VisitIntegerReverseBytes(HInvoke* invoke) { 1888c257da7b0fb6737f65aba426add8831e45404755Artem Serov ArmAssembler* assembler = GetAssembler(); 1889c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary* locations = invoke->GetLocations(); 1890c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1891c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register out = locations->Out().AsRegister<Register>(); 1892c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register in = locations->InAt(0).AsRegister<Register>(); 1893c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1894c257da7b0fb6737f65aba426add8831e45404755Artem Serov __ rev(out, in); 1895c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1896c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1897c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicLocationsBuilderARM::VisitLongReverseBytes(HInvoke* invoke) { 1898c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary* locations = new (arena_) LocationSummary(invoke, 1899c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary::kNoCall, 1900c257da7b0fb6737f65aba426add8831e45404755Artem Serov kIntrinsified); 1901c257da7b0fb6737f65aba426add8831e45404755Artem Serov locations->SetInAt(0, Location::RequiresRegister()); 1902c257da7b0fb6737f65aba426add8831e45404755Artem Serov locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 1903c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1904c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1905c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicCodeGeneratorARM::VisitLongReverseBytes(HInvoke* invoke) { 1906c257da7b0fb6737f65aba426add8831e45404755Artem Serov ArmAssembler* assembler = GetAssembler(); 1907c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary* locations = invoke->GetLocations(); 1908c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1909c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); 1910c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); 1911c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>(); 1912c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>(); 1913c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1914c257da7b0fb6737f65aba426add8831e45404755Artem Serov __ rev(out_reg_lo, in_reg_hi); 1915c257da7b0fb6737f65aba426add8831e45404755Artem Serov __ rev(out_reg_hi, in_reg_lo); 1916c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1917c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1918c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicLocationsBuilderARM::VisitShortReverseBytes(HInvoke* invoke) { 1919c257da7b0fb6737f65aba426add8831e45404755Artem Serov CreateIntToIntLocations(arena_, invoke); 1920c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1921c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1922c257da7b0fb6737f65aba426add8831e45404755Artem Serovvoid IntrinsicCodeGeneratorARM::VisitShortReverseBytes(HInvoke* invoke) { 1923c257da7b0fb6737f65aba426add8831e45404755Artem Serov ArmAssembler* assembler = GetAssembler(); 1924c257da7b0fb6737f65aba426add8831e45404755Artem Serov LocationSummary* locations = invoke->GetLocations(); 1925c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1926c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register out = locations->Out().AsRegister<Register>(); 1927c257da7b0fb6737f65aba426add8831e45404755Artem Serov Register in = locations->InAt(0).AsRegister<Register>(); 1928c257da7b0fb6737f65aba426add8831e45404755Artem Serov 1929c257da7b0fb6737f65aba426add8831e45404755Artem Serov __ revsh(out, in); 1930c257da7b0fb6737f65aba426add8831e45404755Artem Serov} 1931c257da7b0fb6737f65aba426add8831e45404755Artem Serov 193225abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhangvoid IntrinsicLocationsBuilderARM::VisitStringGetCharsNoCheck(HInvoke* invoke) { 193325abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang LocationSummary* locations = new (arena_) LocationSummary(invoke, 193425abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang LocationSummary::kNoCall, 193525abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang kIntrinsified); 193625abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->SetInAt(0, Location::RequiresRegister()); 193725abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->SetInAt(1, Location::RequiresRegister()); 193825abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->SetInAt(2, Location::RequiresRegister()); 193925abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->SetInAt(3, Location::RequiresRegister()); 194025abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->SetInAt(4, Location::RequiresRegister()); 194125abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 194225abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->AddTemp(Location::RequiresRegister()); 194325abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->AddTemp(Location::RequiresRegister()); 194425abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->AddTemp(Location::RequiresRegister()); 194525abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang locations->AddTemp(Location::RequiresRegister()); 194625abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang} 194725abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 194825abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhangvoid IntrinsicCodeGeneratorARM::VisitStringGetCharsNoCheck(HInvoke* invoke) { 194925abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang ArmAssembler* assembler = GetAssembler(); 195025abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang LocationSummary* locations = invoke->GetLocations(); 195125abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 195225abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // Check assumption that sizeof(Char) is 2 (used in scaling below). 195325abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar); 195425abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang DCHECK_EQ(char_size, 2u); 195525abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 195625abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // Location of data in char array buffer. 195725abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value(); 195825abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 195925abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // Location of char array data in string. 196025abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); 196125abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 196225abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // void getCharsNoCheck(int srcBegin, int srcEnd, char[] dst, int dstBegin); 196325abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // Since getChars() calls getCharsNoCheck() - we use registers rather than constants. 196425abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register srcObj = locations->InAt(0).AsRegister<Register>(); 196525abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register srcBegin = locations->InAt(1).AsRegister<Register>(); 196625abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register srcEnd = locations->InAt(2).AsRegister<Register>(); 196725abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register dstObj = locations->InAt(3).AsRegister<Register>(); 196825abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register dstBegin = locations->InAt(4).AsRegister<Register>(); 196925abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 197025abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register src_ptr = locations->GetTemp(0).AsRegister<Register>(); 197125abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register src_ptr_end = locations->GetTemp(1).AsRegister<Register>(); 197225abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register dst_ptr = locations->GetTemp(2).AsRegister<Register>(); 197325abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Register tmp = locations->GetTemp(3).AsRegister<Register>(); 197425abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 197525abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // src range to copy. 197625abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ add(src_ptr, srcObj, ShifterOperand(value_offset)); 197725abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ add(src_ptr_end, src_ptr, ShifterOperand(srcEnd, LSL, 1)); 197825abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ add(src_ptr, src_ptr, ShifterOperand(srcBegin, LSL, 1)); 197925abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 198025abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // dst to be copied. 198125abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ add(dst_ptr, dstObj, ShifterOperand(data_offset)); 198225abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ add(dst_ptr, dst_ptr, ShifterOperand(dstBegin, LSL, 1)); 198325abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 198425abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang // Do the copy. 198525abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang Label loop, done; 198625abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ Bind(&loop); 198725abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ cmp(src_ptr, ShifterOperand(src_ptr_end)); 198825abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ b(&done, EQ); 198925abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ ldrh(tmp, Address(src_ptr, char_size, Address::PostIndex)); 199025abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ strh(tmp, Address(dst_ptr, char_size, Address::PostIndex)); 199125abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ b(&loop); 199225abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang __ Bind(&done); 199325abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang} 199425abd6c0c9f5a6abebcdeeb6f4373e85eedcfb6bTim Zhang 19952f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, IntegerBitCount) 19962f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, LongBitCount) 19972f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathMinDoubleDouble) 19982f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathMinFloatFloat) 19992f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathMaxDoubleDouble) 20002f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathMaxFloatFloat) 20012f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathMinLongLong) 20022f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathMaxLongLong) 20032f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathCeil) // Could be done by changing rounding mode, maybe? 20042f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathFloor) // Could be done by changing rounding mode, maybe? 20052f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathRint) 20062f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathRoundDouble) // Could be done by changing rounding mode, maybe? 20072f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, MathRoundFloat) // Could be done by changing rounding mode, maybe? 20082f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, UnsafeCASLong) // High register pressure. 20092f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, SystemArrayCopyChar) 20102f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, ReferenceGetReferent) 20112f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, FloatIsInfinite) 20122f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, DoubleIsInfinite) 20132f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, IntegerHighestOneBit) 20142f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, LongHighestOneBit) 20152f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, IntegerLowestOneBit) 20162f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(ARM, LongLowestOneBit) 20172f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart Bik 20180e54c0160c84894696c05af6cad9eae3690f9496Aart Bik// 1.8. 20190e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndAddInt) 20200e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndAddLong) 20210e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetInt) 20220e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetLong) 20230e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(ARM, UnsafeGetAndSetObject) 20240e54c0160c84894696c05af6cad9eae3690f9496Aart Bik 20252f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNREACHABLE_INTRINSICS(ARM) 20264d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 20274d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef __ 20284d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 20292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace arm 20302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace art 2031