bool IfConversionPass2::VerifyIf(IfStatement* toConvert)
{
  Statement* thenPart = toConvert->get_then_part() ;
  Statement* elsePart = toConvert->get_else_part() ;

  if (thenPart == NULL || elsePart == NULL)
  {
    return false ;
  }

  StatementList* thenList = dynamic_cast<StatementList*>(thenPart) ;
  StatementList* elseList = dynamic_cast<StatementList*>(elsePart) ;
  
  if (thenList != NULL && thenList->get_statement_count() != 1)
  {
    return false ;
  }
  
  if (elseList != NULL && elseList->get_statement_count() != 1)
  {
    return false ;
  }

  thenPart = Denormalize(thenPart) ;
  elsePart = Denormalize(elsePart) ;

  return CorrectTypes(thenPart, elsePart) ;
}
void TransformSystemsToModules::ReplaceUses(VariableSymbol* original,
					    VariableSymbol* replacement)
{
  assert(procDef != NULL) ;

  StatementList* bodyList = dynamic_cast<StatementList*>(procDef->get_body()) ;
  assert(bodyList != NULL) ;

  for (int i = 0 ; i < bodyList->get_statement_count() ; ++i)
  {
    list<LoadVariableExpression*>* allLoads = 
      collect_objects<LoadVariableExpression>(bodyList->get_statement(i)) ;

    list<LoadVariableExpression*>::iterator loadIter = allLoads->begin() ;
    while (loadIter != allLoads->end())
    {
      if ((*loadIter)->get_source() == original)
      {
	(*loadIter)->set_source(replacement) ;
      }
      ++loadIter ;
    }

    delete allLoads ;

    if (IsDefinition(bodyList->get_statement(i), original))
    {
      // We no longer have to replace the value
      return ;
    }
  }
}
void TransformSystemsToModules::ReplaceDefinition(VariableSymbol* original,
						  VariableSymbol* replacement)
{
  assert(procDef != NULL) ;

  std::cout << "Replacing a definition: " << original << " " << replacement
	    << std::endl ;

  StatementList* bodyList = dynamic_cast<StatementList*>(procDef->get_body()) ;
  assert(bodyList != NULL) ;

  // From the back, find the last definition
  for (int i = bodyList->get_statement_count() - 1 ; i > 0 ; --i)
  {
    Statement* currentStatement = bodyList->get_statement(i) ;
    if (IsDefinition(currentStatement, original))
    {
      
      // This is either going to be a store variable statement or
      //  a symbol address expression (if the definition was in a call)

      list<StoreVariableStatement*>* allStores = 
	collect_objects<StoreVariableStatement>(currentStatement) ;

      list<StoreVariableStatement*>::iterator storeIter = allStores->begin() ;
      while (storeIter != allStores->end())
      {
	if ((*storeIter)->get_destination() == original)
	{
	  (*storeIter)->set_destination(replacement) ;
	}
	++storeIter ;
      }
      delete allStores ;

      list<SymbolAddressExpression*>* allSymAddr = 
	collect_objects<SymbolAddressExpression>(currentStatement) ;
      
      list<SymbolAddressExpression*>::iterator symAddrIter = 
	allSymAddr->begin();
      while (symAddrIter != allSymAddr->end())
      {
	if ((*symAddrIter)->get_addressed_symbol() == original)
	{
	  (*symAddrIter)->set_addressed_symbol(replacement) ;
	}
	++symAddrIter ;
      }
      delete allSymAddr ;

      return ;
    }
  }
  
}
Statement* IfConversionPass2::Denormalize(Statement* x)
{
  if (dynamic_cast<StatementList*>(x) != NULL)
  {
    StatementList* theList = dynamic_cast<StatementList*>(x) ;
    assert(theList->get_statement_count() == 1 && "Unsupported if detected!") ;
    return theList->get_statement(0) ;
  }
  else
  {
    return x ;
  }
}
void RemoveUnsupportedStatements::do_procedure_definition(ProcedureDefinition* p)
{
  procDef = p ;
  assert(procDef != NULL) ;

  OutputInformation("Remove Unsupported statements begins") ;

  CForStatement* innermost = InnermostLoop(procDef) ;
  if (innermost == NULL)
  {
    OutputInformation("Remove Unsupported statements ends") ;
    return ;
  }

  StatementList* parentList = 
    dynamic_cast<StatementList*>(innermost->get_parent()) ;
  CForStatement* outerLoops = 
    dynamic_cast<CForStatement*>(innermost->get_parent()) ;
  CForStatement* outermostLoop = innermost ;
  while (parentList == NULL && outerLoops != NULL)
  {
    parentList = dynamic_cast<StatementList*>(outerLoops->get_parent()) ;
    outermostLoop = outerLoops ;
    outerLoops = dynamic_cast<CForStatement*>(outerLoops->get_parent()) ;
  }
  assert(parentList != NULL) ;
  assert(outermostLoop != NULL) ;

  int position = DeterminePosition(parentList, outermostLoop) ;
  assert(position >= 0) ;
  
  for (int i = 0 ; i < position ; ++i)
  {
    StatementList* blankList = create_statement_list(theEnv) ;
    Statement* toReplace = parentList->get_statement(i) ;
    parentList->replace(toReplace, blankList) ;
    // Will this delete kill me?
    //delete toReplace ;
  }
  
  for (int i = position + 1 ; i < parentList->get_statement_count() ; ++i)
  {
    StatementList* blankList = create_statement_list(theEnv) ;
    Statement* toReplace = parentList->get_statement(i) ;
    parentList->replace(toReplace, blankList) ;
    // Will this delete kill me?... yep!  or not...
    //delete toReplace ;
  }
  
  OutputInformation("Remove Unsupported statments ends") ;
}
static void append_flattened(StatementList *slist,Statement *stat) {
    if (!stat)
	return;
    if (is_kind_of<StatementList>(stat)) {
	StatementList *sl = to<StatementList>(stat);
	int len = sl->get_statement_count();
	for (int i = 0; i < len; i++) {
	    Statement *s = sl->get_statement(i);
	    s->set_parent(0);
	    slist->append_statement(s);
	    }
	}
    else {
	stat->set_parent(0);
	slist->append_statement(stat);
	}
    }
// Modified to handle cases where a variable is defined for the first time
//  in a call and used in a store variable.
void SolveFeedbackVariablesPass3::DetermineNewFeedbacks()
{
  assert(innermost != NULL) ;
  assert(procDef != NULL) ;
  assert(theEnv != NULL) ;

  StatementList* bodyList = 
    dynamic_cast<StatementList*>(innermost->get_body()) ;
  assert(bodyList != NULL) ;

  std::map<VariableSymbol*, Statement*> lastDefinitions ;
  std::map<VariableSymbol*, int> lastLocations ;

  // Go backwards through the list and determine the last definition
  //  for each variable.
  for (int i = bodyList->get_statement_count() - 1 ; i >= 0 ; --i)
  {
    list<VariableSymbol*> definedVariables = 
      AllDefinedVariables(bodyList->get_statement(i)) ;
    
    list<VariableSymbol*>::iterator defIter = definedVariables.begin() ;
    int j = 0 ;
    while (defIter != definedVariables.end())
    {
      if (lastDefinitions[(*defIter)] == NULL)
      {
	lastDefinitions[(*defIter)] = bodyList->get_statement(i) ;
	lastLocations[(*defIter)] = j ;
      }
      ++defIter ;
      ++j ;
    }
  }

  std::map<VariableSymbol*, int> killedVariables ;

  // Now go from the front and create actual feedbacks for each
  //  live variable.
  for (int i = 0 ; i < bodyList->get_statement_count() ; ++i)
  {
    list<LoadVariableExpression*>* allLoads = 
      collect_objects<LoadVariableExpression>(bodyList->get_statement(i)) ;
    list<LoadVariableExpression*>::iterator loadIter = allLoads->begin() ;
    while(loadIter != allLoads->end())
    {
      if (killedVariables[(*loadIter)->get_source()] == 0 &&
	  lastDefinitions[(*loadIter)->get_source()] != NULL)
      {
	// Create a feedback here
	PossibleFeedbackPair toAdd ;
	toAdd.varSym = (*loadIter)->get_source() ;
	toAdd.use = (*loadIter) ;
	toAdd.definition = lastDefinitions[(*loadIter)->get_source()] ;
	toAdd.definitionLocation = lastLocations[(*loadIter)->get_source()] ;
	actualFeedbacks.push_back(toAdd) ;
      }
      ++loadIter ;
    }
    delete allLoads ;

    // Add all the definitions to the list of killed variables.
    list<VariableSymbol*> definedVariables = 
      AllDefinedVariables(bodyList->get_statement(i)) ;
    list<VariableSymbol*>::iterator defIter = definedVariables.begin() ;
    while (defIter != definedVariables.end())
    {
      killedVariables[(*defIter)] = 1 ;
      ++defIter ;
    }
  }

  
  
}
void CombineSummationPass::do_procedure_definition(ProcedureDefinition* p)
{
  procDef = p ;
  assert(procDef != NULL) ;

  OutputInformation("Combine summation pass begins") ;

  StatementList* innermost = InnermostList(procDef) ;
  assert(innermost != NULL) ;

  bool change = false ;
  do
  {
    // Find the first summation
    StoreVariableStatement* firstStatement = NULL ;
    StoreVariableStatement* secondStatement = NULL ;
    change = false ;
    int i ;
    int firstStatementPosition = -1 ;
    i = 0 ;
    while (i < innermost->get_statement_count())
    {
      StoreVariableStatement* currentStoreVariable =
	dynamic_cast<StoreVariableStatement*>(innermost->get_statement(i)) ;
      if (currentStoreVariable != NULL && IsSummation(currentStoreVariable))
      {
	firstStatement = currentStoreVariable ;
	firstStatementPosition = i ;
	break ;
      }
	++i ;
    }
    
    if (firstStatement != NULL)
    {
      VariableSymbol* firstDest = firstStatement->get_destination() ;
      for (int j = i+1 ; j < innermost->get_statement_count() ; ++j)
      {
	StoreVariableStatement* nextStoreVar = 
	  dynamic_cast<StoreVariableStatement*>(innermost->get_statement(j));
	if (nextStoreVar != NULL && IsSummation(nextStoreVar, firstDest))
	{
	  secondStatement = nextStoreVar ;
	  break ;
	}
	if (IsDefinition(innermost->get_statement(j), firstDest) ||
	    HasUses(innermost->get_statement(j), firstDest))
	{
	  break ;
	}						
      }
    }
    if (secondStatement != NULL)
    {
      // Go through each of the variables used in the first statement and
      //  make sure there are no definitions to any of them.
      //  I only have to worry about variables and not array accesses because
      //  we don't allow them to read and write to array values.
      int originalPosition = DeterminePosition(innermost, firstStatement) ;
      assert(originalPosition >= 0) ;
      list<VariableSymbol*> usedVars = 
	AllUsedVariablesBut(firstStatement, firstStatement->get_destination());
      bool goodPath = true ;
      for (int j = originalPosition ; 
	   j < innermost->get_statement_count() && 
	     innermost->get_statement(j) != secondStatement ; 
	   ++j)
      {
	list<VariableSymbol*>::iterator usedIter = usedVars.begin() ;
	while (usedIter != usedVars.end())
	{
	  if (IsOutputVariable((*usedIter), innermost->get_statement(j)))
	  {
	    goodPath = false ;
	    break ;
	  }
	  ++usedIter ;
	}
	if (!goodPath) 
	{
	  break ;
	}
      }
      if (!goodPath)
      {
	continue ;
      }
      // Actually do the combining here
      change = true ;
      Expression* remains = RemoveValue(firstStatement) ;
      Expression* secondRemains = RemoveValue(secondStatement) ;
      // Create two binary expressions
      BinaryExpression* remainsSum = 
	create_binary_expression(theEnv,
				 remains->get_result_type(),
				 LString("add"),
				 remains,
				 secondRemains) ;
      LoadVariableExpression* loadDest = 
	create_load_variable_expression(theEnv,
	    secondStatement->get_destination()->get_type()->get_base_type(),
					secondStatement->get_destination()) ;
      BinaryExpression* finalSum =
	create_binary_expression(theEnv,
				 remainsSum->get_result_type(),
				 LString("add"),
				 remainsSum,
				 loadDest) ;

      secondStatement->set_value(finalSum) ;
      // Delete?
      innermost->remove_statement(firstStatementPosition) ;
    }
     
  } while (change == true) ;  

  OutputInformation("Combine summation pass ends") ;
}
void CopyPropagationPass2::ProcessSpecialIfs()
{
  list<IfStatement*>* allIfs = 
    collect_objects<IfStatement>(procDef->get_body()) ;

  assert(allIfs != NULL) ;

  list<IfStatement*>::iterator ifIter = allIfs->begin() ;
  while (ifIter != allIfs->end())
  {

    Statement* elsePart = (*ifIter)->get_else_part() ;
    assert(elsePart != NULL) ;

    StatementList* elseList = dynamic_cast<StatementList*>(elsePart) ;
    if (elseList == NULL)
    {
      ++ifIter ;
      continue ;
    }

    assert(elseList != NULL) ;

    if (elseList->get_statement_count() == 2)
    {
      // Process this if statement
      Statement* thenPart = (*ifIter)->get_then_part() ;
      assert(thenPart != NULL) ;
      /*
      StatementList* thenList = dynamic_cast<StatementList*>(thenPart) ;
      assert(thenList != NULL) ;

      assert(thenList->get_statement_count() == 1) ;
      Statement* thenStatement = thenList->get_statement(0) ;
      assert(thenStatement != NULL) ;
      */
      StoreVariableStatement* thenStoreVar = 
	dynamic_cast<StoreVariableStatement*>(thenPart) ;
      assert(thenStoreVar != NULL) ;
      
      Statement* firstElseStatement = elseList->get_statement(0) ;
      Statement* secondElseStatement = elseList->get_statement(1) ;
      assert(firstElseStatement != NULL && secondElseStatement != NULL) ;

      // We are definitely going to break the rules here
      //  We know that the destination has to be replaced with 
      //  the source

      StoreVariableStatement* secondElseStore = 
	dynamic_cast<StoreVariableStatement*>(secondElseStatement) ;

      assert(secondElseStore != NULL) ;

      Expression* source = secondElseStore->get_value() ;
      assert(source != NULL) ;
      
      LoadVariableExpression* sourceLoadExp = 
	dynamic_cast<LoadVariableExpression*>(source) ;
      assert(sourceLoadExp != NULL) ;

      VariableSymbol* sourceVariable = sourceLoadExp->get_source() ;
      assert(sourceVariable != NULL) ;

      // First, find the use of the then portion and replace that use
      //  with the source variable
      BrickAnnote* ba = 
	to<BrickAnnote>(thenStoreVar->lookup_annote_by_name("reached_uses")) ;
      assert(ba != NULL) ;

      assert(ba->get_brick_count() == 1) ;

      Iter<SuifBrick*> tmpIter = ba->get_brick_iterator() ;
      
      SuifObjectBrick* sob = 
	to<SuifObjectBrick>(tmpIter.current()) ;
      assert(sob != NULL) ;

      SuifObject* finalDest = sob->get_object() ;

      LoadVariableExpression* finalLoad =
	dynamic_cast<LoadVariableExpression*>(finalDest) ;
      assert(finalLoad != NULL) ;

      // Before we make the change, mark the variable we are replacing as
      //  removed.
      finalLoad->get_source()->append_annote(create_brick_annote(theEnv, "RemovedVariable")) ;

      finalLoad->set_source(sourceVariable) ;

      // Now, change the then portion
      thenStoreVar->set_destination(sourceVariable) ;

      // Now, remove the second else statement
      elseList->remove_statement(1) ;

      // We should be done.

    }

    ++ifIter ;
  }

  delete allIfs ;
}