intrinsics_arm.cc revision bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57
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 2439ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingstatic void GenIntegerRotate(LocationSummary* locations, 2449ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling ArmAssembler* assembler, 2459ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling bool is_left) { 2469ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in = locations->InAt(0).AsRegister<Register>(); 2479ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Location rhs = locations->InAt(1); 2489ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out = locations->Out().AsRegister<Register>(); 2499ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2509ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rhs.IsConstant()) { 2519ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31], 2529ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // so map all rotations to a +ve. equivalent in that range. 2539ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // (e.g. left *or* right by -2 bits == 30 bits in the same direction.) 2549ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue() & 0x1F; 2559ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rot) { 2569ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Rotate, mapping left rotations to right equivalents if necessary. 2579ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // (e.g. left by 2 bits == right by 30.) 2589ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Ror(out, in, is_left ? (0x20 - rot) : rot); 2599ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else if (out != in) { 2609ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Mov(out, in); 2619ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2629ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 2639ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (is_left) { 2649ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rsb(out, rhs.AsRegister<Register>(), ShifterOperand(0)); 2659ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Ror(out, in, out); 2669ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 2679ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Ror(out, in, rhs.AsRegister<Register>()); 2689ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2699ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2709ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2719ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2729ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer 2739ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// rotates by swapping input regs (effectively rotating by the first 32-bits of 2749ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// a larger rotation) or flipping direction (thus treating larger right/left 2759ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// rotations as sub-word sized rotations in the other direction) as appropriate. 2769ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingstatic void GenLongRotate(LocationSummary* locations, 2779ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling ArmAssembler* assembler, 2789ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling bool is_left) { 2799ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); 2809ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); 2819ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Location rhs = locations->InAt(1); 2829ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>(); 2839ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>(); 2849ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2859ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rhs.IsConstant()) { 2869ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue(); 2879ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Map all left rotations to right equivalents. 2889ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (is_left) { 2899ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling rot = 0x40 - rot; 2909ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2919ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Map all rotations to +ve. equivalents on the interval [0,63]. 2929ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling rot &= 0x3F; 2939ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate 2949ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // logic below to a simple pair of binary orr. 2959ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // (e.g. 34 bits == in_reg swap + 2 bits right.) 2969ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rot >= 0x20) { 2979ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling rot -= 0x20; 2989ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling std::swap(in_reg_hi, in_reg_lo); 2999ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3009ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Rotate, or mov to out for zero or word size rotations. 3019ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rot) { 3029ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_hi, in_reg_hi, rot); 3039ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, 0x20 - rot)); 3049ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_lo, in_reg_lo, rot); 3059ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, 0x20 - rot)); 3069ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 3079ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Mov(out_reg_lo, in_reg_lo); 3089ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Mov(out_reg_hi, in_reg_hi); 3099ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3109ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 3119ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register shift_left = locations->GetTemp(0).AsRegister<Register>(); 3129ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register shift_right = locations->GetTemp(1).AsRegister<Register>(); 3139ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Label end; 3149ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Label right; 3159ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3169ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ and_(shift_left, rhs.AsRegister<Register>(), ShifterOperand(0x1F)); 3179ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsrs(shift_right, rhs.AsRegister<Register>(), 6); 3189ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rsb(shift_right, shift_left, ShifterOperand(0x20), AL, kCcKeep); 3199ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3209ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (is_left) { 3219ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ b(&right, CS); 3229ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 3239ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ b(&right, CC); 3249ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling std::swap(shift_left, shift_right); 3259ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3269ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3279ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right). 3289ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right). 3299ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(out_reg_hi, in_reg_hi, shift_left); 3309ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_lo, in_reg_lo, shift_right); 3319ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo)); 3329ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(out_reg_lo, in_reg_lo, shift_left); 3339ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(shift_left, in_reg_hi, shift_right); 3349ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left)); 3359ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ b(&end); 3369ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3379ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left). 3389ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left). 3399ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Bind(&right); 3409ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_hi, in_reg_hi, shift_right); 3419ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(out_reg_lo, in_reg_lo, shift_left); 3429ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo)); 3439ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_lo, in_reg_lo, shift_right); 3449ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(shift_right, in_reg_hi, shift_left); 3459ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right)); 3469ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3479ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Bind(&end); 3489ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3499ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3509ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3519ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerRotateRight(HInvoke* invoke) { 3529ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3539ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3549ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 3559ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 3569ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); 3579ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3589ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3599ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3609ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerRotateRight(HInvoke* invoke) { 361bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenIntegerRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ false); 3629ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3639ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3649ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongRotateRight(HInvoke* invoke) { 3659ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3669ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3679ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 3689ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 3699ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (invoke->InputAt(1)->IsConstant()) { 3709ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant())); 3719ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 3729ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RequiresRegister()); 3739ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 3749ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 3759ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3769ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 3779ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3789ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3799ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongRotateRight(HInvoke* invoke) { 380bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenLongRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ false); 3819ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3829ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3839ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerRotateLeft(HInvoke* invoke) { 3849ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3859ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3869ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 3879ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 3889ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); 3899ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 3909ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3919ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3929ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerRotateLeft(HInvoke* invoke) { 393bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenIntegerRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ true); 3949ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3959ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3969ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongRotateLeft(HInvoke* invoke) { 3979ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3989ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3999ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 4009ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 4019ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (invoke->InputAt(1)->IsConstant()) { 4029ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant())); 4039ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 4049ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RequiresRegister()); 4059ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 4069ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 4079ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 4089ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 4099ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 4109ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 4119ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongRotateLeft(HInvoke* invoke) { 412bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenLongRotate(invoke->GetLocations(), GetAssembler(), /* is_left */ true); 4139ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 4149ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 4152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 4162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location in = locations->InAt(0); 4172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location out = locations->Out(); 4182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 4202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vabsd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 4212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 4222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 4232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vabss(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>()); 4242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 4252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsDouble(HInvoke* invoke) { 4282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 4292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsDouble(HInvoke* invoke) { 432bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); 4332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) { 4362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 4372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsFloat(HInvoke* invoke) { 440bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); 4412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) { 4442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 4452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 4462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 4472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 4482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 4492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 4512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenAbsInteger(LocationSummary* locations, 4542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is64bit, 4552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler) { 4562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location in = locations->InAt(0); 4572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location output = locations->Out(); 4582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register mask = locations->GetTemp(0).AsRegister<Register>(); 4602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 4622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg_lo = in.AsRegisterPairLow<Register>(); 4632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg_hi = in.AsRegisterPairHigh<Register>(); 4642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg_lo = output.AsRegisterPairLow<Register>(); 4652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg_hi = output.AsRegisterPairHigh<Register>(); 4662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK_NE(out_reg_lo, in_reg_hi) << "Diagonal overlap unexpected."; 4682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Asr(mask, in_reg_hi, 31); 4702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ adds(out_reg_lo, in_reg_lo, ShifterOperand(mask)); 4712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ adc(out_reg_hi, in_reg_hi, ShifterOperand(mask)); 4722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg_lo, mask, ShifterOperand(out_reg_lo)); 4732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg_hi, mask, ShifterOperand(out_reg_hi)); 4742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 4752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg = in.AsRegister<Register>(); 4762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg = output.AsRegister<Register>(); 4772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Asr(mask, in_reg, 31); 4792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(out_reg, in_reg, ShifterOperand(mask)); 4802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg, mask, ShifterOperand(out_reg)); 4812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 4822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsInt(HInvoke* invoke) { 4852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntPlusTemp(arena_, invoke); 4862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsInt(HInvoke* invoke) { 489bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenAbsInteger(invoke->GetLocations(), /* is64bit */ false, GetAssembler()); 4902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsLong(HInvoke* invoke) { 4942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntPlusTemp(arena_, invoke); 4952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsLong(HInvoke* invoke) { 498bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenAbsInteger(invoke->GetLocations(), /* is64bit */ true, GetAssembler()); 4992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenMinMax(LocationSummary* locations, 5022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_min, 5032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler) { 5042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register op1 = locations->InAt(0).AsRegister<Register>(); 5052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register op2 = locations->InAt(1).AsRegister<Register>(); 5062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); 5072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(op1, ShifterOperand(op2)); 5092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it((is_min) ? Condition::LT : Condition::GT, kItElse); 5112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(op1), is_min ? Condition::LT : Condition::GT); 5122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(op2), is_min ? Condition::GE : Condition::LE); 5132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 5162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 5172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 5182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 5192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 5202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 5212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 5222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMinIntInt(HInvoke* invoke) { 5252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToIntLocations(arena_, invoke); 5262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMinIntInt(HInvoke* invoke) { 529bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler()); 5302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) { 5332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToIntLocations(arena_, invoke); 5342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMaxIntInt(HInvoke* invoke) { 537bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler()); 5382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathSqrt(HInvoke* invoke) { 5412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 5422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathSqrt(HInvoke* invoke) { 5452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 5462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vsqrtd(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()), 5482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>())); 5492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekByte(HInvoke* invoke) { 5522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekByte(HInvoke* invoke) { 5562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 5582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrsb(invoke->GetLocations()->Out().AsRegister<Register>(), 5592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 5602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 5632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 5672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 5692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(invoke->GetLocations()->Out().AsRegister<Register>(), 5702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 5712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 5742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 5782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 5802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 5812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 5822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // exception. So we can't use ldrd as addr may be unaligned. 5832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>(); 5842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>(); 5852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (addr == lo) { 5862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(hi, Address(addr, 4)); 5872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(lo, Address(addr, 0)); 5882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 5892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(lo, Address(addr, 0)); 5902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(hi, Address(addr, 4)); 5912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 5922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 5952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 5992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 6012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrsh(invoke->GetLocations()->Out().AsRegister<Register>(), 6022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 6032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) { 6062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 6072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 6082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 6092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 6102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 6112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeByte(HInvoke* invoke) { 6142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 6152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeByte(HInvoke* invoke) { 6182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strb(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 6202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 6212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 6242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 6252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 6282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 6302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 6312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 6342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 6352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 6382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 6402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 6412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 6422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // exception. So we can't use ldrd as addr may be unaligned. 6432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>(), Address(addr, 0)); 6442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>(), Address(addr, 4)); 6452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 6482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 6492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 6522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strh(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 6542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 6552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitThreadCurrentThread(HInvoke* invoke) { 6582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 6592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 6602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 6612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister()); 6622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitThreadCurrentThread(HInvoke* invoke) { 6652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ LoadFromOffset(kLoadWord, 6672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe invoke->GetLocations()->Out().AsRegister<Register>(), 6682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe TR, 6692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Thread::PeerOffset<kArmPointerSize>().Int32Value()); 6702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafeGet(HInvoke* invoke, 6732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 6742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 6752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CodeGeneratorARM* codegen) { 6762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 6772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK((type == Primitive::kPrimInt) || 6782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe (type == Primitive::kPrimLong) || 6792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe (type == Primitive::kPrimNot)); 6802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 6813b359c71f2fb784589be113206932e76807787bbRoland Levillain Location base_loc = locations->InAt(1); 6823b359c71f2fb784589be113206932e76807787bbRoland Levillain Register base = base_loc.AsRegister<Register>(); // Object pointer. 6833b359c71f2fb784589be113206932e76807787bbRoland Levillain Location offset_loc = locations->InAt(2); 6843b359c71f2fb784589be113206932e76807787bbRoland Levillain Register offset = offset_loc.AsRegisterPairLow<Register>(); // Long offset, lo part only. 6853b359c71f2fb784589be113206932e76807787bbRoland Levillain Location trg_loc = locations->Out(); 6862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 6883b359c71f2fb784589be113206932e76807787bbRoland Levillain Register trg_lo = trg_loc.AsRegisterPairLow<Register>(); 6892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 6902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 6913b359c71f2fb784589be113206932e76807787bbRoland Levillain Register trg_hi = trg_loc.AsRegisterPairHigh<Register>(); 6922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrexd(trg_lo, trg_hi, IP); 6932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 6942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrd(trg_lo, Address(IP)); 6952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 6962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 6973b359c71f2fb784589be113206932e76807787bbRoland Levillain Register trg = trg_loc.AsRegister<Register>(); 6982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(trg, Address(base, offset)); 6992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile) { 7022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 7032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7044d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 7054d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (type == Primitive::kPrimNot) { 7063b359c71f2fb784589be113206932e76807787bbRoland Levillain codegen->MaybeGenerateReadBarrier(invoke, trg_loc, trg_loc, base_loc, 0U, offset_loc); 7074d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 7082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 7113b359c71f2fb784589be113206932e76807787bbRoland Levillain bool can_call = kEmitCompilerReadBarrier && 7123b359c71f2fb784589be113206932e76807787bbRoland Levillain (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject || 7133b359c71f2fb784589be113206932e76807787bbRoland Levillain invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile); 7142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 7153b359c71f2fb784589be113206932e76807787bbRoland Levillain can_call ? 7163b359c71f2fb784589be113206932e76807787bbRoland Levillain LocationSummary::kCallOnSlowPath : 7173b359c71f2fb784589be113206932e76807787bbRoland Levillain LocationSummary::kNoCall, 7182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 7192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 7202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 7212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 7222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 7232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGet(HInvoke* invoke) { 7262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 7292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLong(HInvoke* invoke) { 7322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 7352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObject(HInvoke* invoke) { 7382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 7412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGet(HInvoke* invoke) { 745bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_); 7462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 748bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_); 7492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLong(HInvoke* invoke) { 751bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_); 7522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 754bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_); 7552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObject(HInvoke* invoke) { 757bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_); 7582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 760bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_); 7612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntToVoid(ArenaAllocator* arena, 7642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const ArmInstructionSetFeatures& features, 7652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 7662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 7672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe HInvoke* invoke) { 7682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 7692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 7702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 7712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 7722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 7732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 7742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(3, Location::RequiresRegister()); 7752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 7772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Potentially need temps for ldrexd-strexd loop. 7782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !features.HasAtomicLdrdAndStrd()) { 7792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp_lo. 7802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp_hi. 7812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else if (type == Primitive::kPrimNot) { 7832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Temps for card-marking. 7842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp. 7852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Card. 7862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePut(HInvoke* invoke) { 790bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke); 7912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutOrdered(HInvoke* invoke) { 793bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ false, invoke); 7942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutVolatile(HInvoke* invoke) { 796bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, /* is_volatile */ true, invoke); 7972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObject(HInvoke* invoke) { 799bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke); 8002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 802bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ false, invoke); 8032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 805bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, /* is_volatile */ true, invoke); 8062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLong(HInvoke* invoke) { 808bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid( 809bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke); 8102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 812bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid( 813bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain arena_, features_, Primitive::kPrimLong, /* is_volatile */ false, invoke); 8142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 816bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain CreateIntIntIntIntToVoid( 817bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain arena_, features_, Primitive::kPrimLong, /* is_volatile */ true, invoke); 8182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafePut(LocationSummary* locations, 8212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 8222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 8232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_ordered, 8242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CodeGeneratorARM* codegen) { 8252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 8262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 8282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Long offset, lo part only. 8292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value; 8302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile || is_ordered) { 8322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 8362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>(); 8372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe value = value_lo; 8382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 8392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp_lo = locations->GetTemp(0).AsRegister<Register>(); 8402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp_hi = locations->GetTemp(1).AsRegister<Register>(); 8412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>(); 8422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 8442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Label loop_head; 8452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(&loop_head); 8462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrexd(temp_lo, temp_hi, IP); 8472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strexd(temp_lo, value_lo, value_hi, IP); 8482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(temp_lo, ShifterOperand(0)); 8492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(&loop_head, NE); 8502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 8512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 8522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strd(value_lo, Address(IP)); 8532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 8554d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain value = locations->InAt(3).AsRegister<Register>(); 8564d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain Register source = value; 8574d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 8584d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain Register temp = locations->GetTemp(0).AsRegister<Register>(); 8594d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ Mov(temp, value); 8604d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ PoisonHeapReference(temp); 8614d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain source = temp; 8624d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 8634d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ str(source, Address(base, offset)); 8642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile) { 8672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimNot) { 8712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp = locations->GetTemp(0).AsRegister<Register>(); 8722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register card = locations->GetTemp(1).AsRegister<Register>(); 87307276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray bool value_can_be_null = true; // TODO: Worth finding out this information? 87407276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray codegen->MarkGCCard(temp, card, base, value, value_can_be_null); 8752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePut(HInvoke* invoke) { 879bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 880bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimInt, 881bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 882bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 883bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 8842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutOrdered(HInvoke* invoke) { 886bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 887bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimInt, 888bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 889bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ true, 890bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 8912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutVolatile(HInvoke* invoke) { 893bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 894bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimInt, 895bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ true, 896bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 897bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 8982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObject(HInvoke* invoke) { 900bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 901bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimNot, 902bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 903bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 904bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 9052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 907bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 908bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimNot, 909bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 910bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ true, 911bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 9122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 914bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 915bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimNot, 916bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ true, 917bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 918bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 9192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLong(HInvoke* invoke) { 921bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 922bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimLong, 923bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 924bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 925bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 9262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 928bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 929bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimLong, 930bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ false, 931bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ true, 932bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 9332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 935bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenUnsafePut(invoke->GetLocations(), 936bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain Primitive::kPrimLong, 937bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_volatile */ true, 938bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* is_ordered */ false, 939bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain codegen_); 9402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, 9432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe HInvoke* invoke) { 9442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 9452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 9462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 9472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 9482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 9492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 9502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(3, Location::RequiresRegister()); 9512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(4, Location::RequiresRegister()); 9522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 9542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Pointer. 9562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp 1. 9572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp 2. 9582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) { 9612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK_NE(type, Primitive::kPrimLong); 9622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 9642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Boolean result. 9662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 9682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Offset (discard high 4B). 9692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register expected_lo = locations->InAt(3).AsRegister<Register>(); // Expected. 9702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_lo = locations->InAt(4).AsRegister<Register>(); // Value. 9712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_ptr = locations->GetTemp(0).AsRegister<Register>(); // Pointer to actual memory. 9732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_lo = locations->GetTemp(1).AsRegister<Register>(); // Value in memory. 9742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimNot) { 9762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Mark card for object assuming new value is stored. Worst case we will mark an unchanged 9772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // object and scan the receiver at the next GC for nothing. 97807276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray bool value_can_be_null = true; // TODO: Worth finding out this information? 97907276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null); 9802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 9812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Prevent reordering with prior memory operations. 9832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 9842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(tmp_ptr, base, ShifterOperand(offset)); 9862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9874d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 9884d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->PoisonHeapReference(expected_lo); 9894d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->PoisonHeapReference(value_lo); 9904d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 9914d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 9922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // do { 9932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // tmp = [r_ptr] - expected; 9942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // } while (tmp == 0 && failure([r_ptr] <- r_new_value)); 9952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // result = tmp != 0; 9962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Label loop_head; 9982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(&loop_head); 9992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrex(tmp_lo, tmp_ptr); 10013b359c71f2fb784589be113206932e76807787bbRoland Levillain // TODO: Do we need a read barrier here when `type == Primitive::kPrimNot`? 10022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ subs(tmp_lo, tmp_lo, ShifterOperand(expected_lo)); 10042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(EQ, ItState::kItT); 10062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strex(tmp_lo, value_lo, tmp_ptr, EQ); 10072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(tmp_lo, ShifterOperand(1), EQ); 10082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(&loop_head, EQ); 10102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 10122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ rsbs(out, tmp_lo, ShifterOperand(1)); 10142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(CC); 10152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(0), CC); 10164d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 10174d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 10184d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(value_lo); 10194d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(expected_lo); 10204d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 10212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 10222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1023ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) { 10242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 10252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1026ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) { 1027985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain // The UnsafeCASObject intrinsic does not always work when heap 1028985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain // poisoning is enabled (it breaks run-test 004-UnsafeTest); turn it 1029985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain // off temporarily as a quick fix. 10303b359c71f2fb784589be113206932e76807787bbRoland Levillain // 1031985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain // TODO(rpl): Fix it and turn it back on. 10323b359c71f2fb784589be113206932e76807787bbRoland Levillain // 10333b359c71f2fb784589be113206932e76807787bbRoland Levillain // TODO(rpl): Also, we should investigate whether we need a read 10343b359c71f2fb784589be113206932e76807787bbRoland Levillain // barrier in the generated code. 1035985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain if (kPoisonHeapReferences) { 1036985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain return; 1037985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain } 1038985ff70d3dbd954f75749fb7109a71fa0e9d8838Roland Levillain 10392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 10402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 10412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) { 10422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_); 10432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 10442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) { 10452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_); 10462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 10472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringCharAt(HInvoke* invoke) { 10492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 10502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kCallOnSlowPath, 10512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 10522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 10532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 10542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 10552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 10572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 10582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 10592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringCharAt(HInvoke* invoke) { 10612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 10622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 10632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of reference to data array 10652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset value_offset = mirror::String::ValueOffset(); 10662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of count 10672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset count_offset = mirror::String::CountOffset(); 10682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register obj = locations->InAt(0).AsRegister<Register>(); // String object pointer. 10702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register idx = locations->InAt(1).AsRegister<Register>(); // Index of character. 10712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Result character. 10722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp = locations->GetTemp(0).AsRegister<Register>(); 10742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register array_temp = locations->GetTemp(1).AsRegister<Register>(); 10752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth 10772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // the cost. 10782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: For simplicity, the index parameter is requested in a register, so different from Quick 10792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // we will not optimize the code for constants (which would save a register). 10802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 108185b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 10822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->AddSlowPath(slow_path); 10832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(temp, Address(obj, count_offset.Int32Value())); // temp = str.length. 10852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->MaybeRecordImplicitNullCheck(invoke); 10862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(idx, ShifterOperand(temp)); 10872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(slow_path->GetEntryLabel(), CS); 10882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1089848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ add(array_temp, obj, ShifterOperand(value_offset.Int32Value())); // array_temp := str.value. 10902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Load the value. 1092848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ ldrh(out, Address(array_temp, idx, LSL, 1)); // out := array_temp[idx]. 10932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(slow_path->GetExitLabel()); 10952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 10962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1097d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitStringCompareTo(HInvoke* invoke) { 1098d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray // The inputs plus one temp. 1099d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = new (arena_) LocationSummary(invoke, 1100d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary::kCall, 1101d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kIntrinsified); 1102d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray InvokeRuntimeCallingConvention calling_convention; 1103d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1104d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1105d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetOut(Location::RegisterLocation(R0)); 1106d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 1107d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1108d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitStringCompareTo(HInvoke* invoke) { 1109d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray ArmAssembler* assembler = GetAssembler(); 1110d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 1111d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1112512e04d1ea7fb33e3992715fe55be8a834d4a79cNicolas Geoffray // Note that the null check must have been done earlier. 1113641547a5f18ca2ea54469cceadcfef64f132e5e0Calin Juravle DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1114d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1115d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray Register argument = locations->InAt(1).AsRegister<Register>(); 1116d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ cmp(argument, ShifterOperand(0)); 111785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1118d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray codegen_->AddSlowPath(slow_path); 1119d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ b(slow_path->GetEntryLabel(), EQ); 1120d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1121d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ LoadFromOffset( 1122d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pStringCompareTo).Int32Value()); 1123d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ blx(LR); 1124d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ Bind(slow_path->GetExitLabel()); 1125d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 1126d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1127289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicLocationsBuilderARM::VisitStringEquals(HInvoke* invoke) { 1128289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = new (arena_) LocationSummary(invoke, 1129289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary::kNoCall, 1130289cd55808111d23c92f2739a096942a8049649aAgi Csaki kIntrinsified); 1131289cd55808111d23c92f2739a096942a8049649aAgi Csaki InvokeRuntimeCallingConvention calling_convention; 1132289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(0, Location::RequiresRegister()); 1133289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(1, Location::RequiresRegister()); 1134289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Temporary registers to store lengths of strings and for calculations. 1135289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Using instruction cbz requires a low register, so explicitly set a temp to be R0. 1136289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RegisterLocation(R0)); 1137289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1138289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1139289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1140289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetOut(Location::RequiresRegister()); 1141289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1142289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1143289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicCodeGeneratorARM::VisitStringEquals(HInvoke* invoke) { 1144289cd55808111d23c92f2739a096942a8049649aAgi Csaki ArmAssembler* assembler = GetAssembler(); 1145289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = invoke->GetLocations(); 1146289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1147289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register str = locations->InAt(0).AsRegister<Register>(); 1148289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register arg = locations->InAt(1).AsRegister<Register>(); 1149289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register out = locations->Out().AsRegister<Register>(); 1150289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1151289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp = locations->GetTemp(0).AsRegister<Register>(); 1152289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp1 = locations->GetTemp(1).AsRegister<Register>(); 1153289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp2 = locations->GetTemp(2).AsRegister<Register>(); 1154289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1155289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label loop; 1156289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label end; 1157289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_true; 1158289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_false; 1159289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1160289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Get offsets of count, value, and class fields within a string object. 1161289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); 1162289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); 1163289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value(); 1164289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1165289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Note that the null check must have been done earlier. 1166289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1167289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1168289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if input is null, return false if it is. 1169289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ CompareAndBranchIfZero(arg, &return_false); 1170289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1171289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Instanceof check for the argument by comparing class fields. 1172289cd55808111d23c92f2739a096942a8049649aAgi Csaki // All string objects must have the same type since String cannot be subclassed. 1173289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Receiver must be a string object, so its class field is equal to all strings' class fields. 1174289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If the argument is a string object, its class field must be equal to receiver's class field. 1175289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, class_offset)); 1176289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, class_offset)); 1177289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1178289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1179289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1180289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Load lengths of this and argument strings. 1181289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, count_offset)); 1182289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, count_offset)); 1183289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if lengths are equal, return false if they're not. 1184289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1185289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1186289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true if both strings are empty. 1187289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cbz(temp, &return_true); 1188289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1189289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Reference equality check, return true if same reference. 1190289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(str, ShifterOperand(arg)); 1191289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_true, EQ); 1192289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1193289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Assertions that must hold in order to compare strings 2 characters at a time. 1194289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK_ALIGNED(value_offset, 4); 1195289cd55808111d23c92f2739a096942a8049649aAgi Csaki static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded"); 1196289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1197289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(temp1, value_offset); 1198289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1199289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Loop to compare strings 2 characters at a time starting at the front of the string. 1200289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Ok to do this because strings with an odd length are zero-padded. 1201289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&loop); 1202289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(out, Address(str, temp1)); 1203289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp2, Address(arg, temp1)); 1204289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(out, ShifterOperand(temp2)); 1205289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1206289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ add(temp1, temp1, ShifterOperand(sizeof(uint32_t))); 1207a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ subs(temp, temp, ShifterOperand(sizeof(uint32_t) / sizeof(uint16_t))); 1208a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ b(&loop, GT); 1209289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1210289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true and exit the function. 1211289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If loop does not result in returning false, we return true. 1212289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_true); 1213289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 1); 1214289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&end); 1215289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1216289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return false and exit the function. 1217289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_false); 1218289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 0); 1219289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&end); 1220289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1221289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1222ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampestatic void GenerateVisitStringIndexOf(HInvoke* invoke, 1223ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArmAssembler* assembler, 1224ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe CodeGeneratorARM* codegen, 1225ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArenaAllocator* allocator, 1226ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe bool start_at_zero) { 1227ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 1228ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register tmp_reg = locations->GetTemp(0).AsRegister<Register>(); 1229ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1230ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Note that the null check must have been done earlier. 1231ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1232ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1233ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically, 1234ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // or directly dispatch if we have a constant. 123585b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = nullptr; 1236ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (invoke->InputAt(1)->IsIntConstant()) { 1237ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) > 1238ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe std::numeric_limits<uint16_t>::max()) { 1239ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Always needs the slow-path. We could directly dispatch to it, but this case should be 1240ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // rare, so for simplicity just put the full slow-path down and branch unconditionally. 1241ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1242ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1243ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel()); 1244ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1245ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe return; 1246ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1247ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } else { 1248ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register char_reg = locations->InAt(1).AsRegister<Register>(); 1249ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, std::numeric_limits<uint16_t>::max()); 1250ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ cmp(char_reg, ShifterOperand(tmp_reg)); 1251ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1252ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1253ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel(), HI); 1254ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1255ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1256ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (start_at_zero) { 1257ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK_EQ(tmp_reg, R2); 1258ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Start-index = 0. 1259ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, 0); 1260ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1261ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1262ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadFromOffset(kLoadWord, LR, TR, 1263ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value()); 1264ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ blx(LR); 1265ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1266ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (slow_path != nullptr) { 1267ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1268ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1269ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1270ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1271ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) { 1272ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1273ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1274ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1275ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1276ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1277ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1278ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1279ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1280ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1281ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1282ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare, and need to send start-index=0. 1283ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1284ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1285ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1286ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) { 1287bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenerateVisitStringIndexOf( 1288bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true); 1289ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1290ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1291ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1292ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1293ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1294ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1295ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1296ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1297ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1298ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1299ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1300ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1301ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1302ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1303ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare. 1304ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 1305ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1306ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1307ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1308bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain GenerateVisitStringIndexOf( 1309bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false); 1310ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1311ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1312848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1313848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1314848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1315848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1316848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1317848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1318848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1319848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1320848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3))); 1321848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1322848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1323848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1324848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1325848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1326848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1327848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1328848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register byte_array = locations->InAt(0).AsRegister<Register>(); 1329848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(byte_array, ShifterOperand(0)); 133085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1331848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1332848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1333848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1334848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1335848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromBytes).Int32Value()); 1336848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1337848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1338848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1339848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1340848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1341848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1342848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1343848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1344848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1345848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1346848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1347848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1348848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1349848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1350848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1351848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1352848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1353848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1354848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1355848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1356848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value()); 1357848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1358848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1359848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1360848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1361848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) { 1362848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1363848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1364848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1365848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1366848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1367848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1368848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1369848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1370848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) { 1371848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1372848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1373848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1374848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register string_to_copy = locations->InAt(0).AsRegister<Register>(); 1375848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(string_to_copy, ShifterOperand(0)); 137685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1377848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1378848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1379848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1380848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset(kLoadWord, 1381848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromString).Int32Value()); 1382848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1383848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1384848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1385848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1386848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 13875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitSystemArrayCopy(HInvoke* invoke) { 13885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CodeGenerator::CreateSystemArrayCopyLocationSummary(invoke); 13895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 13905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (locations == nullptr) { 13915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray return; 13925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 13935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant(); 13955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant(); 13965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray HIntConstant* length = invoke->InputAt(4)->AsIntConstant(); 13975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 13985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(src_pos->GetValue())) { 13995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(1, Location::RequiresRegister()); 14005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos != nullptr && !assembler_->ShifterOperandCanAlwaysHold(dest_pos->GetValue())) { 14025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(3, Location::RequiresRegister()); 14035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length != nullptr && !assembler_->ShifterOperandCanAlwaysHold(length->GetValue())) { 14055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray locations->SetInAt(4, Location::RequiresRegister()); 14065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 14085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffraystatic void CheckPosition(ArmAssembler* assembler, 14105bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location pos, 14115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register input, 14125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location length, 14135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SlowPathCode* slow_path, 14145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register input_len, 14155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp, 14165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray bool length_is_input_length = false) { 14175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Where is the length in the Array? 14185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value(); 14195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (pos.IsConstant()) { 14215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue(); 14225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (pos_const == 0) { 14235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!length_is_input_length) { 14245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that length(input) >= length. 14255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp, input, length_offset); 14265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 14275bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 14285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 14305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that length(input) >= pos. 14355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, input_len, input, length_offset); 14365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ subs(temp, input_len, ShifterOperand(pos_const)); 14375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that (length(input) - pos) >= length. 14405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 14415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 14425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 14445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else if (length_is_input_length) { 14485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // The only way the copy can succeed is if pos is zero. 14495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register pos_reg = pos.AsRegister<Register>(); 14505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(pos_reg, slow_path->GetEntryLabel()); 14515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that pos >= 0. 14535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register pos_reg = pos.AsRegister<Register>(); 14545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(pos_reg, ShifterOperand(0)); 14555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that pos <= length(input). 14585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp, input, length_offset); 14595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ subs(temp, temp, ShifterOperand(pos_reg)); 14605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check that (length(input) - pos) >= length. 14635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 14645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.GetConstant()->AsIntConstant()->GetValue())); 14655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 14665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp, ShifterOperand(length.AsRegister<Register>())); 14675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 14695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 14705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 14715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14723b359c71f2fb784589be113206932e76807787bbRoland Levillain// TODO: Implement read barriers in the SystemArrayCopy intrinsic. 14733b359c71f2fb784589be113206932e76807787bbRoland Levillain// Note that this code path is not used (yet) because we do not 14743b359c71f2fb784589be113206932e76807787bbRoland Levillain// intrinsify methods that can go into the IntrinsicSlowPathARM 14753b359c71f2fb784589be113206932e76807787bbRoland Levillain// slow path. 14765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitSystemArrayCopy(HInvoke* invoke) { 14775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray ArmAssembler* assembler = GetAssembler(); 14785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 14795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 14815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value(); 14825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value(); 14835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value(); 14845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register src = locations->InAt(0).AsRegister<Register>(); 14865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location src_pos = locations->InAt(1); 14875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register dest = locations->InAt(2).AsRegister<Register>(); 14885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location dest_pos = locations->InAt(3); 14895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Location length = locations->InAt(4); 14905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp1 = locations->GetTemp(0).AsRegister<Register>(); 14915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp2 = locations->GetTemp(1).AsRegister<Register>(); 14925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register temp3 = locations->GetTemp(2).AsRegister<Register>(); 14935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 14955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray codegen_->AddSlowPath(slow_path); 14965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 14975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label ok; 14985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray SystemArrayCopyOptimizations optimizations(invoke); 14995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 15015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!src_pos.IsConstant() || !dest_pos.IsConstant()) { 15025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src, ShifterOperand(dest)); 15035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // If source and destination are the same, we go to slow path if we need to do 15075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // forward copying. 15085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos.IsConstant()) { 15095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); 15105bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 15115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Checked when building locations. 15125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray DCHECK(!optimizations.GetDestinationIsSource() 15135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray || (src_pos_constant >= dest_pos.GetConstant()->AsIntConstant()->GetValue())); 15145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 15165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&ok, NE); 15175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(dest_pos.AsRegister<Register>(), ShifterOperand(src_pos_constant)); 15195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), GT); 15205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsSource()) { 15235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&ok, NE); 15245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 15265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); 15275bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos_constant)); 15285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 15295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(src_pos.AsRegister<Register>(), ShifterOperand(dest_pos.AsRegister<Register>())); 15305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 15325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&ok); 15355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetSourceIsNotNull()) { 15375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is null. 15385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(src, slow_path->GetEntryLabel()); 15395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) { 15425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is null. 15435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(dest, slow_path->GetEntryLabel()); 15445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // If the length is negative, bail out. 15475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // We have already checked in the LocationsBuilder for the constant case. 15485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!length.IsConstant() && 15495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetCountIsSourceLength() && 15505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetCountIsDestinationLength()) { 15515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(length.AsRegister<Register>(), ShifterOperand(0)); 15525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), LT); 15535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Validity checks: source. 15565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CheckPosition(assembler, 15575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray src_pos, 15585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray src, 15595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray length, 15605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray slow_path, 15615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp1, 15625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 15635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray optimizations.GetCountIsSourceLength()); 15645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Validity checks: dest. 15665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray CheckPosition(assembler, 15675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest_pos, 15685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest, 15695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray length, 15705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray slow_path, 15715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp1, 15725bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 15735bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray optimizations.GetCountIsDestinationLength()); 15745bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15755bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDoesNotNeedTypeCheck()) { 15765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Check whether all elements of the source array are assignable to the component 15775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // type of the destination array. We do two checks: the classes are the same, 15785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // or the destination is Object[]. If none of these checks succeed, we go to the 15795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // slow path. 15805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, dest, class_offset); 15815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp2, src, class_offset); 15825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray bool did_unpoison = false; 15835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNonPrimitiveArray() || 15845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray !optimizations.GetSourceIsNonPrimitiveArray()) { 15855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // One or two of the references need to be unpoisoned. Unpoisoned them 15865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // both to make the identity check valid. 15875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 15885bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp2); 15895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray did_unpoison = true; 15905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 15915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 15925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetDestinationIsNonPrimitiveArray()) { 15935bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is not a non primitive array. 15945bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset); 15955bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 15965bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 15975bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 15985bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 15995bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 16005bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16015bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16025bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!optimizations.GetSourceIsNonPrimitiveArray()) { 16035bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is not a non primitive array. 16045bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the destination is not a non primitive array. 16055bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp2, component_offset); 16065bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 16075bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 16085bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 16095bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 16105bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 16115bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16125bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16135bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp2)); 16145bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16155bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (optimizations.GetDestinationIsTypedObjectArray()) { 16165bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label do_copy; 16175bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&do_copy, EQ); 16185bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (!did_unpoison) { 16195bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 16205bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16215bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset); 16225bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 16235bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset); 16245bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // No need to unpoison the result, we're comparing against null. 16255bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel()); 16265bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&do_copy); 16275bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 16285bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(slow_path->GetEntryLabel(), NE); 16295bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16305bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { 16315bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); 16325bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Bail out if the source is not a non primitive array. 16335bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp1, src, class_offset); 16345bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp1); 16355bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadWord, temp3, temp1, component_offset); 16365bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfZero(temp3, slow_path->GetEntryLabel()); 16375bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ MaybeUnpoisonHeapReference(temp3); 16385bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ LoadFromOffset(kLoadUnsignedHalfword, temp3, temp3, primitive_offset); 16395bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); 16405bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ CompareAndBranchIfNonZero(temp3, slow_path->GetEntryLabel()); 16415bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16425bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16435bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Compute base source address, base destination address, and end source address. 16445bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16455bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t element_size = sizeof(int32_t); 16465bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray uint32_t offset = mirror::Array::DataOffset(element_size).Uint32Value(); 16475bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (src_pos.IsConstant()) { 16485bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); 16495bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp1, src, element_size * constant + offset); 16505bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 16515bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp1, src, ShifterOperand(src_pos.AsRegister<Register>(), LSL, 2)); 16525bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp1, offset); 16535bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16545bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16555bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (dest_pos.IsConstant()) { 16565bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); 16575bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp2, dest, element_size * constant + offset); 16585bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 16595bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp2, dest, ShifterOperand(dest_pos.AsRegister<Register>(), LSL, 2)); 16605bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp2, offset); 16615bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16625bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16635bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray if (length.IsConstant()) { 16645bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray int32_t constant = length.GetConstant()->AsIntConstant()->GetValue(); 16655bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ AddConstant(temp3, temp1, element_size * constant); 16665bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } else { 16675bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ add(temp3, temp1, ShifterOperand(length.AsRegister<Register>(), LSL, 2)); 16685bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray } 16695bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16705bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // Iterate over the arrays and do a raw copy of the objects. We don't need to 16715bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // poison/unpoison, nor do any read barrier as the next uses of the destination 16725bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // array will do it. 16735bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Label loop, done; 16745bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp3)); 16755bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&done, EQ); 16765bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&loop); 16775bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ ldr(IP, Address(temp1, element_size, Address::PostIndex)); 16785bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ str(IP, Address(temp2, element_size, Address::PostIndex)); 16795bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ cmp(temp1, ShifterOperand(temp3)); 16805bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ b(&loop, NE); 16815bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(&done); 16825bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16835bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray // We only need one card marking on the destination array. 16845bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray codegen_->MarkGCCard(temp1, 16855bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray temp2, 16865bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray dest, 16875bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray Register(kNoRegister), 1688bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain /* can_be_null */ false); 16895bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16905bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray __ Bind(slow_path->GetExitLabel()); 16915bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray} 16925bd05a5c9492189ec28edaf6396d6a39ddf03367Nicolas Geoffray 16932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe// Unimplemented intrinsics. 16942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 16952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define UNIMPLEMENTED_INTRINSIC(Name) \ 16962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 16972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} \ 16982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 16992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 17002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 17012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverse) 17022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverseBytes) 17032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverse) 17042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverseBytes) 17052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ShortReverseBytes) 17062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble) 17072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinFloatFloat) 17082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble) 17092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxFloatFloat) 17102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinLongLong) 17112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxLongLong) 17122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathCeil) // Could be done by changing rounding mode, maybe? 17132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathFloor) // Could be done by changing rounding mode, maybe? 17142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRint) 17152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundDouble) // Could be done by changing rounding mode, maybe? 17162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundFloat) // Could be done by changing rounding mode, maybe? 17172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(UnsafeCASLong) // High register pressure. 17182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) 17192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) 1720848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff HaoUNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) 17212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 17224d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef UNIMPLEMENTED_INTRINSIC 17234d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 17244d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef __ 17254d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 17262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace arm 17272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace art 1728