intrinsics_arm.cc revision 85b62f23fc6dfffe2ddd3ddfa74611666c9ff41d
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(); 472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe return res != nullptr && res->Intrinsified(); 482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define __ assembler-> 512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresFpuRegister()); 572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister()); 582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { 612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresFpuRegister()); 662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MoveFPToInt(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location input = locations->InAt(0); 702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location output = locations->Out(); 712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovrrd(output.AsRegisterPairLow<Register>(), 732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe output.AsRegisterPairHigh<Register>(), 742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(input.AsFpuRegisterPairLow<SRegister>())); 752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovrs(output.AsRegister<Register>(), input.AsFpuRegister<SRegister>()); 772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MoveIntToFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location input = locations->InAt(0); 822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location output = locations->Out(); 832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovdrr(FromLowSToD(output.AsFpuRegisterPairLow<SRegister>()), 852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe input.AsRegisterPairLow<Register>(), 862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe input.AsRegisterPairHigh<Register>()); 872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vmovsr(output.AsFpuRegister<SRegister>(), input.AsRegister<Register>()); 892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { 932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToIntLocations(arena_, invoke); 942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) { 962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToFPLocations(arena_, invoke); 972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) { 1002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe MoveFPToInt(invoke->GetLocations(), true, GetAssembler()); 1012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) { 1032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe MoveIntToFP(invoke->GetLocations(), true, GetAssembler()); 1042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { 1072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToIntLocations(arena_, invoke); 1082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { 1102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToFPLocations(arena_, invoke); 1112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) { 1142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe MoveFPToInt(invoke->GetLocations(), false, GetAssembler()); 1152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitFloatIntBitsToFloat(HInvoke* invoke) { 1172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe MoveIntToFP(invoke->GetLocations(), false, GetAssembler()); 1182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 1212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 1222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 1232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 1242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 1252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) { 1292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 1302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 1312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 1322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresFpuRegister()); 1332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 1352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 136611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingstatic void GenNumberOfLeadingZeros(LocationSummary* locations, 137611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Primitive::Type type, 138611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling ArmAssembler* assembler) { 139611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Location in = locations->InAt(0); 140611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Register out = locations->Out().AsRegister<Register>(); 141611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 142611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong)); 143611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 144611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling if (type == Primitive::kPrimLong) { 145611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Register in_reg_lo = in.AsRegisterPairLow<Register>(); 146611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Register in_reg_hi = in.AsRegisterPairHigh<Register>(); 147611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling Label end; 148611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ clz(out, in_reg_hi); 149611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ CompareAndBranchIfNonZero(in_reg_hi, &end); 150611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ clz(out, in_reg_lo); 151611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ AddConstant(out, 32); 152611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ Bind(&end); 153611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling } else { 154611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling __ clz(out, in.AsRegister<Register>()); 155611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling } 156611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 157611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 158611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { 159611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling CreateIntToIntLocations(arena_, invoke); 160611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 161611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 162611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) { 163611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler()); 164611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 165611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 166611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { 167611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 168611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling LocationSummary::kNoCall, 169611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling kIntrinsified); 170611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 171611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 172611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 173611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 174611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongNumberOfLeadingZeros(HInvoke* invoke) { 175611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling GenNumberOfLeadingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler()); 176611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling} 177611d3395e9efc0ab8dbfa4a197fa022fbd8c7204Scott Wakeling 1789ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingstatic void GenNumberOfTrailingZeros(LocationSummary* locations, 1799ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Primitive::Type type, 1809ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling ArmAssembler* assembler) { 1819ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling DCHECK((type == Primitive::kPrimInt) || (type == Primitive::kPrimLong)); 1829ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 1839ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out = locations->Out().AsRegister<Register>(); 1849ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 1859ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (type == Primitive::kPrimLong) { 1869ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); 1879ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); 1889ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Label end; 1899ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rbit(out, in_reg_lo); 1909ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ clz(out, out); 1919ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ CompareAndBranchIfNonZero(in_reg_lo, &end); 1929ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rbit(out, in_reg_hi); 1939ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ clz(out, out); 1949ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ AddConstant(out, 32); 1959ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Bind(&end); 1969ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 1979ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in = locations->InAt(0).AsRegister<Register>(); 1989ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rbit(out, in); 1999ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ clz(out, out); 2009ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2019ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2029ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2039ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { 2049ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 2059ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 2069ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 2079ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 2089ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2099ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2109ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2119ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) { 2129ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler()); 2139ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2149ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2159ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { 2169ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 2179ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 2189ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 2199ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 2209ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 2219ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2229ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2239ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongNumberOfTrailingZeros(HInvoke* invoke) { 2249ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenNumberOfTrailingZeros(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler()); 2259ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2269ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2279ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingstatic void GenIntegerRotate(LocationSummary* locations, 2289ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling ArmAssembler* assembler, 2299ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling bool is_left) { 2309ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in = locations->InAt(0).AsRegister<Register>(); 2319ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Location rhs = locations->InAt(1); 2329ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out = locations->Out().AsRegister<Register>(); 2339ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2349ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rhs.IsConstant()) { 2359ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Arm32 and Thumb2 assemblers require a rotation on the interval [1,31], 2369ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // so map all rotations to a +ve. equivalent in that range. 2379ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // (e.g. left *or* right by -2 bits == 30 bits in the same direction.) 2389ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue() & 0x1F; 2399ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rot) { 2409ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Rotate, mapping left rotations to right equivalents if necessary. 2419ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // (e.g. left by 2 bits == right by 30.) 2429ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Ror(out, in, is_left ? (0x20 - rot) : rot); 2439ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else if (out != in) { 2449ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Mov(out, in); 2459ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2469ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 2479ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (is_left) { 2489ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rsb(out, rhs.AsRegister<Register>(), ShifterOperand(0)); 2499ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Ror(out, in, out); 2509ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 2519ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Ror(out, in, rhs.AsRegister<Register>()); 2529ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2539ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2549ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 2559ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2569ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// Gain some speed by mapping all Long rotates onto equivalent pairs of Integer 2579ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// rotates by swapping input regs (effectively rotating by the first 32-bits of 2589ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// a larger rotation) or flipping direction (thus treating larger right/left 2599ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling// rotations as sub-word sized rotations in the other direction) as appropriate. 2609ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingstatic void GenLongRotate(LocationSummary* locations, 2619ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling ArmAssembler* assembler, 2629ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling bool is_left) { 2639ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_lo = locations->InAt(0).AsRegisterPairLow<Register>(); 2649ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register in_reg_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); 2659ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Location rhs = locations->InAt(1); 2669ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out_reg_lo = locations->Out().AsRegisterPairLow<Register>(); 2679ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register out_reg_hi = locations->Out().AsRegisterPairHigh<Register>(); 2689ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 2699ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rhs.IsConstant()) { 2709ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling uint32_t rot = rhs.GetConstant()->AsIntConstant()->GetValue(); 2719ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Map all left rotations to right equivalents. 2729ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (is_left) { 2739ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling rot = 0x40 - rot; 2749ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2759ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Map all rotations to +ve. equivalents on the interval [0,63]. 2769ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling rot &= 0x3F; 2779ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // For rotates over a word in size, 'pre-rotate' by 32-bits to keep rotate 2789ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // logic below to a simple pair of binary orr. 2799ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // (e.g. 34 bits == in_reg swap + 2 bits right.) 2809ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rot >= 0x20) { 2819ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling rot -= 0x20; 2829ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling std::swap(in_reg_hi, in_reg_lo); 2839ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2849ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // Rotate, or mov to out for zero or word size rotations. 2859ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (rot) { 2869ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_hi, in_reg_hi, rot); 2879ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ orr(out_reg_hi, out_reg_hi, ShifterOperand(in_reg_lo, arm::LSL, 0x20 - rot)); 2889ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_lo, in_reg_lo, rot); 2899ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ orr(out_reg_lo, out_reg_lo, ShifterOperand(in_reg_hi, arm::LSL, 0x20 - rot)); 2909ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 2919ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Mov(out_reg_lo, in_reg_lo); 2929ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Mov(out_reg_hi, in_reg_hi); 2939ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 2949ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 2959ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register shift_left = locations->GetTemp(0).AsRegister<Register>(); 2969ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Register shift_right = locations->GetTemp(1).AsRegister<Register>(); 2979ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Label end; 2989ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling Label right; 2999ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3009ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ and_(shift_left, rhs.AsRegister<Register>(), ShifterOperand(0x1F)); 3019ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsrs(shift_right, rhs.AsRegister<Register>(), 6); 3029ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ rsb(shift_right, shift_left, ShifterOperand(0x20), AL, kCcKeep); 3039ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3049ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (is_left) { 3059ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ b(&right, CS); 3069ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 3079ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ b(&right, CC); 3089ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling std::swap(shift_left, shift_right); 3099ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3109ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3119ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right). 3129ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_lo = (reg_lo << shift_left) | (reg_hi >> shift_right). 3139ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(out_reg_hi, in_reg_hi, shift_left); 3149ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_lo, in_reg_lo, shift_right); 3159ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo)); 3169ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(out_reg_lo, in_reg_lo, shift_left); 3179ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(shift_left, in_reg_hi, shift_right); 3189ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_left)); 3199ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ b(&end); 3209ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3219ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_hi = (reg_hi >> shift_right) | (reg_lo << shift_left). 3229ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling // out_reg_lo = (reg_lo >> shift_right) | (reg_hi << shift_left). 3239ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Bind(&right); 3249ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_hi, in_reg_hi, shift_right); 3259ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(out_reg_lo, in_reg_lo, shift_left); 3269ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_hi, out_reg_hi, ShifterOperand(out_reg_lo)); 3279ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsr(out_reg_lo, in_reg_lo, shift_right); 3289ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Lsl(shift_right, in_reg_hi, shift_left); 3299ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ add(out_reg_lo, out_reg_lo, ShifterOperand(shift_right)); 3309ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3319ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling __ Bind(&end); 3329ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3339ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3349ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3359ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerRotateRight(HInvoke* invoke) { 3369ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3379ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3389ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 3399ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 3409ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); 3419ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3429ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3439ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3449ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerRotateRight(HInvoke* invoke) { 3459ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenIntegerRotate(invoke->GetLocations(), GetAssembler(), false /* is_left */); 3469ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3479ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3489ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongRotateRight(HInvoke* invoke) { 3499ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3509ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3519ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 3529ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 3539ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (invoke->InputAt(1)->IsConstant()) { 3549ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant())); 3559ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 3569ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RequiresRegister()); 3579ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 3589ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 3599ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3609ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 3619ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3629ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3639ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongRotateRight(HInvoke* invoke) { 3649ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenLongRotate(invoke->GetLocations(), GetAssembler(), false /* is_left */); 3659ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3669ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3679ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitIntegerRotateLeft(HInvoke* invoke) { 3689ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3699ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3709ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 3719ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 3729ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1))); 3739ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 3749ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3759ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3769ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitIntegerRotateLeft(HInvoke* invoke) { 3779ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenIntegerRotate(invoke->GetLocations(), GetAssembler(), true /* is_left */); 3789ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3799ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3809ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicLocationsBuilderARM::VisitLongRotateLeft(HInvoke* invoke) { 3819ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary* locations = new (arena_) LocationSummary(invoke, 3829ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling LocationSummary::kNoCall, 3839ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling kIntrinsified); 3849ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(0, Location::RequiresRegister()); 3859ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling if (invoke->InputAt(1)->IsConstant()) { 3869ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::ConstantLocation(invoke->InputAt(1)->AsConstant())); 3879ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } else { 3889ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetInAt(1, Location::RequiresRegister()); 3899ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 3909ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->AddTemp(Location::RequiresRegister()); 3919ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling } 3929ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 3939ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3949ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3959ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakelingvoid IntrinsicCodeGeneratorARM::VisitLongRotateLeft(HInvoke* invoke) { 3969ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling GenLongRotate(invoke->GetLocations(), GetAssembler(), true /* is_left */); 3979ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling} 3989ee23f4273efed8d6378f6ad8e63c65e30a17139Scott Wakeling 3992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) { 4002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location in = locations->InAt(0); 4012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location out = locations->Out(); 4022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 4042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vabsd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 4052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 4062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 4072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vabss(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>()); 4082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 4092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsDouble(HInvoke* invoke) { 4122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 4132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsDouble(HInvoke* invoke) { 4162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe MathAbsFP(invoke->GetLocations(), true, GetAssembler()); 4172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) { 4202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 4212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsFloat(HInvoke* invoke) { 4242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe MathAbsFP(invoke->GetLocations(), false, GetAssembler()); 4252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) { 4282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 4292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 4302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 4312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 4322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 4332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 4352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenAbsInteger(LocationSummary* locations, 4382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is64bit, 4392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler) { 4402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location in = locations->InAt(0); 4412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Location output = locations->Out(); 4422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register mask = locations->GetTemp(0).AsRegister<Register>(); 4442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is64bit) { 4462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg_lo = in.AsRegisterPairLow<Register>(); 4472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg_hi = in.AsRegisterPairHigh<Register>(); 4482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg_lo = output.AsRegisterPairLow<Register>(); 4492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg_hi = output.AsRegisterPairHigh<Register>(); 4502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK_NE(out_reg_lo, in_reg_hi) << "Diagonal overlap unexpected."; 4522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Asr(mask, in_reg_hi, 31); 4542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ adds(out_reg_lo, in_reg_lo, ShifterOperand(mask)); 4552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ adc(out_reg_hi, in_reg_hi, ShifterOperand(mask)); 4562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg_lo, mask, ShifterOperand(out_reg_lo)); 4572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg_hi, mask, ShifterOperand(out_reg_hi)); 4582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 4592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register in_reg = in.AsRegister<Register>(); 4602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out_reg = output.AsRegister<Register>(); 4612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Asr(mask, in_reg, 31); 4632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(out_reg, in_reg, ShifterOperand(mask)); 4642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ eor(out_reg, mask, ShifterOperand(out_reg)); 4652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 4662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsInt(HInvoke* invoke) { 4692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntPlusTemp(arena_, invoke); 4702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsInt(HInvoke* invoke) { 4732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenAbsInteger(invoke->GetLocations(), false, GetAssembler()); 4742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsLong(HInvoke* invoke) { 4782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntPlusTemp(arena_, invoke); 4792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsLong(HInvoke* invoke) { 4822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenAbsInteger(invoke->GetLocations(), true, GetAssembler()); 4832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenMinMax(LocationSummary* locations, 4862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_min, 4872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler) { 4882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register op1 = locations->InAt(0).AsRegister<Register>(); 4892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register op2 = locations->InAt(1).AsRegister<Register>(); 4902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); 4912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(op1, ShifterOperand(op2)); 4932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it((is_min) ? Condition::LT : Condition::GT, kItElse); 4952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(op1), is_min ? Condition::LT : Condition::GT); 4962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(op2), is_min ? Condition::GE : Condition::LE); 4972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 4982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 4992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 5002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 5012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 5022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 5032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 5042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 5052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 5062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMinIntInt(HInvoke* invoke) { 5092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToIntLocations(arena_, invoke); 5102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMinIntInt(HInvoke* invoke) { 5132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenMinMax(invoke->GetLocations(), true, GetAssembler()); 5142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) { 5172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToIntLocations(arena_, invoke); 5182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMaxIntInt(HInvoke* invoke) { 5212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenMinMax(invoke->GetLocations(), false, GetAssembler()); 5222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathSqrt(HInvoke* invoke) { 5252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateFPToFPLocations(arena_, invoke); 5262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathSqrt(HInvoke* invoke) { 5292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 5302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ vsqrtd(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()), 5322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>())); 5332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekByte(HInvoke* invoke) { 5362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekByte(HInvoke* invoke) { 5402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 5422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrsb(invoke->GetLocations()->Out().AsRegister<Register>(), 5432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 5442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 5472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekIntNative(HInvoke* invoke) { 5512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 5532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(invoke->GetLocations()->Out().AsRegister<Register>(), 5542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 5552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 5582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekLongNative(HInvoke* invoke) { 5622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 5642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 5652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 5662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // exception. So we can't use ldrd as addr may be unaligned. 5672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>(); 5682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>(); 5692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (addr == lo) { 5702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(hi, Address(addr, 4)); 5712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(lo, Address(addr, 0)); 5722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 5732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(lo, Address(addr, 0)); 5742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(hi, Address(addr, 4)); 5752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 5762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 5792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntToIntLocations(arena_, invoke); 5802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekShortNative(HInvoke* invoke) { 5832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 5842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 5852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrsh(invoke->GetLocations()->Out().AsRegister<Register>(), 5862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 5872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) { 5902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 5912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 5922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 5932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 5942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 5952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 5962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 5972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeByte(HInvoke* invoke) { 5982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 5992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeByte(HInvoke* invoke) { 6022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strb(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 6042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 6052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 6082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 6092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeIntNative(HInvoke* invoke) { 6122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 6142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 6152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 6182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 6192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeLongNative(HInvoke* invoke) { 6222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Ignore upper 4B of long address. 6242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>(); 6252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor 6262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // exception. So we can't use ldrd as addr may be unaligned. 6272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>(), Address(addr, 0)); 6282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ str(invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>(), Address(addr, 4)); 6292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 6322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntToVoidLocations(arena_, invoke); 6332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeShortNative(HInvoke* invoke) { 6362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strh(invoke->GetLocations()->InAt(1).AsRegister<Register>(), 6382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>())); 6392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitThreadCurrentThread(HInvoke* invoke) { 6422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 6432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 6442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 6452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister()); 6462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitThreadCurrentThread(HInvoke* invoke) { 6492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 6502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ LoadFromOffset(kLoadWord, 6512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe invoke->GetLocations()->Out().AsRegister<Register>(), 6522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe TR, 6532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Thread::PeerOffset<kArmPointerSize>().Int32Value()); 6542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafeGet(HInvoke* invoke, 6572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 6582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 6592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CodeGeneratorARM* codegen) { 6602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 6612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK((type == Primitive::kPrimInt) || 6622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe (type == Primitive::kPrimLong) || 6632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe (type == Primitive::kPrimNot)); 6642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 6652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 6662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Long offset, lo part only. 6672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 6692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register trg_lo = locations->Out().AsRegisterPairLow<Register>(); 6702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 6712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 6722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register trg_hi = locations->Out().AsRegisterPairHigh<Register>(); 6732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrexd(trg_lo, trg_hi, IP); 6742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 6752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrd(trg_lo, Address(IP)); 6762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 6772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 6782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register trg = locations->Out().AsRegister<Register>(); 6792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(trg, Address(base, offset)); 6802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 6812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile) { 6832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 6842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 6854d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 6864d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (type == Primitive::kPrimNot) { 6874d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain Register trg = locations->Out().AsRegister<Register>(); 6884d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ MaybeUnpoisonHeapReference(trg); 6894d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 6902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 6912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 6922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) { 6932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 6942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 6952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 6962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 6972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 6982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 6992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 7002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGet(HInvoke* invoke) { 7032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 7062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLong(HInvoke* invoke) { 7092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 7122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObject(HInvoke* invoke) { 7152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 7182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntToIntLocations(arena_, invoke); 7192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGet(HInvoke* invoke) { 7222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_); 7232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetVolatile(HInvoke* invoke) { 7252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_); 7262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLong(HInvoke* invoke) { 7282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_); 7292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) { 7312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_); 7322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObject(HInvoke* invoke) { 7342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_); 7352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) { 7372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_); 7382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntToVoid(ArenaAllocator* arena, 7412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const ArmInstructionSetFeatures& features, 7422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 7432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 7442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe HInvoke* invoke) { 7452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 7462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 7472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 7482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 7492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 7502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 7512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(3, Location::RequiresRegister()); 7522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 7542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Potentially need temps for ldrexd-strexd loop. 7552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !features.HasAtomicLdrdAndStrd()) { 7562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp_lo. 7572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp_hi. 7582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else if (type == Primitive::kPrimNot) { 7602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Temps for card-marking. 7612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp. 7622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Card. 7632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 7642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePut(HInvoke* invoke) { 7672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke); 7682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutOrdered(HInvoke* invoke) { 7702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke); 7712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutVolatile(HInvoke* invoke) { 7732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, true, invoke); 7742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObject(HInvoke* invoke) { 7762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke); 7772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 7792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke); 7802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 7822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, true, invoke); 7832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLong(HInvoke* invoke) { 7852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke); 7862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 7882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke); 7892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 7912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, true, invoke); 7922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 7932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 7942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafePut(LocationSummary* locations, 7952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Primitive::Type type, 7962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_volatile, 7972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe bool is_ordered, 7982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CodeGeneratorARM* codegen) { 7992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 8002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 8022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Long offset, lo part only. 8032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value; 8042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile || is_ordered) { 8062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimLong) { 8102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>(); 8112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe value = value_lo; 8122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) { 8132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp_lo = locations->GetTemp(0).AsRegister<Register>(); 8142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp_hi = locations->GetTemp(1).AsRegister<Register>(); 8152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>(); 8162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 8182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Label loop_head; 8192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(&loop_head); 8202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrexd(temp_lo, temp_hi, IP); 8212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strexd(temp_lo, value_lo, value_hi, IP); 8222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(temp_lo, ShifterOperand(0)); 8232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(&loop_head, NE); 8242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 8252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(IP, base, ShifterOperand(offset)); 8262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strd(value_lo, Address(IP)); 8272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } else { 8294d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain value = locations->InAt(3).AsRegister<Register>(); 8304d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain Register source = value; 8314d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 8324d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain Register temp = locations->GetTemp(0).AsRegister<Register>(); 8334d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ Mov(temp, value); 8344d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ PoisonHeapReference(temp); 8354d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain source = temp; 8364d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 8374d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain __ str(source, Address(base, offset)); 8382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (is_volatile) { 8412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 8422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimNot) { 8452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp = locations->GetTemp(0).AsRegister<Register>(); 8462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register card = locations->GetTemp(1).AsRegister<Register>(); 84707276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray bool value_can_be_null = true; // TODO: Worth finding out this information? 84807276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray codegen->MarkGCCard(temp, card, base, value, value_can_be_null); 8492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 8502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePut(HInvoke* invoke) { 8532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, false, codegen_); 8542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutOrdered(HInvoke* invoke) { 8562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, true, codegen_); 8572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutVolatile(HInvoke* invoke) { 8592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, false, codegen_); 8602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObject(HInvoke* invoke) { 8622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, false, codegen_); 8632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) { 8652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, true, codegen_); 8662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) { 8682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, false, codegen_); 8692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLong(HInvoke* invoke) { 8712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, false, codegen_); 8722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongOrdered(HInvoke* invoke) { 8742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, true, codegen_); 8752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongVolatile(HInvoke* invoke) { 8772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, false, codegen_); 8782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena, 8812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe HInvoke* invoke) { 8822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena) LocationSummary(invoke, 8832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kNoCall, 8842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 8852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::NoLocation()); // Unused receiver. 8862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 8872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(2, Location::RequiresRegister()); 8882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(3, Location::RequiresRegister()); 8892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(4, Location::RequiresRegister()); 8902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 8922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Pointer. 8942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp 1. 8952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); // Temp 2. 8962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 8972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 8982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) { 8992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe DCHECK_NE(type, Primitive::kPrimLong); 9002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = codegen->GetAssembler(); 9022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Boolean result. 9042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register base = locations->InAt(1).AsRegister<Register>(); // Object pointer. 9062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register offset = locations->InAt(2).AsRegisterPairLow<Register>(); // Offset (discard high 4B). 9072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register expected_lo = locations->InAt(3).AsRegister<Register>(); // Expected. 9082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register value_lo = locations->InAt(4).AsRegister<Register>(); // Value. 9092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_ptr = locations->GetTemp(0).AsRegister<Register>(); // Pointer to actual memory. 9112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register tmp_lo = locations->GetTemp(1).AsRegister<Register>(); // Value in memory. 9122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe if (type == Primitive::kPrimNot) { 9142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Mark card for object assuming new value is stored. Worst case we will mark an unchanged 9152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // object and scan the receiver at the next GC for nothing. 91607276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray bool value_can_be_null = true; // TODO: Worth finding out this information? 91707276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null); 9182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe } 9192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Prevent reordering with prior memory operations. 9212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 9222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ add(tmp_ptr, base, ShifterOperand(offset)); 9242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9254d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 9264d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->PoisonHeapReference(expected_lo); 9274d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->PoisonHeapReference(value_lo); 9284d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 9294d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 9302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // do { 9312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // tmp = [r_ptr] - expected; 9322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // } while (tmp == 0 && failure([r_ptr] <- r_new_value)); 9332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // result = tmp != 0; 9342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Label loop_head; 9362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(&loop_head); 9372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldrex(tmp_lo, tmp_ptr); 9392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ subs(tmp_lo, tmp_lo, ShifterOperand(expected_lo)); 9412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(EQ, ItState::kItT); 9432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ strex(tmp_lo, value_lo, tmp_ptr, EQ); 9442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(tmp_lo, ShifterOperand(1), EQ); 9452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(&loop_head, EQ); 9472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ dmb(ISH); 9492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ rsbs(out, tmp_lo, ShifterOperand(1)); 9512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ it(CC); 9522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ mov(out, ShifterOperand(0), CC); 9534d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 9544d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain if (kPoisonHeapReferences && type == Primitive::kPrimNot) { 9554d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(value_lo); 9564d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain codegen->GetAssembler()->UnpoisonHeapReference(expected_lo); 9574d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain } 9582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 960ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) { 9612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 9622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 963ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) { 9642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke); 9652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) { 9672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_); 9682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) { 9702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_); 9712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringCharAt(HInvoke* invoke) { 9742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 9752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary::kCallOnSlowPath, 9762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe kIntrinsified); 9772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(0, Location::RequiresRegister()); 9782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetInAt(1, Location::RequiresRegister()); 9792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 9802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 9822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 9832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 9842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringCharAt(HInvoke* invoke) { 9862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe ArmAssembler* assembler = GetAssembler(); 9872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 9882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of reference to data array 9902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset value_offset = mirror::String::ValueOffset(); 9912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Location of count 9922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe const MemberOffset count_offset = mirror::String::CountOffset(); 9932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register obj = locations->InAt(0).AsRegister<Register>(); // String object pointer. 9952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register idx = locations->InAt(1).AsRegister<Register>(); // Index of character. 9962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register out = locations->Out().AsRegister<Register>(); // Result character. 9972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 9982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register temp = locations->GetTemp(0).AsRegister<Register>(); 9992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe Register array_temp = locations->GetTemp(1).AsRegister<Register>(); 10002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth 10022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // the cost. 10032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // TODO: For simplicity, the index parameter is requested in a register, so different from Quick 10042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // we will not optimize the code for constants (which would save a register). 10052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 100685b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 10072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->AddSlowPath(slow_path); 10082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ ldr(temp, Address(obj, count_offset.Int32Value())); // temp = str.length. 10102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe codegen_->MaybeRecordImplicitNullCheck(invoke); 10112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ cmp(idx, ShifterOperand(temp)); 10122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ b(slow_path->GetEntryLabel(), CS); 10132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1014848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ add(array_temp, obj, ShifterOperand(value_offset.Int32Value())); // array_temp := str.value. 10152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe // Load the value. 1017848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ ldrh(out, Address(array_temp, idx, LSL, 1)); // out := array_temp[idx]. 10182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 10192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe __ Bind(slow_path->GetExitLabel()); 10202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 10212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 1022d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitStringCompareTo(HInvoke* invoke) { 1023d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray // The inputs plus one temp. 1024d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = new (arena_) LocationSummary(invoke, 1025d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary::kCall, 1026d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kIntrinsified); 1027d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray InvokeRuntimeCallingConvention calling_convention; 1028d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1029d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1030d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray locations->SetOut(Location::RegisterLocation(R0)); 1031d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 1032d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1033d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitStringCompareTo(HInvoke* invoke) { 1034d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray ArmAssembler* assembler = GetAssembler(); 1035d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray LocationSummary* locations = invoke->GetLocations(); 1036d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1037512e04d1ea7fb33e3992715fe55be8a834d4a79cNicolas Geoffray // Note that the null check must have been done earlier. 1038641547a5f18ca2ea54469cceadcfef64f132e5e0Calin Juravle DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1039d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1040d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray Register argument = locations->InAt(1).AsRegister<Register>(); 1041d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ cmp(argument, ShifterOperand(0)); 104285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1043d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray codegen_->AddSlowPath(slow_path); 1044d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ b(slow_path->GetEntryLabel(), EQ); 1045d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1046d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ LoadFromOffset( 1047d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pStringCompareTo).Int32Value()); 1048d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ blx(LR); 1049d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray __ Bind(slow_path->GetExitLabel()); 1050d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray} 1051d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray 1052289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicLocationsBuilderARM::VisitStringEquals(HInvoke* invoke) { 1053289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = new (arena_) LocationSummary(invoke, 1054289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary::kNoCall, 1055289cd55808111d23c92f2739a096942a8049649aAgi Csaki kIntrinsified); 1056289cd55808111d23c92f2739a096942a8049649aAgi Csaki InvokeRuntimeCallingConvention calling_convention; 1057289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(0, Location::RequiresRegister()); 1058289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetInAt(1, Location::RequiresRegister()); 1059289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Temporary registers to store lengths of strings and for calculations. 1060289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Using instruction cbz requires a low register, so explicitly set a temp to be R0. 1061289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RegisterLocation(R0)); 1062289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1063289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->AddTemp(Location::RequiresRegister()); 1064289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1065289cd55808111d23c92f2739a096942a8049649aAgi Csaki locations->SetOut(Location::RequiresRegister()); 1066289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1067289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1068289cd55808111d23c92f2739a096942a8049649aAgi Csakivoid IntrinsicCodeGeneratorARM::VisitStringEquals(HInvoke* invoke) { 1069289cd55808111d23c92f2739a096942a8049649aAgi Csaki ArmAssembler* assembler = GetAssembler(); 1070289cd55808111d23c92f2739a096942a8049649aAgi Csaki LocationSummary* locations = invoke->GetLocations(); 1071289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1072289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register str = locations->InAt(0).AsRegister<Register>(); 1073289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register arg = locations->InAt(1).AsRegister<Register>(); 1074289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register out = locations->Out().AsRegister<Register>(); 1075289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1076289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp = locations->GetTemp(0).AsRegister<Register>(); 1077289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp1 = locations->GetTemp(1).AsRegister<Register>(); 1078289cd55808111d23c92f2739a096942a8049649aAgi Csaki Register temp2 = locations->GetTemp(2).AsRegister<Register>(); 1079289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1080289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label loop; 1081289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label end; 1082289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_true; 1083289cd55808111d23c92f2739a096942a8049649aAgi Csaki Label return_false; 1084289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1085289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Get offsets of count, value, and class fields within a string object. 1086289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); 1087289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value(); 1088289cd55808111d23c92f2739a096942a8049649aAgi Csaki const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value(); 1089289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1090289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Note that the null check must have been done earlier. 1091289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1092289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1093289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if input is null, return false if it is. 1094289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ CompareAndBranchIfZero(arg, &return_false); 1095289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1096289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Instanceof check for the argument by comparing class fields. 1097289cd55808111d23c92f2739a096942a8049649aAgi Csaki // All string objects must have the same type since String cannot be subclassed. 1098289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Receiver must be a string object, so its class field is equal to all strings' class fields. 1099289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If the argument is a string object, its class field must be equal to receiver's class field. 1100289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, class_offset)); 1101289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, class_offset)); 1102289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1103289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1104289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1105289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Load lengths of this and argument strings. 1106289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp, Address(str, count_offset)); 1107289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp1, Address(arg, count_offset)); 1108289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Check if lengths are equal, return false if they're not. 1109289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(temp, ShifterOperand(temp1)); 1110289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1111289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true if both strings are empty. 1112289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cbz(temp, &return_true); 1113289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1114289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Reference equality check, return true if same reference. 1115289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(str, ShifterOperand(arg)); 1116289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_true, EQ); 1117289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1118289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Assertions that must hold in order to compare strings 2 characters at a time. 1119289cd55808111d23c92f2739a096942a8049649aAgi Csaki DCHECK_ALIGNED(value_offset, 4); 1120289cd55808111d23c92f2739a096942a8049649aAgi Csaki static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded"); 1121289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1122289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(temp1, value_offset); 1123289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1124289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Loop to compare strings 2 characters at a time starting at the front of the string. 1125289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Ok to do this because strings with an odd length are zero-padded. 1126289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&loop); 1127289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(out, Address(str, temp1)); 1128289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ ldr(temp2, Address(arg, temp1)); 1129289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ cmp(out, ShifterOperand(temp2)); 1130289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&return_false, NE); 1131289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ add(temp1, temp1, ShifterOperand(sizeof(uint32_t))); 1132a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ subs(temp, temp, ShifterOperand(sizeof(uint32_t) / sizeof(uint16_t))); 1133a63f0d47edbcbe13a23411851a9c6e81f9342cc2Vladimir Marko __ b(&loop, GT); 1134289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1135289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return true and exit the function. 1136289cd55808111d23c92f2739a096942a8049649aAgi Csaki // If loop does not result in returning false, we return true. 1137289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_true); 1138289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 1); 1139289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ b(&end); 1140289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1141289cd55808111d23c92f2739a096942a8049649aAgi Csaki // Return false and exit the function. 1142289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&return_false); 1143289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ LoadImmediate(out, 0); 1144289cd55808111d23c92f2739a096942a8049649aAgi Csaki __ Bind(&end); 1145289cd55808111d23c92f2739a096942a8049649aAgi Csaki} 1146289cd55808111d23c92f2739a096942a8049649aAgi Csaki 1147ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampestatic void GenerateVisitStringIndexOf(HInvoke* invoke, 1148ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArmAssembler* assembler, 1149ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe CodeGeneratorARM* codegen, 1150ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe ArenaAllocator* allocator, 1151ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe bool start_at_zero) { 1152ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = invoke->GetLocations(); 1153ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register tmp_reg = locations->GetTemp(0).AsRegister<Register>(); 1154ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1155ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Note that the null check must have been done earlier. 1156ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0))); 1157ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1158ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically, 1159ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // or directly dispatch if we have a constant. 116085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = nullptr; 1161ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (invoke->InputAt(1)->IsIntConstant()) { 1162ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) > 1163ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe std::numeric_limits<uint16_t>::max()) { 1164ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Always needs the slow-path. We could directly dispatch to it, but this case should be 1165ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // rare, so for simplicity just put the full slow-path down and branch unconditionally. 1166ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1167ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1168ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel()); 1169ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1170ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe return; 1171ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1172ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } else { 1173ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe Register char_reg = locations->InAt(1).AsRegister<Register>(); 1174ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, std::numeric_limits<uint16_t>::max()); 1175ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ cmp(char_reg, ShifterOperand(tmp_reg)); 1176ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe slow_path = new (allocator) IntrinsicSlowPathARM(invoke); 1177ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe codegen->AddSlowPath(slow_path); 1178ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ b(slow_path->GetEntryLabel(), HI); 1179ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1180ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1181ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (start_at_zero) { 1182ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe DCHECK_EQ(tmp_reg, R2); 1183ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Start-index = 0. 1184ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadImmediate(tmp_reg, 0); 1185ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1186ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1187ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ LoadFromOffset(kLoadWord, LR, TR, 1188ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value()); 1189ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ blx(LR); 1190ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1191ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe if (slow_path != nullptr) { 1192ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe __ Bind(slow_path->GetExitLabel()); 1193ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe } 1194ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1195ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1196ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) { 1197ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1198ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1199ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1200ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1201ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1202ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1203ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1204ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1205ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1206ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1207ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare, and need to send start-index=0. 1208ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1209ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1210ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1211ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) { 1212ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), true); 1213ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1214ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1215ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1216ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary* locations = new (arena_) LocationSummary(invoke, 1217ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe LocationSummary::kCall, 1218ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe kIntrinsified); 1219ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's 1220ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // best to align the inputs accordingly. 1221ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe InvokeRuntimeCallingConvention calling_convention; 1222ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1223ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1224ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1225ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->SetOut(Location::RegisterLocation(R0)); 1226ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1227ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe // Need a temp for slow-path codepoint compare. 1228ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe locations->AddTemp(Location::RequiresRegister()); 1229ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1230ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1231ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) { 1232ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), false); 1233ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe} 1234ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe 1235848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1236848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1237848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1238848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1239848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1240848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1241848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1242848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1243848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3))); 1244848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1245848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1246848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1247848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromBytes(HInvoke* invoke) { 1248848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1249848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1250848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1251848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register byte_array = locations->InAt(0).AsRegister<Register>(); 1252848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(byte_array, ShifterOperand(0)); 125385b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1254848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1255848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1256848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1257848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1258848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromBytes).Int32Value()); 1259848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1260848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1261848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1262848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1263848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1264848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1265848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1266848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1267848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1268848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1269848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1270848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1271848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1272848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1273848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1274848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1275848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) { 1276848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1277848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1278848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset( 1279848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value()); 1280848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1281848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1282848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1283848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1284848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) { 1285848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = new (arena_) LocationSummary(invoke, 1286848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary::kCall, 1287848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao kIntrinsified); 1288848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao InvokeRuntimeCallingConvention calling_convention; 1289848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1290848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao locations->SetOut(Location::RegisterLocation(R0)); 1291848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1292848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1293848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) { 1294848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao ArmAssembler* assembler = GetAssembler(); 1295848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LocationSummary* locations = invoke->GetLocations(); 1296848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1297848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao Register string_to_copy = locations->InAt(0).AsRegister<Register>(); 1298848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ cmp(string_to_copy, ShifterOperand(0)); 129985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke); 1300848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->AddSlowPath(slow_path); 1301848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ b(slow_path->GetEntryLabel(), EQ); 1302848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 1303848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ LoadFromOffset(kLoadWord, 1304848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromString).Int32Value()); 1305848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1306848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ blx(LR); 1307848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao __ Bind(slow_path->GetExitLabel()); 1308848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao} 1309848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao 13102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe// Unimplemented intrinsics. 13112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 13122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define UNIMPLEMENTED_INTRINSIC(Name) \ 13132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 13142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} \ 13152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \ 13162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} 13172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 13182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverse) 13192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverseBytes) 13202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverse) 13212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverseBytes) 13222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ShortReverseBytes) 13232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble) 13242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinFloatFloat) 13252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble) 13262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxFloatFloat) 13272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinLongLong) 13282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxLongLong) 13292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathCeil) // Could be done by changing rounding mode, maybe? 13302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathFloor) // Could be done by changing rounding mode, maybe? 13312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRint) 13322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundDouble) // Could be done by changing rounding mode, maybe? 13332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundFloat) // Could be done by changing rounding mode, maybe? 13342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(UnsafeCASLong) // High register pressure. 13352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) 13362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) 1337848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff HaoUNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck) 13382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe 13394d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef UNIMPLEMENTED_INTRINSIC 13404d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 13414d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef __ 13424d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain 13432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace arm 13442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe} // namespace art 1345