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