/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_
#define ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_
#include "sea_node.h"
#include "visitor.h"
#include "dex_instruction-inl.h"

namespace sea_ir {

enum SpecialRegisters {
  NO_REGISTER = -1,             // Usually signifies that there is no register
                                // that respects the condition you asked for.
  RETURN_REGISTER = -2,         // Written by the invoke* instructions, read by move-results.
  UNNAMED_CONST_REGISTER = -3   // Written by UnnamedConst* instructions, read by *Lit* instruction.
};

class IRVisitor;

// This class represents an instruction in SEA IR.
// As we add support for specific classes of instructions,
// the number of InstructionNode objects should dwindle, while the
// number of subclasses and instances of subclasses will go up.
class InstructionNode: public SeaNode {
 public:
  static std::vector<sea_ir::InstructionNode*> Create(const art::Instruction* in);
  // Returns the Dalvik instruction around which this InstructionNode is wrapped.
  const art::Instruction* GetInstruction() const {
    DCHECK(NULL != instruction_) << "Tried to access NULL instruction in an InstructionNode.";
    return instruction_;
  }
  // Returns the register that is defined by the current instruction, or NO_REGISTER otherwise.
  virtual int GetResultRegister() const;
  // Returns the set of registers defined by the current instruction.
  virtual std::vector<int> GetDefinitions() const;
  // Returns the set of register numbers that are used by the instruction.
  virtual std::vector<int> GetUses();
  // Appends to @result the .dot string representation of the instruction.
  virtual void ToDot(std::string& result) const;
  // Mark the current instruction as a downward exposed definition.
  void MarkAsDEDef();
  // Rename the use of @reg_no to refer to the instruction @definition,
  // essentially creating SSA form.
  void RenameToSSA(int reg_no, InstructionNode* definition) {
    definition_edges_.insert(std::pair<int, InstructionNode*>(reg_no, definition));
  }
  // Returns the ordered set of Instructions that define the input operands of this instruction.
  // Precondition: SeaGraph.ConvertToSSA().
  std::vector<InstructionNode*> GetSSAUses() {
    std::vector<int> uses = GetUses();
    std::vector<InstructionNode*> ssa_uses;
    for (std::vector<int>::const_iterator cit = uses.begin(); cit != uses.end(); cit++) {
      ssa_uses.push_back((*definition_edges_.find(*cit)).second);
    }
    return ssa_uses;
  }

  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
  // Set the region to which this instruction belongs.
  Region* GetRegion() {
    DCHECK(NULL != region_);
    return region_;
  }
  // Get the region to which this instruction belongs.
  void SetRegion(Region* region) {
    region_ = region;
  }

 protected:
  explicit InstructionNode(const art::Instruction* in):
      SeaNode(), instruction_(in), de_def_(false), region_(NULL) { }

 protected:
  const art::Instruction* const instruction_;
  std::map<int, InstructionNode* > definition_edges_;
  bool de_def_;
  Region* region_;
};

class ConstInstructionNode: public InstructionNode {
 public:
  explicit ConstInstructionNode(const art::Instruction* inst):
      InstructionNode(inst) { }

  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }

  virtual int32_t GetConstValue() const {
    return GetInstruction()->VRegB_11n();
  }
};

class UnnamedConstInstructionNode: public ConstInstructionNode {
 public:
  explicit UnnamedConstInstructionNode(const art::Instruction* inst, int32_t value):
      ConstInstructionNode(inst), value_(value) { }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }

  int GetResultRegister() const {
    return UNNAMED_CONST_REGISTER;
  }

  int32_t GetConstValue() const {
    return value_;
  }

  void ToDot(std::string& result) const {
    std::ostringstream sstream;
    sstream << GetConstValue();
    const std::string value_as_string(sstream.str());
    result += "// Instruction ("+StringId()+"): \n" + StringId() +
        " [label=\"const/x v-3, #"+ value_as_string + "\"";
    if (de_def_) {
      result += "style=bold";
    }
    result += "];\n";
    // SSA definitions:
    for (std::map<int, InstructionNode* >::const_iterator def_it = definition_edges_.begin();
        def_it != definition_edges_.end(); def_it++) {
      if (NULL != def_it->second) {
        result += def_it->second->StringId() + " -> " + StringId() +"[color=red,label=\"";
        std::stringstream ss;
        ss << def_it->first;
        result.append(ss.str());
        result += "\"] ; // ssa edge\n";
      }
    }
  }

 private:
  const int32_t value_;
};

class ReturnInstructionNode: public InstructionNode {
 public:
  explicit ReturnInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};

class IfNeInstructionNode: public InstructionNode {
 public:
  explicit IfNeInstructionNode(const art::Instruction* inst): InstructionNode(inst) {
    DCHECK(InstructionTools::IsDefinition(inst) == false);
  }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};



class MoveResultInstructionNode: public InstructionNode {
 public:
  explicit MoveResultInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
  std::vector<int> GetUses() {
    std::vector<int> uses; // Using vector<> instead of set<> because order matters.
    uses.push_back(RETURN_REGISTER);
    return uses;
  }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};

class InvokeStaticInstructionNode: public InstructionNode {
 public:
  explicit InvokeStaticInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
  int GetResultRegister() const {
    return RETURN_REGISTER;
  }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};

class AddIntInstructionNode: public InstructionNode {
 public:
  explicit AddIntInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};

class AddIntLitInstructionNode: public AddIntInstructionNode {
 public:
  explicit AddIntLitInstructionNode(const art::Instruction* inst):
      AddIntInstructionNode(inst) { }

  std::vector<int> GetUses() {
    std::vector<int> uses =  AddIntInstructionNode::GetUses();
    uses.push_back(UNNAMED_CONST_REGISTER);
    return uses;
    }

  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};

class GotoInstructionNode: public InstructionNode {
 public:
  explicit GotoInstructionNode(const art::Instruction* inst): InstructionNode(inst) { }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};

class IfEqzInstructionNode: public InstructionNode {
 public:
  explicit IfEqzInstructionNode(const art::Instruction* inst): InstructionNode(inst) {
    DCHECK(InstructionTools::IsDefinition(inst) == false);
  }
  void Accept(IRVisitor* v) {
    v->Visit(this);
    v->Traverse(this);
  }
};
} // end namespace sea_ir
#endif  // ART_COMPILER_SEA_IR_INSTRUCTION_NODES_H_
