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