// Copyright 2013 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#if V8_TARGET_ARCH_ARM64
#include "src/arm64/delayed-masm-arm64.h"
#include "src/arm64/lithium-codegen-arm64.h"
namespace v8 {
namespace internal {
#define __ ACCESS_MASM(masm_)
void DelayedMasm::StackSlotMove(LOperand* src, LOperand* dst) {
DCHECK(src->IsStackSlot());
DCHECK(dst->IsStackSlot());
MemOperand src_operand = cgen_->ToMemOperand(src);
MemOperand dst_operand = cgen_->ToMemOperand(dst);
if (pending_ == kStackSlotMove) {
DCHECK(pending_pc_ == masm_->pc_offset());
UseScratchRegisterScope scope(masm_);
DoubleRegister temp1 = scope.AcquireD();
DoubleRegister temp2 = scope.AcquireD();
switch (MemOperand::AreConsistentForPair(pending_address_src_,
src_operand)) {
case MemOperand::kNotPair:
__ Ldr(temp1, pending_address_src_);
__ Ldr(temp2, src_operand);
break;
case MemOperand::kPairAB:
__ Ldp(temp1, temp2, pending_address_src_);
break;
case MemOperand::kPairBA:
__ Ldp(temp2, temp1, src_operand);
break;
}
switch (MemOperand::AreConsistentForPair(pending_address_dst_,
dst_operand)) {
case MemOperand::kNotPair:
__ Str(temp1, pending_address_dst_);
__ Str(temp2, dst_operand);
break;
case MemOperand::kPairAB:
__ Stp(temp1, temp2, pending_address_dst_);
break;
case MemOperand::kPairBA:
__ Stp(temp2, temp1, dst_operand);
break;
}
ResetPending();
return;
}
EmitPending();
pending_ = kStackSlotMove;
pending_address_src_ = src_operand;
pending_address_dst_ = dst_operand;
#ifdef DEBUG
pending_pc_ = masm_->pc_offset();
#endif
}
void DelayedMasm::StoreConstant(uint64_t value, const MemOperand& operand) {
DCHECK(!scratch_register_acquired_);
if ((pending_ == kStoreConstant) && (value == pending_value_)) {
MemOperand::PairResult result =
MemOperand::AreConsistentForPair(pending_address_dst_, operand);
if (result != MemOperand::kNotPair) {
const MemOperand& dst =
(result == MemOperand::kPairAB) ?
pending_address_dst_ :
operand;
DCHECK(pending_pc_ == masm_->pc_offset());
if (pending_value_ == 0) {
__ Stp(xzr, xzr, dst);
} else {
SetSavedValue(pending_value_);
__ Stp(ScratchRegister(), ScratchRegister(), dst);
}
ResetPending();
return;
}
}
EmitPending();
pending_ = kStoreConstant;
pending_address_dst_ = operand;
pending_value_ = value;
#ifdef DEBUG
pending_pc_ = masm_->pc_offset();
#endif
}
void DelayedMasm::Load(const CPURegister& rd, const MemOperand& operand) {
if ((pending_ == kLoad) &&
pending_register_.IsSameSizeAndType(rd)) {
switch (MemOperand::AreConsistentForPair(pending_address_src_, operand)) {
case MemOperand::kNotPair:
break;
case MemOperand::kPairAB:
DCHECK(pending_pc_ == masm_->pc_offset());
DCHECK(!IsScratchRegister(pending_register_) ||
scratch_register_acquired_);
DCHECK(!IsScratchRegister(rd) || scratch_register_acquired_);
__ Ldp(pending_register_, rd, pending_address_src_);
ResetPending();
return;
case MemOperand::kPairBA:
DCHECK(pending_pc_ == masm_->pc_offset());
DCHECK(!IsScratchRegister(pending_register_) ||
scratch_register_acquired_);
DCHECK(!IsScratchRegister(rd) || scratch_register_acquired_);
__ Ldp(rd, pending_register_, operand);
ResetPending();
return;
}
}
EmitPending();
pending_ = kLoad;
pending_register_ = rd;
pending_address_src_ = operand;
#ifdef DEBUG
pending_pc_ = masm_->pc_offset();
#endif
}
void DelayedMasm::Store(const CPURegister& rd, const MemOperand& operand) {
if ((pending_ == kStore) &&
pending_register_.IsSameSizeAndType(rd)) {
switch (MemOperand::AreConsistentForPair(pending_address_dst_, operand)) {
case MemOperand::kNotPair:
break;
case MemOperand::kPairAB:
DCHECK(pending_pc_ == masm_->pc_offset());
__ Stp(pending_register_, rd, pending_address_dst_);
ResetPending();
return;
case MemOperand::kPairBA:
DCHECK(pending_pc_ == masm_->pc_offset());
__ Stp(rd, pending_register_, operand);
ResetPending();
return;
}
}
EmitPending();
pending_ = kStore;
pending_register_ = rd;
pending_address_dst_ = operand;
#ifdef DEBUG
pending_pc_ = masm_->pc_offset();
#endif
}
void DelayedMasm::EmitPending() {
DCHECK((pending_ == kNone) || (pending_pc_ == masm_->pc_offset()));
switch (pending_) {
case kNone:
return;
case kStoreConstant:
if (pending_value_ == 0) {
__ Str(xzr, pending_address_dst_);
} else {
SetSavedValue(pending_value_);
__ Str(ScratchRegister(), pending_address_dst_);
}
break;
case kLoad:
DCHECK(!IsScratchRegister(pending_register_) ||
scratch_register_acquired_);
__ Ldr(pending_register_, pending_address_src_);
break;
case kStore:
__ Str(pending_register_, pending_address_dst_);
break;
case kStackSlotMove: {
UseScratchRegisterScope scope(masm_);
DoubleRegister temp = scope.AcquireD();
__ Ldr(temp, pending_address_src_);
__ Str(temp, pending_address_dst_);
break;
}
}
ResetPending();
}
} } // namespace v8::internal
#endif // V8_TARGET_ARCH_ARM64