// Turn an reference pointer into an array reference expression
void ReferenceCleanupPass::CleanupArrayStore(StoreStatement* s)
{
  assert(s != NULL) ;
  
  // Check to see if the destination is a reference variable
  Expression* destination = s->get_destination_address() ;

  VariableSymbol* storedVariable = FindVariable(destination) ;

  if (storedVariable == NULL)
  {
    return ;
  }

  if (dynamic_cast<ReferenceType*>(storedVariable->get_type()->get_base_type()))
  {
    // Can I just change the type?  Pointer conversion should take care of it
    //  then, but I'll have to annotate it
    ReferenceType* refType = 
      dynamic_cast<ReferenceType*>(storedVariable->get_type()->get_base_type()) ;
    QualifiedType* internalType = 
      dynamic_cast<QualifiedType*>(refType->get_reference_type()) ;
    assert(internalType != NULL) ;

    DataType* internalType2 = internalType->get_base_type() ;
    QualifiedType* qualType = storedVariable->get_type() ;
    qualType->set_base_type(NULL) ;
    refType->set_parent(NULL) ;
    internalType->set_parent(NULL) ;
    refType->set_reference_type(NULL) ;
    qualType->set_base_type(internalType2) ;
  }
}
void ExportPass::AddSymbols()
{
  assert(repository != NULL) ;
  assert(constructedType != NULL) ;
  assert(constructedSymbol != NULL) ;

  // By this point, the repository has been read in and the symbol table
  //  has been completely overwritten.

  SymbolTable* symTab = repository->get_external_symbol_table() ;
  assert(symTab != NULL) ;

  DataType* resultType = constructedType->get_result_type() ;
  bool resultReplaced = false ;
  for (int j = 0 ; j < symTab->get_symbol_table_object_count() ; ++j)
  {
    DataType* existingType = 
      dynamic_cast<DataType*>(symTab->get_symbol_table_object(j)) ;
    if (existingType != NULL && EquivalentTypes(resultType, existingType))
    {
      constructedType->set_result_type(existingType) ;
      resultReplaced = true ;
      delete resultType ;
      break ;
    }
  }
  if (!resultReplaced)
  {
    symTab->append_symbol_table_object(resultType) ;
  }
  
  // Go through all of the arguments and replace them with appropriate types
  //  if they already exist in the symbol table.
  for (int i = 0 ; i < constructedType->get_argument_count() ; ++i)
  {
    QualifiedType* currentArg = constructedType->get_argument(i) ;
    assert(currentArg != NULL) ;
    bool replaced = false ;
    for (int j = 0 ; j < symTab->get_symbol_table_object_count() ; ++j)
    {
      QualifiedType* existingType = 
	dynamic_cast<QualifiedType*>(symTab->get_symbol_table_object(j)) ;
      if (existingType != NULL && EquivalentTypes(currentArg, existingType) &&
	  existingType->get_annote_count() == currentArg->get_annote_count())
      {
	constructedType->replace_argument(i, existingType) ;
	replaced = true ;
	break ;
      }
    }    
    if (replaced == false)
    {
      symTab->append_symbol_table_object(currentArg) ;
      symTab->append_symbol_table_object(currentArg->get_base_type()) ;
    }
  }

  symTab->append_symbol_table_object(constructedType) ;
  symTab->append_symbol_table_object(constructedSymbol) ;
}
DataType* ExportPass::CloneDataType(DataType* t)
{
  assert(t != NULL) ;
  PointerType* pointerClone = dynamic_cast<PointerType*>(t) ;
  ReferenceType* referenceClone = dynamic_cast<ReferenceType*>(t) ;
  ArrayType* arrayClone = dynamic_cast<ArrayType*>(t) ;
  if (pointerClone != NULL)
  {
    QualifiedType* refType = 
      dynamic_cast<QualifiedType*>(pointerClone->get_reference_type()) ;
    assert(refType != NULL) ;
    DataType* cloneType = CloneDataType(refType->get_base_type()) ;
    assert(cloneType != NULL) ;

    return create_pointer_type(theEnv, 
			       IInteger(32),
			       0,
			       create_qualified_type(theEnv, cloneType)) ;
  }
  if (referenceClone != NULL)
  {
    QualifiedType* refType = 
      dynamic_cast<QualifiedType*>(referenceClone->get_reference_type()) ;
    assert(refType != NULL) ;
    DataType* clonedType = CloneDataType(refType->get_base_type()) ;
    
    return create_reference_type(theEnv,
				 IInteger(32),
				 0,
				 create_qualified_type(theEnv, clonedType)) ;
  }
  if (arrayClone != NULL)
  {
    QualifiedType* elementType = arrayClone->get_element_type() ;
    DataType* internalType = CloneDataType(elementType->get_base_type()) ;
    QualifiedType* finalQual = create_qualified_type(theEnv, internalType) ;
    return create_pointer_type(theEnv,
			       IInteger(32),
			       0, 
			       finalQual) ;    
  }
  return dynamic_cast<DataType*>(t->deep_clone()) ;
}
bool ConstantArrayPropagationPass::ValidSymbol(VariableSymbol* var)
{
  assert(var != NULL) ;
  // The variable should be an array type and have the const qualifier.
  if (dynamic_cast<ArrayType*>(var->get_type()->get_base_type()) == NULL)
  {
    return false ;
  }
  QualifiedType* qualType = var->get_type() ;
  while (dynamic_cast<ArrayType*>(qualType->get_base_type()) != NULL)
  {
    ArrayType* array = dynamic_cast<ArrayType*>(qualType->get_base_type()) ;
    qualType = array->get_element_type() ;
  }
  assert(qualType != NULL) ;
  for (int i = 0 ; i < qualType->get_qualification_count(); ++i)
  {
    if (qualType->get_qualification(i) == LString("const"))
    {
      return true ;
    }
  }
  return false ;
}
void ReferenceCleanupPass::CleanupCall(CallStatement* c)
{
  assert(procDef != NULL) ;
  assert(c != NULL) ;

  // We only need to clean up module calls.  If they are built in
  //  functions, like boolsel, we don't want to do this.
  if (IsBuiltIn(c))
  {
    return ;
  }
  
  // Go through the arguments and see if any of them are load variable
  //  expressions to a reference typed variable, and replace those with
  //  symbol address expressions
  for (unsigned int i = 0 ; i < c->get_argument_count() ; ++i)
  {
    Expression* currentArg = c->get_argument(i) ;
    LoadVariableExpression* currentLoadVar = 
      dynamic_cast<LoadVariableExpression*>(currentArg) ;
    if (currentLoadVar != NULL)
    {
      VariableSymbol* currentVar = currentLoadVar->get_source() ;
      DataType* varType = currentVar->get_type()->get_base_type() ;
      ReferenceType* refType = dynamic_cast<ReferenceType*>(varType) ;
      if (refType != NULL)
      {
	QualifiedType* internalType = 
	  dynamic_cast<QualifiedType*>(refType->get_reference_type()) ;
	assert(internalType != NULL) ;
	//	currentVar->set_type(internalType) ;
	SymbolAddressExpression* symAddrExp = 
	  create_symbol_address_expression(theEnv, 
					   internalType->get_base_type(),
					   currentVar) ;
	if (currentLoadVar->lookup_annote_by_name("UndefinedPath") != NULL)
	{
	  symAddrExp->append_annote(create_brick_annote(theEnv, "UndefinedPath")) ;
	}
	currentLoadVar->get_parent()->replace(currentLoadVar, symAddrExp) ;
      }
    }
  }
}
void ExportPass::ConstructSystemSymbols()
{
  ProcedureSymbol* originalSymbol = originalProcedure->get_procedure_symbol() ;
  assert(originalSymbol != NULL) ;
  CProcedureType* originalType = 
    dynamic_cast<CProcedureType*>(originalSymbol->get_type()) ;
  assert(originalType != NULL) ;

  constructedType = create_c_procedure_type(theEnv,
    dynamic_cast<DataType*>(originalType->get_result_type()->deep_clone()),
					    false, // has variable arguments
					    false, // arguments known
					    0) ; // bit alignment

  // The system has been written in one of two ways, either the old
  //  way where there are no arguments, or the new way where everything
  //  is put into the arguments.
  
  if (originalType->get_argument_count() > 0)
  {
    for (int i = 0 ; i < originalType->get_argument_count() ; ++i)
    {
      QualifiedType* originalArgument = originalType->get_argument(i) ;
      DataType* originalBase = originalArgument->get_base_type() ;
      DataType* constructedBase = CloneDataType(originalBase) ;
      QualifiedType* constructedArgument = 
	create_qualified_type(theEnv, constructedBase) ;
      constructedType->append_argument(constructedArgument) ;

      // Go through the symbol table and find the parameter symbol 
      //  that matches the parameter number, and check to see if it
      //  is an output or not...
      SymbolTable* symTab = originalProcedure->get_symbol_table() ;
      ParameterSymbol* correspondingSymbol = NULL ;
      for (int j = 0 ; j < symTab->get_symbol_table_object_count() ; ++j)
      {
	ParameterSymbol* currentSym = 
	  dynamic_cast<ParameterSymbol*>(symTab->get_symbol_table_object(j)) ;
	if (currentSym != NULL)
	{
	  BrickAnnote* orderAnnote = dynamic_cast<BrickAnnote*>(currentSym->lookup_annote_by_name("ParameterOrder")) ;
	  assert(orderAnnote != NULL) ;
	  IntegerBrick* orderBrick = 
	    dynamic_cast<IntegerBrick*>(orderAnnote->get_brick(0)) ;
	  assert(orderBrick != NULL) ;
	  if (orderBrick->get_value().c_int() == i)
	  {
	    correspondingSymbol = currentSym ;
	    break ;
	  }
	}
      }
      if (correspondingSymbol != NULL)
      {
        if (correspondingSymbol->lookup_annote_by_name("OutputScalar") != NULL ||
	    correspondingSymbol->lookup_annote_by_name("OutputVariable") != NULL ||
	    correspondingSymbol->lookup_annote_by_name("OutputFifo") != NULL)
        {
	  constructedArgument->append_annote(create_brick_annote(theEnv,
								 "Output")) ;
        }
      }
      //      if (dynamic_cast<ReferenceType*>(originalBase) != NULL)
      //{
      //	constructedArgument->append_annote(create_brick_annote(theEnv,
      //						       "Output")) ;
      //      }
    }
  }
  else
  {   
    SymbolTable* symTab = originalProcedure->get_symbol_table() ;
    assert(symTab != NULL) ;
    list<VariableSymbol*> inputScalars ;
    list<VariableSymbol*> inputFifos ; 
    list<VariableSymbol*> outputScalars ;
    list<VariableSymbol*> outputFifos ;

    for (int i = 0 ; i < symTab->get_symbol_table_object_count() ; ++i)
    {
      VariableSymbol* currentVar = 
	dynamic_cast<VariableSymbol*>(symTab->get_symbol_table_object(i)) ;
      if (currentVar != NULL &&
	  currentVar->lookup_annote_by_name("InputScalar") != NULL &&
	  currentVar->lookup_annote_by_name("TemporalFeedback") == NULL &&
	  currentVar->lookup_annote_by_name("NormalFeedback") == NULL &&
	  currentVar->lookup_annote_by_name("DebugRegister") == NULL)
      {
	inputScalars.push_back(currentVar) ;
      }
      if (currentVar != NULL &&
	  currentVar->lookup_annote_by_name("InputFifo") != NULL)
      {
	inputFifos.push_back(currentVar) ;
      }
      if (currentVar != NULL &&
	  currentVar->lookup_annote_by_name("OutputVariable") != NULL &&
	  currentVar->lookup_annote_by_name("Dummy") == NULL &&
	  currentVar->lookup_annote_by_name("FeedbackSource") == NULL)
      {
	outputScalars.push_back(currentVar) ;
      }
      if (currentVar != NULL &&
	  currentVar->lookup_annote_by_name("OutputFifo") != NULL)
      {
	outputFifos.push_back(currentVar) ;
      }
    }
    // Add the types of the input scalars, then the input fifos, 
    //  then the output scalars, and finally the output fifos.
    list<VariableSymbol*>::iterator varIter = inputScalars.begin() ;
    while (varIter != inputScalars.end())
    {
      QualifiedType* originalQual = (*varIter)->get_type() ;
      assert(originalQual != NULL) ;
      DataType* originalBase = originalQual->get_base_type() ;
      assert(originalBase != NULL) ;
      DataType* constructedBase = 
	dynamic_cast<DataType*>(originalBase->deep_clone()) ;
      QualifiedType* constructedQual = 
	create_qualified_type(theEnv, constructedBase) ;
      constructedType->append_argument(constructedQual) ;
      ++varIter ;
    }
    varIter = inputFifos.begin() ;
    while (varIter != inputFifos.end())
    {
      QualifiedType* originalQual = (*varIter)->get_type() ;
      assert(originalQual != NULL) ;
      DataType* originalBase = originalQual->get_base_type() ;
      assert(originalBase != NULL) ;
      // Fifos will have pointer types or reference types.  A 
      //  simple deep clone will not suffice, I need to build up a
      //  new type from the bottom up.
      DataType* constructedBase = CloneDataType(originalBase) ;
      assert(constructedBase != NULL) ;
      QualifiedType* constructedQual = 
	create_qualified_type(theEnv, constructedBase) ;
      assert(constructedBase != NULL) ;
      assert(constructedType != NULL) ;
      constructedType->append_argument(constructedQual) ;
      ++varIter ;
    }
    varIter = outputScalars.begin() ;
    while (varIter != outputScalars.end())
    {
      QualifiedType* originalQual = (*varIter)->get_type() ;
      DataType* originalBase = originalQual->get_base_type() ;
      DataType* constructedBase = CloneDataType(originalBase) ;
      QualifiedType* constructedQual = 
	create_qualified_type(theEnv, constructedBase) ;
      constructedQual->append_annote(create_brick_annote(theEnv, "Output")) ;
      constructedType->append_argument(constructedQual) ;
      ++varIter ;
    }
    varIter = outputFifos.begin() ;
    while (varIter != outputFifos.end())
    {
      QualifiedType* originalQual = (*varIter)->get_type() ;
      assert(originalQual != NULL) ;
      DataType* originalBase = originalQual->get_base_type() ;
      assert(originalBase != NULL) ;
      DataType* constructedBase = CloneDataType(originalBase) ;
      assert(constructedBase != NULL) ;
      QualifiedType* constructedQual = 
	create_qualified_type(theEnv, constructedBase) ;
      assert(constructedQual != NULL) ;
      constructedQual->append_annote(create_brick_annote(theEnv, "Output")) ;
      assert(constructedType != NULL) ;
      constructedType->append_argument(constructedQual) ;
      ++varIter ;
    }
    
  }
  constructedSymbol = create_procedure_symbol(theEnv, constructedType,
					      originalProcedure->get_procedure_symbol()->get_name()) ;
}
// Do a sort of garbage collection.  Take all of the types that we want to
//  delete and collect them.  If there are no uses of them after this function
//  has finished, then remove them.
void RemoveModulePass::RemoveProcedure(ProcedureSymbol* p)
{
    assert(repository != NULL) ;
    list<Type*> usedTypes ;

    if (p == NULL)
    {
        return ;
    }

    // There should be no definition, but just in case remove it
    ProcedureDefinition* defToRemove = p->get_definition() ;
    p->set_definition(NULL) ;
    if (defToRemove != NULL)
    {
        delete defToRemove ;
    }

    // Clear out all of the values associated with the procedure type
    CProcedureType* procType =
        dynamic_cast<CProcedureType*>(p->get_type()) ;
    assert(procType != NULL) ;

    DataType* returnTypeToRemove = procType->get_result_type() ;
    procType->set_result_type(NULL) ;
    if (returnTypeToRemove != NULL)
    {
        usedTypes.push_back(returnTypeToRemove) ;
    }

    while (procType->get_argument_count() > 0)
    {
        QualifiedType* currentArg = procType->get_argument(0) ;
        procType->remove_argument(0) ;
        if (!InList(usedTypes, currentArg))
        {
            usedTypes.push_back(currentArg) ;
        }
    }
    SymbolTable* symTab = repository->get_external_symbol_table() ;
    p->set_type(NULL) ;
    symTab->remove_symbol_table_object(procType) ;
    delete procType ;
    symTab->remove_symbol_table_object(p) ;
    delete p ;

    // Now, go through each used type and see if it is used anywhere
    list<Type*>::iterator typeIter = usedTypes.begin() ;
    while (typeIter != usedTypes.end())
    {
        bool removeMe = true ;
        for (int i = 0 ; i < symTab->get_symbol_table_object_count() ; ++i)
        {
            CProcedureType* currentType =
                dynamic_cast<CProcedureType*>(symTab->get_symbol_table_object(i)) ;
            if (currentType != NULL)
            {
                if (IsUsed(*typeIter, currentType))
                {
                    removeMe = false ;
                    break ;
                }
            }
        }
        if (removeMe)
        {
            if ((*typeIter)->lookup_annote_by_name("Output") != NULL)
            {
                delete (*typeIter)->remove_annote_by_name("Output") ;
            }
            QualifiedType* q = dynamic_cast<QualifiedType*>(*typeIter) ;
            DataType* d = dynamic_cast<DataType*>(*typeIter) ;
            if (q != NULL)
            {
                DataType* internalD = q->get_base_type() ;
                q->set_base_type(NULL) ;
                symTab->remove_symbol_table_object(internalD) ;
                symTab->remove_symbol_table_object(q) ;
                delete internalD ;
                delete q ;
            }
            else if (d != NULL)
            {
                symTab->remove_symbol_table_object(d) ;
                delete d ;
            }
            else
            {
                assert(0 && "Trying to remove something weird...") ;
            }

        }
        ++typeIter ;
    }

}
// All of the array references expressions in the passed in the struct are
//  equivalent, so we can determine types of the original and use that
//  to create a new expression with which to replace everything.
bool TransformUnrolledArraysPass::ReplaceNDReference(EquivalentReferences* a)
{
  assert(a != NULL) ;
  assert(a->original != NULL) ;

  // Check to see if the reference at this stage is a constant or not
  IntConstant* constantIndex = 
    dynamic_cast<IntConstant*>(a->original->get_index()) ;
  
  if (constantIndex == NULL)
  {
    // There was no replacement made
    return false ;
  }

  Expression* baseAddress = a->original->get_base_array_address() ;
  assert(baseAddress != NULL) ;
  assert(constantIndex != NULL) ;

  // Create a replacement expression for this value.  This will either
  //  be another array reference expression or a single variable.
  Expression* replacementExp = NULL ;
  //  QualifiedType* elementType = GetQualifiedTypeOfElement(a->original) ;
  VariableSymbol* originalSymbol = GetArrayVariable(a->original) ;
  assert(originalSymbol != NULL) ;
  LString replacementName = 
    GetReplacementName(originalSymbol->get_name(), 
		       constantIndex->get_value().c_int()) ;
  int dimensionality = GetDimensionality(a->original) ;
  
  QualifiedType* elementType = originalSymbol->get_type() ;
  while (dynamic_cast<ArrayType*>(elementType->get_base_type()) != NULL)
  {
    elementType = dynamic_cast<ArrayType*>(elementType->get_base_type())->get_element_type() ;
  }
  
  // There is a special case for one dimensional arrays as opposed to all
  //  other dimensional arrays.  It only should happen if we are truly
  //  replacing an array with a one dimensional array.
  if (dimensionality == 1 && 
      dynamic_cast<ArrayReferenceExpression*>(a->original->get_parent())==NULL)
  {

    VariableSymbol* replacementVar = 
      create_variable_symbol(theEnv,
			     GetQualifiedTypeOfElement(a->original),
			     TempName(replacementName)) ;
    procDef->get_symbol_table()->append_symbol_table_object(replacementVar) ;
    
    replacementExp = 
      create_load_variable_expression(theEnv,
				      elementType->get_base_type(),
				      replacementVar) ;
  }
  else
  {
    // Create a new array with one less dimension.  This requires a new
    //  array type.
    ArrayType* varType = 
      dynamic_cast<ArrayType*>(originalSymbol->get_type()->get_base_type()) ;
    assert(varType != NULL) ;
   
    ArrayType* replacementArrayType =
      create_array_type(theEnv,
	varType->get_element_type()->get_base_type()->get_bit_size(),
	0, // bit alignment
	OneLessDimension(originalSymbol->get_type(), dimensionality),
	dynamic_cast<Expression*>(varType->get_lower_bound()->deep_clone()),
	dynamic_cast<Expression*>(varType->get_upper_bound()->deep_clone()),
	TempName(varType->get_name())) ;

    procDef->get_symbol_table()->append_symbol_table_object(replacementArrayType) ;

    VariableSymbol* replacementArraySymbol = 
      create_variable_symbol(theEnv,
			     create_qualified_type(theEnv,
						   replacementArrayType,
						   TempName(LString("qualType"))),
			     TempName(replacementName)) ;

    procDef->get_symbol_table()->append_symbol_table_object(replacementArraySymbol) ;

    // Create a new symbol address expression for this variable symbol
    SymbolAddressExpression* replacementAddrExp =
      create_symbol_address_expression(theEnv,
				       replacementArrayType,
				       replacementArraySymbol) ;

    // Now, replace the symbol address expression in the base
    //  array address with this symbol.
    ReplaceSymbol(a->original, replacementAddrExp) ;
    
    // And replace this reference with the base array address.
    replacementExp = a->original->get_base_array_address() ;
    a->original->set_base_array_address(NULL) ;
    replacementExp->set_parent(NULL) ;
  }

  // Replace all of the equivalent expressions with the newly generated
  //  replacement expression.
  assert(replacementExp != NULL) ;
  a->original->get_parent()->replace(a->original, replacementExp) ;
   
  //  ReplaceChildExpression(a->original->get_parent(),
  //			 a->original,
  //			 replacementExp) ;

  list<ArrayReferenceExpression*>::iterator equivIter = 
    a->allEquivalent.begin() ;
  while (equivIter != a->allEquivalent.end()) 
  {
    (*equivIter)->get_parent()->replace((*equivIter),
					dynamic_cast<Expression*>(replacementExp->deep_clone())) ;
    //    ReplaceChildExpression((*equivIter)->get_parent(),
    //			   (*equivIter),
    //			   dynamic_cast<Expression*>(replacementExp->deep_clone())) ;
    ++equivIter ;
  }

  return true ;
}
void TransformSystemsToModules::Transform()
{
  assert(procDef != NULL) ;

  // Collect all the input scalars and output scalars
  list<VariableSymbol*> ports ;
  
  SymbolTable* procSymTab = procDef->get_symbol_table() ;
  bool foundInputs = false ;
  bool foundOutputs = false ;
 
  for (int i = 0 ; i < procSymTab->get_symbol_table_object_count() ; ++i)
  {
    SymbolTableObject* nextObject = procSymTab->get_symbol_table_object(i) ;

    if (nextObject->lookup_annote_by_name("InputScalar") != NULL)
    {
      VariableSymbol* toConvert = 
	dynamic_cast<VariableSymbol*>(nextObject) ;
      assert(toConvert != NULL) ;
      LString inputName = toConvert->get_name() ;
      inputName = inputName + "_in" ;
      toConvert->set_name(inputName) ;
      ports.push_back(toConvert) ;
      foundInputs = true ;
    }
    if (nextObject->lookup_annote_by_name("OutputVariable") != NULL)
    {
      VariableSymbol* toConvert = 
	dynamic_cast<VariableSymbol*>(nextObject) ;
      assert(toConvert != NULL) ;
      LString outputName = toConvert->get_name() ;
      outputName = outputName + "_out" ;
      toConvert->set_name(outputName) ;
      ports.push_back(toConvert) ;
      foundOutputs = true ;
    }
  }
  assert(foundInputs && 
	 "Could not identify inputs.  Were they removed via optimizations?") ;
  assert(foundOutputs && 
	 "Could not identify outputs.  Were they removed via optimizations?") ;

  // Determine the bit size and add everything to a new symbol table
  int bitSize = 0 ;
  GroupSymbolTable* structTable = 
    create_group_symbol_table(theEnv,
			      procDef->get_symbol_table()) ;

  std::map<VariableSymbol*, FieldSymbol*> replacementFields ;

  bool portsRemoved = false ;
  // If this was actually a new style module, we should make sure to
  //  put these in the correct order.
  if (isModule(procDef))
  {
    // Go through the original symbol table and remove any parameter 
    //  symbols that originally existed
    SymbolTable* originalSymTab = procDef->get_symbol_table() ;
    Iter<SymbolTableObject*> originalIter = 
      originalSymTab->get_symbol_table_object_iterator() ;
    while (originalIter.is_valid())
    {
      SymbolTableObject* currentObj = originalIter.current() ;
      originalIter.next() ;
      if (dynamic_cast<ParameterSymbol*>(currentObj) != NULL)
      {
	originalSymTab->remove_symbol_table_object(currentObj) ;
      }
    }
    portsRemoved = true ;

    // Sort the variable symbols in parameter order.  This is just an 
    //  insertion sort, so it could be done faster.
    list<VariableSymbol*> sortedPorts ;
    for (int i = 0 ; i < ports.size() ; ++i)
    {
      list<VariableSymbol*>::iterator portIter = ports.begin() ;
      while (portIter != ports.end())
      {
	BrickAnnote* orderAnnote = 
	  dynamic_cast<BrickAnnote*>((*portIter)->
				     lookup_annote_by_name("ParameterOrder")) ;
	if (orderAnnote == NULL)
	{
	  ++portIter ;
	  continue ;
	}
	IntegerBrick* orderBrick = 
	  dynamic_cast<IntegerBrick*>(orderAnnote->get_brick(0)) ;
	assert(orderBrick != NULL) ;
	if (orderBrick->get_value().c_int() == i)
	{
	  sortedPorts.push_back(*portIter) ;
	  break ;
	}
	++portIter ;
      }
    }
    if (sortedPorts.size() != ports.size())
    {
      OutputWarning("Warning! Analysis detected some input scalars not in"
		    " the parameter list") ;
    }
    // Replace ports with sortedPorts
    ports = sortedPorts ;
  }

  list<VariableSymbol*>::iterator portIter = ports.begin() ;  
  while (portIter != ports.end()) 
  {
    bitSize += 
      (*portIter)->get_type()->get_base_type()->get_bit_size().c_int() ;

    LString dupeName = (*portIter)->get_name() ;

    // Create offset expression:
    IntConstant* offset = 
      create_int_constant(theEnv,
			  create_data_type(theEnv,
					   IInteger(32),
					   0),
			  IInteger(bitSize)) ;


    QualifiedType* dupeType = (*portIter)->get_type() ;
    // Deal with the case where reference types were passed in
    ReferenceType* refType = 
      dynamic_cast<ReferenceType*>(dupeType->get_base_type()) ;
    while (refType != NULL)
    {
      dupeType = dynamic_cast<QualifiedType*>(refType->get_reference_type()) ;
      assert(dupeType != NULL) ;
      refType = dynamic_cast<ReferenceType*>(dupeType->get_base_type()) ;
    }

    // Create a new variable symbol clone
    FieldSymbol* dupe = 
      create_field_symbol(theEnv,
			  dupeType,
			  offset,
			  dupeName) ;
        
    structTable->append_symbol_table_object(dupe) ;

    // Make the connection with the duplicated symbol
    replacementFields[(*portIter)] = dupe ;

    // Remove the original variable symbol from the procedure definition
    //  symbol table.
    if (!portsRemoved)
    {
      procDef->get_symbol_table()->remove_symbol_table_object(*portIter) ;
    }
    
    ++portIter ;
  }
  assert(bitSize != 0);

  StructType* moduleStruct = 
    create_struct_type(theEnv,
		       IInteger(bitSize),
		       0, // bit_alignment
		       TempName(procDef->get_procedure_symbol()->get_name()),
		       0, // is_complete
		       structTable) ;

  
  Iter<FileBlock*> fBlocks = 
    theEnv->get_file_set_block()->get_file_block_iterator() ;
  
  assert(fBlocks.is_valid()) ;
  (fBlocks.current())->get_symbol_table()->append_symbol_table_object(moduleStruct) ;
  
  // This is commented out because it is in the file state block
  //procDef->get_symbol_table()->append_symbol_table_object(moduleStruct) ;

  QualifiedType* qualifiedModuleStruct =
    create_qualified_type(theEnv,
			  moduleStruct,
			  TempName(LString("qualifiedModuleStruct"))) ;
  
  procDef->get_symbol_table()->append_symbol_table_object(qualifiedModuleStruct) ;

  // Create an instance of this type and add it to the symbol table.
  ParameterSymbol* structInstance = 
    create_parameter_symbol(theEnv,
			   qualifiedModuleStruct,
			   TempName(LString("structInstance"))) ;

  procDef->get_symbol_table()->append_symbol_table_object(structInstance) ;

  // Now, set up the procedure symbol to take the struct and return the 
  //  struct.
  assert(procDef != NULL) ;
  ProcedureSymbol* procSym = procDef->get_procedure_symbol() ;
  assert(procSym != NULL) ;
  ProcedureType* procType = procSym->get_type() ;
  assert(procType != NULL) ;
  CProcedureType* cProcType = dynamic_cast<CProcedureType*>(procType) ;
  assert(cProcType != NULL) ;

  // Instead of appending the struct argument, we need to replace all of the 
  //  arguments with the struct.

  while (cProcType->get_argument_count() > 0)
  {
    cProcType->remove_argument(0) ;
  }

  cProcType->set_result_type(moduleStruct) ;
  cProcType->append_argument(qualifiedModuleStruct) ;

  // Now go through all load variable expressions and replace them all with
  //  field symbol values if appropriate
  
  list<LoadVariableExpression*>* allLoads = 
    collect_objects<LoadVariableExpression>(procDef->get_body()) ;

  list<LoadVariableExpression*>::iterator loadIter = allLoads->begin() ;
  while (loadIter != allLoads->end())
  {
    VariableSymbol* currentVariable = (*loadIter)->get_source() ;
    if (replacementFields.find(currentVariable) != replacementFields.end())
    {
      (*loadIter)->set_source(replacementFields[currentVariable]) ;
    }
    ++loadIter ;
  }
  delete allLoads ;

  // Also replace all of the definitions with the field symbol
  list<StoreVariableStatement*>* allStoreVars = 
    collect_objects<StoreVariableStatement>(procDef->get_body()) ;
  list<StoreVariableStatement*>::iterator storeVarIter = allStoreVars->begin();
  while (storeVarIter != allStoreVars->end())
  {
    VariableSymbol* currentDest = (*storeVarIter)->get_destination() ;
    if (replacementFields.find(currentDest) != replacementFields.end())
    {
      (*storeVarIter)->set_destination(replacementFields[currentDest]) ;
    }
    ++storeVarIter ;
  }
  delete allStoreVars ;

  list<SymbolAddressExpression*>* allSymAddr = 
    collect_objects<SymbolAddressExpression>(procDef->get_body()) ;
  list<SymbolAddressExpression*>::iterator symAddrIter = allSymAddr->begin() ;
  while (symAddrIter != allSymAddr->end())
  {
    VariableSymbol* currentVar = 
      dynamic_cast<VariableSymbol*>((*symAddrIter)->get_addressed_symbol()) ;
    if (currentVar != NULL &&
	replacementFields.find(currentVar) != replacementFields.end())
    {
      (*symAddrIter)->set_addressed_symbol(replacementFields[currentVar]) ;
    }
    ++symAddrIter ;
  }
  delete allSymAddr ;
  // One final for bool selects
  list<CallStatement*>* allCalls = 
    collect_objects<CallStatement>(procDef->get_body()) ;
  list<CallStatement*>::iterator callIter = allCalls->begin() ;
  while(callIter != allCalls->end())
  {
    VariableSymbol* currentVar = (*callIter)->get_destination() ;
    if (currentVar != NULL &&
	replacementFields.find(currentVar) != replacementFields.end())
    {
      (*callIter)->set_destination(replacementFields[currentVar]) ;
    }
    ++callIter ;
  }
  delete allCalls ;
}
void DismantleStructuredReturns::do_file_set_block( FileSetBlock* file_set_block ) {
    suif_map<CProcedureType *,QualifiedType *> type_map;
    list<ArrayReferenceExpression*> ref_exprs;
    SuifEnv *env = 0;
    TypeBuilder *tb = 0;
    VoidType *vt = 0;
    for (Iter<ProcedureSymbol> iter =
                object_iterator<ProcedureSymbol>(file_set_block);
	iter.is_valid();
	iter.next()) {
	ProcedureSymbol *sym = &iter.current();
	Type *type = sym->get_type();
	if (!is_kind_of<CProcedureType>(type))
	    continue;
	CProcedureType *cp_type = to<CProcedureType>(type);
	type = cp_type->get_result_type();
	if (!env) {
	    env = type->get_suif_env();
	    tb = (TypeBuilder*)
                env->get_object_factory(TypeBuilder::get_class_name());
	    vt = tb->get_void_type();
	    }
	suif_map<CProcedureType *,QualifiedType *>::iterator t_iter = type_map.find(cp_type);

	QualifiedType *qtype;
	
 	if (t_iter == type_map.end()) {
	    if (!is_kind_of<GroupType>(type) && !is_kind_of<ArrayType>(type))
                continue;
	    qtype = tb->get_qualified_type(
                        tb->get_pointer_type(to<DataType>(type)));

	    cp_type->set_result_type(vt);
	    
	    cp_type->insert_argument(0,qtype);
	    type_map.enter_value(cp_type,qtype);
	    }
	else {
	    qtype = (*t_iter).second;
	    }
	ProcedureDefinition *def = sym->get_definition();
	if (!def) 
	    continue;
	ParameterSymbol *par = create_parameter_symbol(env,qtype);
	def->get_symbol_table()->append_symbol_table_object(par);
        def->insert_formal_parameter(0,par);
	//	Convert all returns into assigned and returns
	for (Iter<ReturnStatement> ret_iter = object_iterator<ReturnStatement>(def->get_body());
        	ret_iter.is_valid();
        	ret_iter.next()) {
	    ReturnStatement *ret = &ret_iter.current();
	    Expression *retval = ret->get_return_value();
	    ret->set_return_value(0);
	    retval->set_parent(0);
	    insert_statement_before(ret,
			create_store_statement(env,retval,create_var_use(par)));
	    }
	}
    //	Change all calls to the new form
    for (Iter<CallStatement> cs_iter =
                object_iterator<CallStatement>(file_set_block);
        cs_iter.is_valid();
        cs_iter.next()) {
        CallStatement *call = &cs_iter.current();
	Type *type = call->get_callee_address()->get_result_type();
	Type *p_type = tb->unqualify_type(to<PointerType>(type)->get_reference_type());
        if (!is_kind_of<PointerType>(p_type))
            continue;
        p_type = tb->unqualify_type(to<PointerType>(p_type)->get_reference_type());

	if (!is_kind_of<CProcedureType>(p_type))
	    continue;
	CProcedureType *cp_type = to<CProcedureType>(p_type);
	
	suif_map<CProcedureType *,QualifiedType *>::iterator t_iter = type_map.find(cp_type);
	if (t_iter == type_map.end())
	    continue;
	QualifiedType *qtype = (*t_iter).second;
	DataType *var_type = to<DataType>(tb->unqualify_type(to<PointerType>(qtype->get_base_type())
		->get_reference_type()));
	VariableSymbol *var =
      	    new_anonymous_variable(env,call,tb->get_qualified_type(var_type));
	Expression *exp = create_symbol_address_expression(
		env,
		tb->get_pointer_type(var_type),
		var);
        call->insert_argument(0,exp);
        call->set_destination(0);
	}

    for (Iter<CallExpression> ce_iter =
                object_iterator<CallExpression>(file_set_block);
        ce_iter.is_valid();
        ce_iter.next()) {
        CallExpression *call = &ce_iter.current();
        Type *type = call->get_callee_address()->get_result_type();
        Type *p_type = tb->unqualify_type(to<PointerType>(type)->get_reference_type());
	if (!is_kind_of<PointerType>(p_type))
            continue;
	p_type = tb->unqualify_type(to<PointerType>(p_type)->get_reference_type());
        if (!is_kind_of<CProcedureType>(p_type))
            continue;
        CProcedureType *cp_type = to<CProcedureType>(p_type);
;
        suif_map<CProcedureType *,QualifiedType *>::iterator t_iter = type_map.find(cp_type);
        if (t_iter == type_map.end())
            continue;
        QualifiedType *qtype = (*t_iter).second;
        DataType *var_type = to<DataType>(tb->unqualify_type(to<PointerType>(qtype->get_base_type())
                ->get_reference_type()));
        VariableSymbol *var =
            new_anonymous_variable(env,call,tb->get_qualified_type(var_type));
        Expression *exp = create_symbol_address_expression(
                env,
                tb->get_pointer_type(var_type),
                var);
        call->insert_argument(0,exp);

	Statement *loc = get_expression_owner(call);
	call->get_parent()->replace(call,create_var_use(var));
	call->set_parent(0);
        suif_assert(vt != 0);
        call->set_result_type(vt);

	EvalStatement *es = create_eval_statement(env);
	insert_statement_before(loc,es);
	// Would be better to turn this into a call statement
	es->append_expression(call);
        }
    }