#include "Utility.hpp"

#include <llvm/Function.h>
#include <llvm/Instructions.h>
#include <llvm/Support/Debug.h>

#include <boost/format.hpp>

#include <sstream>

using namespace boost;
using namespace llvm;

const Value * normalizeValue(const Value * v)
{
  while(const BitCastInst * bci = dyn_cast<const BitCastInst>(v))
    v = bci->getOperand(0);
  
  return v;
}

static void internalFlatten(const PHINode * pn,
                            value_set & visited,
                            value_set & ret)
{
  // There can be cycles in PHI node pointers.
  // Keep track of which nodes we have started
  // visiting so we know to never get stuck in
  // a cycle
  if(visited.find(pn) != visited.end())
    return;
  
  visited.insert(pn);

  for(unsigned i = 0; i < pn->getNumIncomingValues(); ++i)
  {
    const Value * v = pn->getIncomingValue(i);
    v = normalizeValue(v);
  
    if(const PHINode * p = dyn_cast<const PHINode>(v))
    {
      internalFlatten(p, visited, ret);
    }
    else
    {
      ret.insert(v);
    }
  }
}

value_set flattenPhiNode(const Value * v)
{
  value_set ret;

  v = normalizeValue(v);
  if(!isa<const PHINode>(v))
  {
    ret.insert(v);

    return ret;
  }
  
  value_set visited;
  const PHINode * pn = cast<const PHINode>(v);
  internalFlatten(pn, visited, ret);
  
  return ret;
}

Function* getParentFunction(Value* V)
{
  if(Instruction* I = dyn_cast<Instruction>(V))
  {
    return I->getParent()->getParent();
  }
  else if(Argument* A = dyn_cast<Argument>(V))
  {
    return A->getParent();
  }

  return NULL;
  cerr << format("[ERROR] Unknown value type: %s\n") % valueToString(V);  
  assert(false && "Unknown value type, cannot derive parent");
  return NULL;
}

std::string valueToString(const Value* V)
{
  std::ostringstream os;
  //V->print(os);
  os << V;
  return os.str();
}

