| Index: src/arm64/delayed-masm-arm64.h
|
| diff --git a/src/arm64/delayed-masm-arm64.h b/src/arm64/delayed-masm-arm64.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a8782c3dd7a5f832603ceb24e17dc37275e2a06c
|
| --- /dev/null
|
| +++ b/src/arm64/delayed-masm-arm64.h
|
| @@ -0,0 +1,164 @@
|
| +// 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.
|
| +
|
| +#ifndef V8_ARM64_DELAYED_MASM_ARM64_H_
|
| +#define V8_ARM64_DELAYED_MASM_ARM64_H_
|
| +
|
| +#include "src/lithium.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +
|
| +class LCodeGen;
|
| +
|
| +// This class delays the generation of some instructions. This way, we have a
|
| +// chance to merge two instructions in one (with load/store pair).
|
| +// Each instruction must either:
|
| +// - merge with the pending instruction and generate just one instruction.
|
| +// - emit the pending instruction and then generate the instruction (or set the
|
| +// pending instruction).
|
| +class DelayedMasm BASE_EMBEDDED {
|
| + public:
|
| + DelayedMasm(LCodeGen* owner,
|
| + MacroAssembler* masm,
|
| + const Register& scratch_register)
|
| + : cgen_(owner), masm_(masm), scratch_register_(scratch_register),
|
| + scratch_register_used_(false), pending_(kNone), saved_value_(0) {
|
| +#ifdef DEBUG
|
| + pending_register_ = no_reg;
|
| + pending_value_ = 0;
|
| + pending_pc_ = 0;
|
| + scratch_register_acquired_ = false;
|
| +#endif
|
| + }
|
| + ~DelayedMasm() {
|
| + ASSERT(!scratch_register_acquired_);
|
| + ASSERT(!scratch_register_used_);
|
| + ASSERT(!pending());
|
| + }
|
| + inline void EndDelayedUse();
|
| +
|
| + const Register& ScratchRegister() {
|
| + scratch_register_used_ = true;
|
| + return scratch_register_;
|
| + }
|
| + bool IsScratchRegister(const CPURegister& reg) {
|
| + return reg.Is(scratch_register_);
|
| + }
|
| + bool scratch_register_used() const { return scratch_register_used_; }
|
| + void reset_scratch_register_used() { scratch_register_used_ = false; }
|
| + // Acquire/Release scratch register for use outside this class.
|
| + void AcquireScratchRegister() {
|
| + EmitPending();
|
| + ResetSavedValue();
|
| +#ifdef DEBUG
|
| + ASSERT(!scratch_register_acquired_);
|
| + scratch_register_acquired_ = true;
|
| +#endif
|
| + }
|
| + void ReleaseScratchRegister() {
|
| +#ifdef DEBUG
|
| + ASSERT(scratch_register_acquired_);
|
| + scratch_register_acquired_ = false;
|
| +#endif
|
| + }
|
| + bool pending() { return pending_ != kNone; }
|
| +
|
| + // Extra layer over the macro-assembler instructions (which emits the
|
| + // potential pending instruction).
|
| + inline void Mov(const Register& rd,
|
| + const Operand& operand,
|
| + DiscardMoveMode discard_mode = kDontDiscardForSameWReg);
|
| + inline void Fmov(FPRegister fd, FPRegister fn);
|
| + inline void Fmov(FPRegister fd, double imm);
|
| + inline void LoadObject(Register result, Handle<Object> object);
|
| + // Instructions which try to merge which the pending instructions.
|
| + void StackSlotMove(LOperand* src, LOperand* dst);
|
| + // StoreConstant can only be used if the scratch register is not acquired.
|
| + void StoreConstant(uint64_t value, const MemOperand& operand);
|
| + void Load(const CPURegister& rd, const MemOperand& operand);
|
| + void Store(const CPURegister& rd, const MemOperand& operand);
|
| + // Emit the potential pending instruction.
|
| + void EmitPending();
|
| + // Reset the pending state.
|
| + void ResetPending() {
|
| + pending_ = kNone;
|
| +#ifdef DEBUG
|
| + pending_register_ = no_reg;
|
| + MemOperand tmp;
|
| + pending_address_src_ = tmp;
|
| + pending_address_dst_ = tmp;
|
| + pending_value_ = 0;
|
| + pending_pc_ = 0;
|
| +#endif
|
| + }
|
| + void InitializeRootRegister() {
|
| + masm_->InitializeRootRegister();
|
| + }
|
| +
|
| + private:
|
| + // Set the saved value and load the ScratchRegister with it.
|
| + void SetSavedValue(uint64_t saved_value) {
|
| + ASSERT(saved_value != 0);
|
| + if (saved_value_ != saved_value) {
|
| + masm_->Mov(ScratchRegister(), saved_value);
|
| + saved_value_ = saved_value;
|
| + }
|
| + }
|
| + // Reset the saved value (i.e. the value of ScratchRegister is no longer
|
| + // known).
|
| + void ResetSavedValue() {
|
| + saved_value_ = 0;
|
| + }
|
| +
|
| + LCodeGen* cgen_;
|
| + MacroAssembler* masm_;
|
| +
|
| + // Register used to store a constant.
|
| + Register scratch_register_;
|
| + bool scratch_register_used_;
|
| +
|
| + // Sometimes we store or load two values in two contiguous stack slots.
|
| + // In this case, we try to use the ldp/stp instructions to reduce code size.
|
| + // To be able to do that, instead of generating directly the instructions,
|
| + // we register with the following fields that an instruction needs to be
|
| + // generated. Then with the next instruction, if the instruction is
|
| + // consistent with the pending one for stp/ldp we generate ldp/stp. Else,
|
| + // if they are not consistent, we generate the pending instruction and we
|
| + // register the new instruction (which becomes pending).
|
| +
|
| + // Enumeration of instructions which can be pending.
|
| + enum Pending {
|
| + kNone,
|
| + kStoreConstant,
|
| + kLoad, kStore,
|
| + kStackSlotMove
|
| + };
|
| + // The pending instruction.
|
| + Pending pending_;
|
| + // For kLoad, kStore: register which must be loaded/stored.
|
| + CPURegister pending_register_;
|
| + // For kLoad, kStackSlotMove: address of the load.
|
| + MemOperand pending_address_src_;
|
| + // For kStoreConstant, kStore, kStackSlotMove: address of the store.
|
| + MemOperand pending_address_dst_;
|
| + // For kStoreConstant: value to be stored.
|
| + uint64_t pending_value_;
|
| + // Value held into the ScratchRegister if the saved_value_ is not 0.
|
| + // For 0, we use xzr.
|
| + uint64_t saved_value_;
|
| +#ifdef DEBUG
|
| + // Address where the pending instruction must be generated. It's only used to
|
| + // check that nothing else has been generated since we set the pending
|
| + // instruction.
|
| + int pending_pc_;
|
| + // If true, the scratch register has been acquired outside this class. The
|
| + // scratch register can no longer be used for constants.
|
| + bool scratch_register_acquired_;
|
| +#endif
|
| +};
|
| +
|
| +} } // namespace v8::internal
|
| +
|
| +#endif // V8_ARM64_DELAYED_MASM_ARM64_H_
|
|
|