// Copyright 2020 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_TORQUE_TORQUE_CODE_GENERATOR_H_
#define V8_TORQUE_TORQUE_CODE_GENERATOR_H_

#include <iostream>

#include "src/torque/cfg.h"
#include "src/torque/declarable.h"

namespace v8 {
namespace internal {
namespace torque {

class TorqueCodeGenerator {
 public:
  TorqueCodeGenerator(const ControlFlowGraph& cfg, std::ostream& out)
      : cfg_(cfg),
        out_(&out),
        out_decls_(&out),
        previous_position_(SourcePosition::Invalid()) {}

 protected:
  const ControlFlowGraph& cfg_;
  std::ostream* out_;
  std::ostream* out_decls_;
  size_t fresh_id_ = 0;
  SourcePosition previous_position_;
  std::map<DefinitionLocation, std::string> location_map_;

  std::string DefinitionToVariable(const DefinitionLocation& location) {
    if (location.IsPhi()) {
      std::stringstream stream;
      stream << "phi_bb" << location.GetPhiBlock()->id() << "_"
             << location.GetPhiIndex();
      return stream.str();
    } else if (location.IsParameter()) {
      auto it = location_map_.find(location);
      DCHECK_NE(it, location_map_.end());
      return it->second;
    } else {
      DCHECK(location.IsInstruction());
      auto it = location_map_.find(location);
      if (it == location_map_.end()) {
        it = location_map_.insert(std::make_pair(location, FreshNodeName()))
                 .first;
      }
      return it->second;
    }
  }

  void SetDefinitionVariable(const DefinitionLocation& definition,
                             const std::string& str) {
    DCHECK_EQ(location_map_.find(definition), location_map_.end());
    location_map_.insert(std::make_pair(definition, str));
  }

  std::ostream& out() { return *out_; }
  std::ostream& decls() { return *out_decls_; }

  static bool IsEmptyInstruction(const Instruction& instruction);
  virtual void EmitSourcePosition(SourcePosition pos,
                                  bool always_emit = false) = 0;

  std::string FreshNodeName() { return "tmp" + std::to_string(fresh_id_++); }
  std::string FreshCatchName() { return "catch" + std::to_string(fresh_id_++); }
  std::string FreshLabelName() { return "label" + std::to_string(fresh_id_++); }
  std::string BlockName(const Block* block) {
    return "block" + std::to_string(block->id());
  }

  void EmitInstruction(const Instruction& instruction,
                       Stack<std::string>* stack);

#define EMIT_INSTRUCTION_DECLARATION(T) \
  void EmitInstruction(const T& instruction, Stack<std::string>* stack);
  TORQUE_BACKEND_AGNOSTIC_INSTRUCTION_LIST(EMIT_INSTRUCTION_DECLARATION)
#undef EMIT_INSTRUCTION_DECLARATION

#define EMIT_INSTRUCTION_DECLARATION(T)              \
  virtual void EmitInstruction(const T& instruction, \
                               Stack<std::string>* stack) = 0;
  TORQUE_BACKEND_DEPENDENT_INSTRUCTION_LIST(EMIT_INSTRUCTION_DECLARATION)
#undef EMIT_INSTRUCTION_DECLARATION
};

}  // namespace torque
}  // namespace internal
}  // namespace v8

#endif  // V8_TORQUE_TORQUE_CODE_GENERATOR_H_
