/*******************************************************************\

Module: Slicer

Author: Daniel Kroening, kroening@cs.cmu.edu

\*******************************************************************/

#include <i2string.h>

#include "slicer.h"
#include "remove_skip.h"

class slicing_data_entryt
{
public:
  slicing_data_entryt():reaches_assertion(false)
  {
  }

  typedef std::list<goto_programt::const_targett> predecessorst;
  predecessorst predecessors;
  bool reaches_assertion;
};

/*******************************************************************\

Function: compute_successors

  Inputs:

 Outputs:

 Purpose:

\*******************************************************************/

void compute_successors(
  goto_programt &goto_program,
  std::map<goto_programt::const_targett, slicing_data_entryt> &slicing_data,
  goto_programt::const_targett PC)
{
  goto_programt::const_targett next_PC(PC);
  next_PC++;
  
  const goto_programt::instructiont &instruction=*PC;
  
  if(instruction.is_goto() || instruction.is_start_thread())
  {
    for(goto_programt::instructiont::targetst::const_iterator
        t_it=instruction.targets.begin();
        t_it!=instruction.targets.end();
        t_it++)
    {
      goto_programt::const_targett t=*t_it;
      if(t!=goto_program.instructions.end())
        slicing_data[t].predecessors.push_back(PC);
    }
  
    if(next_PC!=goto_program.instructions.end())
      slicing_data[next_PC].predecessors.push_back(PC);
  }
  else if(next_PC!=goto_program.instructions.end())
    slicing_data[next_PC].predecessors.push_back(PC);
}

/*******************************************************************\

Function: slicer

  Inputs:

 Outputs:

 Purpose:

\*******************************************************************/

void slicer(goto_programt &goto_program)
{
  // first compute predecessors

  std::map<goto_programt::const_targett, slicing_data_entryt>
    slicing_data;
    
  for(goto_programt::instructionst::const_iterator
      it=goto_program.instructions.begin();
      it!=goto_program.instructions.end();
      it++)
    compute_successors(goto_program, slicing_data, it);

  // get assertions
  std::list<goto_programt::const_targett> queue;
  
  for(goto_programt::instructionst::const_iterator
      it=goto_program.instructions.begin();
      it!=goto_program.instructions.end();
      it++)
    if(it->is_assert())
      queue.push_back(it);
  
  // fixed-point
  while(!queue.empty())
  {
    goto_programt::const_targett t=queue.back();
    queue.pop_back();
    
    slicing_data_entryt &e=slicing_data[t];
    
    if(e.reaches_assertion) continue;

    e.reaches_assertion=true;
    
    for(slicing_data_entryt::predecessorst::const_iterator
        p_it=e.predecessors.begin();
        p_it!=e.predecessors.end();
        p_it++)
      queue.push_back(*p_it);
  }
  
  // now remove those instructions that do not reach any assertions

  for(goto_programt::instructionst::iterator
      it=goto_program.instructions.begin();
      it!=goto_program.instructions.end();
      it++)
  {
    const slicing_data_entryt &e=slicing_data[it];
    if(!e.reaches_assertion) 
      it->make_skip();
  }
  
  // remove the skips
  remove_skip(goto_program);
  goto_program.update();
}

/*******************************************************************\

Function: slicer

  Inputs:

 Outputs:

 Purpose:

\*******************************************************************/

void slicer(goto_functionst &goto_functions)
{
}
