// Copyright 2014 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_COMPILER_INSTRUCTION_SELECTOR_H_
#define V8_COMPILER_INSTRUCTION_SELECTOR_H_

#include <deque>

#include "src/compiler/common-operator.h"
#include "src/compiler/instruction.h"
#include "src/compiler/machine-operator.h"
#include "src/zone-containers.h"

namespace v8 {
namespace internal {
namespace compiler {

// Forward declarations.
struct CallBuffer;  // TODO(bmeurer): Remove this.
class FlagsContinuation;

class InstructionSelector FINAL {
 public:
  // Forward declarations.
  class Features;

  InstructionSelector(InstructionSequence* sequence,
                      SourcePositionTable* source_positions,
                      Features features = SupportedFeatures());

  // Visit code for the entire graph with the included schedule.
  void SelectInstructions();

  // ===========================================================================
  // ============= Architecture-independent code emission methods. =============
  // ===========================================================================

  Instruction* Emit(InstructionCode opcode, InstructionOperand* output,
                    size_t temp_count = 0, InstructionOperand* *temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand* output,
                    InstructionOperand* a, size_t temp_count = 0,
                    InstructionOperand* *temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand* output,
                    InstructionOperand* a, InstructionOperand* b,
                    size_t temp_count = 0, InstructionOperand* *temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand* output,
                    InstructionOperand* a, InstructionOperand* b,
                    InstructionOperand* c, size_t temp_count = 0,
                    InstructionOperand* *temps = NULL);
  Instruction* Emit(InstructionCode opcode, InstructionOperand* output,
                    InstructionOperand* a, InstructionOperand* b,
                    InstructionOperand* c, InstructionOperand* d,
                    size_t temp_count = 0, InstructionOperand* *temps = NULL);
  Instruction* Emit(InstructionCode opcode, size_t output_count,
                    InstructionOperand** outputs, size_t input_count,
                    InstructionOperand** inputs, size_t temp_count = 0,
                    InstructionOperand* *temps = NULL);
  Instruction* Emit(Instruction* instr);

  // ===========================================================================
  // ============== Architecture-independent CPU feature methods. ==============
  // ===========================================================================

  class Features FINAL {
   public:
    Features() : bits_(0) {}
    explicit Features(unsigned bits) : bits_(bits) {}
    explicit Features(CpuFeature f) : bits_(1u << f) {}
    Features(CpuFeature f1, CpuFeature f2) : bits_((1u << f1) | (1u << f2)) {}

    bool Contains(CpuFeature f) const { return (bits_ & (1u << f)); }

   private:
    unsigned bits_;
  };

  bool IsSupported(CpuFeature feature) const {
    return features_.Contains(feature);
  }

  // Returns the features supported on the target platform.
  static Features SupportedFeatures() {
    return Features(CpuFeatures::SupportedFeatures());
  }

 private:
  friend class OperandGenerator;

  // ===========================================================================
  // ============ Architecture-independent graph covering methods. =============
  // ===========================================================================

  // Checks if {block} will appear directly after {current_block_} when
  // assembling code, in which case, a fall-through can be used.
  bool IsNextInAssemblyOrder(const BasicBlock* block) const;

  // Used in pattern matching during code generation.
  // Check if {node} can be covered while generating code for the current
  // instruction. A node can be covered if the {user} of the node has the only
  // edge and the two are in the same basic block.
  bool CanCover(Node* user, Node* node) const;

  // Checks if {node} was already defined, and therefore code was already
  // generated for it.
  bool IsDefined(Node* node) const;

  // Inform the instruction selection that {node} was just defined.
  void MarkAsDefined(Node* node);

  // Checks if {node} has any uses, and therefore code has to be generated for
  // it.
  bool IsUsed(Node* node) const;

  // Inform the instruction selection that {node} has at least one use and we
  // will need to generate code for it.
  void MarkAsUsed(Node* node);

  // Checks if {node} is marked as double.
  bool IsDouble(const Node* node) const;

  // Inform the register allocator of a double result.
  void MarkAsDouble(Node* node);

  // Checks if {node} is marked as reference.
  bool IsReference(const Node* node) const;

  // Inform the register allocator of a reference result.
  void MarkAsReference(Node* node);

  // Inform the register allocation of the representation of the value produced
  // by {node}.
  void MarkAsRepresentation(MachineType rep, Node* node);

  // Initialize the call buffer with the InstructionOperands, nodes, etc,
  // corresponding
  // to the inputs and outputs of the call.
  // {call_code_immediate} to generate immediate operands to calls of code.
  // {call_address_immediate} to generate immediate operands to address calls.
  void InitializeCallBuffer(Node* call, CallBuffer* buffer,
                            bool call_code_immediate,
                            bool call_address_immediate);

  FrameStateDescriptor* GetFrameStateDescriptor(Node* node);
  void AddFrameStateInputs(Node* state, InstructionOperandVector* inputs,
                           FrameStateDescriptor* descriptor);

  // ===========================================================================
  // ============= Architecture-specific graph covering methods. ===============
  // ===========================================================================

  // Visit nodes in the given block and generate code.
  void VisitBlock(BasicBlock* block);

  // Visit the node for the control flow at the end of the block, generating
  // code if necessary.
  void VisitControl(BasicBlock* block);

  // Visit the node and generate code, if any.
  void VisitNode(Node* node);

#define DECLARE_GENERATOR(x) void Visit##x(Node* node);
  MACHINE_OP_LIST(DECLARE_GENERATOR)
#undef DECLARE_GENERATOR

  void VisitInt32AddWithOverflow(Node* node, FlagsContinuation* cont);
  void VisitInt32SubWithOverflow(Node* node, FlagsContinuation* cont);

  void VisitWord32Test(Node* node, FlagsContinuation* cont);
  void VisitWord64Test(Node* node, FlagsContinuation* cont);
  void VisitWord32Compare(Node* node, FlagsContinuation* cont);
  void VisitWord64Compare(Node* node, FlagsContinuation* cont);
  void VisitFloat64Compare(Node* node, FlagsContinuation* cont);

  void VisitFinish(Node* node);
  void VisitParameter(Node* node);
  void VisitPhi(Node* node);
  void VisitProjection(Node* node);
  void VisitConstant(Node* node);
  void VisitCall(Node* call, BasicBlock* continuation,
                 BasicBlock* deoptimization);
  void VisitGoto(BasicBlock* target);
  void VisitBranch(Node* input, BasicBlock* tbranch, BasicBlock* fbranch);
  void VisitReturn(Node* value);
  void VisitThrow(Node* value);
  void VisitDeoptimize(Node* deopt);

  // ===========================================================================

  Graph* graph() const { return sequence()->graph(); }
  Linkage* linkage() const { return sequence()->linkage(); }
  Schedule* schedule() const { return sequence()->schedule(); }
  InstructionSequence* sequence() const { return sequence_; }
  Zone* instruction_zone() const { return sequence()->zone(); }
  Zone* zone() { return &zone_; }

  // ===========================================================================

  Zone zone_;
  InstructionSequence* sequence_;
  SourcePositionTable* source_positions_;
  Features features_;
  BasicBlock* current_block_;
  ZoneDeque<Instruction*> instructions_;
  BoolVector defined_;
  BoolVector used_;
};

}  // namespace compiler
}  // namespace internal
}  // namespace v8

#endif  // V8_COMPILER_INSTRUCTION_SELECTOR_H_
