109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell/*
209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * Copyright (C) 2015 The Android Open Source Project
309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell *
409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * Licensed under the Apache License, Version 2.0 (the "License");
509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * you may not use this file except in compliance with the License.
609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * You may obtain a copy of the License at
709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell *
809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell *      http://www.apache.org/licenses/LICENSE-2.0
909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell *
1009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * Unless required by applicable law or agreed to in writing, software
1109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * distributed under the License is distributed on an "AS IS" BASIS,
1209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * See the License for the specific language governing permissions and
1409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell * limitations under the License.
1509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell */
1609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
1709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "intrinsics_x86.h"
1809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
1921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe#include <limits>
2021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
21fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell#include "arch/x86/instruction_set_features_x86.h"
22e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier#include "art_method.h"
23d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell#include "base/bit_utils.h"
2409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "code_generator_x86.h"
2509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "entrypoints/quick/quick_entrypoints.h"
2609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "intrinsics.h"
2785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe#include "intrinsics_utils.h"
2809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "mirror/array-inl.h"
2909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "mirror/string.h"
3009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "thread.h"
3109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "utils/x86/assembler_x86.h"
3209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#include "utils/x86/constants_x86.h"
3309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
3409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellnamespace art {
3509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
3609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellnamespace x86 {
3709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
3809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic constexpr int kDoubleNaNHigh = 0x7FF80000;
3909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic constexpr int kDoubleNaNLow = 0x00000000;
402f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendellstatic constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000);
412f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendellstatic constexpr int32_t kFloatNaN = INT32_C(0x7FC00000);
4209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
43fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark MendellIntrinsicLocationsBuilderX86::IntrinsicLocationsBuilderX86(CodeGeneratorX86* codegen)
442f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  : arena_(codegen->GetGraph()->GetArena()),
452f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    codegen_(codegen) {
46fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
47fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
48fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
4909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark MendellX86Assembler* IntrinsicCodeGeneratorX86::GetAssembler() {
50b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain  return down_cast<X86Assembler*>(codegen_->GetAssembler());
5109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
5209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
5309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark MendellArenaAllocator* IntrinsicCodeGeneratorX86::GetAllocator() {
5409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  return codegen_->GetGraph()->GetArena();
5509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
5609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
5709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellbool IntrinsicLocationsBuilderX86::TryDispatch(HInvoke* invoke) {
5809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Dispatch(invoke);
5909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* res = invoke->GetLocations();
600d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  if (res == nullptr) {
610d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    return false;
620d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  }
630d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  if (kEmitCompilerReadBarrier && res->CanCall()) {
640d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // Generating an intrinsic for this HInvoke may produce an
650d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // IntrinsicSlowPathX86 slow path.  Currently this approach
660d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // does not work when using read barriers, as the emitted
670d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // calling sequence will make use of another slow path
680d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // (ReadBarrierForRootSlowPathX86 for HInvokeStaticOrDirect,
690d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // ReadBarrierSlowPathX86 for HInvokeVirtual).  So we bail
700d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // out in this case.
710d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    //
720d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // TODO: Find a way to have intrinsics work with read barriers.
730d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    invoke->SetLocations(nullptr);
740d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    return false;
750d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  }
760d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  return res->Intrinsified();
7709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
7809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
79ec525fc30848189051b888da53ba051bc0878b78Roland Levillainstatic void MoveArguments(HInvoke* invoke, CodeGeneratorX86* codegen) {
802d27c8e338af7262dbd4aaa66127bb8fa1758b86Roland Levillain  InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
81ec525fc30848189051b888da53ba051bc0878b78Roland Levillain  IntrinsicVisitor::MoveArguments(invoke, codegen, &calling_convention_visitor);
8209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
8309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
8485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampeusing IntrinsicSlowPathX86 = IntrinsicSlowPath<InvokeDexCallingConventionVisitorX86>;
8509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
8609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell#define __ assembler->
8709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
8809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateFPToIntLocations(ArenaAllocator* arena, HInvoke* invoke, bool is64bit) {
8909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
9009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
9109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
9209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresFpuRegister());
9309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::RequiresRegister());
9409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is64bit) {
9509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->AddTemp(Location::RequiresFpuRegister());
9609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
9709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
9809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
9909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateIntToFPLocations(ArenaAllocator* arena, HInvoke* invoke, bool is64bit) {
10009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
10109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
10209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
10309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
10409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::RequiresFpuRegister());
10509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is64bit) {
10609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->AddTemp(Location::RequiresFpuRegister());
10709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->AddTemp(Location::RequiresFpuRegister());
10809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
10909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
11009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
11109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void MoveFPToInt(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
11209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location input = locations->InAt(0);
11309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location output = locations->Out();
11409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is64bit) {
11509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Need to use the temporary.
11609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
11709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movsd(temp, input.AsFpuRegister<XmmRegister>());
11809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movd(output.AsRegisterPairLow<Register>(), temp);
11909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ psrlq(temp, Immediate(32));
12009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movd(output.AsRegisterPairHigh<Register>(), temp);
12109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
12209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movd(output.AsRegister<Register>(), input.AsFpuRegister<XmmRegister>());
12309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
12409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
12509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
12609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void MoveIntToFP(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
12709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location input = locations->InAt(0);
12809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location output = locations->Out();
12909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is64bit) {
13009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Need to use the temporary.
13109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
13209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
13309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movd(temp1, input.AsRegisterPairLow<Register>());
13409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movd(temp2, input.AsRegisterPairHigh<Register>());
13509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ punpckldq(temp1, temp2);
13609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movsd(output.AsFpuRegister<XmmRegister>(), temp1);
13709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
13809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movd(output.AsFpuRegister<XmmRegister>(), input.AsRegister<Register>());
13909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
14009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
14109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
14209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
143bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateFPToIntLocations(arena_, invoke, /* is64bit */ true);
14409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
14509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
146bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntToFPLocations(arena_, invoke, /* is64bit */ true);
14709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
14809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
14909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitDoubleDoubleToRawLongBits(HInvoke* invoke) {
150bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  MoveFPToInt(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
15109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
15209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitDoubleLongBitsToDouble(HInvoke* invoke) {
153bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  MoveIntToFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
15409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
15509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
15609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
157bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateFPToIntLocations(arena_, invoke, /* is64bit */ false);
15809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
15909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
160bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntToFPLocations(arena_, invoke, /* is64bit */ false);
16109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
16209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
16309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitFloatFloatToRawIntBits(HInvoke* invoke) {
164bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  MoveFPToInt(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
16509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
16609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitFloatIntBitsToFloat(HInvoke* invoke) {
167bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  MoveIntToFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
16809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
16909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
17009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
17109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
17209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
17309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
17409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
17509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
17609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
17709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
17809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateLongToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
17909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
18009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
18109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
18209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
18309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::RequiresRegister());
18409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
18509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
18609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateLongToLongLocations(ArenaAllocator* arena, HInvoke* invoke) {
18709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
18809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
18909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
19009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
19109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
19209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
19309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
19409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void GenReverseBytes(LocationSummary* locations,
19509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                            Primitive::Type size,
19609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                            X86Assembler* assembler) {
19709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register out = locations->Out().AsRegister<Register>();
19809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
19909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  switch (size) {
20009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimShort:
20109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      // TODO: Can be done with an xchg of 8b registers. This is straight from Quick.
20209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ bswapl(out);
20309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ sarl(out, Immediate(16));
20409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
20509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimInt:
20609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ bswapl(out);
20709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
20809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    default:
20909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      LOG(FATAL) << "Unexpected size for reverse-bytes: " << size;
21009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      UNREACHABLE();
21109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
21209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
21309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
21409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitIntegerReverseBytes(HInvoke* invoke) {
21509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateIntToIntLocations(arena_, invoke);
21609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
21709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
21809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitIntegerReverseBytes(HInvoke* invoke) {
21909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
22009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
22109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
22258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitLongReverseBytes(HInvoke* invoke) {
22358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  CreateLongToLongLocations(arena_, invoke);
22458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
22558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
22658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitLongReverseBytes(HInvoke* invoke) {
22758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  LocationSummary* locations = invoke->GetLocations();
22858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Location input = locations->InAt(0);
22958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register input_lo = input.AsRegisterPairLow<Register>();
23058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register input_hi = input.AsRegisterPairHigh<Register>();
23158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Location output = locations->Out();
23258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register output_lo = output.AsRegisterPairLow<Register>();
23358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register output_hi = output.AsRegisterPairHigh<Register>();
23458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
23558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  X86Assembler* assembler = GetAssembler();
23658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // Assign the inputs to the outputs, mixing low/high.
23758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ movl(output_lo, input_hi);
23858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ movl(output_hi, input_lo);
23958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ bswapl(output_lo);
24058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ bswapl(output_hi);
24158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
24258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
24309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitShortReverseBytes(HInvoke* invoke) {
24409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateIntToIntLocations(arena_, invoke);
24509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
24609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
24709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitShortReverseBytes(HInvoke* invoke) {
24809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenReverseBytes(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
24909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
25009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
25109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
25209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell// TODO: Consider Quick's way of doing Double abs through integer operations, as the immediate we
25309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell//       need is 64b.
25409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
25509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateFloatToFloat(ArenaAllocator* arena, HInvoke* invoke) {
25609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // TODO: Enable memory operations when the assembler supports them.
25709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
25809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
25909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
26009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresFpuRegister());
26109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
2622f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
2632f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  DCHECK(static_or_direct != nullptr);
2649779307ce8f2dd40c429abb0f0cafc1415f70648Nicolas Geoffray  if (static_or_direct->HasSpecialInput() &&
2659779307ce8f2dd40c429abb0f0cafc1415f70648Nicolas Geoffray      invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) {
2662f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    // We need addressibility for the constant area.
2672f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    locations->SetInAt(1, Location::RequiresRegister());
2682f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    // We need a temporary to hold the constant.
2692f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    locations->AddTemp(Location::RequiresFpuRegister());
2702f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  }
27109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
27209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
2732f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendellstatic void MathAbsFP(LocationSummary* locations,
2742f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell                      bool is64bit,
2752f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell                      X86Assembler* assembler,
2762f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell                      CodeGeneratorX86* codegen) {
27709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location output = locations->Out();
27809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
2792f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  DCHECK(output.IsFpuRegister());
2809779307ce8f2dd40c429abb0f0cafc1415f70648Nicolas Geoffray  if (locations->GetInputCount() == 2 && locations->InAt(1).IsValid()) {
2812f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    DCHECK(locations->InAt(1).IsRegister());
2822f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    // We also have a constant area pointer.
2832f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    Register constant_area = locations->InAt(1).AsRegister<Register>();
2842f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2852f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    if (is64bit) {
2862f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ movsd(temp, codegen->LiteralInt64Address(INT64_C(0x7FFFFFFFFFFFFFFF), constant_area));
2872f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ andpd(output.AsFpuRegister<XmmRegister>(), temp);
2882f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    } else {
2892f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ movss(temp, codegen->LiteralInt32Address(INT32_C(0x7FFFFFFF), constant_area));
2902f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ andps(output.AsFpuRegister<XmmRegister>(), temp);
2912f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    }
2922f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  } else {
29309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Create the right constant on an aligned stack.
29409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    if (is64bit) {
29509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ subl(ESP, Immediate(8));
29609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ pushl(Immediate(0x7FFFFFFF));
29709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ pushl(Immediate(0xFFFFFFFF));
29809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ andpd(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
29909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    } else {
30009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ subl(ESP, Immediate(12));
30109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ pushl(Immediate(0x7FFFFFFF));
30209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ andps(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
30309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    }
30409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ addl(ESP, Immediate(16));
30509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
30609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
30709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
30809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAbsDouble(HInvoke* invoke) {
30909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateFloatToFloat(arena_, invoke);
31009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
31109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
31209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAbsDouble(HInvoke* invoke) {
3132f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler(), codegen_);
31409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
31509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
31609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) {
31709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateFloatToFloat(arena_, invoke);
31809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
31909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
32009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAbsFloat(HInvoke* invoke) {
3212f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler(), codegen_);
32209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
32309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
32409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateAbsIntLocation(ArenaAllocator* arena, HInvoke* invoke) {
32509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
32609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
32709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
32809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RegisterLocation(EAX));
32909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
33009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->AddTemp(Location::RegisterLocation(EDX));
33109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
33209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
33309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void GenAbsInteger(LocationSummary* locations, X86Assembler* assembler) {
33409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location output = locations->Out();
33509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register out = output.AsRegister<Register>();
33609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  DCHECK_EQ(out, EAX);
33709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register temp = locations->GetTemp(0).AsRegister<Register>();
33809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  DCHECK_EQ(temp, EDX);
33909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
34009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Sign extend EAX into EDX.
34109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ cdq();
34209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
34309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // XOR EAX with sign.
34409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ xorl(EAX, EDX);
34509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
34609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Subtract out sign to correct.
34709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ subl(EAX, EDX);
34809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
34909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // The result is in EAX.
35009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
35109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
35209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateAbsLongLocation(ArenaAllocator* arena, HInvoke* invoke) {
35309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
35409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
35509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
35609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
35709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
35809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->AddTemp(Location::RequiresRegister());
35909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
36009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
36109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void GenAbsLong(LocationSummary* locations, X86Assembler* assembler) {
36209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location input = locations->InAt(0);
36309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register input_lo = input.AsRegisterPairLow<Register>();
36409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register input_hi = input.AsRegisterPairHigh<Register>();
36509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location output = locations->Out();
36609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register output_lo = output.AsRegisterPairLow<Register>();
36709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register output_hi = output.AsRegisterPairHigh<Register>();
36809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register temp = locations->GetTemp(0).AsRegister<Register>();
36909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
37009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Compute the sign into the temporary.
37109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ movl(temp, input_hi);
37209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ sarl(temp, Immediate(31));
37309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
37409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Store the sign into the output.
37509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ movl(output_lo, temp);
37609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ movl(output_hi, temp);
37709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
37809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // XOR the input to the output.
37909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ xorl(output_lo, input_lo);
38009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ xorl(output_hi, input_hi);
38109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
38209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Subtract the sign.
38309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ subl(output_lo, temp);
38409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ sbbl(output_hi, temp);
38509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
38609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
38709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAbsInt(HInvoke* invoke) {
38809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateAbsIntLocation(arena_, invoke);
38909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
39009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
39109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAbsInt(HInvoke* invoke) {
39209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenAbsInteger(invoke->GetLocations(), GetAssembler());
39309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
39409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
39509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAbsLong(HInvoke* invoke) {
39609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateAbsLongLocation(arena_, invoke);
39709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
39809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
39909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAbsLong(HInvoke* invoke) {
40009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenAbsLong(invoke->GetLocations(), GetAssembler());
40109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
40209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
4032f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendellstatic void GenMinMaxFP(LocationSummary* locations,
4042f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell                        bool is_min,
4052f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell                        bool is_double,
4062f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell                        X86Assembler* assembler,
4072f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell                        CodeGeneratorX86* codegen) {
40809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location op1_loc = locations->InAt(0);
40909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location op2_loc = locations->InAt(1);
41009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location out_loc = locations->Out();
41109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  XmmRegister out = out_loc.AsFpuRegister<XmmRegister>();
41209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
41309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Shortcut for same input locations.
41409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (op1_loc.Equals(op2_loc)) {
41509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    DCHECK(out_loc.Equals(op1_loc));
41609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    return;
41709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
41809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
41909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  (out := op1)
42009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  out <=? op2
42109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  if Nan jmp Nan_label
42209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  if out is min jmp done
42309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  if op2 is min jmp op2_label
42409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  handle -0/+0
42509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  jmp done
42609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Nan_label:
42709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  out := NaN
42809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // op2_label:
42909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //  out := op2
43009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // done:
43109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //
43209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // This removes one jmp, but needs to copy one input (op1) to out.
43309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //
43409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath?
43509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
43609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>();
43709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
4380c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell  NearLabel nan, done, op2_label;
43909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is_double) {
44009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ ucomisd(out, op2);
44109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
44209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ ucomiss(out, op2);
44309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
44409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
44509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ j(Condition::kParityEven, &nan);
44609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
44709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label);
44809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ j(is_min ? Condition::kBelow : Condition::kAbove, &done);
44909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
45009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Handle 0.0/-0.0.
45109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is_min) {
45209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    if (is_double) {
45309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ orpd(out, op2);
45409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    } else {
45509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ orps(out, op2);
45609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    }
45709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
45809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    if (is_double) {
45909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ andpd(out, op2);
46009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    } else {
46109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ andps(out, op2);
46209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    }
46309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
46409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ jmp(&done);
46509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
46609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // NaN handling.
46709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ Bind(&nan);
4682f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  // Do we have a constant area pointer?
4699779307ce8f2dd40c429abb0f0cafc1415f70648Nicolas Geoffray  if (locations->GetInputCount() == 3 && locations->InAt(2).IsValid()) {
4702f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    DCHECK(locations->InAt(2).IsRegister());
4712f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    Register constant_area = locations->InAt(2).AsRegister<Register>();
4722f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    if (is_double) {
4732f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ movsd(out, codegen->LiteralInt64Address(kDoubleNaN, constant_area));
4742f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    } else {
4752f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ movss(out, codegen->LiteralInt32Address(kFloatNaN, constant_area));
4762f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    }
47709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
4782f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    if (is_double) {
4792f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ pushl(Immediate(kDoubleNaNHigh));
4802f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ pushl(Immediate(kDoubleNaNLow));
4812f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ movsd(out, Address(ESP, 0));
4822f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ addl(ESP, Immediate(8));
4832f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    } else {
4842f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ pushl(Immediate(kFloatNaN));
4852f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ movss(out, Address(ESP, 0));
4862f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell      __ addl(ESP, Immediate(4));
4872f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    }
48809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
48909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ jmp(&done);
49009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
49109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // out := op2;
49209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ Bind(&op2_label);
49309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is_double) {
49409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movsd(out, op2);
49509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
49609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movss(out, op2);
49709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
49809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
49909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Done.
50009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ Bind(&done);
50109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
50209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
50309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateFPFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
50409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
50509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
50609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
50709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresFpuRegister());
50809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(1, Location::RequiresFpuRegister());
50909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // The following is sub-optimal, but all we can do for now. It would be fine to also accept
51009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // the second input to be the output (we can simply swap inputs).
51109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
5122f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
5132f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  DCHECK(static_or_direct != nullptr);
5149779307ce8f2dd40c429abb0f0cafc1415f70648Nicolas Geoffray  if (static_or_direct->HasSpecialInput() &&
5159779307ce8f2dd40c429abb0f0cafc1415f70648Nicolas Geoffray      invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) {
5162f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell    locations->SetInAt(2, Location::RequiresRegister());
5172f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  }
51809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
51909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
52009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
52109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateFPFPToFPLocations(arena_, invoke);
52209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
52309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
52409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
5252f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  GenMinMaxFP(invoke->GetLocations(),
5262f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_min */ true,
5272f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_double */ true,
5282f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              GetAssembler(),
5292f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              codegen_);
53009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
53109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
53209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) {
53309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateFPFPToFPLocations(arena_, invoke);
53409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
53509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
53609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMinFloatFloat(HInvoke* invoke) {
5372f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  GenMinMaxFP(invoke->GetLocations(),
5382f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_min */ true,
5392f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_double */ false,
5402f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              GetAssembler(),
5412f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              codegen_);
54209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
54309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
54409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
54509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateFPFPToFPLocations(arena_, invoke);
54609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
54709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
54809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
5492f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  GenMinMaxFP(invoke->GetLocations(),
5502f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_min */ false,
5512f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_double */ true,
5522f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              GetAssembler(),
5532f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              codegen_);
55409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
55509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
55609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
55709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateFPFPToFPLocations(arena_, invoke);
55809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
55909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
56009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
5612f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell  GenMinMaxFP(invoke->GetLocations(),
5622f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_min */ false,
5632f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              /* is_double */ false,
5642f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              GetAssembler(),
5652f10a5fb8c236a6786928f0323bd312c3ee9a4ccMark P Mendell              codegen_);
56609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
56709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
56809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void GenMinMax(LocationSummary* locations, bool is_min, bool is_long,
56909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                      X86Assembler* assembler) {
57009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location op1_loc = locations->InAt(0);
57109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location op2_loc = locations->InAt(1);
57209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
57309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Shortcut for same input locations.
57409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (op1_loc.Equals(op2_loc)) {
57509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Can return immediately, as op1_loc == out_loc.
57609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Note: if we ever support separate registers, e.g., output into memory, we need to check for
57709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    //       a copy here.
57809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    DCHECK(locations->Out().Equals(op1_loc));
57909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    return;
58009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
58109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
58209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is_long) {
58309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Need to perform a subtract to get the sign right.
58409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // op1 is already in the same location as the output.
58509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Location output = locations->Out();
58609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register output_lo = output.AsRegisterPairLow<Register>();
58709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register output_hi = output.AsRegisterPairHigh<Register>();
58809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
58909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register op2_lo = op2_loc.AsRegisterPairLow<Register>();
59009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register op2_hi = op2_loc.AsRegisterPairHigh<Register>();
59109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
59209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Spare register to compute the subtraction to set condition code.
59309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register temp = locations->GetTemp(0).AsRegister<Register>();
59409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
59509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Subtract off op2_low.
59609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movl(temp, output_lo);
59709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ subl(temp, op2_lo);
59809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
59909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Now use the same tempo and the borrow to finish the subtraction of op2_hi.
60009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movl(temp, output_hi);
60109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ sbbl(temp, op2_hi);
60209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
60309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Now the condition code is correct.
60409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Condition cond = is_min ? Condition::kGreaterEqual : Condition::kLess;
60509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ cmovl(cond, output_lo, op2_lo);
60609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ cmovl(cond, output_hi, op2_hi);
60709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
60809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register out = locations->Out().AsRegister<Register>();
60909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register op2 = op2_loc.AsRegister<Register>();
61009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
61109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    //  (out := op1)
61209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    //  out <=? op2
61309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    //  if out is min jmp done
61409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    //  out := op2
61509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // done:
61609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
61709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ cmpl(out, op2);
61809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Condition cond = is_min ? Condition::kGreater : Condition::kLess;
61909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ cmovl(cond, out, op2);
62009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
62109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
62209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
62309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateIntIntToIntLocations(ArenaAllocator* arena, HInvoke* invoke) {
62409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
62509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
62609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
62709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
62809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(1, Location::RequiresRegister());
62909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
63009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
63109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
63209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateLongLongToLongLocations(ArenaAllocator* arena, HInvoke* invoke) {
63309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
63409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
63509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
63609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
63709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(1, Location::RequiresRegister());
63809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
63909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // Register to use to perform a long subtract to set cc.
64009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->AddTemp(Location::RequiresRegister());
64109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
64209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
64309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMinIntInt(HInvoke* invoke) {
64409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateIntIntToIntLocations(arena_, invoke);
64509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
64609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
64709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMinIntInt(HInvoke* invoke) {
648bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetAssembler());
64909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
65009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
65109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMinLongLong(HInvoke* invoke) {
65209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongLongToLongLocations(arena_, invoke);
65309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
65409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
65509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMinLongLong(HInvoke* invoke) {
656bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetAssembler());
65709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
65809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
65909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMaxIntInt(HInvoke* invoke) {
66009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateIntIntToIntLocations(arena_, invoke);
66109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
66209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
66309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMaxIntInt(HInvoke* invoke) {
664bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetAssembler());
66509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
66609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
66709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathMaxLongLong(HInvoke* invoke) {
66809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongLongToLongLocations(arena_, invoke);
66909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
67009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
67109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathMaxLongLong(HInvoke* invoke) {
672bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetAssembler());
67309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
67409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
67509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
67609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
67709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
67809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
67909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresFpuRegister());
68009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::RequiresFpuRegister());
68109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
68209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
68309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathSqrt(HInvoke* invoke) {
68409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateFPToFPLocations(arena_, invoke);
68509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
68609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
68709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathSqrt(HInvoke* invoke) {
68809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = invoke->GetLocations();
68909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
69009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
69109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
69209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GetAssembler()->sqrtsd(out, in);
69309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
69409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
695fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellstatic void InvokeOutOfLineIntrinsic(CodeGeneratorX86* codegen, HInvoke* invoke) {
696ec525fc30848189051b888da53ba051bc0878b78Roland Levillain  MoveArguments(invoke, codegen);
697fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
698fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  DCHECK(invoke->IsInvokeStaticOrDirect());
69994015b939060f5041d408d48717f22443e55b6adNicolas Geoffray  codegen->GenerateStaticOrDirectCall(invoke->AsInvokeStaticOrDirect(),
70094015b939060f5041d408d48717f22443e55b6adNicolas Geoffray                                      Location::RegisterLocation(EAX));
701e90db127277823e92398e112c9c23f2005554f95Mingyao Yang  codegen->RecordPcInfo(invoke, invoke->GetDexPc());
702fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
703fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Copy the result back to the expected output.
704fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  Location out = invoke->GetLocations()->Out();
705fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  if (out.IsValid()) {
706fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    DCHECK(out.IsRegister());
70785b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe    codegen->MoveFromReturnRegister(out, invoke->GetType());
708fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  }
709fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
710fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
711fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellstatic void CreateSSE41FPToFPLocations(ArenaAllocator* arena,
712fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                      HInvoke* invoke,
713fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                      CodeGeneratorX86* codegen) {
714fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Do we have instruction support?
715fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  if (codegen->GetInstructionSetFeatures().HasSSE4_1()) {
716fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    CreateFPToFPLocations(arena, invoke);
717fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    return;
718fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  }
719fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
720fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // We have to fall back to a call to the intrinsic.
721fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
722fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                                           LocationSummary::kCall);
723fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  InvokeRuntimeCallingConvention calling_convention;
724fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
725fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  locations->SetOut(Location::FpuRegisterLocation(XMM0));
726fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Needs to be EAX for the invoke.
727fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  locations->AddTemp(Location::RegisterLocation(EAX));
728fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
729fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
730fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellstatic void GenSSE41FPToFPIntrinsic(CodeGeneratorX86* codegen,
731fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                   HInvoke* invoke,
732fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                   X86Assembler* assembler,
733fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                   int round_mode) {
734fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  LocationSummary* locations = invoke->GetLocations();
735fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  if (locations->WillCall()) {
736fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    InvokeOutOfLineIntrinsic(codegen, invoke);
737fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  } else {
738fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
739fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
740fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    __ roundsd(out, in, Immediate(round_mode));
741fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  }
742fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
743fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
744fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathCeil(HInvoke* invoke) {
745fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  CreateSSE41FPToFPLocations(arena_, invoke, codegen_);
746fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
747fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
748fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathCeil(HInvoke* invoke) {
749fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  GenSSE41FPToFPIntrinsic(codegen_, invoke, GetAssembler(), 2);
750fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
751fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
752fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathFloor(HInvoke* invoke) {
753fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  CreateSSE41FPToFPLocations(arena_, invoke, codegen_);
754fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
755fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
756fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathFloor(HInvoke* invoke) {
757fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  GenSSE41FPToFPIntrinsic(codegen_, invoke, GetAssembler(), 1);
758fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
759fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
760fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathRint(HInvoke* invoke) {
761fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  CreateSSE41FPToFPLocations(arena_, invoke, codegen_);
762fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
763fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
764fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathRint(HInvoke* invoke) {
765fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  GenSSE41FPToFPIntrinsic(codegen_, invoke, GetAssembler(), 0);
766fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
767fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
768fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell// Note that 32 bit x86 doesn't have the capability to inline MathRoundDouble,
769fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell// as it needs 64 bit instructions.
770fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathRoundFloat(HInvoke* invoke) {
771e6d0d8de85f79c8702ee722a04cd89ee7e89aeb7Andreas Gampe  // See intrinsics.h.
772e6d0d8de85f79c8702ee722a04cd89ee7e89aeb7Andreas Gampe  if (!kRoundIsPlusPointFive) {
773e6d0d8de85f79c8702ee722a04cd89ee7e89aeb7Andreas Gampe    return;
774e6d0d8de85f79c8702ee722a04cd89ee7e89aeb7Andreas Gampe  }
775e6d0d8de85f79c8702ee722a04cd89ee7e89aeb7Andreas Gampe
776fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Do we have instruction support?
777fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  if (codegen_->GetInstructionSetFeatures().HasSSE4_1()) {
778fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    LocationSummary* locations = new (arena_) LocationSummary(invoke,
779fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                                              LocationSummary::kNoCall,
780fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                                              kIntrinsified);
781fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    locations->SetInAt(0, Location::RequiresFpuRegister());
782d9b92403254225dd5ff84559886b93680ba0ed64Nicolas Geoffray    locations->SetOut(Location::RequiresRegister());
783fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    locations->AddTemp(Location::RequiresFpuRegister());
784fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    locations->AddTemp(Location::RequiresFpuRegister());
785fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    return;
786fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  }
787fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
788fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // We have to fall back to a call to the intrinsic.
789fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  LocationSummary* locations = new (arena_) LocationSummary(invoke,
790fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell                                                           LocationSummary::kCall);
791fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  InvokeRuntimeCallingConvention calling_convention;
792fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetFpuRegisterAt(0)));
793fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  locations->SetOut(Location::RegisterLocation(EAX));
794fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Needs to be EAX for the invoke.
795fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  locations->AddTemp(Location::RegisterLocation(EAX));
796fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
797fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
798fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathRoundFloat(HInvoke* invoke) {
799fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  LocationSummary* locations = invoke->GetLocations();
800fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  if (locations->WillCall()) {
801fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    InvokeOutOfLineIntrinsic(codegen_, invoke);
802fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell    return;
803fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  }
804fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
805fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Implement RoundFloat as t1 = floor(input + 0.5f);  convert to int.
806fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  XmmRegister in = locations->InAt(0).AsFpuRegister<XmmRegister>();
807fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  Register out = locations->Out().AsRegister<Register>();
808fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  XmmRegister maxInt = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
809fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  XmmRegister inPlusPointFive = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
8100c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell  NearLabel done, nan;
811fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  X86Assembler* assembler = GetAssembler();
812fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
813fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Generate 0.5 into inPlusPointFive.
814fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ movl(out, Immediate(bit_cast<int32_t, float>(0.5f)));
815fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ movd(inPlusPointFive, out);
816fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
817fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // Add in the input.
818fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ addss(inPlusPointFive, in);
819fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
820fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // And truncate to an integer.
821fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ roundss(inPlusPointFive, inPlusPointFive, Immediate(1));
822fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
823fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ movl(out, Immediate(kPrimIntMax));
824fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // maxInt = int-to-float(out)
825fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ cvtsi2ss(maxInt, out);
826fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
827fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // if inPlusPointFive >= maxInt goto done
828fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ comiss(inPlusPointFive, maxInt);
829fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ j(kAboveEqual, &done);
830fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
831fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // if input == NaN goto nan
832fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ j(kUnordered, &nan);
833fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
834fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  // output = float-to-int-truncate(input)
835fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ cvttss2si(out, inPlusPointFive);
836fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ jmp(&done);
837fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ Bind(&nan);
838fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
839fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  //  output = 0
840fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ xorl(out, out);
841fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell  __ Bind(&done);
842fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell}
843fb8d279bc011b31d0765dc7ca59afea324fd0d0cMark Mendell
844a4f1220c1518074db18ca1044e9201492975750bMark Mendellstatic void CreateFPToFPCallLocations(ArenaAllocator* arena,
845a4f1220c1518074db18ca1044e9201492975750bMark Mendell                                      HInvoke* invoke) {
846a4f1220c1518074db18ca1044e9201492975750bMark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
847a4f1220c1518074db18ca1044e9201492975750bMark Mendell                                                           LocationSummary::kCall,
848a4f1220c1518074db18ca1044e9201492975750bMark Mendell                                                           kIntrinsified);
849a4f1220c1518074db18ca1044e9201492975750bMark Mendell  InvokeRuntimeCallingConvention calling_convention;
850a4f1220c1518074db18ca1044e9201492975750bMark Mendell  locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
851a4f1220c1518074db18ca1044e9201492975750bMark Mendell  locations->SetOut(Location::FpuRegisterLocation(XMM0));
852a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
853a4f1220c1518074db18ca1044e9201492975750bMark Mendell
854a4f1220c1518074db18ca1044e9201492975750bMark Mendellstatic void GenFPToFPCall(HInvoke* invoke, CodeGeneratorX86* codegen, QuickEntrypointEnum entry) {
855a4f1220c1518074db18ca1044e9201492975750bMark Mendell  LocationSummary* locations = invoke->GetLocations();
856a4f1220c1518074db18ca1044e9201492975750bMark Mendell  DCHECK(locations->WillCall());
857a4f1220c1518074db18ca1044e9201492975750bMark Mendell  DCHECK(invoke->IsInvokeStaticOrDirect());
858a4f1220c1518074db18ca1044e9201492975750bMark Mendell  X86Assembler* assembler = codegen->GetAssembler();
859a4f1220c1518074db18ca1044e9201492975750bMark Mendell
860a4f1220c1518074db18ca1044e9201492975750bMark Mendell  // We need some place to pass the parameters.
861a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ subl(ESP, Immediate(16));
862a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ cfi().AdjustCFAOffset(16);
863a4f1220c1518074db18ca1044e9201492975750bMark Mendell
864a4f1220c1518074db18ca1044e9201492975750bMark Mendell  // Pass the parameters at the bottom of the stack.
865a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ movsd(Address(ESP, 0), XMM0);
866a4f1220c1518074db18ca1044e9201492975750bMark Mendell
867a4f1220c1518074db18ca1044e9201492975750bMark Mendell  // If we have a second parameter, pass it next.
868a4f1220c1518074db18ca1044e9201492975750bMark Mendell  if (invoke->GetNumberOfArguments() == 2) {
869a4f1220c1518074db18ca1044e9201492975750bMark Mendell    __ movsd(Address(ESP, 8), XMM1);
870a4f1220c1518074db18ca1044e9201492975750bMark Mendell  }
871a4f1220c1518074db18ca1044e9201492975750bMark Mendell
872a4f1220c1518074db18ca1044e9201492975750bMark Mendell  // Now do the actual call.
873a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(entry)));
874a4f1220c1518074db18ca1044e9201492975750bMark Mendell
875a4f1220c1518074db18ca1044e9201492975750bMark Mendell  // Extract the return value from the FP stack.
876a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ fstpl(Address(ESP, 0));
877a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ movsd(XMM0, Address(ESP, 0));
878a4f1220c1518074db18ca1044e9201492975750bMark Mendell
879a4f1220c1518074db18ca1044e9201492975750bMark Mendell  // And clean up the stack.
880a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ addl(ESP, Immediate(16));
881a4f1220c1518074db18ca1044e9201492975750bMark Mendell  __ cfi().AdjustCFAOffset(-16);
882a4f1220c1518074db18ca1044e9201492975750bMark Mendell
883a4f1220c1518074db18ca1044e9201492975750bMark Mendell  codegen->RecordPcInfo(invoke, invoke->GetDexPc());
884a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
885a4f1220c1518074db18ca1044e9201492975750bMark Mendell
886a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathCos(HInvoke* invoke) {
887a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
888a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
889a4f1220c1518074db18ca1044e9201492975750bMark Mendell
890a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathCos(HInvoke* invoke) {
891a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickCos);
892a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
893a4f1220c1518074db18ca1044e9201492975750bMark Mendell
894a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathSin(HInvoke* invoke) {
895a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
896a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
897a4f1220c1518074db18ca1044e9201492975750bMark Mendell
898a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathSin(HInvoke* invoke) {
899a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickSin);
900a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
901a4f1220c1518074db18ca1044e9201492975750bMark Mendell
902a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAcos(HInvoke* invoke) {
903a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
904a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
905a4f1220c1518074db18ca1044e9201492975750bMark Mendell
906a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAcos(HInvoke* invoke) {
907a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickAcos);
908a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
909a4f1220c1518074db18ca1044e9201492975750bMark Mendell
910a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAsin(HInvoke* invoke) {
911a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
912a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
913a4f1220c1518074db18ca1044e9201492975750bMark Mendell
914a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAsin(HInvoke* invoke) {
915a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickAsin);
916a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
917a4f1220c1518074db18ca1044e9201492975750bMark Mendell
918a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAtan(HInvoke* invoke) {
919a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
920a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
921a4f1220c1518074db18ca1044e9201492975750bMark Mendell
922a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAtan(HInvoke* invoke) {
923a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickAtan);
924a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
925a4f1220c1518074db18ca1044e9201492975750bMark Mendell
926a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathCbrt(HInvoke* invoke) {
927a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
928a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
929a4f1220c1518074db18ca1044e9201492975750bMark Mendell
930a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathCbrt(HInvoke* invoke) {
931a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickCbrt);
932a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
933a4f1220c1518074db18ca1044e9201492975750bMark Mendell
934a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathCosh(HInvoke* invoke) {
935a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
936a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
937a4f1220c1518074db18ca1044e9201492975750bMark Mendell
938a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathCosh(HInvoke* invoke) {
939a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickCosh);
940a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
941a4f1220c1518074db18ca1044e9201492975750bMark Mendell
942a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathExp(HInvoke* invoke) {
943a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
944a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
945a4f1220c1518074db18ca1044e9201492975750bMark Mendell
946a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathExp(HInvoke* invoke) {
947a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickExp);
948a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
949a4f1220c1518074db18ca1044e9201492975750bMark Mendell
950a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathExpm1(HInvoke* invoke) {
951a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
952a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
953a4f1220c1518074db18ca1044e9201492975750bMark Mendell
954a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathExpm1(HInvoke* invoke) {
955a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickExpm1);
956a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
957a4f1220c1518074db18ca1044e9201492975750bMark Mendell
958a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathLog(HInvoke* invoke) {
959a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
960a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
961a4f1220c1518074db18ca1044e9201492975750bMark Mendell
962a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathLog(HInvoke* invoke) {
963a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickLog);
964a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
965a4f1220c1518074db18ca1044e9201492975750bMark Mendell
966a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathLog10(HInvoke* invoke) {
967a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
968a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
969a4f1220c1518074db18ca1044e9201492975750bMark Mendell
970a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathLog10(HInvoke* invoke) {
971a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickLog10);
972a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
973a4f1220c1518074db18ca1044e9201492975750bMark Mendell
974a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathSinh(HInvoke* invoke) {
975a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
976a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
977a4f1220c1518074db18ca1044e9201492975750bMark Mendell
978a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathSinh(HInvoke* invoke) {
979a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickSinh);
980a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
981a4f1220c1518074db18ca1044e9201492975750bMark Mendell
982a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathTan(HInvoke* invoke) {
983a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
984a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
985a4f1220c1518074db18ca1044e9201492975750bMark Mendell
986a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathTan(HInvoke* invoke) {
987a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickTan);
988a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
989a4f1220c1518074db18ca1044e9201492975750bMark Mendell
990a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathTanh(HInvoke* invoke) {
991a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPToFPCallLocations(arena_, invoke);
992a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
993a4f1220c1518074db18ca1044e9201492975750bMark Mendell
994a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathTanh(HInvoke* invoke) {
995a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickTanh);
996a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
997a4f1220c1518074db18ca1044e9201492975750bMark Mendell
998a4f1220c1518074db18ca1044e9201492975750bMark Mendellstatic void CreateFPFPToFPCallLocations(ArenaAllocator* arena,
999a4f1220c1518074db18ca1044e9201492975750bMark Mendell                                        HInvoke* invoke) {
1000a4f1220c1518074db18ca1044e9201492975750bMark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
1001a4f1220c1518074db18ca1044e9201492975750bMark Mendell                                                           LocationSummary::kCall,
1002a4f1220c1518074db18ca1044e9201492975750bMark Mendell                                                           kIntrinsified);
1003a4f1220c1518074db18ca1044e9201492975750bMark Mendell  InvokeRuntimeCallingConvention calling_convention;
1004a4f1220c1518074db18ca1044e9201492975750bMark Mendell  locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0)));
1005a4f1220c1518074db18ca1044e9201492975750bMark Mendell  locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1)));
1006a4f1220c1518074db18ca1044e9201492975750bMark Mendell  locations->SetOut(Location::FpuRegisterLocation(XMM0));
1007a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
1008a4f1220c1518074db18ca1044e9201492975750bMark Mendell
1009a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathAtan2(HInvoke* invoke) {
1010a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPFPToFPCallLocations(arena_, invoke);
1011a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
1012a4f1220c1518074db18ca1044e9201492975750bMark Mendell
1013a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathAtan2(HInvoke* invoke) {
1014a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickAtan2);
1015a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
1016a4f1220c1518074db18ca1044e9201492975750bMark Mendell
1017a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathHypot(HInvoke* invoke) {
1018a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPFPToFPCallLocations(arena_, invoke);
1019a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
1020a4f1220c1518074db18ca1044e9201492975750bMark Mendell
1021a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathHypot(HInvoke* invoke) {
1022a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickHypot);
1023a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
1024a4f1220c1518074db18ca1044e9201492975750bMark Mendell
1025a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicLocationsBuilderX86::VisitMathNextAfter(HInvoke* invoke) {
1026a4f1220c1518074db18ca1044e9201492975750bMark Mendell  CreateFPFPToFPCallLocations(arena_, invoke);
1027a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
1028a4f1220c1518074db18ca1044e9201492975750bMark Mendell
1029a4f1220c1518074db18ca1044e9201492975750bMark Mendellvoid IntrinsicCodeGeneratorX86::VisitMathNextAfter(HInvoke* invoke) {
1030a4f1220c1518074db18ca1044e9201492975750bMark Mendell  GenFPToFPCall(invoke, codegen_, kQuickNextAfter);
1031a4f1220c1518074db18ca1044e9201492975750bMark Mendell}
1032a4f1220c1518074db18ca1044e9201492975750bMark Mendell
103309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitStringCharAt(HInvoke* invoke) {
103409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // The inputs plus one temp.
103509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena_) LocationSummary(invoke,
103609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                            LocationSummary::kCallOnSlowPath,
103709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                            kIntrinsified);
103809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
103909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(1, Location::RequiresRegister());
104009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
104109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
104209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
104309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitStringCharAt(HInvoke* invoke) {
104409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = invoke->GetLocations();
104509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
10466bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Location of reference to data array.
104709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  const int32_t value_offset = mirror::String::ValueOffset().Int32Value();
10486bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Location of count.
104909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  const int32_t count_offset = mirror::String::CountOffset().Int32Value();
105009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
105109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register obj = locations->InAt(0).AsRegister<Register>();
105209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register idx = locations->InAt(1).AsRegister<Register>();
105309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register out = locations->Out().AsRegister<Register>();
105409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
105509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // TODO: Maybe we can support range check elimination. Overall, though, I think it's not worth
105609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //       the cost.
105709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // TODO: For simplicity, the index parameter is requested in a register, so different from Quick
105809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  //       we will not optimize the code for constants (which would save a register).
105909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
106085b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
106109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  codegen_->AddSlowPath(slow_path);
106209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
106309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  X86Assembler* assembler = GetAssembler();
106409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
106509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ cmpl(idx, Address(obj, count_offset));
106609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  codegen_->MaybeRecordImplicitNullCheck(invoke);
106709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ j(kAboveEqual, slow_path->GetEntryLabel());
106809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
1069848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  // out = out[2*idx].
1070848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ movzxw(out, Address(out, idx, ScaleFactor::TIMES_2, value_offset));
107109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
107209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  __ Bind(slow_path->GetExitLabel());
107309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
107409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
10756bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitSystemArrayCopyChar(HInvoke* invoke) {
10766bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // We need at least two of the positions or length to be an integer constant,
10776bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // or else we won't have enough free registers.
10786bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstant();
10796bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstant();
10806bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  HIntConstant* length = invoke->InputAt(4)->AsIntConstant();
10816bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
10826bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  int num_constants =
10836bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      ((src_pos != nullptr) ? 1 : 0)
10846bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      + ((dest_pos != nullptr) ? 1 : 0)
10856bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      + ((length != nullptr) ? 1 : 0);
10866bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
10876bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if (num_constants < 2) {
10886bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    // Not enough free registers.
10896bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    return;
10906bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
10916bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
10926bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // As long as we are checking, we might as well check to see if the src and dest
10936bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // positions are >= 0.
10946bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if ((src_pos != nullptr && src_pos->GetValue() < 0) ||
10956bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      (dest_pos != nullptr && dest_pos->GetValue() < 0)) {
10966bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    // We will have to fail anyways.
10976bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    return;
10986bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
10996bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11006bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // And since we are already checking, check the length too.
11016bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if (length != nullptr) {
11026bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    int32_t len = length->GetValue();
11036bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    if (len < 0) {
11046bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      // Just call as normal.
11056bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      return;
11066bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    }
11076bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
11086bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11096bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Okay, it is safe to generate inline code.
11106bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  LocationSummary* locations =
11116bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    new (arena_) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
11126bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // arraycopy(Object src, int srcPos, Object dest, int destPos, int length).
11136bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
11146bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
11156bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->SetInAt(2, Location::RequiresRegister());
11166bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->SetInAt(3, Location::RegisterOrConstant(invoke->InputAt(3)));
11176bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->SetInAt(4, Location::RegisterOrConstant(invoke->InputAt(4)));
11186bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11196bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // And we need some temporaries.  We will use REP MOVSW, so we need fixed registers.
11206bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->AddTemp(Location::RegisterLocation(ESI));
11216bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->AddTemp(Location::RegisterLocation(EDI));
11226bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  locations->AddTemp(Location::RegisterLocation(ECX));
11236bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell}
11246bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11256bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendellstatic void CheckPosition(X86Assembler* assembler,
11266bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell                          Location pos,
11276bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell                          Register input,
11286bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell                          Register length,
112985b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe                          SlowPathCode* slow_path,
11306bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell                          Register input_len,
11316bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell                          Register temp) {
11326bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Where is the length in the String?
11336bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  const uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
11346bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11356bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if (pos.IsConstant()) {
11366bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue();
11376bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    if (pos_const == 0) {
11386bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      // Check that length(input) >= length.
11396bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ cmpl(Address(input, length_offset), length);
11406bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ j(kLess, slow_path->GetEntryLabel());
11416bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    } else {
11426bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      // Check that length(input) >= pos.
11436bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ movl(input_len, Address(input, length_offset));
11446bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ cmpl(input_len, Immediate(pos_const));
11456bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ j(kLess, slow_path->GetEntryLabel());
11466bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11476bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      // Check that (length(input) - pos) >= length.
11486bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ leal(temp, Address(input_len, -pos_const));
11496bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ cmpl(temp, length);
11506bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell      __ j(kLess, slow_path->GetEntryLabel());
11516bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    }
11526bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  } else {
11536bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    // Check that pos >= 0.
11546bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    Register pos_reg = pos.AsRegister<Register>();
11556bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ testl(pos_reg, pos_reg);
11566bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ j(kLess, slow_path->GetEntryLabel());
11576bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11586bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    // Check that pos <= length(input).
11596bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ cmpl(Address(input, length_offset), pos_reg);
11606bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ j(kLess, slow_path->GetEntryLabel());
11616bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11626bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    // Check that (length(input) - pos) >= length.
11636bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ movl(temp, Address(input, length_offset));
11646bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ subl(temp, pos_reg);
11656bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ cmpl(temp, length);
11666bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ j(kLess, slow_path->GetEntryLabel());
11676bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
11686bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell}
11696bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11706bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitSystemArrayCopyChar(HInvoke* invoke) {
11716bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  X86Assembler* assembler = GetAssembler();
11726bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  LocationSummary* locations = invoke->GetLocations();
11736bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11746bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Register src = locations->InAt(0).AsRegister<Register>();
11756bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Location srcPos = locations->InAt(1);
11766bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Register dest = locations->InAt(2).AsRegister<Register>();
11776bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Location destPos = locations->InAt(3);
11786bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Location length = locations->InAt(4);
11796bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11806bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Temporaries that we need for MOVSW.
11816bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Register src_base = locations->GetTemp(0).AsRegister<Register>();
11826bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  DCHECK_EQ(src_base, ESI);
11836bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Register dest_base = locations->GetTemp(1).AsRegister<Register>();
11846bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  DCHECK_EQ(dest_base, EDI);
11856bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  Register count = locations->GetTemp(2).AsRegister<Register>();
11866bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  DCHECK_EQ(count, ECX);
11876bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
118885b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
11896bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  codegen_->AddSlowPath(slow_path);
11906bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11916bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Bail out if the source and destination are the same (to handle overlap).
11926bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ cmpl(src, dest);
11936bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ j(kEqual, slow_path->GetEntryLabel());
11946bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11956bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Bail out if the source is null.
11966bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ testl(src, src);
11976bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ j(kEqual, slow_path->GetEntryLabel());
11986bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
11996bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Bail out if the destination is null.
12006bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ testl(dest, dest);
12016bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ j(kEqual, slow_path->GetEntryLabel());
12026bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12036bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // If the length is negative, bail out.
12046bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // We have already checked in the LocationsBuilder for the constant case.
12056bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if (!length.IsConstant()) {
12066bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ cmpl(length.AsRegister<Register>(), length.AsRegister<Register>());
12076bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ j(kLess, slow_path->GetEntryLabel());
12086bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
12096bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12106bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // We need the count in ECX.
12116bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if (length.IsConstant()) {
12126bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ movl(count, Immediate(length.GetConstant()->AsIntConstant()->GetValue()));
12136bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  } else {
12146bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ movl(count, length.AsRegister<Register>());
12156bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
12166bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12176bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Validity checks: source.
12186bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  CheckPosition(assembler, srcPos, src, count, slow_path, src_base, dest_base);
12196bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12206bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Validity checks: dest.
12216bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  CheckPosition(assembler, destPos, dest, count, slow_path, src_base, dest_base);
12226bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12236bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Okay, everything checks out.  Finally time to do the copy.
12246bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Check assumption that sizeof(Char) is 2 (used in scaling below).
12256bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
12266bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  DCHECK_EQ(char_size, 2u);
12276bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12286bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  const uint32_t data_offset = mirror::Array::DataOffset(char_size).Uint32Value();
12296bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12306bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if (srcPos.IsConstant()) {
12316bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    int32_t srcPos_const = srcPos.GetConstant()->AsIntConstant()->GetValue();
12326bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ leal(src_base, Address(src, char_size * srcPos_const + data_offset));
12336bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  } else {
12346bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ leal(src_base, Address(src, srcPos.AsRegister<Register>(),
12356bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell                              ScaleFactor::TIMES_2, data_offset));
12366bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
12376bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  if (destPos.IsConstant()) {
12386bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    int32_t destPos_const = destPos.GetConstant()->AsIntConstant()->GetValue();
12396bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12406bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ leal(dest_base, Address(dest, char_size * destPos_const + data_offset));
12416bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  } else {
12426bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell    __ leal(dest_base, Address(dest, destPos.AsRegister<Register>(),
12436bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell                               ScaleFactor::TIMES_2, data_offset));
12446bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  }
12456bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12466bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  // Do the move.
12476bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ rep_movsw();
12486bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
12496bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell  __ Bind(slow_path->GetExitLabel());
12506bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell}
12516bc53a9d884265e0a0b14c4383bef0aa47824e64Mark Mendell
1252d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicLocationsBuilderX86::VisitStringCompareTo(HInvoke* invoke) {
1253d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  // The inputs plus one temp.
1254d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  LocationSummary* locations = new (arena_) LocationSummary(invoke,
1255d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray                                                            LocationSummary::kCall,
1256d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray                                                            kIntrinsified);
1257d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  InvokeRuntimeCallingConvention calling_convention;
1258d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1259d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1260d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  locations->SetOut(Location::RegisterLocation(EAX));
1261d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray}
1262d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
1263d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffrayvoid IntrinsicCodeGeneratorX86::VisitStringCompareTo(HInvoke* invoke) {
1264d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  X86Assembler* assembler = GetAssembler();
1265d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  LocationSummary* locations = invoke->GetLocations();
1266d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
1267512e04d1ea7fb33e3992715fe55be8a834d4a79cNicolas Geoffray  // Note that the null check must have been done earlier.
1268641547a5f18ca2ea54469cceadcfef64f132e5e0Calin Juravle  DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1269d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
1270d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  Register argument = locations->InAt(1).AsRegister<Register>();
1271d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ testl(argument, argument);
127285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
1273d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  codegen_->AddSlowPath(slow_path);
1274d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ j(kEqual, slow_path->GetEntryLabel());
1275d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
1276d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pStringCompareTo)));
1277d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray  __ Bind(slow_path->GetExitLabel());
1278d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray}
1279d75948ac93a4a317feaf136cae78823071234ba5Nicolas Geoffray
1280d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csakivoid IntrinsicLocationsBuilderX86::VisitStringEquals(HInvoke* invoke) {
1281d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  LocationSummary* locations = new (arena_) LocationSummary(invoke,
1282d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki                                                            LocationSummary::kNoCall,
1283d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki                                                            kIntrinsified);
1284d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  locations->SetInAt(0, Location::RequiresRegister());
1285d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  locations->SetInAt(1, Location::RequiresRegister());
1286d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1287d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Request temporary registers, ECX and EDI needed for repe_cmpsl instruction.
1288d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  locations->AddTemp(Location::RegisterLocation(ECX));
1289d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  locations->AddTemp(Location::RegisterLocation(EDI));
1290d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1291d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Set output, ESI needed for repe_cmpsl instruction anyways.
1292d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  locations->SetOut(Location::RegisterLocation(ESI), Location::kOutputOverlap);
1293d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki}
1294d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1295d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csakivoid IntrinsicCodeGeneratorX86::VisitStringEquals(HInvoke* invoke) {
1296d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  X86Assembler* assembler = GetAssembler();
1297d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  LocationSummary* locations = invoke->GetLocations();
1298d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1299d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  Register str = locations->InAt(0).AsRegister<Register>();
1300d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  Register arg = locations->InAt(1).AsRegister<Register>();
1301d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  Register ecx = locations->GetTemp(0).AsRegister<Register>();
1302d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  Register edi = locations->GetTemp(1).AsRegister<Register>();
1303d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  Register esi = locations->Out().AsRegister<Register>();
1304d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
13050c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell  NearLabel end, return_true, return_false;
1306d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1307d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Get offsets of count, value, and class fields within a string object.
1308d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
1309d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
1310d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  const uint32_t class_offset = mirror::Object::ClassOffset().Uint32Value();
1311d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1312d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Note that the null check must have been done earlier.
1313d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
1314d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1315a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray  StringEqualsOptimizations optimizations(invoke);
1316a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray  if (!optimizations.GetArgumentNotNull()) {
1317a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray    // Check if input is null, return false if it is.
1318a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray    __ testl(arg, arg);
1319a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray    __ j(kEqual, &return_false);
1320a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray  }
1321d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1322d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Instanceof check for the argument by comparing class fields.
1323d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // All string objects must have the same type since String cannot be subclassed.
1324d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Receiver must be a string object, so its class field is equal to all strings' class fields.
1325d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // If the argument is a string object, its class field must be equal to receiver's class field.
1326a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray  if (!optimizations.GetArgumentIsString()) {
1327a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray    __ movl(ecx, Address(str, class_offset));
1328a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray    __ cmpl(ecx, Address(arg, class_offset));
1329a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray    __ j(kNotEqual, &return_false);
1330a83a54d7f2322060f08480f8aabac5eb07268912Nicolas Geoffray  }
1331d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1332d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Reference equality check, return true if same reference.
1333d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ cmpl(str, arg);
1334d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ j(kEqual, &return_true);
1335d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1336d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Load length of receiver string.
1337d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ movl(ecx, Address(str, count_offset));
1338d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Check if lengths are equal, return false if they're not.
1339d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ cmpl(ecx, Address(arg, count_offset));
1340d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ j(kNotEqual, &return_false);
1341d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Return true if both strings are empty.
13420c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell  __ jecxz(&return_true);
1343d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1344d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Load starting addresses of string values into ESI/EDI as required for repe_cmpsl instruction.
1345d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ leal(esi, Address(str, value_offset));
1346d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ leal(edi, Address(arg, value_offset));
1347d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1348d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Divide string length by 2 to compare characters 2 at a time and adjust for odd lengths.
1349d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ addl(ecx, Immediate(1));
1350d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ shrl(ecx, Immediate(1));
1351d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1352d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Assertions that must hold in order to compare strings 2 characters at a time.
1353d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  DCHECK_ALIGNED(value_offset, 4);
1354d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
1355d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1356d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Loop to compare strings two characters at a time starting at the beginning of the string.
1357d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ repe_cmpsl();
1358d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // If strings are not equal, zero flag will be cleared.
1359d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ j(kNotEqual, &return_false);
1360d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1361d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Return true and exit the function.
1362d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // If loop does not result in returning false, we return true.
1363d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ Bind(&return_true);
1364d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ movl(esi, Immediate(1));
1365d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ jmp(&end);
1366d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
1367d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  // Return false and exit the function.
1368d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ Bind(&return_false);
1369d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ xorl(esi, esi);
1370d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki  __ Bind(&end);
1371d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki}
1372d7138c813ad72a824fff19f8b10f3fb61f4f43cfAgi Csaki
137321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampestatic void CreateStringIndexOfLocations(HInvoke* invoke,
137421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                         ArenaAllocator* allocator,
137521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                         bool start_at_zero) {
137621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  LocationSummary* locations = new (allocator) LocationSummary(invoke,
137721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                                               LocationSummary::kCallOnSlowPath,
137821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                                               kIntrinsified);
137921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // The data needs to be in EDI for scasw. So request that the string is there, anyways.
138021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  locations->SetInAt(0, Location::RegisterLocation(EDI));
138121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // If we look for a constant char, we'll still have to copy it into EAX. So just request the
138221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // allocator to do that, anyways. We can still do the constant check by checking the parameter
138321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // of the instruction explicitly.
138421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Note: This works as we don't clobber EAX anywhere.
138521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  locations->SetInAt(1, Location::RegisterLocation(EAX));
138621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  if (!start_at_zero) {
138721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    locations->SetInAt(2, Location::RequiresRegister());          // The starting index.
138821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  }
138921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // As we clobber EDI during execution anyways, also use it as the output.
139021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  locations->SetOut(Location::SameAsFirstInput());
139121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
139221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // repne scasw uses ECX as the counter.
139321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  locations->AddTemp(Location::RegisterLocation(ECX));
139421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Need another temporary to be able to compute the result.
139521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  locations->AddTemp(Location::RequiresRegister());
139621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe}
139721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
139821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampestatic void GenerateStringIndexOf(HInvoke* invoke,
139921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                  X86Assembler* assembler,
140021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                  CodeGeneratorX86* codegen,
140121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                  ArenaAllocator* allocator,
140221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe                                  bool start_at_zero) {
140321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  LocationSummary* locations = invoke->GetLocations();
140421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
140521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Note that the null check must have been done earlier.
140621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  DCHECK(!invoke->CanDoImplicitNullCheckOn(invoke->InputAt(0)));
140721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
140821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  Register string_obj = locations->InAt(0).AsRegister<Register>();
140921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  Register search_value = locations->InAt(1).AsRegister<Register>();
141021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  Register counter = locations->GetTemp(0).AsRegister<Register>();
141121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  Register string_length = locations->GetTemp(1).AsRegister<Register>();
141221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  Register out = locations->Out().AsRegister<Register>();
141321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
141421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Check our assumptions for registers.
141521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  DCHECK_EQ(string_obj, EDI);
141621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  DCHECK_EQ(search_value, EAX);
141721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  DCHECK_EQ(counter, ECX);
141821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  DCHECK_EQ(out, EDI);
141921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
142021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Check for code points > 0xFFFF. Either a slow-path check when we don't know statically,
142121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // or directly dispatch if we have a constant.
142285b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  SlowPathCode* slow_path = nullptr;
142321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  if (invoke->InputAt(1)->IsIntConstant()) {
142421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    if (static_cast<uint32_t>(invoke->InputAt(1)->AsIntConstant()->GetValue()) >
142521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    std::numeric_limits<uint16_t>::max()) {
142621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe      // Always needs the slow-path. We could directly dispatch to it, but this case should be
142721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe      // rare, so for simplicity just put the full slow-path down and branch unconditionally.
142821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe      slow_path = new (allocator) IntrinsicSlowPathX86(invoke);
142921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe      codegen->AddSlowPath(slow_path);
143021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe      __ jmp(slow_path->GetEntryLabel());
143121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe      __ Bind(slow_path->GetExitLabel());
143221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe      return;
143321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    }
143421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  } else {
143521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ cmpl(search_value, Immediate(std::numeric_limits<uint16_t>::max()));
143621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    slow_path = new (allocator) IntrinsicSlowPathX86(invoke);
143721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    codegen->AddSlowPath(slow_path);
143821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ j(kAbove, slow_path->GetEntryLabel());
143921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  }
144021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
144121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // From here down, we know that we are looking for a char that fits in 16 bits.
144221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Location of reference to data array within the String object.
144321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  int32_t value_offset = mirror::String::ValueOffset().Int32Value();
144421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Location of count within the String object.
144521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  int32_t count_offset = mirror::String::CountOffset().Int32Value();
144621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
144721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Load string length, i.e., the count field of the string.
144821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ movl(string_length, Address(string_obj, count_offset));
144921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
145021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Do a zero-length check.
145121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // TODO: Support jecxz.
14520c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell  NearLabel not_found_label;
145321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ testl(string_length, string_length);
145421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ j(kEqual, &not_found_label);
145521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
145621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  if (start_at_zero) {
145721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    // Number of chars to scan is the same as the string length.
145821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ movl(counter, string_length);
145921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
146021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    // Move to the start of the string.
146121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ addl(string_obj, Immediate(value_offset));
146221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  } else {
146321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    Register start_index = locations->InAt(2).AsRegister<Register>();
146421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
146521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    // Do a start_index check.
146621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ cmpl(start_index, string_length);
146721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ j(kGreaterEqual, &not_found_label);
146821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
146921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    // Ensure we have a start index >= 0;
147021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ xorl(counter, counter);
147121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ cmpl(start_index, Immediate(0));
147221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ cmovl(kGreater, counter, start_index);
147321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
147421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    // Move to the start of the string: string_obj + value_offset + 2 * start_index.
147521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
147621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
147721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
147821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    // compare.
147921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ negl(counter);
148021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ leal(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
148121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  }
148221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
148321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Everything is set up for repne scasw:
148421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  //   * Comparison address in EDI.
148521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  //   * Counter in ECX.
148621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ repne_scasw();
148721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
148821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Did we find a match?
148921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ j(kNotEqual, &not_found_label);
149021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
149121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Yes, we matched.  Compute the index of the result.
149221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ subl(string_length, counter);
149321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ leal(out, Address(string_length, -1));
149421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
14950c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell  NearLabel done;
149621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ jmp(&done);
149721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
149821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // Failed to match; return -1.
149921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ Bind(&not_found_label);
150021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ movl(out, Immediate(-1));
150121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
150221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  // And join up at the end.
150321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  __ Bind(&done);
150421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  if (slow_path != nullptr) {
150521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe    __ Bind(slow_path->GetExitLabel());
150621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe  }
150721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe}
150821030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
150921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampevoid IntrinsicLocationsBuilderX86::VisitStringIndexOf(HInvoke* invoke) {
1510bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ true);
151121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe}
151221030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
151321030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampevoid IntrinsicCodeGeneratorX86::VisitStringIndexOf(HInvoke* invoke) {
1514bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenerateStringIndexOf(invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ true);
151521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe}
151621030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
151721030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampevoid IntrinsicLocationsBuilderX86::VisitStringIndexOfAfter(HInvoke* invoke) {
1518bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateStringIndexOfLocations(invoke, arena_, /* start_at_zero */ false);
151921030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe}
152021030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
152121030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampevoid IntrinsicCodeGeneratorX86::VisitStringIndexOfAfter(HInvoke* invoke) {
1522bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenerateStringIndexOf(
1523bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      invoke, GetAssembler(), codegen_, GetAllocator(), /* start_at_zero */ false);
152421030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe}
152521030dd59b1e350f6f43de39e3c4ce0886ff539cAndreas Gampe
1526848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
1527848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = new (arena_) LocationSummary(invoke,
1528848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            LocationSummary::kCall,
1529848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            kIntrinsified);
1530848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  InvokeRuntimeCallingConvention calling_convention;
1531848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1532848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1533848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1534848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
1535848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetOut(Location::RegisterLocation(EAX));
1536848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1537848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1538848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorX86::VisitStringNewStringFromBytes(HInvoke* invoke) {
1539848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  X86Assembler* assembler = GetAssembler();
1540848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = invoke->GetLocations();
1541848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1542848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  Register byte_array = locations->InAt(0).AsRegister<Register>();
1543848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ testl(byte_array, byte_array);
154485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
1545848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->AddSlowPath(slow_path);
1546848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ j(kEqual, slow_path->GetEntryLabel());
1547848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1548848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocStringFromBytes)));
1549f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain  CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>();
1550848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1551848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ Bind(slow_path->GetExitLabel());
1552848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1553848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1554848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderX86::VisitStringNewStringFromChars(HInvoke* invoke) {
1555848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = new (arena_) LocationSummary(invoke,
1556848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            LocationSummary::kCall,
1557848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            kIntrinsified);
1558848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  InvokeRuntimeCallingConvention calling_convention;
1559848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1560848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1561848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1562848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetOut(Location::RegisterLocation(EAX));
1563848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1564848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1565848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorX86::VisitStringNewStringFromChars(HInvoke* invoke) {
1566848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  X86Assembler* assembler = GetAssembler();
1567848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1568cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain  // No need to emit code checking whether `locations->InAt(2)` is a null
1569cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain  // pointer, as callers of the native method
1570cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain  //
1571cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain  //   java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data)
1572cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain  //
1573cc3839c15555a2751e13980638fc40e4d3da633eRoland Levillain  // all include a null check on `data` before calling that method.
1574848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocStringFromChars)));
1575f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain  CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>();
1576848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1577848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1578848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1579848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicLocationsBuilderX86::VisitStringNewStringFromString(HInvoke* invoke) {
1580848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = new (arena_) LocationSummary(invoke,
1581848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            LocationSummary::kCall,
1582848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao                                                            kIntrinsified);
1583848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  InvokeRuntimeCallingConvention calling_convention;
1584848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1585848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  locations->SetOut(Location::RegisterLocation(EAX));
1586848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1587848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1588848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Haovoid IntrinsicCodeGeneratorX86::VisitStringNewStringFromString(HInvoke* invoke) {
1589848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  X86Assembler* assembler = GetAssembler();
1590848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  LocationSummary* locations = invoke->GetLocations();
1591848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1592848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  Register string_to_copy = locations->InAt(0).AsRegister<Register>();
1593848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ testl(string_to_copy, string_to_copy);
159485b62f23fc6dfffe2ddd3ddfa74611666c9ff41dAndreas Gampe  SlowPathCode* slow_path = new (GetAllocator()) IntrinsicSlowPathX86(invoke);
1595848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->AddSlowPath(slow_path);
1596848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ j(kEqual, slow_path->GetEntryLabel());
1597848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
1598848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocStringFromString)));
1599f969a209c30e3af636342d2fb7851d82a2529bf7Roland Levillain  CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>();
1600848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1601848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao  __ Bind(slow_path->GetExitLabel());
1602848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao}
1603848f70a3d73833fc1bf3032a9ff6812e429661d9Jeff Hao
16048f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendellvoid IntrinsicLocationsBuilderX86::VisitStringGetCharsNoCheck(HInvoke* invoke) {
16058f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
16068f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  LocationSummary* locations = new (arena_) LocationSummary(invoke,
16078f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell                                                            LocationSummary::kNoCall,
16088f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell                                                            kIntrinsified);
16098f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  locations->SetInAt(0, Location::RequiresRegister());
16108f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  locations->SetInAt(1, Location::RegisterOrConstant(invoke->InputAt(1)));
16118f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Place srcEnd in ECX to save a move below.
16128f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  locations->SetInAt(2, Location::RegisterLocation(ECX));
16138f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  locations->SetInAt(3, Location::RequiresRegister());
16148f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  locations->SetInAt(4, Location::RequiresRegister());
16158f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16168f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // And we need some temporaries.  We will use REP MOVSW, so we need fixed registers.
16178f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // We don't have enough registers to also grab ECX, so handle below.
16188f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  locations->AddTemp(Location::RegisterLocation(ESI));
16198f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  locations->AddTemp(Location::RegisterLocation(EDI));
16208f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell}
16218f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16228f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendellvoid IntrinsicCodeGeneratorX86::VisitStringGetCharsNoCheck(HInvoke* invoke) {
16238f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  X86Assembler* assembler = GetAssembler();
16248f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  LocationSummary* locations = invoke->GetLocations();
16258f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16268f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  size_t char_component_size = Primitive::ComponentSize(Primitive::kPrimChar);
16278f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Location of data in char array buffer.
16288f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  const uint32_t data_offset = mirror::Array::DataOffset(char_component_size).Uint32Value();
16298f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Location of char array data in string.
16308f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  const uint32_t value_offset = mirror::String::ValueOffset().Uint32Value();
16318f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16328f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin);
16338f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  Register obj = locations->InAt(0).AsRegister<Register>();
16348f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  Location srcBegin = locations->InAt(1);
16358f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  int srcBegin_value =
16368f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    srcBegin.IsConstant() ? srcBegin.GetConstant()->AsIntConstant()->GetValue() : 0;
16378f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  Register srcEnd = locations->InAt(2).AsRegister<Register>();
16388f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  Register dst = locations->InAt(3).AsRegister<Register>();
16398f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  Register dstBegin = locations->InAt(4).AsRegister<Register>();
16408f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16418f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Check assumption that sizeof(Char) is 2 (used in scaling below).
16428f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
16438f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  DCHECK_EQ(char_size, 2u);
16448f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16458f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Compute the address of the destination buffer.
16468f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
16478f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16488f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Compute the address of the source string.
16498f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  if (srcBegin.IsConstant()) {
16508f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    // Compute the address of the source string by adding the number of chars from
16518f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    // the source beginning to the value offset of a string.
16528f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    __ leal(ESI, Address(obj, srcBegin_value * char_size + value_offset));
16538f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  } else {
16548f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    __ leal(ESI, Address(obj, srcBegin.AsRegister<Register>(),
16558f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell                         ScaleFactor::TIMES_2, value_offset));
16568f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  }
16578f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16588f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Compute the number of chars (words) to move.
16598f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Now is the time to save ECX, since we don't know if it will be used later.
16608f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  __ pushl(ECX);
16618f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  int stack_adjust = kX86WordSize;
16628f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  __ cfi().AdjustCFAOffset(stack_adjust);
16638f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  DCHECK_EQ(srcEnd, ECX);
16648f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  if (srcBegin.IsConstant()) {
16658f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    if (srcBegin_value != 0) {
16668f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell      __ subl(ECX, Immediate(srcBegin_value));
16678f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    }
16688f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  } else {
16698f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    DCHECK(srcBegin.IsRegister());
16708f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell    __ subl(ECX, srcBegin.AsRegister<Register>());
16718f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  }
16728f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16738f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // Do the move.
16748f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  __ rep_movsw();
16758f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
16768f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  // And restore ECX.
16778f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  __ popl(ECX);
16788f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell  __ cfi().AdjustCFAOffset(-stack_adjust);
16798f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell}
16808f8926a5c7ea332ab387c2b3ebc6fd378a5761bcMark Mendell
168109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void GenPeek(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
168209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register address = locations->InAt(0).AsRegisterPairLow<Register>();
168309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location out_loc = locations->Out();
168409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // x86 allows unaligned access. We do not have to check the input or use specific instructions
168509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // to avoid a SIGBUS.
168609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  switch (size) {
168709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimByte:
168809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movsxb(out_loc.AsRegister<Register>(), Address(address, 0));
168909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
169009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimShort:
169109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movsxw(out_loc.AsRegister<Register>(), Address(address, 0));
169209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
169309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimInt:
169409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movl(out_loc.AsRegister<Register>(), Address(address, 0));
169509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
169609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimLong:
169709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movl(out_loc.AsRegisterPairLow<Register>(), Address(address, 0));
169809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movl(out_loc.AsRegisterPairHigh<Register>(), Address(address, 4));
169909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
170009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    default:
170109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      LOG(FATAL) << "Type not recognized for peek: " << size;
170209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      UNREACHABLE();
170309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
170409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
170509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
170609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPeekByte(HInvoke* invoke) {
170709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongToIntLocations(arena_, invoke);
170809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
170909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
171009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPeekByte(HInvoke* invoke) {
171109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPeek(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
171209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
171309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
171409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
171509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongToIntLocations(arena_, invoke);
171609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
171709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
171809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPeekIntNative(HInvoke* invoke) {
171909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPeek(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
172009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
172109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
172209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
172309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongToLongLocations(arena_, invoke);
172409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
172509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
172609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPeekLongNative(HInvoke* invoke) {
172709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPeek(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
172809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
172909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
173009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
173109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongToIntLocations(arena_, invoke);
173209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
173309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
173409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPeekShortNative(HInvoke* invoke) {
173509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPeek(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
173609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
173709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
173809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateLongIntToVoidLocations(ArenaAllocator* arena, Primitive::Type size,
173909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                         HInvoke* invoke) {
174009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
174109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
174209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
174309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
17444c0eb42259d790fddcd9978b66328dbb3ab65615Roland Levillain  HInstruction* value = invoke->InputAt(1);
174509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (size == Primitive::kPrimByte) {
174609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->SetInAt(1, Location::ByteRegisterOrConstant(EDX, value));
174709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
174809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->SetInAt(1, Location::RegisterOrConstant(value));
174909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
175009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
175109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
175209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void GenPoke(LocationSummary* locations, Primitive::Type size, X86Assembler* assembler) {
175309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register address = locations->InAt(0).AsRegisterPairLow<Register>();
175409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location value_loc = locations->InAt(1);
175509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // x86 allows unaligned access. We do not have to check the input or use specific instructions
175609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  // to avoid a SIGBUS.
175709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  switch (size) {
175809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimByte:
175909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      if (value_loc.IsConstant()) {
176009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movb(Address(address, 0),
176109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
176209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      } else {
176309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movb(Address(address, 0), value_loc.AsRegister<ByteRegister>());
176409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      }
176509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
176609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimShort:
176709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      if (value_loc.IsConstant()) {
176809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movw(Address(address, 0),
176909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
177009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      } else {
177109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movw(Address(address, 0), value_loc.AsRegister<Register>());
177209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      }
177309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
177409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimInt:
177509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      if (value_loc.IsConstant()) {
177609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movl(Address(address, 0),
177709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                Immediate(value_loc.GetConstant()->AsIntConstant()->GetValue()));
177809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      } else {
177909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movl(Address(address, 0), value_loc.AsRegister<Register>());
178009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      }
178109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
178209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimLong:
178309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      if (value_loc.IsConstant()) {
178409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        int64_t value = value_loc.GetConstant()->AsLongConstant()->GetValue();
178509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movl(Address(address, 0), Immediate(Low32Bits(value)));
178609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movl(Address(address, 4), Immediate(High32Bits(value)));
178709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      } else {
178809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movl(Address(address, 0), value_loc.AsRegisterPairLow<Register>());
178909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        __ movl(Address(address, 4), value_loc.AsRegisterPairHigh<Register>());
179009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      }
179109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
179209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    default:
179309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      LOG(FATAL) << "Type not recognized for poke: " << size;
179409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      UNREACHABLE();
179509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
179609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
179709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
179809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPokeByte(HInvoke* invoke) {
179909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongIntToVoidLocations(arena_, Primitive::kPrimByte, invoke);
180009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
180109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
180209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPokeByte(HInvoke* invoke) {
180309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPoke(invoke->GetLocations(), Primitive::kPrimByte, GetAssembler());
180409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
180509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
180609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
180709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongIntToVoidLocations(arena_, Primitive::kPrimInt, invoke);
180809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
180909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
181009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPokeIntNative(HInvoke* invoke) {
181109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPoke(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
181209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
181309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
181409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
181509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongIntToVoidLocations(arena_, Primitive::kPrimLong, invoke);
181609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
181709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
181809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPokeLongNative(HInvoke* invoke) {
181909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPoke(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
182009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
182109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
182209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
182309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  CreateLongIntToVoidLocations(arena_, Primitive::kPrimShort, invoke);
182409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
182509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
182609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitMemoryPokeShortNative(HInvoke* invoke) {
182709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GenPoke(invoke->GetLocations(), Primitive::kPrimShort, GetAssembler());
182809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
182909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
183009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitThreadCurrentThread(HInvoke* invoke) {
183109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena_) LocationSummary(invoke,
183209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                            LocationSummary::kNoCall,
183309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                            kIntrinsified);
183409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetOut(Location::RequiresRegister());
183509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
183609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
183709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitThreadCurrentThread(HInvoke* invoke) {
183809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register out = invoke->GetLocations()->Out().AsRegister<Register>();
183909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  GetAssembler()->fs()->movl(out, Address::Absolute(Thread::PeerOffset<kX86WordSize>()));
184009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
184109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
18420d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillainstatic void GenUnsafeGet(HInvoke* invoke,
18430d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain                         Primitive::Type type,
18440d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain                         bool is_volatile,
18450d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain                         CodeGeneratorX86* codegen) {
18460d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
18470d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  LocationSummary* locations = invoke->GetLocations();
18480d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  Location base_loc = locations->InAt(1);
18490d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  Register base = base_loc.AsRegister<Register>();
18500d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  Location offset_loc = locations->InAt(2);
18510d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  Register offset = offset_loc.AsRegisterPairLow<Register>();
18520d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  Location output_loc = locations->Out();
185309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
185409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  switch (type) {
18557c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain    case Primitive::kPrimInt: {
18560d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain      Register output = output_loc.AsRegister<Register>();
18570d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain      __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
18587c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain      break;
18597c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain    }
18607c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain
18617c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain    case Primitive::kPrimNot: {
18627c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain      Register output = output_loc.AsRegister<Register>();
18637c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain      if (kEmitCompilerReadBarrier) {
18647c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain        if (kUseBakerReadBarrier) {
18657c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain          Location temp = locations->GetTemp(0);
18667c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain          codegen->GenerateArrayLoadWithBakerReadBarrier(
18677c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain              invoke, output_loc, base, 0U, offset_loc, temp, /* needs_null_check */ false);
18687c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain        } else {
18697c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain          __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
18707c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain          codegen->GenerateReadBarrierSlow(
18717c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain              invoke, output_loc, output_loc, base_loc, 0U, offset_loc);
18727c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain        }
18737c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain      } else {
18747c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain        __ movl(output, Address(base, offset, ScaleFactor::TIMES_1, 0));
18757c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain        __ MaybeUnpoisonHeapReference(output);
18764d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain      }
187709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
18784d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    }
187909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
188009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    case Primitive::kPrimLong: {
18810d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain        Register output_lo = output_loc.AsRegisterPairLow<Register>();
18820d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain        Register output_hi = output_loc.AsRegisterPairHigh<Register>();
188309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        if (is_volatile) {
188409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          // Need to use a XMM to read atomically.
188509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
188609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          __ movsd(temp, Address(base, offset, ScaleFactor::TIMES_1, 0));
188709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          __ movd(output_lo, temp);
188809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          __ psrlq(temp, Immediate(32));
188909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          __ movd(output_hi, temp);
189009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        } else {
189109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          __ movl(output_lo, Address(base, offset, ScaleFactor::TIMES_1, 0));
189209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell          __ movl(output_hi, Address(base, offset, ScaleFactor::TIMES_1, 4));
189309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell        }
189409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      }
189509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      break;
189609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
189709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    default:
189809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      LOG(FATAL) << "Unsupported op size " << type;
189909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      UNREACHABLE();
190009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
190109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
190209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
19037c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillainstatic void CreateIntIntIntToIntLocations(ArenaAllocator* arena,
19047c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain                                          HInvoke* invoke,
19057c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain                                          Primitive::Type type,
19067c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain                                          bool is_volatile) {
19070d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain  bool can_call = kEmitCompilerReadBarrier &&
19080d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain      (invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObject ||
19090d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain       invoke->GetIntrinsic() == Intrinsics::kUnsafeGetObjectVolatile);
191009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
19110d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain                                                           can_call ?
19120d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain                                                               LocationSummary::kCallOnSlowPath :
19130d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain                                                               LocationSummary::kNoCall,
191409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
191509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
191609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(1, Location::RequiresRegister());
191709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(2, Location::RequiresRegister());
19187c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  if (type == Primitive::kPrimLong) {
191909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    if (is_volatile) {
192009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      // Need to use XMM to read volatile.
192109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      locations->AddTemp(Location::RequiresFpuRegister());
192209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      locations->SetOut(Location::RequiresRegister());
192309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    } else {
192409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
192509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    }
192609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
192709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->SetOut(Location::RequiresRegister());
192809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
19297c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  if (type == Primitive::kPrimNot && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
19307c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain    // We need a temporary register for the read barrier marking slow
19317c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain    // path in InstructionCodeGeneratorX86::GenerateArrayLoadWithBakerReadBarrier.
19327c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain    locations->AddTemp(Location::RequiresRegister());
19337c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  }
193409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
193509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
193609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeGet(HInvoke* invoke) {
19377c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt, /* is_volatile */ false);
193809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
193909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
19407c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimInt, /* is_volatile */ true);
194109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
194209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeGetLong(HInvoke* invoke) {
19437c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong, /* is_volatile */ false);
194409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
194509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
19467c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimLong, /* is_volatile */ true);
194709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
194809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeGetObject(HInvoke* invoke) {
19497c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot, /* is_volatile */ false);
195009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
195109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
19527c1559a06041c9c299d5ab514d54b2102f204a84Roland Levillain  CreateIntIntIntToIntLocations(arena_, invoke, Primitive::kPrimNot, /* is_volatile */ true);
195309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
195409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
195509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
195609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeGet(HInvoke* invoke) {
1957bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ false, codegen_);
195809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
195909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeGetVolatile(HInvoke* invoke) {
1960bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafeGet(invoke, Primitive::kPrimInt, /* is_volatile */ true, codegen_);
196109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
196209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeGetLong(HInvoke* invoke) {
1963bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ false, codegen_);
196409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
196509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeGetLongVolatile(HInvoke* invoke) {
1966bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafeGet(invoke, Primitive::kPrimLong, /* is_volatile */ true, codegen_);
196709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
196809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeGetObject(HInvoke* invoke) {
1969bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ false, codegen_);
197009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
197109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeGetObjectVolatile(HInvoke* invoke) {
1972bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafeGet(invoke, Primitive::kPrimNot, /* is_volatile */ true, codegen_);
197309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
197409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
197509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
197609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void CreateIntIntIntIntToVoidPlusTempsLocations(ArenaAllocator* arena,
197709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                       Primitive::Type type,
197809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                       HInvoke* invoke,
197909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                       bool is_volatile) {
198009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
198109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           LocationSummary::kNoCall,
198209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                                                           kIntrinsified);
198309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
198409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(1, Location::RequiresRegister());
198509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(2, Location::RequiresRegister());
198609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  locations->SetInAt(3, Location::RequiresRegister());
198709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (type == Primitive::kPrimNot) {
198809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Need temp registers for card-marking.
19894d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
199009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    // Ensure the value is in a byte register.
199109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->AddTemp(Location::RegisterLocation(ECX));
199209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else if (type == Primitive::kPrimLong && is_volatile) {
199309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->AddTemp(Location::RequiresFpuRegister());
199409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    locations->AddTemp(Location::RequiresFpuRegister());
199509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
199609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
199709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
199809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePut(HInvoke* invoke) {
1999bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2000bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false);
200109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
200209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutOrdered(HInvoke* invoke) {
2003bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2004bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimInt, invoke, /* is_volatile */ false);
200509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
200609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutVolatile(HInvoke* invoke) {
2007bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2008bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimInt, invoke, /* is_volatile */ true);
200909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
201009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutObject(HInvoke* invoke) {
2011bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2012bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false);
201309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
201409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
2015bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2016bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimNot, invoke, /* is_volatile */ false);
201709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
201809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
2019bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2020bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimNot, invoke, /* is_volatile */ true);
202109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
202209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutLong(HInvoke* invoke) {
2023bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2024bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false);
202509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
202609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
2027bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2028bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimLong, invoke, /* is_volatile */ false);
202909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
203009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
2031bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  CreateIntIntIntIntToVoidPlusTempsLocations(
2032bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain      arena_, Primitive::kPrimLong, invoke, /* is_volatile */ true);
203309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
203409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
203509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell// We don't care for ordered: it requires an AnyStore barrier, which is already given by the x86
203609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell// memory model.
203709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellstatic void GenUnsafePut(LocationSummary* locations,
203809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                         Primitive::Type type,
203909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                         bool is_volatile,
204009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                         CodeGeneratorX86* codegen) {
2041b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain  X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
204209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register base = locations->InAt(1).AsRegister<Register>();
204309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
204409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  Location value_loc = locations->InAt(3);
204509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
204609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (type == Primitive::kPrimLong) {
204709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register value_lo = value_loc.AsRegisterPairLow<Register>();
204809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    Register value_hi = value_loc.AsRegisterPairHigh<Register>();
204909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    if (is_volatile) {
205009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
205109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
205209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movd(temp1, value_lo);
205309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movd(temp2, value_hi);
205409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ punpckldq(temp1, temp2);
205509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movsd(Address(base, offset, ScaleFactor::TIMES_1, 0), temp1);
205609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    } else {
205709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_lo);
205809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell      __ movl(Address(base, offset, ScaleFactor::TIMES_1, 4), value_hi);
205909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    }
20604d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  } else if (kPoisonHeapReferences && type == Primitive::kPrimNot) {
20614d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    Register temp = locations->GetTemp(0).AsRegister<Register>();
20624d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    __ movl(temp, value_loc.AsRegister<Register>());
20634d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    __ PoisonHeapReference(temp);
20644d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), temp);
206509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  } else {
206609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    __ movl(Address(base, offset, ScaleFactor::TIMES_1, 0), value_loc.AsRegister<Register>());
206709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
206809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
206909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (is_volatile) {
207017077d888a6752a2e5f8161eee1b2c3285783d12Mark P Mendell    codegen->MemoryFence();
207109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
207209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
207309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  if (type == Primitive::kPrimNot) {
207407276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray    bool value_can_be_null = true;  // TODO: Worth finding out this information?
207509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell    codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
207609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                        locations->GetTemp(1).AsRegister<Register>(),
207709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell                        base,
207807276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray                        value_loc.AsRegister<Register>(),
207907276db28d654594e0e86e9e467cad393f752e6eNicolas Geoffray                        value_can_be_null);
208009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell  }
208109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
208209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
208309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePut(HInvoke* invoke) {
2084bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
208509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
208609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutOrdered(HInvoke* invoke) {
2087bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ false, codegen_);
208809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
208909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutVolatile(HInvoke* invoke) {
2090bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimInt, /* is_volatile */ true, codegen_);
209109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
209209ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutObject(HInvoke* invoke) {
2093bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
209409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
209509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutObjectOrdered(HInvoke* invoke) {
2096bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ false, codegen_);
209709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
209809ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutObjectVolatile(HInvoke* invoke) {
2099bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimNot, /* is_volatile */ true, codegen_);
210009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
210109ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutLong(HInvoke* invoke) {
2102bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
210309ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
210409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutLongOrdered(HInvoke* invoke) {
2105bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ false, codegen_);
210609ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
210709ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafePutLongVolatile(HInvoke* invoke) {
2108bf84a3d2aa29c0975b4ac0f6f983d56724b2cc57Roland Levillain  GenUnsafePut(invoke->GetLocations(), Primitive::kPrimLong, /* is_volatile */ true, codegen_);
210909ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}
211009ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell
211158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellstatic void CreateIntIntIntIntIntToInt(ArenaAllocator* arena, Primitive::Type type,
211258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                                       HInvoke* invoke) {
211358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
211458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                                                           LocationSummary::kNoCall,
211558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                                                           kIntrinsified);
211658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetInAt(0, Location::NoLocation());        // Unused receiver.
211758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetInAt(1, Location::RequiresRegister());
211858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // Offset is a long, but in 32 bit mode, we only need the low word.
211958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // Can we update the invoke here to remove a TypeConvert to Long?
212058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetInAt(2, Location::RequiresRegister());
212158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // Expected value must be in EAX or EDX:EAX.
212258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // For long, new value must be in ECX:EBX.
212358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  if (type == Primitive::kPrimLong) {
212458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    locations->SetInAt(3, Location::RegisterPairLocation(EAX, EDX));
212558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    locations->SetInAt(4, Location::RegisterPairLocation(EBX, ECX));
212658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  } else {
212758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    locations->SetInAt(3, Location::RegisterLocation(EAX));
212858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    locations->SetInAt(4, Location::RequiresRegister());
212958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  }
213058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
213158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // Force a byte register for the output.
213258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetOut(Location::RegisterLocation(EAX));
213358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  if (type == Primitive::kPrimNot) {
213458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    // Need temp registers for card-marking.
2135b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    locations->AddTemp(Location::RequiresRegister());  // Possibly used for reference poisoning too.
213658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    // Need a byte register for marking.
213758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    locations->AddTemp(Location::RegisterLocation(ECX));
213858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  }
213958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
214058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
214158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeCASInt(HInvoke* invoke) {
214258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimInt, invoke);
214358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
214458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
214558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeCASLong(HInvoke* invoke) {
214658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimLong, invoke);
214758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
214858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
214958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitUnsafeCASObject(HInvoke* invoke) {
2150391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  // The UnsafeCASObject intrinsic is missing a read barrier, and
2151391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  // therefore sometimes does not work as expected (b/25883050).
2152391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  // Turn it off temporarily as a quick fix, until the read barrier is
2153391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  // implemented.
2154391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  //
2155391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  // TODO(rpl): Implement a read barrier in GenCAS below and re-enable
2156391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  // this intrinsic.
2157391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  if (kEmitCompilerReadBarrier) {
2158391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    return;
2159391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain  }
2160391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain
216158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  CreateIntIntIntIntIntToInt(arena_, Primitive::kPrimNot, invoke);
216258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
216358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
216458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellstatic void GenCAS(Primitive::Type type, HInvoke* invoke, CodeGeneratorX86* codegen) {
2165b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain  X86Assembler* assembler = down_cast<X86Assembler*>(codegen->GetAssembler());
216658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  LocationSummary* locations = invoke->GetLocations();
216758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
216858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register base = locations->InAt(1).AsRegister<Register>();
216958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register offset = locations->InAt(2).AsRegisterPairLow<Register>();
217058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Location out = locations->Out();
217158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  DCHECK_EQ(out.AsRegister<Register>(), EAX);
217258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
2173b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain  if (type == Primitive::kPrimNot) {
21744d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    Register expected = locations->InAt(3).AsRegister<Register>();
2175b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    // Ensure `expected` is in EAX (required by the CMPXCHG instruction).
21764d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain    DCHECK_EQ(expected, EAX);
217758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    Register value = locations->InAt(4).AsRegister<Register>();
2178b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain
2179b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    // Mark card for object assuming new value is stored.
2180b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    bool value_can_be_null = true;  // TODO: Worth finding out this information?
2181b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    codegen->MarkGCCard(locations->GetTemp(0).AsRegister<Register>(),
2182b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain                        locations->GetTemp(1).AsRegister<Register>(),
2183b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain                        base,
2184b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain                        value,
2185b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain                        value_can_be_null);
2186b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain
2187b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    bool base_equals_value = (base == value);
2188b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    if (kPoisonHeapReferences) {
2189b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      if (base_equals_value) {
2190b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        // If `base` and `value` are the same register location, move
2191b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        // `value` to a temporary register.  This way, poisoning
2192b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        // `value` won't invalidate `base`.
2193b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        value = locations->GetTemp(0).AsRegister<Register>();
2194b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        __ movl(value, base);
21954d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain      }
2196b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain
2197b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // Check that the register allocator did not assign the location
2198b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // of `expected` (EAX) to `value` nor to `base`, so that heap
2199b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // poisoning (when enabled) works as intended below.
2200b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // - If `value` were equal to `expected`, both references would
2201b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      //   be poisoned twice, meaning they would not be poisoned at
2202b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      //   all, as heap poisoning uses address negation.
2203b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // - If `base` were equal to `expected`, poisoning `expected`
2204b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      //   would invalidate `base`.
2205b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      DCHECK_NE(value, expected);
2206b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      DCHECK_NE(base, expected);
2207b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain
2208b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      __ PoisonHeapReference(expected);
2209b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      __ PoisonHeapReference(value);
221058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    }
221158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
2212391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    // TODO: Add a read barrier for the reference stored in the object
2213391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    // before attempting the CAS, similar to the one in the
2214391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    // art::Unsafe_compareAndSwapObject JNI implementation.
2215391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    //
2216391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    // Note that this code is not (yet) used when read barriers are
2217391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    // enabled (see IntrinsicLocationsBuilderX86::VisitUnsafeCASObject).
2218391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    DCHECK(!kEmitCompilerReadBarrier);
221958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell    __ LockCmpxchgl(Address(base, offset, TIMES_1, 0), value);
222058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
22210d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // LOCK CMPXCHG has full barrier semantics, and we don't need
2222b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    // scheduling barriers at this time.
222358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
2224b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    // Convert ZF into the boolean result.
2225b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    __ setb(kZero, out.AsRegister<Register>());
2226b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
22274d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain
2228391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    // If heap poisoning is enabled, we need to unpoison the values
2229391b866ce55b8e78b1f9a6b98321d837256e8d66Roland Levillain    // that were poisoned earlier.
2230b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    if (kPoisonHeapReferences) {
2231b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      if (base_equals_value) {
2232b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        // `value` has been moved to a temporary register, no need to
2233b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        // unpoison it.
2234b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      } else {
2235b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        // Ensure `value` is different from `out`, so that unpoisoning
2236b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        // the former does not invalidate the latter.
2237b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        DCHECK_NE(value, out.AsRegister<Register>());
2238b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain        __ UnpoisonHeapReference(value);
2239b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      }
2240b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // Do not unpoison the reference contained in register
2241b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // `expected`, as it is the same as register `out` (EAX).
2242b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    }
2243b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain  } else {
2244b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    if (type == Primitive::kPrimInt) {
2245b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // Ensure the expected value is in EAX (required by the CMPXCHG
2246b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // instruction).
2247b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      DCHECK_EQ(locations->InAt(3).AsRegister<Register>(), EAX);
2248b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      __ LockCmpxchgl(Address(base, offset, TIMES_1, 0),
2249b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain                      locations->InAt(4).AsRegister<Register>());
2250b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    } else if (type == Primitive::kPrimLong) {
2251b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // Ensure the expected value is in EAX:EDX and that the new
2252b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      // value is in EBX:ECX (required by the CMPXCHG8B instruction).
2253b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      DCHECK_EQ(locations->InAt(3).AsRegisterPairLow<Register>(), EAX);
2254b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      DCHECK_EQ(locations->InAt(3).AsRegisterPairHigh<Register>(), EDX);
2255b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      DCHECK_EQ(locations->InAt(4).AsRegisterPairLow<Register>(), EBX);
2256b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      DCHECK_EQ(locations->InAt(4).AsRegisterPairHigh<Register>(), ECX);
2257b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      __ LockCmpxchg8b(Address(base, offset, TIMES_1, 0));
2258b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    } else {
2259b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain      LOG(FATAL) << "Unexpected CAS type " << type;
2260b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    }
2261b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain
22620d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // LOCK CMPXCHG/LOCK CMPXCHG8B have full barrier semantics, and we
22630d5a281c671444bfa75d63caf1427a8c0e6e1177Roland Levillain    // don't need scheduling barriers at this time.
2264b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain
2265b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    // Convert ZF into the boolean result.
2266b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    __ setb(kZero, out.AsRegister<Register>());
2267b488b7864b7bf9cade82d45c8bdda2372f48a10cRoland Levillain    __ movzxb(out.AsRegister<Register>(), out.AsRegister<ByteRegister>());
22684d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain  }
226958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
227058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
227158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeCASInt(HInvoke* invoke) {
227258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  GenCAS(Primitive::kPrimInt, invoke, codegen_);
227358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
227458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
227558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeCASLong(HInvoke* invoke) {
227658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  GenCAS(Primitive::kPrimLong, invoke, codegen_);
227758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
227858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
227958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitUnsafeCASObject(HInvoke* invoke) {
228058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  GenCAS(Primitive::kPrimNot, invoke, codegen_);
228158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
228258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
228358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitIntegerReverse(HInvoke* invoke) {
228458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  LocationSummary* locations = new (arena_) LocationSummary(invoke,
228558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                                                           LocationSummary::kNoCall,
228658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                                                           kIntrinsified);
228758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
228858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
228958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->AddTemp(Location::RequiresRegister());
229058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
229158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
229258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellstatic void SwapBits(Register reg, Register temp, int32_t shift, int32_t mask,
229358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                     X86Assembler* assembler) {
229458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Immediate imm_shift(shift);
229558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Immediate imm_mask(mask);
229658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ movl(temp, reg);
229758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ shrl(reg, imm_shift);
229858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ andl(temp, imm_mask);
229958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ andl(reg, imm_mask);
230058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ shll(temp, imm_shift);
230158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ orl(reg, temp);
230258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
230358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
230458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitIntegerReverse(HInvoke* invoke) {
2305a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  X86Assembler* assembler = GetAssembler();
230658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  LocationSummary* locations = invoke->GetLocations();
230758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
230858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register reg = locations->InAt(0).AsRegister<Register>();
230958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register temp = locations->GetTemp(0).AsRegister<Register>();
231058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
231158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  /*
231258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   * Use one bswap instruction to reverse byte order first and then use 3 rounds of
231358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   * swapping bits to reverse bits in a number x. Using bswap to save instructions
231458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   * compared to generic luni implementation which has 5 rounds of swapping bits.
231558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   * x = bswap x
231658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   * x = (x & 0x55555555) << 1 | (x >> 1) & 0x55555555;
231758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   * x = (x & 0x33333333) << 2 | (x >> 2) & 0x33333333;
231858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   * x = (x & 0x0F0F0F0F) << 4 | (x >> 4) & 0x0F0F0F0F;
231958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell   */
232058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ bswapl(reg);
232158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg, temp, 1, 0x55555555, assembler);
232258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg, temp, 2, 0x33333333, assembler);
232358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg, temp, 4, 0x0f0f0f0f, assembler);
232458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
232558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
232658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitLongReverse(HInvoke* invoke) {
232758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  LocationSummary* locations = new (arena_) LocationSummary(invoke,
232858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                                                           LocationSummary::kNoCall,
232958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell                                                           kIntrinsified);
233058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetInAt(0, Location::RequiresRegister());
233158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->SetOut(Location::SameAsFirstInput());
233258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  locations->AddTemp(Location::RequiresRegister());
233358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
233458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
233558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitLongReverse(HInvoke* invoke) {
2336a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  X86Assembler* assembler = GetAssembler();
233758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  LocationSummary* locations = invoke->GetLocations();
233858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
233958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register reg_low = locations->InAt(0).AsRegisterPairLow<Register>();
234058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register reg_high = locations->InAt(0).AsRegisterPairHigh<Register>();
234158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  Register temp = locations->GetTemp(0).AsRegister<Register>();
234258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
234358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // We want to swap high/low, then bswap each one, and then do the same
234458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // as a 32 bit reverse.
234558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // Exchange high and low.
234658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ movl(temp, reg_low);
234758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ movl(reg_low, reg_high);
234858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ movl(reg_high, temp);
234958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
235058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // bit-reverse low
235158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ bswapl(reg_low);
235258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg_low, temp, 1, 0x55555555, assembler);
235358d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg_low, temp, 2, 0x33333333, assembler);
235458d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg_low, temp, 4, 0x0f0f0f0f, assembler);
235558d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
235658d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  // bit-reverse high
235758d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  __ bswapl(reg_high);
235858d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg_high, temp, 1, 0x55555555, assembler);
235958d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg_high, temp, 2, 0x33333333, assembler);
236058d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell  SwapBits(reg_high, temp, 4, 0x0f0f0f0f, assembler);
236158d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell}
236258d25fd052e999a24734b0cf856a1563e3d1b2d0Mark Mendell
2363c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bikstatic void CreateBitCountLocations(
2364c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    ArenaAllocator* arena, CodeGeneratorX86* codegen, HInvoke* invoke, bool is_long) {
2365c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  if (!codegen->GetInstructionSetFeatures().HasPopCnt()) {
2366c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    // Do nothing if there is no popcnt support. This results in generating
2367c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    // a call for the intrinsic rather than direct code.
2368c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    return;
2369c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  }
2370c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  LocationSummary* locations = new (arena) LocationSummary(invoke,
2371c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik                                                           LocationSummary::kNoCall,
2372c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik                                                           kIntrinsified);
2373c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  if (is_long) {
2374c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    locations->AddTemp(Location::RequiresRegister());
2375c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  }
23762a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik  locations->SetInAt(0, Location::Any());
2377c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  locations->SetOut(Location::RequiresRegister());
2378c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik}
2379c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2380a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bikstatic void GenBitCount(X86Assembler* assembler,
2381a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik                        CodeGeneratorX86* codegen,
2382a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik                        HInvoke* invoke, bool is_long) {
2383c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  LocationSummary* locations = invoke->GetLocations();
2384c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  Location src = locations->InAt(0);
2385c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  Register out = locations->Out().AsRegister<Register>();
2386c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2387c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  if (invoke->InputAt(0)->IsConstant()) {
2388c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    // Evaluate this at compile time.
2389c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
2390fa3912edfac60a9f0a9b95a5862c7361b403fcc2Roland Levillain    int32_t result = is_long
2391c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik        ? POPCOUNT(static_cast<uint64_t>(value))
2392c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik        : POPCOUNT(static_cast<uint32_t>(value));
2393fa3912edfac60a9f0a9b95a5862c7361b403fcc2Roland Levillain    codegen->Load32BitValue(out, result);
2394c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    return;
2395c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  }
2396c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2397c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  // Handle the non-constant cases.
2398c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  if (!is_long) {
2399c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    if (src.IsRegister()) {
2400c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik      __ popcntl(out, src.AsRegister<Register>());
2401c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    } else {
2402c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik      DCHECK(src.IsStackSlot());
2403c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik      __ popcntl(out, Address(ESP, src.GetStackIndex()));
2404c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik    }
24052a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik  } else {
24062a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik    // The 64-bit case needs to worry about two parts.
24072a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik    Register temp = locations->GetTemp(0).AsRegister<Register>();
24082a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik    if (src.IsRegisterPair()) {
24092a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik      __ popcntl(temp, src.AsRegisterPairLow<Register>());
24102a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik      __ popcntl(out, src.AsRegisterPairHigh<Register>());
24112a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik    } else {
24122a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik      DCHECK(src.IsDoubleStackSlot());
24132a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik      __ popcntl(temp, Address(ESP, src.GetStackIndex()));
24142a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik      __ popcntl(out, Address(ESP, src.GetHighStackIndex(kX86WordSize)));
24152a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik    }
24162a946077daf5bfcaf613da49bed58bb0aba435bfAart Bik    __ addl(out, temp);
2417c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  }
2418c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik}
2419c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2420c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bikvoid IntrinsicLocationsBuilderX86::VisitIntegerBitCount(HInvoke* invoke) {
2421c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  CreateBitCountLocations(arena_, codegen_, invoke, /* is_long */ false);
2422c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik}
2423c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2424c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bikvoid IntrinsicCodeGeneratorX86::VisitIntegerBitCount(HInvoke* invoke) {
2425a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ false);
2426c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik}
2427c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2428c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bikvoid IntrinsicLocationsBuilderX86::VisitLongBitCount(HInvoke* invoke) {
2429c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik  CreateBitCountLocations(arena_, codegen_, invoke, /* is_long */ true);
2430c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik}
2431c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2432c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bikvoid IntrinsicCodeGeneratorX86::VisitLongBitCount(HInvoke* invoke) {
2433a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ true);
2434c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik}
2435c39dac148cce137ffd78a8e43499fba10c5c79e0Aart Bik
2436d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendellstatic void CreateLeadingZeroLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_long) {
2437d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
2438d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell                                                           LocationSummary::kNoCall,
2439d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell                                                           kIntrinsified);
2440d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  if (is_long) {
2441d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    locations->SetInAt(0, Location::RequiresRegister());
2442d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  } else {
2443d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    locations->SetInAt(0, Location::Any());
2444d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  }
2445d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  locations->SetOut(Location::RequiresRegister());
2446d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell}
2447d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2448a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bikstatic void GenLeadingZeros(X86Assembler* assembler,
2449a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik                            CodeGeneratorX86* codegen,
2450a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik                            HInvoke* invoke, bool is_long) {
2451d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  LocationSummary* locations = invoke->GetLocations();
2452d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  Location src = locations->InAt(0);
2453d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  Register out = locations->Out().AsRegister<Register>();
2454d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2455d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  if (invoke->InputAt(0)->IsConstant()) {
2456d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    // Evaluate this at compile time.
2457d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
2458d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    if (value == 0) {
2459d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell      value = is_long ? 64 : 32;
2460d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    } else {
2461d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell      value = is_long ? CLZ(static_cast<uint64_t>(value)) : CLZ(static_cast<uint32_t>(value));
2462d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    }
2463a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik    codegen->Load32BitValue(out, value);
2464d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    return;
2465d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  }
2466d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2467d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // Handle the non-constant cases.
2468d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  if (!is_long) {
2469d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    if (src.IsRegister()) {
2470d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell      __ bsrl(out, src.AsRegister<Register>());
2471d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    } else {
2472d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell      DCHECK(src.IsStackSlot());
2473d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell      __ bsrl(out, Address(ESP, src.GetStackIndex()));
2474d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    }
2475d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2476d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    // BSR sets ZF if the input was zero, and the output is undefined.
24770c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell    NearLabel all_zeroes, done;
2478d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    __ j(kEqual, &all_zeroes);
2479d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2480d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    // Correct the result from BSR to get the final CLZ result.
2481d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    __ xorl(out, Immediate(31));
2482d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    __ jmp(&done);
2483d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2484d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    // Fix the zero case with the expected result.
2485d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    __ Bind(&all_zeroes);
2486d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    __ movl(out, Immediate(32));
2487d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2488d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    __ Bind(&done);
2489d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell    return;
2490d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  }
2491d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2492d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // 64 bit case needs to worry about both parts of the register.
2493d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  DCHECK(src.IsRegisterPair());
2494d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  Register src_lo = src.AsRegisterPairLow<Register>();
2495d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  Register src_hi = src.AsRegisterPairHigh<Register>();
24960c9497da9485ba688c592e5f452b7b1305a519c0Mark Mendell  NearLabel handle_low, done, all_zeroes;
2497d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2498d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // Is the high word zero?
2499d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ testl(src_hi, src_hi);
2500d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ j(kEqual, &handle_low);
2501d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2502d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // High word is not zero. We know that the BSR result is defined in this case.
2503d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ bsrl(out, src_hi);
2504d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2505d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // Correct the result from BSR to get the final CLZ result.
2506d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ xorl(out, Immediate(31));
2507d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ jmp(&done);
2508d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2509d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // High word was zero.  We have to compute the low word count and add 32.
2510d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ Bind(&handle_low);
2511d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ bsrl(out, src_lo);
2512d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ j(kEqual, &all_zeroes);
2513d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2514d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // We had a valid result.  Use an XOR to both correct the result and add 32.
2515d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ xorl(out, Immediate(63));
2516d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ jmp(&done);
2517d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2518d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  // All zero case.
2519d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ Bind(&all_zeroes);
2520d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ movl(out, Immediate(64));
2521d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2522d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  __ Bind(&done);
2523d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell}
2524d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2525d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
2526d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  CreateLeadingZeroLocations(arena_, invoke, /* is_long */ false);
2527d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell}
2528d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2529d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
2530a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false);
2531d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell}
2532d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2533d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
2534d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell  CreateLeadingZeroLocations(arena_, invoke, /* is_long */ true);
2535d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell}
2536d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
2537d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
2538a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
2539d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell}
2540d5897678eb555a797d4e84e07814d79f0e0bb465Mark Mendell
25412d554795420be0be88bb4600ea81d1ec293217c4Mark Mendellstatic void CreateTrailingZeroLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_long) {
25422d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  LocationSummary* locations = new (arena) LocationSummary(invoke,
25432d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell                                                           LocationSummary::kNoCall,
25442d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell                                                           kIntrinsified);
25452d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  if (is_long) {
25462d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    locations->SetInAt(0, Location::RequiresRegister());
25472d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  } else {
25482d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    locations->SetInAt(0, Location::Any());
25492d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  }
25502d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  locations->SetOut(Location::RequiresRegister());
25512d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell}
25522d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
2553a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bikstatic void GenTrailingZeros(X86Assembler* assembler,
2554a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik                             CodeGeneratorX86* codegen,
2555a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik                             HInvoke* invoke, bool is_long) {
25562d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  LocationSummary* locations = invoke->GetLocations();
25572d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  Location src = locations->InAt(0);
25582d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  Register out = locations->Out().AsRegister<Register>();
25592d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
25602d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  if (invoke->InputAt(0)->IsConstant()) {
25612d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    // Evaluate this at compile time.
25622d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
25632d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    if (value == 0) {
25642d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell      value = is_long ? 64 : 32;
25652d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    } else {
25662d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell      value = is_long ? CTZ(static_cast<uint64_t>(value)) : CTZ(static_cast<uint32_t>(value));
25672d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    }
2568a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik    codegen->Load32BitValue(out, value);
25692d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    return;
25702d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  }
25712d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
25722d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  // Handle the non-constant cases.
25732d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  if (!is_long) {
25742d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    if (src.IsRegister()) {
25752d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell      __ bsfl(out, src.AsRegister<Register>());
25762d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    } else {
25772d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell      DCHECK(src.IsStackSlot());
25782d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell      __ bsfl(out, Address(ESP, src.GetStackIndex()));
25792d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    }
25802d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
25812d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    // BSF sets ZF if the input was zero, and the output is undefined.
25822d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    NearLabel done;
25832d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    __ j(kNotEqual, &done);
25842d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
25852d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    // Fix the zero case with the expected result.
25862d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    __ movl(out, Immediate(32));
25872d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
25882d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    __ Bind(&done);
25892d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell    return;
25902d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  }
25912d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
25922d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  // 64 bit case needs to worry about both parts of the register.
25932d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  DCHECK(src.IsRegisterPair());
25942d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  Register src_lo = src.AsRegisterPairLow<Register>();
25952d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  Register src_hi = src.AsRegisterPairHigh<Register>();
25962d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  NearLabel done, all_zeroes;
25972d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
25982d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  // If the low word is zero, then ZF will be set.  If not, we have the answer.
25992d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ bsfl(out, src_lo);
26002d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ j(kNotEqual, &done);
26012d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26022d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  // Low word was zero.  We have to compute the high word count and add 32.
26032d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ bsfl(out, src_hi);
26042d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ j(kEqual, &all_zeroes);
26052d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26062d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  // We had a valid result.  Add 32 to account for the low word being zero.
26072d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ addl(out, Immediate(32));
26082d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ jmp(&done);
26092d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26102d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  // All zero case.
26112d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ Bind(&all_zeroes);
26122d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ movl(out, Immediate(64));
26132d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26142d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  __ Bind(&done);
26152d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell}
26162d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26172d554795420be0be88bb4600ea81d1ec293217c4Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
26182d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  CreateTrailingZeroLocations(arena_, invoke, /* is_long */ false);
26192d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell}
26202d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26212d554795420be0be88bb4600ea81d1ec293217c4Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
2622a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false);
26232d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell}
26242d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26252d554795420be0be88bb4600ea81d1ec293217c4Mark Mendellvoid IntrinsicLocationsBuilderX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
26262d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell  CreateTrailingZeroLocations(arena_, invoke, /* is_long */ true);
26272d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell}
26282d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26292d554795420be0be88bb4600ea81d1ec293217c4Mark Mendellvoid IntrinsicCodeGeneratorX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
2630a19616e3363276e7f2c471eb2839fb16f1d43f27Aart Bik  GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
26312d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell}
26322d554795420be0be88bb4600ea81d1ec293217c4Mark Mendell
26332f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, MathRoundDouble)
26342f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, ReferenceGetReferent)
26352f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, SystemArrayCopy)
26362f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, FloatIsInfinite)
26372f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, DoubleIsInfinite)
26382f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, IntegerHighestOneBit)
26392f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit)
26402f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, IntegerLowestOneBit)
26412f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNIMPLEMENTED_INTRINSIC(X86, LongLowestOneBit)
26422f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart Bik
26430e54c0160c84894696c05af6cad9eae3690f9496Aart Bik// 1.8.
26440e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndAddInt)
26450e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndAddLong)
26460e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetInt)
26470e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetLong)
26480e54c0160c84894696c05af6cad9eae3690f9496Aart BikUNIMPLEMENTED_INTRINSIC(X86, UnsafeGetAndSetObject)
26490e54c0160c84894696c05af6cad9eae3690f9496Aart Bik
26502f9fcc999fab4ba6cd86c30e664325b47b9618e5Aart BikUNREACHABLE_INTRINSICS(X86)
26514d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain
26524d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain#undef __
26534d02711ea578dbb789abb30cbaf12f9926e13d81Roland Levillain
265409ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}  // namespace x86
265509ed1a3125849ec6ac07cb886e3c502e1dcfada2Mark Mendell}  // namespace art
2656