blob: 885f10f3441e9159c5a6a24063d0de5480adfdcb [file] [log] [blame]
// Copyright 2016 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_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
#define V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
#include "src/base/compiler-specific.h"
#include "src/globals.h"
#include "src/interpreter/bytecode-pipeline.h"
namespace v8 {
namespace internal {
namespace interpreter {
// An optimization stage for eliminating unnecessary transfers between
// registers. The bytecode generator uses temporary registers
// liberally for correctness and convenience and this stage removes
// transfers that are not required and preserves correctness.
class V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
: public NON_EXPORTED_BASE(BytecodeRegisterAllocator::Observer),
public NON_EXPORTED_BASE(ZoneObject) {
public:
BytecodeRegisterOptimizer(Zone* zone,
BytecodeRegisterAllocator* register_allocator,
int fixed_registers_count, int parameter_count,
BytecodePipelineStage* next_stage);
virtual ~BytecodeRegisterOptimizer() {}
// Perform explicit register transfer operations.
void DoLdar(Register input, BytecodeSourceInfo source_info) {
RegisterInfo* input_info = GetRegisterInfo(input);
RegisterTransfer(input_info, accumulator_info_, source_info);
}
void DoStar(Register output, BytecodeSourceInfo source_info) {
RegisterInfo* output_info = GetRegisterInfo(output);
RegisterTransfer(accumulator_info_, output_info, source_info);
}
void DoMov(Register input, Register output, BytecodeSourceInfo source_info) {
RegisterInfo* input_info = GetRegisterInfo(input);
RegisterInfo* output_info = GetRegisterInfo(output);
RegisterTransfer(input_info, output_info, source_info);
}
// Materialize all live registers and flush equivalence sets.
void Flush();
// Prepares for |bytecode|.
void PrepareForBytecode(Bytecode bytecode);
// Prepares |reg| for being used as an output operand.
void PrepareOutputRegister(Register reg);
// Prepares registers in |reg_list| for being used as an output operand.
void PrepareOutputRegisterList(RegisterList reg_list);
// Returns an equivalent register to |reg| to be used as an input operand.
Register GetInputRegister(Register reg);
// Returns an equivalent register list to |reg_list| to be used as an input
// operand.
RegisterList GetInputRegisterList(RegisterList reg_list);
int maxiumum_register_index() const { return max_register_index_; }
private:
static const uint32_t kInvalidEquivalenceId;
class RegisterInfo;
// BytecodeRegisterAllocator::Observer interface.
void RegisterAllocateEvent(Register reg) override;
void RegisterListAllocateEvent(RegisterList reg_list) override;
void RegisterListFreeEvent(RegisterList reg) override;
// Update internal state for register transfer from |input| to
// |output| using |source_info| as source position information if
// any bytecodes are emitted due to transfer.
void RegisterTransfer(RegisterInfo* input, RegisterInfo* output,
BytecodeSourceInfo source_info);
// Emit a register transfer bytecode from |input| to |output|.
void OutputRegisterTransfer(
RegisterInfo* input, RegisterInfo* output,
BytecodeSourceInfo source_info = BytecodeSourceInfo());
// Emits a Nop to preserve source position information in the
// bytecode pipeline.
void EmitNopForSourceInfo(BytecodeSourceInfo source_info) const;
void CreateMaterializedEquivalent(RegisterInfo* info);
RegisterInfo* GetMaterializedEquivalent(RegisterInfo* info);
RegisterInfo* GetMaterializedEquivalentNotAccumulator(RegisterInfo* info);
void Materialize(RegisterInfo* info);
void AddToEquivalenceSet(RegisterInfo* set_member,
RegisterInfo* non_set_member);
// Methods for finding and creating metadata for each register.
RegisterInfo* GetRegisterInfo(Register reg) {
size_t index = GetRegisterInfoTableIndex(reg);
DCHECK_LT(index, register_info_table_.size());
return register_info_table_[index];
}
RegisterInfo* GetOrCreateRegisterInfo(Register reg) {
size_t index = GetRegisterInfoTableIndex(reg);
return index < register_info_table_.size() ? register_info_table_[index]
: NewRegisterInfo(reg);
}
RegisterInfo* NewRegisterInfo(Register reg) {
size_t index = GetRegisterInfoTableIndex(reg);
DCHECK_GE(index, register_info_table_.size());
GrowRegisterMap(reg);
return register_info_table_[index];
}
void GrowRegisterMap(Register reg);
bool RegisterIsTemporary(Register reg) const {
return reg >= temporary_base_;
}
bool RegisterIsObservable(Register reg) const {
return reg != accumulator_ && !RegisterIsTemporary(reg);
}
static Register OperandToRegister(uint32_t operand) {
return Register::FromOperand(static_cast<int32_t>(operand));
}
size_t GetRegisterInfoTableIndex(Register reg) const {
return static_cast<size_t>(reg.index() + register_info_table_offset_);
}
Register RegisterFromRegisterInfoTableIndex(size_t index) const {
return Register(static_cast<int>(index) - register_info_table_offset_);
}
uint32_t NextEquivalenceId() {
equivalence_id_++;
CHECK_NE(equivalence_id_, kInvalidEquivalenceId);
return equivalence_id_;
}
Zone* zone() { return zone_; }
const Register accumulator_;
RegisterInfo* accumulator_info_;
const Register temporary_base_;
int max_register_index_;
// Direct mapping to register info.
ZoneVector<RegisterInfo*> register_info_table_;
int register_info_table_offset_;
// Counter for equivalence sets identifiers.
int equivalence_id_;
BytecodePipelineStage* next_stage_;
bool flush_required_;
Zone* zone_;
DISALLOW_COPY_AND_ASSIGN(BytecodeRegisterOptimizer);
};
} // namespace interpreter
} // namespace internal
} // namespace v8
#endif // V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_