intrinsics_arm.cc revision 4bedb3845ac33c95cb779987abd4e76a88b19989
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, 8102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe HInvoke* invoke) { 8112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 8122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 8132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 8142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 8152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 8162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 8172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(3, Location::RequiresRegister()); 8182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(4, Location::RequiresRegister()); 8192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 8212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Pointer. 8232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp 1. 8242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp 2. 8252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) { 8282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK_NE(type, Primitive::kPrimLong); 8292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 8312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Boolean result. 8332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 8352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Offset (discard high 4B). 8362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register expected_lo = locations->InAt(3).AsRegister<Register>(); // Expected. 8372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_lo = locations->InAt(4).AsRegister<Register>(); // Value. 8382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_ptr = locations->GetTemp(0).AsRegister<Register>(); // Pointer to actual memory. 8402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_lo = locations->GetTemp(1).AsRegister<Register>(); // Value in memory. 8412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimNot) { 8432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Mark card for object assuming new value is stored. Worst case we will mark an unchanged 8442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // object and scan the receiver at the next GC for nothing. 84507276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray bool value_can_be_null = true; // TODO: Worth finding out this information? 84607276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null); 8472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Prevent reordering with prior memory operations. 8504bedb3845ac33c95cb779987abd4e76a88b19989Roland Levillain // Emit a DMB ISH instruction instead of an DMB ISHST one, as the 8514bedb3845ac33c95cb779987abd4e76a88b19989Roland Levillain // latter allows a preceding load to be delayed past the STXR 8524bedb3845ac33c95cb779987abd4e76a88b19989Roland Levillain // instruction below. 8532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(tmp_ptr, base, ShifterOperand(offset)); 8562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8574d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 8584d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->PoisonHeapReference(expected_lo); 8594d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->PoisonHeapReference(value_lo); 8604d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 8614d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 8622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // do { 8632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // tmp = [r_ptr] - expected; 8642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // } while (tmp == 0 && failure([r_ptr] <- r_new_value)); 8652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // result = tmp != 0; 8662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Label loop_head; 8682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(&loop_head); 8692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 870391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // TODO: When `type == Primitive::kPrimNot`, add a read barrier for 871391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // the reference stored in the object before attempting the CAS, 872391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // similar to the one in the art::Unsafe_compareAndSwapObject JNI 873391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // implementation. 874391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // 875391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // Note that this code is not (yet) used when read barriers are 876391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // enabled (see IntrinsicLocationsBuilderARM::VisitUnsafeCASObject). 877391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain DCHECK(!(type == Primitive::kPrimNot && kEmitCompilerReadBarrier)); 8782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrex(tmp_lo, tmp_ptr); 8792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ subs(tmp_lo, tmp_lo, ShifterOperand(expected_lo)); 8812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(EQ, ItState::kItT); 8832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strex(tmp_lo, value_lo, tmp_ptr, EQ); 8842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(tmp_lo, ShifterOperand(1), EQ); 8852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(&loop_head, EQ); 8872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ rsbs(out, tmp_lo, ShifterOperand(1)); 8912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(CC); 8922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(0), CC); 8934d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 8944d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 8954d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(value_lo); 8964d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(expected_lo); 8974d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 8982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 900ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) { 9012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 9022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 903ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) { 904391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // The UnsafeCASObject intrinsic is missing a read barrier, and 905391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // therefore sometimes does not work as expected (b/25883050). 906391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // Turn it off temporarily as a quick fix, until the read barrier is 907391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // implemented (see TODO in GenCAS below). 9083b359c71f2fb784589be113206932e76807787bbRoland Levillain // 909391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // Also, the UnsafeCASObject intrinsic does not always work when heap 910391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // poisoning is enabled (it breaks run-test 004-UnsafeTest); turn it 911391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // off temporarily as a quick fix (b/26204023). 9123b359c71f2fb784589be113206932e76807787bbRoland Levillain // 913391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain // TODO(rpl): Fix these two issues and re-enable this intrinsic. 914391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain if (kEmitCompilerReadBarrier || kPoisonHeapReferences) { 915985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain return; 916985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain } 917985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain 9182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 9192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) { 9212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_); 9222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) { 9242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_); 9252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringCharAt(HInvoke* invoke) { 9282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 9292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kCallOnSlowPath, 9302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 9312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 9322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 9332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 9342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 9362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 9372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringCharAt(HInvoke* invoke) { 9402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 9412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 9422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of reference to data array 9442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset value_offset = mirror::String::ValueOffset(); 9452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of count 9462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset count_offset = mirror::String::CountOffset(); 9472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register obj = locations->InAt(0).AsRegister<Register>(); // String object pointer. 9492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register idx = locations->InAt(1).AsRegister<Register>(); // Index of character. 9502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Result character. 9512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp = locations->GetTemp(0).AsRegister<Register>(); 9532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register array_temp = locations->GetTemp(1).AsRegister<Register>(); 9542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth 9562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // the cost. 9572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: For simplicity, the index parameter is requested in a register, so different from Quick 9582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // we will not optimize the code for constants (which would save a register). 9592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 96085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 9612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->AddSlowPath(slow_path); 9622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(temp, Address(obj, count_offset.Int32Value())); // temp = str.length. 9642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->MaybeRecordImplicitNullCheck(invoke); 9652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(idx, ShifterOperand(temp)); 9662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(slow_path->GetEntryLabel(), CS); 9672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 968848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ add(array_temp, obj, ShifterOperand(value_offset.Int32Value())); // array_temp := str.value. 9692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Load the value. 971848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ ldrh(out, Address(array_temp, idx, LSL, 1)); // out := array_temp[idx]. 9722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(slow_path->GetExitLabel()); 9742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 976d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitStringCompareTo(HInvoke* invoke) { 977d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray // The inputs plus one temp. 978d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = new (arena_) LocationSummary(invoke, 979d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary::kCall, 980d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kIntrinsified); 981d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray InvokeRuntimeCallingConvention calling_convention; 982d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 983d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 984d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetOut(Location::RegisterLocation(R0)); 985d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 986d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 987d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitStringCompareTo(HInvoke* invoke) { 988d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray ArmAssembler* assembler = GetAssembler(); 989d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 990d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 991512e04d1ea7fb33e3992715fe55be8a834d4a79cNicolas Geoffray // Note that the null check must have been done earlier. 992641547a5f18ca2ea54469cceadcfef64f132e5e0Calin Juravle DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 993d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 994d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray Register argument = locations->InAt(1).AsRegister<Register>(); 995d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ cmp(argument, ShifterOperand(0)); 99685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 997d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray codegen_->AddSlowPath(slow_path); 998d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ b(slow_path->GetEntryLabel(), EQ); 999d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1000d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ LoadFromOffset( 1001d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pStringCompareTo).Int32Value()); 1002d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ blx(LR); 1003d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ Bind(slow_path->GetExitLabel()); 1004d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 1005d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1006289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicLocationsBuilderARM::VisitStringEquals(HInvoke* invoke) { 1007289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = new (arena_) LocationSummary(invoke, 1008289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary::kNoCall, 1009289cd55808111d23c92f2739a096942a8049649aAgi Csaki kIntrinsified); 1010289cd55808111d23c92f2739a096942a8049649aAgi Csaki InvokeRuntimeCallingConvention calling_convention; 1011289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(0, Location::RequiresRegister()); 1012289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(1, Location::RequiresRegister()); 1013289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Temporary registers to store lengths of strings and for calculations. 1014289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Using instruction cbz requires a low register, so explicitly set a temp to be R0. 1015289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RegisterLocation(R0)); 1016289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1017289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1018289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1019289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetOut(Location::RequiresRegister()); 1020289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1021289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1022289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicCodeGeneratorARM::VisitStringEquals(HInvoke* invoke) { 1023289cd55808111d23c92f2739a096942a8049649aAgi Csaki ArmAssembler* assembler = GetAssembler(); 1024289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = invoke->GetLocations(); 1025289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1026289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register str = locations->InAt(0).AsRegister<Register>(); 1027289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register arg = locations->InAt(1).AsRegister<Register>(); 1028289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register out = locations->Out().AsRegister<Register>(); 1029289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1030289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp = locations->GetTemp(0).AsRegister<Register>(); 1031289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp1 = locations->GetTemp(1).AsRegister<Register>(); 1032289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp2 = locations->GetTemp(2).AsRegister<Register>(); 1033289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1034289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label loop; 1035289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label end; 1036289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_true; 1037289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_false; 1038289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1039289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Get offsets of count, value, and class fields within a string object. 1040289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); 1041289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); 1042289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value(); 1043289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1044289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Note that the null check must have been done earlier. 1045289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1046289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1047289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if input is null, return false if it is. 1048289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ CompareAndBranchIfZero(arg, &return_false); 1049289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1050289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Instanceof check for the argument by comparing class fields. 1051289cd55808111d23c92f2739a096942a8049649aAgi Csaki // All string objects must have the same type since String cannot be subclassed. 1052289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Receiver must be a string object, so its class field is equal to all strings' class fields. 1053289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If the argument is a string object, its class field must be equal to receiver's class field. 1054289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, class_offset)); 1055289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, class_offset)); 1056289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1057289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1058289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1059289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Load lengths of this and argument strings. 1060289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, count_offset)); 1061289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, count_offset)); 1062289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if lengths are equal, return false if they're not. 1063289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1064289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1065289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true if both strings are empty. 1066289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cbz(temp, &return_true); 1067289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1068289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Reference equality check, return true if same reference. 1069289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(str, ShifterOperand(arg)); 1070289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_true, EQ); 1071289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1072289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Assertions that must hold in order to compare strings 2 characters at a time. 1073289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK_ALIGNED(value_offset, 4); 1074289cd55808111d23c92f2739a096942a8049649aAgi Csaki static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded"); 1075289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1076289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(temp1, value_offset); 1077289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1078289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Loop to compare strings 2 characters at a time starting at the front of the string. 1079289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Ok to do this because strings with an odd length are zero-padded. 1080289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&loop); 1081289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(out, Address(str, temp1)); 1082289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp2, Address(arg, temp1)); 1083289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(out, ShifterOperand(temp2)); 1084289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1085289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ add(temp1, temp1, ShifterOperand(sizeof(uint32_t))); 1086a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ subs(temp, temp, ShifterOperand(sizeof(uint32_t) / sizeof(uint16_t))); 1087a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ b(&loop, GT); 1088289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1089289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true and exit the function. 1090289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If loop does not result in returning false, we return true. 1091289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_true); 1092289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 1); 1093289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&end); 1094289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1095289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return false and exit the function. 1096289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_false); 1097289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 0); 1098289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&end); 1099289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1100289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1101ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampestatic void GenerateVisitStringIndexOf(HInvoke* invoke, 1102ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArmAssembler* assembler, 1103ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe CodeGeneratorARM* codegen, 1104ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArenaAllocator* allocator, 1105ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe bool start_at_zero) { 1106ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 1107ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register tmp_reg = locations->GetTemp(0).AsRegister<Register>(); 1108ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1109ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Note that the null check must have been done earlier. 1110ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1111ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1112ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically, 1113ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // or directly dispatch if we have a constant. 111485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = nullptr; 1115ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (invoke->InputAt(1)->IsIntConstant()) { 1116ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) > 1117ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe std::numeric_limits<uint16_t>::max()) { 1118ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Always needs the slow-path. We could directly dispatch to it, but this case should be 1119ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // rare, so for simplicity just put the full slow-path down and branch unconditionally. 1120ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1121ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1122ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel()); 1123ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1124ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe return; 1125ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1126ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } else { 1127ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register char_reg = locations->InAt(1).AsRegister<Register>(); 1128ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, std::numeric_limits<uint16_t>::max()); 1129ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ cmp(char_reg, ShifterOperand(tmp_reg)); 1130ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1131ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1132ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel(), HI); 1133ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1134ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1135ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (start_at_zero) { 1136ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK_EQ(tmp_reg, R2); 1137ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Start-index = 0. 1138ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, 0); 1139ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1140ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1141ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadFromOffset(kLoadWord, LR, TR, 1142ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value()); 1143ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ blx(LR); 1144ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1145ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (slow_path != nullptr) { 1146ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1147ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1148ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1149ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1150ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) { 1151ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1152ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1153ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1154ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1155ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1156ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1157ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1158ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1159ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1160ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1161ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare, and need to send start-index=0. 1162ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1163ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1164ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1165ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) { 1166bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenerateVisitStringIndexOf( 1167bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); 1168ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1169ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1170ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1171ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1172ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1173ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1174ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1175ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1176ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1177ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1178ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1179ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1180ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1181ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1182ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare. 1183ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 1184ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1185ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1186ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1187bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenerateVisitStringIndexOf( 1188bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); 1189ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1190ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1191848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1192848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1193848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1194848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1195848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1196848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1197848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1198848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1199848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3))); 1200848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1201848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1202848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1203848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1204848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1205848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1206848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1207848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register byte_array = locations->InAt(0).AsRegister<Register>(); 1208848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(byte_array, ShifterOperand(0)); 120985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1210848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1211848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1212848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1213848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1214848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromBytes).Int32Value()); 1215848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1216848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1217848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1218848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1219848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1220848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1221848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1222848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1223848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1224848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1225848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1226848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1227848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1228848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1229848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1230848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1231848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1232848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1233848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1234848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1235848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value()); 1236848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1237848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1238848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1239848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1240848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) { 1241848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1242848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1243848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1244848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1245848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1246848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1247848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1248848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1249848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) { 1250848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1251848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1252848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1253848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register string_to_copy = locations->InAt(0).AsRegister<Register>(); 1254848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(string_to_copy, ShifterOperand(0)); 125585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1256848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1257848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1258848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1259848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset(kLoadWord, 1260848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromString).Int32Value()); 1261848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1262848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1263848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1264848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1265848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 12665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitSystemArrayCopy(HInvoke* invoke) { 12675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke); 12685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 12695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (locations == nullptr) { 12705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray return; 12715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 12725bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 12735bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant(); 12745bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant(); 12755bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* length = invoke->InputAt(4)->AsIntConstant(); 12765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 12775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(src_pos->GetValue())) { 12785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(1, Location::RequiresRegister()); 12795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 12805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(dest_pos->GetValue())) { 12815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(3, Location::RequiresRegister()); 12825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 12835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length != nullptr && !assembler_->ShifterOperandCanAlwaysHold(length->GetValue())) { 12845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(4, Location::RequiresRegister()); 12855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 12865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 12875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 12885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffraystatic void CheckPosition(ArmAssembler* assembler, 12895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location pos, 12905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register input, 12915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location length, 12925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SlowPathCode* slow_path, 12935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register input_len, 12945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp, 12955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray bool length_is_input_length = false) { 12965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Where is the length in the Array? 12975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value(); 12985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 12995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (pos.IsConstant()) { 13005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue(); 13015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (pos_const == 0) { 13025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!length_is_input_length) { 13035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that length(input) >= length. 13045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp, input, length_offset); 13055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 13065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 13075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 13095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13105bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that length(input) >= pos. 13145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, input_len, input, length_offset); 13155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ subs(temp, input_len, ShifterOperand(pos_const)); 13165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that (length(input) - pos) >= length. 13195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 13205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 13215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 13235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else if (length_is_input_length) { 13275bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // The only way the copy can succeed is if pos is zero. 13285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register pos_reg = pos.AsRegister<Register>(); 13295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(pos_reg, slow_path->GetEntryLabel()); 13305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that pos >= 0. 13325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register pos_reg = pos.AsRegister<Register>(); 13335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(pos_reg, ShifterOperand(0)); 13345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that pos <= length(input). 13375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp, input, length_offset); 13385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ subs(temp, temp, ShifterOperand(pos_reg)); 13395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that (length(input) - pos) >= length. 13425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 13435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 13445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 13465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 13485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 13505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13513b359c71f2fb784589be113206932e76807787bbRoland Levillain// TODO: Implement read barriers in the SystemArrayCopy intrinsic. 13523b359c71f2fb784589be113206932e76807787bbRoland Levillain// Note that this code path is not used (yet) because we do not 13533b359c71f2fb784589be113206932e76807787bbRoland Levillain// intrinsify methods that can go into the IntrinsicSlowPathARM 13543b359c71f2fb784589be113206932e76807787bbRoland Levillain// slow path. 13555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) { 13565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray ArmAssembler* assembler = GetAssembler(); 13575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 13585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 13605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); 13615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); 13625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); 13635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register src = locations->InAt(0).AsRegister<Register>(); 13655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location src_pos = locations->InAt(1); 13665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register dest = locations->InAt(2).AsRegister<Register>(); 13675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location dest_pos = locations->InAt(3); 13685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location length = locations->InAt(4); 13695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp1 = locations->GetTemp(0).AsRegister<Register>(); 13705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp2 = locations->GetTemp(1).AsRegister<Register>(); 13715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp3 = locations->GetTemp(2).AsRegister<Register>(); 13725bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13735bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 13745bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray codegen_->AddSlowPath(slow_path); 13755bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label ok; 13775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SystemArrayCopyOptimizations optimizations(invoke); 13785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 13805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!src_pos.IsConstant() || !dest_pos.IsConstant()) { 13815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src, ShifterOperand(dest)); 13825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // If source and destination are the same, we go to slow path if we need to do 13865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // forward copying. 13875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos.IsConstant()) { 13885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); 13895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 13905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Checked when building locations. 13915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray DCHECK(!optimizations.GetDestinationIsSource() 13925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray || (src_pos_constant >= dest_pos.GetConstant()->AsIntConstant()->GetValue())); 13935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 13945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 13955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&ok, NE); 13965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(dest_pos.AsRegister<Register>(), ShifterOperand(src_pos_constant)); 13985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), GT); 13995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 14025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&ok, NE); 14035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 14055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); 14065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos_constant)); 14075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos.AsRegister<Register>())); 14095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14105bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&ok); 14145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetSourceIsNotNull()) { 14165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is null. 14175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(src, slow_path->GetEntryLabel()); 14185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) { 14215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is null. 14225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(dest, slow_path->GetEntryLabel()); 14235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // If the length is negative, bail out. 14265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // We have already checked in the LocationsBuilder for the constant case. 14275bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!length.IsConstant() && 14285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetCountIsSourceLength() && 14295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetCountIsDestinationLength()) { 14305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(length.AsRegister<Register>(), ShifterOperand(0)); 14315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Validity checks: source. 14355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CheckPosition(assembler, 14365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray src_pos, 14375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray src, 14385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray length, 14395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray slow_path, 14405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp1, 14415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 14425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray optimizations.GetCountIsSourceLength()); 14435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Validity checks: dest. 14455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CheckPosition(assembler, 14465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest_pos, 14475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest, 14485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray length, 14495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray slow_path, 14505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp1, 14515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 14525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray optimizations.GetCountIsDestinationLength()); 14535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDoesNotNeedTypeCheck()) { 14555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check whether all elements of the source array are assignable to the component 14565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // type of the destination array. We do two checks: the classes are the same, 14575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // or the destination is Object[]. If none of these checks succeed, we go to the 14585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // slow path. 14595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, dest, class_offset); 14605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp2, src, class_offset); 14615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray bool did_unpoison = false; 14625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNonPrimitiveArray() || 14635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetSourceIsNonPrimitiveArray()) { 14645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // One or two of the references need to be unpoisoned. Unpoisoned them 14655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // both to make the identity check valid. 14665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 14675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp2); 14685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray did_unpoison = true; 14695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNonPrimitiveArray()) { 14725bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is not a non primitive array. 14735bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset); 14745bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 14755bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 14765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 14775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 14785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 14795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetSourceIsNonPrimitiveArray()) { 14825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is not a non primitive array. 14835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is not a non primitive array. 14845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp2, component_offset); 14855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 14865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 14875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 14885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 14895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 14905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp2)); 14935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (optimizations.GetDestinationIsTypedObjectArray()) { 14955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label do_copy; 14965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&do_copy, EQ); 14975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!did_unpoison) { 14985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 14995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset); 15015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 15025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset); 15035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // No need to unpoison the result, we're comparing against null. 15045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel()); 15055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&do_copy); 15065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), NE); 15085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { 15105bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); 15115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is not a non primitive array. 15125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, src, class_offset); 15135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 15145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset); 15155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 15165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 15175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 15185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 15195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 15205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Compute base source address, base destination address, and end source address. 15235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t element_size = sizeof(int32_t); 15255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t offset = mirror::Array::DataOffset(element_size).Uint32Value(); 15265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos.IsConstant()) { 15275bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); 15285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp1, src, element_size * constant + offset); 15295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp1, src, ShifterOperand(src_pos.AsRegister<Register>(), LSL, 2)); 15315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp1, offset); 15325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 15355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); 15365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp2, dest, element_size * constant + offset); 15375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp2, dest, ShifterOperand(dest_pos.AsRegister<Register>(), LSL, 2)); 15395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp2, offset); 15405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 15435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = length.GetConstant()->AsIntConstant()->GetValue(); 15445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp3, temp1, element_size * constant); 15455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp3, temp1, ShifterOperand(length.AsRegister<Register>(), LSL, 2)); 15475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Iterate over the arrays and do a raw copy of the objects. We don't need to 15505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // poison/unpoison, nor do any read barrier as the next uses of the destination 15515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // array will do it. 15525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label loop, done; 15535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp3)); 15545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&done, EQ); 15555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&loop); 15565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ ldr(IP, Address(temp1, element_size, Address::PostIndex)); 15575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ str(IP, Address(temp2, element_size, Address::PostIndex)); 15585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp3)); 15595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&loop, NE); 15605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&done); 15615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // We only need one card marking on the destination array. 15635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray codegen_->MarkGCCard(temp1, 15645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 15655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest, 15665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register(kNoRegister), 1567bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* can_be_null */ false); 15685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(slow_path->GetExitLabel()); 15705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 15715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe// Unimplemented intrinsics. 15732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 15742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define UNIMPLEMENTED_INTRINSIC(Name) \ 15752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 15762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} \ 15772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 15782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 15792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 15802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverse) 15812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverseBytes) 158240a04bf64e5837fa48aceaffe970c9984c94084aScott WakelingUNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) 158340a04bf64e5837fa48aceaffe970c9984c94084aScott WakelingUNIMPLEMENTED_INTRINSIC(IntegerRotateRight) 15842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverse) 15852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverseBytes) 158640a04bf64e5837fa48aceaffe970c9984c94084aScott WakelingUNIMPLEMENTED_INTRINSIC(LongRotateLeft) 158740a04bf64e5837fa48aceaffe970c9984c94084aScott WakelingUNIMPLEMENTED_INTRINSIC(LongRotateRight) 15882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ShortReverseBytes) 15892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble) 15902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinFloatFloat) 15912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble) 15922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxFloatFloat) 15932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinLongLong) 15942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxLongLong) 15952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathCeil) // Could be done by changing rounding mode, maybe? 15962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathFloor) // Could be done by changing rounding mode, maybe? 15972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRint) 15982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundDouble) // Could be done by changing rounding mode, maybe? 15992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundFloat) // Could be done by changing rounding mode, maybe? 16002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(UnsafeCASLong) // High register pressure. 16012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) 16022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) 1603848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff HaoUNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) 1604a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathCos) 1605a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathSin) 1606a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathAcos) 1607a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathAsin) 1608a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathAtan) 1609a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathAtan2) 1610a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathCbrt) 1611a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathCosh) 1612a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathExp) 1613a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathExpm1) 1614a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathHypot) 1615a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathLog) 1616a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathLog10) 1617a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathNextAfter) 1618a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathSinh) 1619a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathTan) 1620a4f1220c1518074db18ca1044e9201492975750bMark MendellUNIMPLEMENTED_INTRINSIC(MathTanh) 16212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 16224d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef UNIMPLEMENTED_INTRINSIC 16234d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 16244d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef __ 16254d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 16262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace arm 16272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace art 1628