intrinsics_arm.cc revision 07276db28d654594e0e86e9e467cad393f752e6e
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"
202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "code_generator_arm.h"
212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "entrypoints/quick/quick_entrypoints.h"
222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "intrinsics.h"
232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "mirror/array-inl.h"
242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "mirror/art_method.h"
252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "mirror/string.h"
262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "thread.h"
272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#include "utils/arm/assembler_arm.h"
282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampenamespace art {
302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampenamespace arm {
322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeArmAssembler* IntrinsicCodeGeneratorARM::GetAssembler() {
342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  return codegen_->GetAssembler();
352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeArenaAllocator* IntrinsicCodeGeneratorARM::GetAllocator() {
382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  return codegen_->GetGraph()->GetArena();
392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define __ codegen->GetAssembler()->
422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MoveFromReturnRegister(Location trg, Primitive::Type type, CodeGeneratorARM* codegen) {
442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (!trg.IsValid()) {
452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    DCHECK(type == Primitive::kPrimVoid);
462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    return;
472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  DCHECK_NE(type, Primitive::kPrimVoid);
502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
51848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  if (Primitive::IsIntegralType(type) || type == Primitive::kPrimNot) {
522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    if (type == Primitive::kPrimLong) {
532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register trg_reg_lo = trg.AsRegisterPairLow<Register>();
542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register trg_reg_hi = trg.AsRegisterPairHigh<Register>();
552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register res_reg_lo = R0;
562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register res_reg_hi = R1;
572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      if (trg_reg_lo != res_reg_hi) {
582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe        if (trg_reg_lo != res_reg_lo) {
592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe          __ mov(trg_reg_lo, ShifterOperand(res_reg_lo));
602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe          __ mov(trg_reg_hi, ShifterOperand(res_reg_hi));
612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe        } else {
622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe          DCHECK_EQ(trg_reg_lo + 1, trg_reg_hi);
632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe        }
642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      } else {
652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe        __ mov(trg_reg_hi, ShifterOperand(res_reg_hi));
662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe        __ mov(trg_reg_lo, ShifterOperand(res_reg_lo));
672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      }
682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    } else {
692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register trg_reg = trg.AsRegister<Register>();
702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register res_reg = R0;
712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      if (trg_reg != res_reg) {
722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe        __ mov(trg_reg, ShifterOperand(res_reg));
732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      }
742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    }
752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    UNIMPLEMENTED(FATAL) << "Floating-point return.";
772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
80ec525fc30848189051b888da53ba051bc0878b78Roland Levillainstatic void MoveArguments(HInvoke* invoke, CodeGeneratorARM* codegen) {
812d27c8e338af7262dbd4aaa66127bb8fa1758b86Roland Levillain  InvokeDexCallingConventionVisitorARM calling_convention_visitor;
82ec525fc30848189051b888da53ba051bc0878b78Roland Levillain  IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe// Slow-path for fallback (calling the managed code to handle the intrinsic) in an intrinsified
862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe// call. This will copy the arguments into the positions for a regular call.
872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe//
882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe// Note: The actual parameters are required to be in the locations given by the invoke's location
892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe//       summary. If an intrinsic modifies those locations before a slowpath call, they must be
902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe//       restored!
912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampeclass IntrinsicSlowPathARM : public SlowPathCodeARM {
922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe public:
932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  explicit IntrinsicSlowPathARM(HInvoke* invoke) : invoke_(invoke) { }
942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  void EmitNativeCode(CodeGenerator* codegen_in) OVERRIDE {
962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    CodeGeneratorARM* codegen = down_cast<CodeGeneratorARM*>(codegen_in);
972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ Bind(GetEntryLabel());
982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
99a8ac9130b872c080299afacf5dcaab513d13ea87Nicolas Geoffray    SaveLiveRegisters(codegen, invoke_->GetLocations());
1002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
101ec525fc30848189051b888da53ba051bc0878b78Roland Levillain    MoveArguments(invoke_, codegen);
1022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    if (invoke_->IsInvokeStaticOrDirect()) {
1042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(), kArtMethodRegister);
105a8ac9130b872c080299afacf5dcaab513d13ea87Nicolas Geoffray      RecordPcInfo(codegen, invoke_, invoke_->GetDexPc());
1062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    } else {
1072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
1082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      UNREACHABLE();
1092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    }
1102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    // Copy the result back to the expected output.
1122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Location out = invoke_->GetLocations()->Out();
1132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    if (out.IsValid()) {
1142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      DCHECK(out.IsRegister());  // TODO: Replace this when we support output in memory.
1152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      DCHECK(!invoke_->GetLocations()->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
1162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      MoveFromReturnRegister(out, invoke_->GetType(), codegen);
1172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    }
1182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
119a8ac9130b872c080299afacf5dcaab513d13ea87Nicolas Geoffray    RestoreLiveRegisters(codegen, invoke_->GetLocations());
1202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ b(GetExitLabel());
1212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
1222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe private:
1242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // The instruction where this slow path is happening.
1252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  HInvoke* const invoke_;
1262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  DISALLOW_COPY_AND_ASSIGN(IntrinsicSlowPathARM);
1282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe};
1292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#undef __
1312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampebool IntrinsicLocationsBuilderARM::TryDispatch(HInvoke* invoke) {
1332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Dispatch(invoke);
1342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* res = invoke->GetLocations();
1352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  return res != nullptr && res->Intrinsified();
1362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define __ assembler->
1392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
1412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
1422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
1432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
1442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresFpuRegister());
1452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister());
1462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
1492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
1502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
1512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
1522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresRegister());
1532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresFpuRegister());
1542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MoveFPToInt(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
1572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location input = locations->InAt(0);
1582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location output = locations->Out();
1592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (is64bit) {
1602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ vmovrrd(output.AsRegisterPairLow<Register>(),
1612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe               output.AsRegisterPairHigh<Register>(),
1622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe               FromLowSToD(input.AsFpuRegisterPairLow<SRegister>()));
1632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
1642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ vmovrs(output.AsRegister<Register>(), input.AsFpuRegister<SRegister>());
1652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
1662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MoveIntToFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
1692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location input = locations->InAt(0);
1702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location output = locations->Out();
1712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (is64bit) {
1722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ vmovdrr(FromLowSToD(output.AsFpuRegisterPairLow<SRegister>()),
1732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe               input.AsRegisterPairLow<Register>(),
1742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe               input.AsRegisterPairHigh<Register>());
1752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
1762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ vmovsr(output.AsFpuRegister<SRegister>(), input.AsRegister<Register>());
1772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
1782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
1812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateFPToIntLocations(arena_, invoke);
1822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
1842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToFPLocations(arena_, invoke);
1852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
1882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  MoveFPToInt(invoke->GetLocations(), true, GetAssembler());
1892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
1912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  MoveIntToFP(invoke->GetLocations(), true, GetAssembler());
1922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
1942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
1952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateFPToIntLocations(arena_, invoke);
1962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
1972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitFloatIntBitsToFloat(HInvoke* invoke) {
1982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToFPLocations(arena_, invoke);
1992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
2022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  MoveFPToInt(invoke->GetLocations(), false, GetAssembler());
2032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitFloatIntBitsToFloat(HInvoke* invoke) {
2052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  MoveIntToFP(invoke->GetLocations(), false, GetAssembler());
2062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
2092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
2102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
2112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
2122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresRegister());
2132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
2172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
2182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
2192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
2202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresFpuRegister());
2212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
2222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void MathAbsFP(LocationSummary* locations, bool is64bit, ArmAssembler* assembler) {
2252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location in = locations->InAt(0);
2262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location out = locations->Out();
2272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (is64bit) {
2292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ vabsd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()),
2302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe             FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
2312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
2322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ vabss(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>());
2332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
2342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsDouble(HInvoke* invoke) {
2372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateFPToFPLocations(arena_, invoke);
2382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsDouble(HInvoke* invoke) {
2412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  MathAbsFP(invoke->GetLocations(), true, GetAssembler());
2422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsFloat(HInvoke* invoke) {
2452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateFPToFPLocations(arena_, invoke);
2462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsFloat(HInvoke* invoke) {
2492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  MathAbsFP(invoke->GetLocations(), false, GetAssembler());
2502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntToIntPlusTemp(ArenaAllocator* arena, HInvoke* invoke) {
2532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
2542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
2552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
2562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresRegister());
2572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->AddTemp(Location::RequiresRegister());
2602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenAbsInteger(LocationSummary* locations,
2632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                          bool is64bit,
2642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                          ArmAssembler* assembler) {
2652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location in = locations->InAt(0);
2662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Location output = locations->Out();
2672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register mask = locations->GetTemp(0).AsRegister<Register>();
2692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (is64bit) {
2712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register in_reg_lo = in.AsRegisterPairLow<Register>();
2722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register in_reg_hi = in.AsRegisterPairHigh<Register>();
2732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register out_reg_lo = output.AsRegisterPairLow<Register>();
2742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register out_reg_hi = output.AsRegisterPairHigh<Register>();
2752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    DCHECK_NE(out_reg_lo, in_reg_hi) << "Diagonal overlap unexpected.";
2772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ Asr(mask, in_reg_hi, 31);
2792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ adds(out_reg_lo, in_reg_lo, ShifterOperand(mask));
2802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ adc(out_reg_hi, in_reg_hi, ShifterOperand(mask));
2812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ eor(out_reg_lo, mask, ShifterOperand(out_reg_lo));
2822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ eor(out_reg_hi, mask, ShifterOperand(out_reg_hi));
2832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
2842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register in_reg = in.AsRegister<Register>();
2852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register out_reg = output.AsRegister<Register>();
2862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ Asr(mask, in_reg, 31);
2882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ add(out_reg, in_reg, ShifterOperand(mask));
2892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ eor(out_reg, mask, ShifterOperand(out_reg));
2902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
2912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsInt(HInvoke* invoke) {
2942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToIntPlusTemp(arena_, invoke);
2952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
2962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
2972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsInt(HInvoke* invoke) {
2982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenAbsInteger(invoke->GetLocations(), false, GetAssembler());
2992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathAbsLong(HInvoke* invoke) {
3032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToIntPlusTemp(arena_, invoke);
3042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathAbsLong(HInvoke* invoke) {
3072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenAbsInteger(invoke->GetLocations(), true, GetAssembler());
3082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenMinMax(LocationSummary* locations,
3112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                      bool is_min,
3122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                      ArmAssembler* assembler) {
3132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register op1 = locations->InAt(0).AsRegister<Register>();
3142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register op2 = locations->InAt(1).AsRegister<Register>();
3152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register out = locations->Out().AsRegister<Register>();
3162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ cmp(op1, ShifterOperand(op2));
3182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ it((is_min) ? Condition::LT : Condition::GT, kItElse);
3202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ mov(out, ShifterOperand(op1), is_min ? Condition::LT : Condition::GT);
3212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ mov(out, ShifterOperand(op2), is_min ? Condition::GE : Condition::LE);
3222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
3252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
3262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
3272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
3282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresRegister());
3292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(1, Location::RequiresRegister());
3302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMinIntInt(HInvoke* invoke) {
3342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntToIntLocations(arena_, invoke);
3352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMinIntInt(HInvoke* invoke) {
3382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenMinMax(invoke->GetLocations(), true, GetAssembler());
3392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathMaxIntInt(HInvoke* invoke) {
3422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntToIntLocations(arena_, invoke);
3432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathMaxIntInt(HInvoke* invoke) {
3462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenMinMax(invoke->GetLocations(), false, GetAssembler());
3472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMathSqrt(HInvoke* invoke) {
3502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateFPToFPLocations(arena_, invoke);
3512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMathSqrt(HInvoke* invoke) {
3542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = invoke->GetLocations();
3552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
3562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ vsqrtd(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
3572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe            FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
3582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekByte(HInvoke* invoke) {
3612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToIntLocations(arena_, invoke);
3622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekByte(HInvoke* invoke) {
3652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
3662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Ignore upper 4B of long address.
3672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ ldrsb(invoke->GetLocations()->Out().AsRegister<Register>(),
3682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe           Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
3692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekIntNative(HInvoke* invoke) {
3722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToIntLocations(arena_, invoke);
3732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekIntNative(HInvoke* invoke) {
3762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
3772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Ignore upper 4B of long address.
3782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ ldr(invoke->GetLocations()->Out().AsRegister<Register>(),
3792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe         Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
3802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekLongNative(HInvoke* invoke) {
3832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToIntLocations(arena_, invoke);
3842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
3852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
3862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekLongNative(HInvoke* invoke) {
3872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
3882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Ignore upper 4B of long address.
3892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
3902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor
3912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // exception. So we can't use ldrd as addr may be unaligned.
3922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register lo = invoke->GetLocations()->Out().AsRegisterPairLow<Register>();
3932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register hi = invoke->GetLocations()->Out().AsRegisterPairHigh<Register>();
3942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (addr == lo) {
3952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ ldr(hi, Address(addr, 4));
3962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ ldr(lo, Address(addr, 0));
3972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
3982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ ldr(lo, Address(addr, 0));
3992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ ldr(hi, Address(addr, 4));
4002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
4012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPeekShortNative(HInvoke* invoke) {
4042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntToIntLocations(arena_, invoke);
4052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPeekShortNative(HInvoke* invoke) {
4082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
4092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Ignore upper 4B of long address.
4102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ ldrsh(invoke->GetLocations()->Out().AsRegister<Register>(),
4112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe           Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
4122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
4152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
4162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
4172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
4182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresRegister());
4192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(1, Location::RequiresRegister());
4202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeByte(HInvoke* invoke) {
4232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntToVoidLocations(arena_, invoke);
4242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeByte(HInvoke* invoke) {
4272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
4282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ strb(invoke->GetLocations()->InAt(1).AsRegister<Register>(),
4292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe          Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
4302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeIntNative(HInvoke* invoke) {
4332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntToVoidLocations(arena_, invoke);
4342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeIntNative(HInvoke* invoke) {
4372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
4382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ str(invoke->GetLocations()->InAt(1).AsRegister<Register>(),
4392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe         Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
4402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeLongNative(HInvoke* invoke) {
4432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntToVoidLocations(arena_, invoke);
4442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeLongNative(HInvoke* invoke) {
4472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
4482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Ignore upper 4B of long address.
4492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register addr = invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>();
4502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor
4512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // exception. So we can't use ldrd as addr may be unaligned.
4522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ str(invoke->GetLocations()->InAt(1).AsRegisterPairLow<Register>(), Address(addr, 0));
4532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ str(invoke->GetLocations()->InAt(1).AsRegisterPairHigh<Register>(), Address(addr, 4));
4542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitMemoryPokeShortNative(HInvoke* invoke) {
4572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntToVoidLocations(arena_, invoke);
4582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitMemoryPokeShortNative(HInvoke* invoke) {
4612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
4622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ strh(invoke->GetLocations()->InAt(1).AsRegister<Register>(),
4632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe          Address(invoke->GetLocations()->InAt(0).AsRegisterPairLow<Register>()));
4642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitThreadCurrentThread(HInvoke* invoke) {
4672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena_) LocationSummary(invoke,
4682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                            LocationSummary::kNoCall,
4692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                            kIntrinsified);
4702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister());
4712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitThreadCurrentThread(HInvoke* invoke) {
4742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
4752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ LoadFromOffset(kLoadWord,
4762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                    invoke->GetLocations()->Out().AsRegister<Register>(),
4772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                    TR,
4782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                    Thread::PeerOffset<kArmPointerSize>().Int32Value());
4792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
4802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafeGet(HInvoke* invoke,
4822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                         Primitive::Type type,
4832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                         bool is_volatile,
4842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                         CodeGeneratorARM* codegen) {
4852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = invoke->GetLocations();
4862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  DCHECK((type == Primitive::kPrimInt) ||
4872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe         (type == Primitive::kPrimLong) ||
4882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe         (type == Primitive::kPrimNot));
4892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = codegen->GetAssembler();
4902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register base = locations->InAt(1).AsRegister<Register>();           // Object pointer.
4912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register offset = locations->InAt(2).AsRegisterPairLow<Register>();  // Long offset, lo part only.
4922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
4932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (type == Primitive::kPrimLong) {
4942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register trg_lo = locations->Out().AsRegisterPairLow<Register>();
4952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ add(IP, base, ShifterOperand(offset));
4962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) {
4972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register trg_hi = locations->Out().AsRegisterPairHigh<Register>();
4982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ ldrexd(trg_lo, trg_hi, IP);
4992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    } else {
5002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ ldrd(trg_lo, Address(IP));
5012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    }
5022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
5032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register trg = locations->Out().AsRegister<Register>();
5042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ ldr(trg, Address(base, offset));
5052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
5062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
5072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (is_volatile) {
5082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ dmb(ISH);
5092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
5102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
5122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
5132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
5142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
5152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
5162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
5172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(1, Location::RequiresRegister());
5182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(2, Location::RequiresRegister());
5192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
5202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
5222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGet(HInvoke* invoke) {
5232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntToIntLocations(arena_, invoke);
5242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetVolatile(HInvoke* invoke) {
5262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntToIntLocations(arena_, invoke);
5272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLong(HInvoke* invoke) {
5292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntToIntLocations(arena_, invoke);
5302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
5322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntToIntLocations(arena_, invoke);
5332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObject(HInvoke* invoke) {
5352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntToIntLocations(arena_, invoke);
5362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
5382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntToIntLocations(arena_, invoke);
5392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
5412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGet(HInvoke* invoke) {
5422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafeGet(invoke, Primitive::kPrimInt, false, codegen_);
5432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetVolatile(HInvoke* invoke) {
5452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafeGet(invoke, Primitive::kPrimInt, true, codegen_);
5462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLong(HInvoke* invoke) {
5482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafeGet(invoke, Primitive::kPrimLong, false, codegen_);
5492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
5512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafeGet(invoke, Primitive::kPrimLong, true, codegen_);
5522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObject(HInvoke* invoke) {
5542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafeGet(invoke, Primitive::kPrimNot, false, codegen_);
5552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
5572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafeGet(invoke, Primitive::kPrimNot, true, codegen_);
5582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
5602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntToVoid(ArenaAllocator* arena,
5612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                     const ArmInstructionSetFeatures& features,
5622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                     Primitive::Type type,
5632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                     bool is_volatile,
5642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                     HInvoke* invoke) {
5652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
5662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
5672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
5682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
5692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(1, Location::RequiresRegister());
5702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(2, Location::RequiresRegister());
5712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(3, Location::RequiresRegister());
5722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
5732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (type == Primitive::kPrimLong) {
5742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    // Potentially need temps for ldrexd-strexd loop.
5752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    if (is_volatile && !features.HasAtomicLdrdAndStrd()) {
5762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      locations->AddTemp(Location::RequiresRegister());  // Temp_lo.
5772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      locations->AddTemp(Location::RequiresRegister());  // Temp_hi.
5782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    }
5792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else if (type == Primitive::kPrimNot) {
5802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    // Temps for card-marking.
5812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    locations->AddTemp(Location::RequiresRegister());  // Temp.
5822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    locations->AddTemp(Location::RequiresRegister());  // Card.
5832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
5842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
5862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePut(HInvoke* invoke) {
5872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke);
5882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutOrdered(HInvoke* invoke) {
5902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, false, invoke);
5912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutVolatile(HInvoke* invoke) {
5932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimInt, true, invoke);
5942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObject(HInvoke* invoke) {
5962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke);
5972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
5982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
5992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, false, invoke);
6002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
6022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimNot, true, invoke);
6032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLong(HInvoke* invoke) {
6052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke);
6062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongOrdered(HInvoke* invoke) {
6082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, false, invoke);
6092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafePutLongVolatile(HInvoke* invoke) {
6112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntToVoid(arena_, features_, Primitive::kPrimLong, true, invoke);
6122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenUnsafePut(LocationSummary* locations,
6152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                         Primitive::Type type,
6162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                         bool is_volatile,
6172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                         bool is_ordered,
6182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                         CodeGeneratorARM* codegen) {
6192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = codegen->GetAssembler();
6202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register base = locations->InAt(1).AsRegister<Register>();           // Object pointer.
6222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register offset = locations->InAt(2).AsRegisterPairLow<Register>();  // Long offset, lo part only.
6232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register value;
6242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (is_volatile || is_ordered) {
6262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ dmb(ISH);
6272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
6282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (type == Primitive::kPrimLong) {
6302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register value_lo = locations->InAt(3).AsRegisterPairLow<Register>();
6312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    value = value_lo;
6322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    if (is_volatile && !codegen->GetInstructionSetFeatures().HasAtomicLdrdAndStrd()) {
6332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register temp_lo = locations->GetTemp(0).AsRegister<Register>();
6342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register temp_hi = locations->GetTemp(1).AsRegister<Register>();
6352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Register value_hi = locations->InAt(3).AsRegisterPairHigh<Register>();
6362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ add(IP, base, ShifterOperand(offset));
6382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      Label loop_head;
6392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ Bind(&loop_head);
6402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ ldrexd(temp_lo, temp_hi, IP);
6412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ strexd(temp_lo, value_lo, value_hi, IP);
6422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ cmp(temp_lo, ShifterOperand(0));
6432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ b(&loop_head, NE);
6442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    } else {
6452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ add(IP, base, ShifterOperand(offset));
6462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe      __ strd(value_lo, Address(IP));
6472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    }
6482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  } else {
6492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    value =  locations->InAt(3).AsRegister<Register>();
6502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ str(value, Address(base, offset));
6512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
6522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (is_volatile) {
6542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    __ dmb(ISH);
6552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
6562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (type == Primitive::kPrimNot) {
6582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register temp = locations->GetTemp(0).AsRegister<Register>();
6592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    Register card = locations->GetTemp(1).AsRegister<Register>();
66007276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray    bool value_can_be_null = true;  // TODO: Worth finding out this information?
66107276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray    codegen->MarkGCCard(temp, card, base, value, value_can_be_null);
6622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
6632bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePut(HInvoke* invoke) {
6662bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, false, codegen_);
6672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutOrdered(HInvoke* invoke) {
6692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, false, true, codegen_);
6702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutVolatile(HInvoke* invoke) {
6722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, true, false, codegen_);
6732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObject(HInvoke* invoke) {
6752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, false, codegen_);
6762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
6782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, false, true, codegen_);
6792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
6812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, true, false, codegen_);
6822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLong(HInvoke* invoke) {
6842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, false, codegen_);
6852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongOrdered(HInvoke* invoke) {
6872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, false, true, codegen_);
6882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafePutLongVolatile(HInvoke* invoke) {
6902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, true, false, codegen_);
6912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
6922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
6932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void CreateIntIntIntIntIntToIntPlusTemps(ArenaAllocator* arena,
6942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                HInvoke* invoke) {
6952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena) LocationSummary(invoke,
6962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           LocationSummary::kNoCall,
6972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                           kIntrinsified);
6982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
6992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(1, Location::RequiresRegister());
7002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(2, Location::RequiresRegister());
7012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(3, Location::RequiresRegister());
7022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(4, Location::RequiresRegister());
7032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
7052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->AddTemp(Location::RequiresRegister());  // Pointer.
7072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->AddTemp(Location::RequiresRegister());  // Temp 1.
7082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->AddTemp(Location::RequiresRegister());  // Temp 2.
7092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
7102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampestatic void GenCas(LocationSummary* locations, Primitive::Type type, CodeGeneratorARM* codegen) {
7122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  DCHECK_NE(type, Primitive::kPrimLong);
7132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = codegen->GetAssembler();
7152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register out = locations->Out().AsRegister<Register>();              // Boolean result.
7172bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register base = locations->InAt(1).AsRegister<Register>();           // Object pointer.
7192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register offset = locations->InAt(2).AsRegisterPairLow<Register>();  // Offset (discard high 4B).
7202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register expected_lo = locations->InAt(3).AsRegister<Register>();    // Expected.
7212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register value_lo = locations->InAt(4).AsRegister<Register>();       // Value.
7222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register tmp_ptr = locations->GetTemp(0).AsRegister<Register>();     // Pointer to actual memory.
7242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register tmp_lo = locations->GetTemp(1).AsRegister<Register>();      // Value in memory.
7252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  if (type == Primitive::kPrimNot) {
7272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    // Mark card for object assuming new value is stored. Worst case we will mark an unchanged
7282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe    // object and scan the receiver at the next GC for nothing.
72907276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray    bool value_can_be_null = true;  // TODO: Worth finding out this information?
73007276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray    codegen->MarkGCCard(tmp_ptr, tmp_lo, base, value_lo, value_can_be_null);
7312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  }
7322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Prevent reordering with prior memory operations.
7342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ dmb(ISH);
7352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ add(tmp_ptr, base, ShifterOperand(offset));
7372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // do {
7392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  //   tmp = [r_ptr] - expected;
7402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // } while (tmp == 0 && failure([r_ptr] <- r_new_value));
7412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // result = tmp != 0;
7422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Label loop_head;
7442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ Bind(&loop_head);
7452bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ ldrex(tmp_lo, tmp_ptr);
7472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ subs(tmp_lo, tmp_lo, ShifterOperand(expected_lo));
7492bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7502bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ it(EQ, ItState::kItT);
7512bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ strex(tmp_lo, value_lo, tmp_ptr, EQ);
7522bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ cmp(tmp_lo, ShifterOperand(1), EQ);
7532bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7542bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ b(&loop_head, EQ);
7552bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7562bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ dmb(ISH);
7572bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7582bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ rsbs(out, tmp_lo, ShifterOperand(1));
7592bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ it(CC);
7602bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ mov(out, ShifterOperand(0), CC);
7612bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
7622bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
763ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASInt(HInvoke* invoke) {
7642bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
7652bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
766ca71458862be8505330b7fd5649a062f31d143dcAndreas Gampevoid IntrinsicLocationsBuilderARM::VisitUnsafeCASObject(HInvoke* invoke) {
7672bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  CreateIntIntIntIntIntToIntPlusTemps(arena_, invoke);
7682bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
7692bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASInt(HInvoke* invoke) {
7702bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenCas(invoke->GetLocations(), Primitive::kPrimInt, codegen_);
7712bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
7722bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitUnsafeCASObject(HInvoke* invoke) {
7732bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  GenCas(invoke->GetLocations(), Primitive::kPrimNot, codegen_);
7742bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
7752bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7762bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringCharAt(HInvoke* invoke) {
7772bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = new (arena_) LocationSummary(invoke,
7782bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                            LocationSummary::kCallOnSlowPath,
7792bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe                                                            kIntrinsified);
7802bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(0, Location::RequiresRegister());
7812bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetInAt(1, Location::RequiresRegister());
7822bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
7832bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7842bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->AddTemp(Location::RequiresRegister());
7852bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  locations->AddTemp(Location::RequiresRegister());
7862bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
7872bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7882bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringCharAt(HInvoke* invoke) {
7892bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  ArmAssembler* assembler = GetAssembler();
7902bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  LocationSummary* locations = invoke->GetLocations();
7912bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7922bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Location of reference to data array
7932bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  const MemberOffset value_offset = mirror::String::ValueOffset();
7942bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Location of count
7952bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  const MemberOffset count_offset = mirror::String::CountOffset();
7962bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
7972bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register obj = locations->InAt(0).AsRegister<Register>();  // String object pointer.
7982bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register idx = locations->InAt(1).AsRegister<Register>();  // Index of character.
7992bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register out = locations->Out().AsRegister<Register>();    // Result character.
8002bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
8012bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register temp = locations->GetTemp(0).AsRegister<Register>();
8022bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  Register array_temp = locations->GetTemp(1).AsRegister<Register>();
8032bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
8042bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth
8052bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  //       the cost.
8062bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // TODO: For simplicity, the index parameter is requested in a register, so different from Quick
8072bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  //       we will not optimize the code for constants (which would save a register).
8082bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
8092bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
8102bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  codegen_->AddSlowPath(slow_path);
8112bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
8122bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ ldr(temp, Address(obj, count_offset.Int32Value()));          // temp = str.length.
8132bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  codegen_->MaybeRecordImplicitNullCheck(invoke);
8142bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ cmp(idx, ShifterOperand(temp));
8152bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ b(slow_path->GetEntryLabel(), CS);
8162bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
817848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ add(array_temp, obj, ShifterOperand(value_offset.Int32Value()));  // array_temp := str.value.
8182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
8192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  // Load the value.
820848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ ldrh(out, Address(array_temp, idx, LSL, 1));                 // out := array_temp[idx].
8212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
8222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe  __ Bind(slow_path->GetExitLabel());
8232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
8242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
825d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicLocationsBuilderARM::VisitStringCompareTo(HInvoke* invoke) {
826d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  // The inputs plus one temp.
827d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  LocationSummary* locations = new (arena_) LocationSummary(invoke,
828d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray                                                            LocationSummary::kCall,
829d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray                                                            kIntrinsified);
830d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  InvokeRuntimeCallingConvention calling_convention;
831d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
832d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
833d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  locations->SetOut(Location::RegisterLocation(R0));
834d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray}
835d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
836d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicCodeGeneratorARM::VisitStringCompareTo(HInvoke* invoke) {
837d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  ArmAssembler* assembler = GetAssembler();
838d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  LocationSummary* locations = invoke->GetLocations();
839d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
840512e04d1ea7fb33e3992715fe55be8a834d4a79cNicolas Geoffray  // Note that the null check must have been done earlier.
841641547a5f18ca2ea54469cceadcfef64f132e5e0Calin Juravle  DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
842d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
843d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  Register argument = locations->InAt(1).AsRegister<Register>();
844d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ cmp(argument, ShifterOperand(0));
845d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
846d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  codegen_->AddSlowPath(slow_path);
847d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ b(slow_path->GetEntryLabel(), EQ);
848d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
849d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ LoadFromOffset(
850d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray      kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pStringCompareTo).Int32Value());
851d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ blx(LR);
852d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ Bind(slow_path->GetExitLabel());
853d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray}
854d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
855ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampestatic void GenerateVisitStringIndexOf(HInvoke* invoke,
856ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                       ArmAssembler* assembler,
857ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                       CodeGeneratorARM* codegen,
858ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                       ArenaAllocator* allocator,
859ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                       bool start_at_zero) {
860ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  LocationSummary* locations = invoke->GetLocations();
861ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  Register tmp_reg = locations->GetTemp(0).AsRegister<Register>();
862ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
863ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // Note that the null check must have been done earlier.
864ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
865ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
866ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
867ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // or directly dispatch if we have a constant.
868ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  SlowPathCodeARM* slow_path = nullptr;
869ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  if (invoke->InputAt(1)->IsIntConstant()) {
870ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) >
871ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe        std::numeric_limits<uint16_t>::max()) {
872ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe      // Always needs the slow-path. We could directly dispatch to it, but this case should be
873ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe      // rare, so for simplicity just put the full slow-path down and branch unconditionally.
874ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe      slow_path = new (allocator) IntrinsicSlowPathARM(invoke);
875ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe      codegen->AddSlowPath(slow_path);
876ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe      __ b(slow_path->GetEntryLabel());
877ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe      __ Bind(slow_path->GetExitLabel());
878ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe      return;
879ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    }
880ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  } else {
881ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    Register char_reg = locations->InAt(1).AsRegister<Register>();
882ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    __ LoadImmediate(tmp_reg, std::numeric_limits<uint16_t>::max());
883ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    __ cmp(char_reg, ShifterOperand(tmp_reg));
884ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    slow_path = new (allocator) IntrinsicSlowPathARM(invoke);
885ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    codegen->AddSlowPath(slow_path);
886ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    __ b(slow_path->GetEntryLabel(), HI);
887ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  }
888ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
889ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  if (start_at_zero) {
890ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    DCHECK_EQ(tmp_reg, R2);
891ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    // Start-index = 0.
892ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    __ LoadImmediate(tmp_reg, 0);
893ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  }
894ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
895ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  __ LoadFromOffset(kLoadWord, LR, TR,
896ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                    QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pIndexOf).Int32Value());
897ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  __ blx(LR);
898ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
899ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  if (slow_path != nullptr) {
900ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe    __ Bind(slow_path->GetExitLabel());
901ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  }
902ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe}
903ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
904ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOf(HInvoke* invoke) {
905ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  LocationSummary* locations = new (arena_) LocationSummary(invoke,
906ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                                            LocationSummary::kCall,
907ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                                            kIntrinsified);
908ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
909ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // best to align the inputs accordingly.
910ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  InvokeRuntimeCallingConvention calling_convention;
911ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
912ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
913ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->SetOut(Location::RegisterLocation(R0));
914ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
915ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // Need a temp for slow-path codepoint compare, and need to send start-index=0.
916ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
917ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe}
918ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
919ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOf(HInvoke* invoke) {
920ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), true);
921ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe}
922ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
923ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicLocationsBuilderARM::VisitStringIndexOfAfter(HInvoke* invoke) {
924ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  LocationSummary* locations = new (arena_) LocationSummary(invoke,
925ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                                            LocationSummary::kCall,
926ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe                                                            kIntrinsified);
927ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // We have a hand-crafted assembly stub that follows the runtime calling convention. So it's
928ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // best to align the inputs accordingly.
929ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  InvokeRuntimeCallingConvention calling_convention;
930ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
931ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
932ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
933ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->SetOut(Location::RegisterLocation(R0));
934ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
935ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  // Need a temp for slow-path codepoint compare.
936ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  locations->AddTemp(Location::RequiresRegister());
937ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe}
938ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
939ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampevoid IntrinsicCodeGeneratorARM::VisitStringIndexOfAfter(HInvoke* invoke) {
940ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe  GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), false);
941ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe}
942ba6fdbcb764d5a8972f5ff2d7147e4d78226b347Andreas Gampe
943848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromBytes(HInvoke* invoke) {
944848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = new (arena_) LocationSummary(invoke,
945848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            LocationSummary::kCall,
946848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            kIntrinsified);
947848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  InvokeRuntimeCallingConvention calling_convention;
948848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
949848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
950848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
951848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
952848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetOut(Location::RegisterLocation(R0));
953848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
954848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
955848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromBytes(HInvoke* invoke) {
956848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  ArmAssembler* assembler = GetAssembler();
957848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = invoke->GetLocations();
958848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
959848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  Register byte_array = locations->InAt(0).AsRegister<Register>();
960848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ cmp(byte_array, ShifterOperand(0));
961848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
962848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->AddSlowPath(slow_path);
963848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ b(slow_path->GetEntryLabel(), EQ);
964848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
965848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ LoadFromOffset(
966848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromBytes).Int32Value());
967848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
968848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ blx(LR);
969848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ Bind(slow_path->GetExitLabel());
970848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
971848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
972848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromChars(HInvoke* invoke) {
973848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = new (arena_) LocationSummary(invoke,
974848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            LocationSummary::kCall,
975848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            kIntrinsified);
976848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  InvokeRuntimeCallingConvention calling_convention;
977848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
978848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
979848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
980848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetOut(Location::RegisterLocation(R0));
981848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
982848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
983848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromChars(HInvoke* invoke) {
984848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  ArmAssembler* assembler = GetAssembler();
985848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
986848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ LoadFromOffset(
987848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      kLoadWord, LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromChars).Int32Value());
988848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
989848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ blx(LR);
990848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
991848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
992848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderARM::VisitStringNewStringFromString(HInvoke* invoke) {
993848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = new (arena_) LocationSummary(invoke,
994848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            LocationSummary::kCall,
995848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            kIntrinsified);
996848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  InvokeRuntimeCallingConvention calling_convention;
997848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
998848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetOut(Location::RegisterLocation(R0));
999848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1000848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1001848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorARM::VisitStringNewStringFromString(HInvoke* invoke) {
1002848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  ArmAssembler* assembler = GetAssembler();
1003848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = invoke->GetLocations();
1004848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1005848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  Register string_to_copy = locations->InAt(0).AsRegister<Register>();
1006848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ cmp(string_to_copy, ShifterOperand(0));
1007848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  SlowPathCodeARM* slow_path = new (GetAllocator()) IntrinsicSlowPathARM(invoke);
1008848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->AddSlowPath(slow_path);
1009848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ b(slow_path->GetEntryLabel(), EQ);
1010848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1011848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ LoadFromOffset(kLoadWord,
1012848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao      LR, TR, QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocStringFromString).Int32Value());
1013848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1014848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ blx(LR);
1015848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ Bind(slow_path->GetExitLabel());
1016848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1017848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
10182bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe// Unimplemented intrinsics.
10192bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
10202bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe#define UNIMPLEMENTED_INTRINSIC(Name)                                                  \
10212bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicLocationsBuilderARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
10222bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}                                                                                      \
10232bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampevoid IntrinsicCodeGeneratorARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) {    \
10242bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}
10252bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
10262bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverse)
10272bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(IntegerReverseBytes)
10282bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverse)
10292bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(LongReverseBytes)
10302bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ShortReverseBytes)
10312bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble)
10322bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinFloatFloat)
10332bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxDoubleDouble)
10342bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxFloatFloat)
10352bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMinLongLong)
10362bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathMaxLongLong)
10372bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathCeil)          // Could be done by changing rounding mode, maybe?
10382bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathFloor)         // Could be done by changing rounding mode, maybe?
10392bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRint)
10402bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundDouble)   // Could be done by changing rounding mode, maybe?
10412bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(MathRoundFloat)    // Could be done by changing rounding mode, maybe?
10422bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(UnsafeCASLong)     // High register pressure.
10432bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
10442bcf9bf784a0021630d8fe63d7230d46d6891780Andreas GampeUNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
1045848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff HaoUNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
10462bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe
10472bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}  // namespace arm
10482bcf9bf784a0021630d8fe63d7230d46d6891780Andreas Gampe}  // namespace art
1049