11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#ifndef V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
61cb0ef41Sopenharmony_ci#define V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci#include "src/base/compiler-specific.h"
91cb0ef41Sopenharmony_ci#include "src/common/globals.h"
101cb0ef41Sopenharmony_ci#include "src/interpreter/bytecode-register-allocator.h"
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cinamespace v8 {
131cb0ef41Sopenharmony_cinamespace internal {
141cb0ef41Sopenharmony_cinamespace interpreter {
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci// An optimization stage for eliminating unnecessary transfers between
171cb0ef41Sopenharmony_ci// registers. The bytecode generator uses temporary registers
181cb0ef41Sopenharmony_ci// liberally for correctness and convenience and this stage removes
191cb0ef41Sopenharmony_ci// transfers that are not required and preserves correctness.
201cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE BytecodeRegisterOptimizer final
211cb0ef41Sopenharmony_ci    : public NON_EXPORTED_BASE(BytecodeRegisterAllocator::Observer),
221cb0ef41Sopenharmony_ci      public NON_EXPORTED_BASE(ZoneObject) {
231cb0ef41Sopenharmony_ci public:
241cb0ef41Sopenharmony_ci  class BytecodeWriter {
251cb0ef41Sopenharmony_ci   public:
261cb0ef41Sopenharmony_ci    BytecodeWriter() = default;
271cb0ef41Sopenharmony_ci    virtual ~BytecodeWriter() = default;
281cb0ef41Sopenharmony_ci    BytecodeWriter(const BytecodeWriter&) = delete;
291cb0ef41Sopenharmony_ci    BytecodeWriter& operator=(const BytecodeWriter&) = delete;
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci    // Called to emit a register transfer bytecode.
321cb0ef41Sopenharmony_ci    virtual void EmitLdar(Register input) = 0;
331cb0ef41Sopenharmony_ci    virtual void EmitStar(Register output) = 0;
341cb0ef41Sopenharmony_ci    virtual void EmitMov(Register input, Register output) = 0;
351cb0ef41Sopenharmony_ci  };
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci  BytecodeRegisterOptimizer(Zone* zone,
381cb0ef41Sopenharmony_ci                            BytecodeRegisterAllocator* register_allocator,
391cb0ef41Sopenharmony_ci                            int fixed_registers_count, int parameter_count,
401cb0ef41Sopenharmony_ci                            BytecodeWriter* bytecode_writer);
411cb0ef41Sopenharmony_ci  ~BytecodeRegisterOptimizer() override = default;
421cb0ef41Sopenharmony_ci  BytecodeRegisterOptimizer(const BytecodeRegisterOptimizer&) = delete;
431cb0ef41Sopenharmony_ci  BytecodeRegisterOptimizer& operator=(const BytecodeRegisterOptimizer&) =
441cb0ef41Sopenharmony_ci      delete;
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  // Perform explicit register transfer operations.
471cb0ef41Sopenharmony_ci  void DoLdar(Register input) {
481cb0ef41Sopenharmony_ci    // TODO(rmcilroy): Avoid treating accumulator loads as clobbering the
491cb0ef41Sopenharmony_ci    // accumulator until the value is actually materialized in the accumulator.
501cb0ef41Sopenharmony_ci    RegisterInfo* input_info = GetRegisterInfo(input);
511cb0ef41Sopenharmony_ci    RegisterTransfer(input_info, accumulator_info_);
521cb0ef41Sopenharmony_ci  }
531cb0ef41Sopenharmony_ci  void DoStar(Register output) {
541cb0ef41Sopenharmony_ci    RegisterInfo* output_info = GetRegisterInfo(output);
551cb0ef41Sopenharmony_ci    RegisterTransfer(accumulator_info_, output_info);
561cb0ef41Sopenharmony_ci  }
571cb0ef41Sopenharmony_ci  void DoMov(Register input, Register output) {
581cb0ef41Sopenharmony_ci    RegisterInfo* input_info = GetRegisterInfo(input);
591cb0ef41Sopenharmony_ci    RegisterInfo* output_info = GetRegisterInfo(output);
601cb0ef41Sopenharmony_ci    RegisterTransfer(input_info, output_info);
611cb0ef41Sopenharmony_ci  }
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  // Materialize all live registers and flush equivalence sets.
641cb0ef41Sopenharmony_ci  void Flush();
651cb0ef41Sopenharmony_ci  bool EnsureAllRegistersAreFlushed() const;
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  // Prepares for |bytecode|.
681cb0ef41Sopenharmony_ci  template <Bytecode bytecode, ImplicitRegisterUse implicit_register_use>
691cb0ef41Sopenharmony_ci  V8_INLINE void PrepareForBytecode() {
701cb0ef41Sopenharmony_ci    if (Bytecodes::IsJump(bytecode) || Bytecodes::IsSwitch(bytecode) ||
711cb0ef41Sopenharmony_ci        bytecode == Bytecode::kDebugger ||
721cb0ef41Sopenharmony_ci        bytecode == Bytecode::kSuspendGenerator ||
731cb0ef41Sopenharmony_ci        bytecode == Bytecode::kResumeGenerator) {
741cb0ef41Sopenharmony_ci      // All state must be flushed before emitting
751cb0ef41Sopenharmony_ci      // - a jump bytecode (as the register equivalents at the jump target
761cb0ef41Sopenharmony_ci      //   aren't known)
771cb0ef41Sopenharmony_ci      // - a switch bytecode (as the register equivalents at the switch targets
781cb0ef41Sopenharmony_ci      //   aren't known)
791cb0ef41Sopenharmony_ci      // - a call to the debugger (as it can manipulate locals and parameters),
801cb0ef41Sopenharmony_ci      // - a generator suspend (as this involves saving all registers).
811cb0ef41Sopenharmony_ci      // - a generator register restore.
821cb0ef41Sopenharmony_ci      Flush();
831cb0ef41Sopenharmony_ci    }
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    // Materialize the accumulator if it is read by the bytecode. The
861cb0ef41Sopenharmony_ci    // accumulator is special and no other register can be materialized
871cb0ef41Sopenharmony_ci    // in it's place.
881cb0ef41Sopenharmony_ci    if (BytecodeOperands::ReadsAccumulator(implicit_register_use)) {
891cb0ef41Sopenharmony_ci      Materialize(accumulator_info_);
901cb0ef41Sopenharmony_ci    }
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci    // Materialize an equivalent to the accumulator if it will be
931cb0ef41Sopenharmony_ci    // clobbered when the bytecode is dispatched.
941cb0ef41Sopenharmony_ci    if (BytecodeOperands::WritesAccumulator(implicit_register_use)) {
951cb0ef41Sopenharmony_ci      PrepareOutputRegister(accumulator_);
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ci  // Prepares |reg| for being used as an output operand.
1001cb0ef41Sopenharmony_ci  void PrepareOutputRegister(Register reg);
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  // Prepares registers in |reg_list| for being used as an output operand.
1031cb0ef41Sopenharmony_ci  void PrepareOutputRegisterList(RegisterList reg_list);
1041cb0ef41Sopenharmony_ci
1051cb0ef41Sopenharmony_ci  // Returns an equivalent register to |reg| to be used as an input operand.
1061cb0ef41Sopenharmony_ci  Register GetInputRegister(Register reg);
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci  // Returns an equivalent register list to |reg_list| to be used as an input
1091cb0ef41Sopenharmony_ci  // operand.
1101cb0ef41Sopenharmony_ci  RegisterList GetInputRegisterList(RegisterList reg_list);
1111cb0ef41Sopenharmony_ci
1121cb0ef41Sopenharmony_ci  int maxiumum_register_index() const { return max_register_index_; }
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci private:
1151cb0ef41Sopenharmony_ci  static const uint32_t kInvalidEquivalenceId;
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  class RegisterInfo;
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  // BytecodeRegisterAllocator::Observer interface.
1201cb0ef41Sopenharmony_ci  void RegisterAllocateEvent(Register reg) override;
1211cb0ef41Sopenharmony_ci  void RegisterListAllocateEvent(RegisterList reg_list) override;
1221cb0ef41Sopenharmony_ci  void RegisterListFreeEvent(RegisterList reg) override;
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci  // Update internal state for register transfer from |input| to |output|
1251cb0ef41Sopenharmony_ci  void RegisterTransfer(RegisterInfo* input, RegisterInfo* output);
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci  // Emit a register transfer bytecode from |input| to |output|.
1281cb0ef41Sopenharmony_ci  void OutputRegisterTransfer(RegisterInfo* input, RegisterInfo* output);
1291cb0ef41Sopenharmony_ci
1301cb0ef41Sopenharmony_ci  void CreateMaterializedEquivalent(RegisterInfo* info);
1311cb0ef41Sopenharmony_ci  RegisterInfo* GetMaterializedEquivalent(RegisterInfo* info);
1321cb0ef41Sopenharmony_ci  RegisterInfo* GetMaterializedEquivalentNotAccumulator(RegisterInfo* info);
1331cb0ef41Sopenharmony_ci  void Materialize(RegisterInfo* info);
1341cb0ef41Sopenharmony_ci  void AddToEquivalenceSet(RegisterInfo* set_member,
1351cb0ef41Sopenharmony_ci                           RegisterInfo* non_set_member);
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci  void PushToRegistersNeedingFlush(RegisterInfo* reg);
1381cb0ef41Sopenharmony_ci  // Methods for finding and creating metadata for each register.
1391cb0ef41Sopenharmony_ci  RegisterInfo* GetRegisterInfo(Register reg) {
1401cb0ef41Sopenharmony_ci    size_t index = GetRegisterInfoTableIndex(reg);
1411cb0ef41Sopenharmony_ci    DCHECK_LT(index, register_info_table_.size());
1421cb0ef41Sopenharmony_ci    return register_info_table_[index];
1431cb0ef41Sopenharmony_ci  }
1441cb0ef41Sopenharmony_ci  RegisterInfo* GetOrCreateRegisterInfo(Register reg) {
1451cb0ef41Sopenharmony_ci    size_t index = GetRegisterInfoTableIndex(reg);
1461cb0ef41Sopenharmony_ci    return index < register_info_table_.size() ? register_info_table_[index]
1471cb0ef41Sopenharmony_ci                                               : NewRegisterInfo(reg);
1481cb0ef41Sopenharmony_ci  }
1491cb0ef41Sopenharmony_ci  RegisterInfo* NewRegisterInfo(Register reg) {
1501cb0ef41Sopenharmony_ci    size_t index = GetRegisterInfoTableIndex(reg);
1511cb0ef41Sopenharmony_ci    DCHECK_GE(index, register_info_table_.size());
1521cb0ef41Sopenharmony_ci    GrowRegisterMap(reg);
1531cb0ef41Sopenharmony_ci    return register_info_table_[index];
1541cb0ef41Sopenharmony_ci  }
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  void GrowRegisterMap(Register reg);
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_ci  bool RegisterIsTemporary(Register reg) const {
1591cb0ef41Sopenharmony_ci    return reg >= temporary_base_;
1601cb0ef41Sopenharmony_ci  }
1611cb0ef41Sopenharmony_ci
1621cb0ef41Sopenharmony_ci  bool RegisterIsObservable(Register reg) const {
1631cb0ef41Sopenharmony_ci    return reg != accumulator_ && !RegisterIsTemporary(reg);
1641cb0ef41Sopenharmony_ci  }
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  static Register OperandToRegister(uint32_t operand) {
1671cb0ef41Sopenharmony_ci    return Register::FromOperand(static_cast<int32_t>(operand));
1681cb0ef41Sopenharmony_ci  }
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci  size_t GetRegisterInfoTableIndex(Register reg) const {
1711cb0ef41Sopenharmony_ci    return static_cast<size_t>(reg.index() + register_info_table_offset_);
1721cb0ef41Sopenharmony_ci  }
1731cb0ef41Sopenharmony_ci
1741cb0ef41Sopenharmony_ci  Register RegisterFromRegisterInfoTableIndex(size_t index) const {
1751cb0ef41Sopenharmony_ci    return Register(static_cast<int>(index) - register_info_table_offset_);
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci  uint32_t NextEquivalenceId() {
1791cb0ef41Sopenharmony_ci    equivalence_id_++;
1801cb0ef41Sopenharmony_ci    // TODO(rmcilroy): use the same type for these and remove static_cast.
1811cb0ef41Sopenharmony_ci    CHECK_NE(static_cast<size_t>(equivalence_id_), kInvalidEquivalenceId);
1821cb0ef41Sopenharmony_ci    return equivalence_id_;
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  void AllocateRegister(RegisterInfo* info);
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci  Zone* zone() { return zone_; }
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  const Register accumulator_;
1901cb0ef41Sopenharmony_ci  RegisterInfo* accumulator_info_;
1911cb0ef41Sopenharmony_ci  const Register temporary_base_;
1921cb0ef41Sopenharmony_ci  int max_register_index_;
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_ci  // Direct mapping to register info.
1951cb0ef41Sopenharmony_ci  ZoneVector<RegisterInfo*> register_info_table_;
1961cb0ef41Sopenharmony_ci  int register_info_table_offset_;
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_ci  ZoneDeque<RegisterInfo*> registers_needing_flushed_;
1991cb0ef41Sopenharmony_ci
2001cb0ef41Sopenharmony_ci  // Counter for equivalence sets identifiers.
2011cb0ef41Sopenharmony_ci  int equivalence_id_;
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci  BytecodeWriter* bytecode_writer_;
2041cb0ef41Sopenharmony_ci  bool flush_required_;
2051cb0ef41Sopenharmony_ci  Zone* zone_;
2061cb0ef41Sopenharmony_ci};
2071cb0ef41Sopenharmony_ci
2081cb0ef41Sopenharmony_ci}  // namespace interpreter
2091cb0ef41Sopenharmony_ci}  // namespace internal
2101cb0ef41Sopenharmony_ci}  // namespace v8
2111cb0ef41Sopenharmony_ci
2121cb0ef41Sopenharmony_ci#endif  // V8_INTERPRETER_BYTECODE_REGISTER_OPTIMIZER_H_
213