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