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, ¬_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, ¬_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, ¬_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(¬_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