<commit_before>/*****************************************************************************\
 * Copyright 2005, 2006, 2007 Niels Lohmann, Christian Gierds                *
 *                                                                           *
 * This file is part of GNU BPEL2oWFN.                                       *
 *                                                                           *
 * GNU BPEL2oWFN is free software; you can redistribute it and/or modify it  *
 * under the terms of the GNU General Public License as published by the     *
 * Free Software Foundation; either version 2 of the License, or (at your    *
 * option) any later version.                                                *
 *                                                                           *
 * GNU BPEL2oWFN is distributed in the hope that it will be useful, but      *
 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General  *
 * Public License for more details.                                          *
 *                                                                           *
 * You should have received a copy of the GNU General Public License along   *
 * with GNU BPEL2oWFN; see file COPYING. if not, write to the Free Software  *
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
\*****************************************************************************/

/*!
 * \file    bpel2owfn.cc
 *
 * \brief   BPEL2oWFN's main
 *
 * \author  Niels Lohmann <nlohmann@informatik.hu-berlin.de>,
 *          Christian Gierds <gierds@informatik.hu-berlin.de>,
 *          last changes of: \$Author: gierds $
 *
 * \since   2005/10/18
 *
 * \date    \$Date: 2007/03/27 12:37:48 $
 *
 * \note    This file is part of the tool BPEL2oWFN and was created during the
 *          project "Tools4BPEL" at the Humboldt-Universitt zu Berlin. See
 *          http://www.informatik.hu-berlin.de/top/forschung/projekte/tools4bpel
 *          for details.
 *
 * \version \$Revision: 1.152 $
 */

/******************************************************************************
 * Headers
 *****************************************************************************/

#include <cstdio>
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
#include <map>

#include "bpel2owfn.h"          // generated configuration file

#include "petrinet.h"           // Petri Net support
#include "cfg.h"		// Control Flow Graph
#include "debug.h"		// debugging help
#include "options.h"
#include "ast-config.h"
#include "ast-details.h"
#include "globals.h"

using std::cerr;
using std::cout;
using std::endl;
using std::string;
using std::map;

/******************************************************************************
 * External functions
 *****************************************************************************/

extern int frontend_parse();			// from Bison
extern int frontend_debug;			// from Bison
extern int frontend__flex_debug;		// from flex
extern FILE *frontend_in;			// from flex

/******************************************************************************
 * Global variables
 *****************************************************************************/

/// The Petri Net
PetriNet PN = PetriNet();

/*!
 * \brief entry point of BPEL2oWFN
 *
 * Controls the behaviour of input and output.
 *
 * \param argc	number of command line arguments
 * \param argv	array with command line arguments
 *
 * \returns 0 if everything went well
 * \returns 1 if an error occurred
 *
 * \todo This function is definitly too long. It should be partitioned!
 */
int main( int argc, char *argv[])
{
  globals::program_name = string(argv[0]);

  // generate the invocation string
  for (int i = 0; i < argc; i++)
  {
    globals::invocation += string(argv[i]);
    if (i != (argc-1))
      globals::invocation += " ";
  }

  /*
   * Reading command line arguments and triggering appropriate behaviour.
   * In case of false parameters call command line help function and exit.
   */
  parse_command_line(argc, argv);

  PetriNet PN2 = PetriNet();

  set< string >::iterator file = inputfiles.begin();

  do
  {
    if (inputfiles.size() >= 1)
    {
      globals::filename = *file;
      if (!(frontend_in = fopen(globals::filename.c_str(), "r"))) {
		cerr << "Could not open file for reading: " << globals::filename.c_str() << endl;
		exit(1);
	    }
    }

    trace(TRACE_INFORMATION, "Parsing " + globals::filename + " ...\n");

    // invoke Bison parser
    int error = frontend_parse();

    if (!error)
    {
      trace(TRACE_INFORMATION, "Parsing complete.\n");

      if ( globals::filename != "<STDIN>" && frontend_in != NULL)
      {
	trace(TRACE_INFORMATION," + Closing input file: " + globals::filename + "\n");
	fclose(frontend_in);
      }

      // apply first set of rewrite rules
      trace(TRACE_INFORMATION, "Rewriting...\n");
      globals::AST = globals::AST->rewrite(kc::invoke);
      globals::AST = globals::AST->rewrite(kc::implicit);
      trace(TRACE_INFORMATION, "Rewriting complete...\n");

      // postprocess and annotate the AST
      trace(TRACE_INFORMATION, "Postprocessing...\n");
      globals::AST->unparse(kc::printer, kc::postprocessing);
      trace(TRACE_INFORMATION, "Postprocessing complete...\n");

      // apply second set of rewrite rules
      trace(TRACE_INFORMATION, "Rewriting 2...\n");
      globals::AST = globals::AST->rewrite(kc::newNames);
      trace(TRACE_INFORMATION, "Rewriting 2 complete...\n");

      // print information about the process
      show_process_information();

// an experiment
//      cout << "digraph G{" << endl;
//      globals::ASTEmap[1]->output();
//      cout << "}" << endl;

      // print the AST?
      if (modus == M_AST)
      {
	trace(TRACE_INFORMATION, "-> Printing AST ...\n");
	if (formats[F_DOT])
	{
	  string dot_filename = globals::output_filename + "." + suffixes[F_DOT];
	  FILE *dotfile = fopen(dot_filename.c_str(), "w+");
	  globals::AST->fprintdot(dotfile, "", "", "", true, true, true);
	  fclose(dotfile);
#ifdef HAVE_DOT
  	  string systemcall = "dot -q -Tpng -o" + globals::output_filename + ".png " + globals::output_filename + "." + suffixes[F_DOT];
  	  trace(TRACE_INFORMATION, "Invoking dot with the following options:\n");
  	  trace(TRACE_INFORMATION, systemcall + "\n\n");
  	  system(systemcall.c_str());
#endif
	}
	else
	  globals::AST->print();
      }

      if (modus == M_PRETTY)
      {
        if (formats[F_XML])
        {
          if (globals::output_filename != "")
          {
            output = openOutput(globals::output_filename + "." + suffixes[F_XML]);
          }
          trace(TRACE_INFORMATION, "-> Printing \"pretty\" XML ...\n");
          globals::AST->unparse(kc::printer, kc::xml);
          if (globals::output_filename != "")
          {
            closeOutput(output);
	    output = NULL;
          }
        }
      }

        // generate and process the control flow graph?
      if (modus == M_CFG)
	processCFG();

      // generate a Petri net?
      if (modus == M_PETRINET || modus == M_CONSISTENCY)
      {
	trace(TRACE_INFORMATION, "-> Unparsing AST to Petri net ...\n");

	// choose Petri net patterns
	if (globals::parameters[P_COMMUNICATIONONLY] == true)
	  globals::AST->unparse(kc::pseudoPrinter, kc::petrinetsmall);
	else
	  globals::AST->unparse(kc::pseudoPrinter, kc::petrinetnew);

        // calculate maximum occurences
        PN.calculate_max_occurrences();

        if (modus == M_CONSISTENCY)
	{
	  unsigned int pos = file->rfind(".bpel", file->length());
	  unsigned int pos2 = file->rfind("/", file->length());
	  string prefix = "";
	  if (pos == (file->length() - 5))
	  {
	    prefix = file->substr(pos2 + 1, pos - pos2 - 1) + "_";
	  }

	  // apply structural reduction rules?
	  if (globals::parameters[P_REDUCE])
	  {
	    trace(TRACE_INFORMATION, "-> Structurally simplifying Petri Net ...\n");
	    PN.reduce();
	  }

          PN.addPrefix(prefix);
	  PN2.compose(PN);
	  PN = PetriNet();

	  globals::AST = NULL;
	}
      }
    }
    else /* parse error */
    {
      cleanup();
      return error;
    }

    file++;
  } while (modus == M_CONSISTENCY && file != inputfiles.end());

  /*
   * parsing complete
   */

  if (modus == M_CONSISTENCY)
    PN = PN2;

  if (modus == M_PETRINET || modus == M_CONSISTENCY)
  {
    // apply structural reduction rules?
    if ( globals::parameters[P_REDUCE] )
    {
      trace(TRACE_INFORMATION, "-> Structurally simplifying Petri Net ...\n");
      PN.reduce();
    }

    // now the net will not change any more, thus the nodes are re-enumerated
    // and the maximal occurrences of the nodes are calculated.
    PN.reenumerate();
//    PN.calculate_max_occurrences();
    cerr << PN.information() << endl;

    // create oWFN output ?
    if (formats[F_OWFN])
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_OWFN]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for oWFN ...\n");
      PN.set_format(FORMAT_OWFN);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create LoLA output ?
    if ( formats[F_LOLA] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_LOLA]);
      }
      if (modus == M_CONSISTENCY)
      {
	PN.makeChannelsInternal();
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for LoLA ...\n");
      PN.set_format(FORMAT_LOLA);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }

      if (modus == M_CONSISTENCY || modus == M_PETRINET)
      {
	if (globals::output_filename != "")
	{
	  output = openOutput(globals::output_filename + ".task");
	}
	string comment = "{ AG EF (";
	string formula = "FORMULA\n  ALLPATH ALWAYS EXPATH EVENTUALLY (";
	string andStr = "";

        set< Place * > finalPlaces = PN.getFinalPlaces();
	for (set< Place * >::iterator place = finalPlaces.begin(); place != finalPlaces.end(); place++)
	{
	  comment += andStr + (*place)->nodeFullName();
	  formula += andStr + (*place)->nodeShortName() + " > 0";
       	  andStr = " AND ";
	}
	comment += ") }";
	formula += ")";
	(*output) << comment << endl << endl;
	(*output) << formula << endl << endl;
	if (globals::output_filename != "")
	{
	  closeOutput(output);
	  output = NULL;
	}
      }
    }

    // create PNML output ?
    if ( formats[F_PNML] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_PNML]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for PNML ...\n");
      PN.set_format(FORMAT_PNML);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create PEP output ?
    if ( formats[F_PEP] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_PEP]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for PEP ...\n");
      PN.set_format(FORMAT_PEP);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create INA output ?
    if ( formats[F_INA] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_INA]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for INA ...\n");
      PN.set_format(FORMAT_INA);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create SPIN output ?
    if ( formats[F_SPIN] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_SPIN]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for SPIN ...\n");
      PN.set_format(FORMAT_SPIN);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create APNN output ?
    if ( formats[F_APNN] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_APNN]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for APNN ...\n");
      PN.set_format(FORMAT_APNN);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create dot output ?
    if ( formats[F_DOT] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_DOT]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for dot ...\n");
      PN.set_format(FORMAT_DOT);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;

#ifdef HAVE_DOT
	string systemcall = "dot -q -Tpng -o" + globals::output_filename + ".png " + globals::output_filename + "." + suffixes[F_DOT];
	trace(TRACE_INFORMATION, "Invoking dot with the following options:\n");
	trace(TRACE_INFORMATION, systemcall + "\n\n");
	system(systemcall.c_str());
#endif
      }
    }

    // create info file ?
    if ( formats[F_INFO] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_INFO]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net information ...\n");
      PN.set_format(FORMAT_INFO);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }
  }

  // everything went fine
  return 0;
}

/*!
 * \defgroup frontend Front End
 * \defgroup patterns Petri Net Patterns
 */
<commit_msg>+ Partitioned the main function into some program parts<commit_after>/*****************************************************************************\
 * Copyright 2005, 2006, 2007 Niels Lohmann, Christian Gierds                *
 *                                                                           *
 * This file is part of GNU BPEL2oWFN.                                       *
 *                                                                           *
 * GNU BPEL2oWFN is free software; you can redistribute it and/or modify it  *
 * under the terms of the GNU General Public License as published by the     *
 * Free Software Foundation; either version 2 of the License, or (at your    *
 * option) any later version.                                                *
 *                                                                           *
 * GNU BPEL2oWFN is distributed in the hope that it will be useful, but      *
 * WITHOUT ANY WARRANTY; without even the implied warranty of                *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General  *
 * Public License for more details.                                          *
 *                                                                           *
 * You should have received a copy of the GNU General Public License along   *
 * with GNU BPEL2oWFN; see file COPYING. if not, write to the Free Software  *
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
\*****************************************************************************/

/*!
 * \file    bpel2owfn.cc
 *
 * \brief   BPEL2oWFN's main
 *
 * \author  Niels Lohmann <nlohmann@informatik.hu-berlin.de>,
 *          Christian Gierds <gierds@informatik.hu-berlin.de>,
 *          last changes of: \$Author: znamirow $
 *
 * \since   2005/10/18
 *
 * \date    \$Date: 2007/03/29 15:24:26 $
 *
 * \note    This file is part of the tool BPEL2oWFN and was created during the
 *          project "Tools4BPEL" at the Humboldt-Universitt zu Berlin. See
 *          http://www.informatik.hu-berlin.de/top/forschung/projekte/tools4bpel
 *          for details.
 *
 * \version \$Revision: 1.153 $
 */

/******************************************************************************
 * Headers
 *****************************************************************************/

#include <cstdio>
#include <iostream>
#include <fstream>
#include <string>
#include <cassert>
#include <map>

#include "bpel2owfn.h"          // generated configuration file

#include "petrinet.h"           // Petri Net support
#include "cfg.h"		// Control Flow Graph
#include "debug.h"		// debugging help
#include "options.h"
#include "ast-config.h"
#include "ast-details.h"
#include "globals.h"

using std::cerr;
using std::cout;
using std::endl;
using std::string;
using std::map;

/******************************************************************************
 * External functions
 *****************************************************************************/

extern int frontend_parse();			// from Bison
extern int frontend_debug;			// from Bison
extern int frontend__flex_debug;		// from flex
extern FILE *frontend_in;			// from flex

/******************************************************************************
 * Global variables
 *****************************************************************************/

/// The Petri Net
PetriNet PN = PetriNet();

/******************************************************************************
 * program parts
 *****************************************************************************/

// analyzation of the commandline
void analyze_cl(int argc, char *argv[])
{

  // setting globals
  globals::program_name = string(argv[0]);

  for (int i = 0; i < argc; i++)
  {
    globals::invocation += string(argv[i]);
    if (i != (argc-1))
      globals::invocation += " ";
  }

  /*
   * Reading command line arguments and triggering appropriate behaviour.
   * In case of false parameters call command line help function and exit.
   */
  parse_command_line(argc, argv);

}

// opening a file
void open_file(set< string >::iterator file)
{
  if (inputfiles.size() >= 1)
  {
    globals::filename = *file;
    if (!(frontend_in = fopen(globals::filename.c_str(), "r")))
    {
      cerr << "Could not open file for reading: " << globals::filename.c_str() << endl;
      exit(1);
    }
  }
}

// closing a file
void close_file(set< string >::iterator file)
{
  if ( globals::filename != "<STDIN>" && frontend_in != NULL)
  {
    trace(TRACE_INFORMATION," + Closing input file: " + globals::filename + "\n");
    fclose(frontend_in);
  }
}

// finishing AST
void finish_AST()
{
  // apply first set of rewrite rules
  trace(TRACE_INFORMATION, "Rewriting...\n");
  globals::AST = globals::AST->rewrite(kc::invoke);
  globals::AST = globals::AST->rewrite(kc::implicit);
  trace(TRACE_INFORMATION, "Rewriting complete...\n");

  // postprocess and annotate the AST
  trace(TRACE_INFORMATION, "Postprocessing...\n");
  globals::AST->unparse(kc::printer, kc::postprocessing);
  trace(TRACE_INFORMATION, "Postprocessing complete...\n");

  // apply second set of rewrite rules
  trace(TRACE_INFORMATION, "Rewriting 2...\n");
  globals::AST = globals::AST->rewrite(kc::newNames);
  trace(TRACE_INFORMATION, "Rewriting 2 complete...\n");

  // print information about the process
  show_process_information();

  // an experiment
  //      cout << "digraph G{" << endl;
  //      globals::ASTEmap[1]->output();
  //      cout << "}" << endl;
}

// output of every single processed file
void single_output(set< string >::iterator file, PetriNet PN2)
{
  // print the AST?
  if (modus == M_AST)
  {
    trace(TRACE_INFORMATION, "-> Printing AST ...\n");
    if (formats[F_DOT])
    {
      string dot_filename = globals::output_filename + "." + suffixes[F_DOT];
      FILE *dotfile = fopen(dot_filename.c_str(), "w+");
      globals::AST->fprintdot(dotfile, "", "", "", true, true, true);
      fclose(dotfile);
      #ifdef HAVE_DOT
      string systemcall = "dot -q -Tpng -o" + globals::output_filename + ".png " + globals::output_filename + "." + suffixes[F_DOT];
      trace(TRACE_INFORMATION, "Invoking dot with the following options:\n");
      trace(TRACE_INFORMATION, systemcall + "\n\n");
      system(systemcall.c_str());
      #endif
    }
    else
    globals::AST->print();
  }

  if (modus == M_PRETTY)
  {
    if (formats[F_XML])
    {
      if (globals::output_filename != "")
      {
        output = openOutput(globals::output_filename + "." + suffixes[F_XML]);
      }
      trace(TRACE_INFORMATION, "-> Printing \"pretty\" XML ...\n");
      globals::AST->unparse(kc::printer, kc::xml);
      if (globals::output_filename != "")
      {
        closeOutput(output);
        output = NULL;
      }
    }
  }

  // generate and process the control flow graph?
  if (modus == M_CFG)
  processCFG();

  // generate a Petri net?
  if (modus == M_PETRINET || modus == M_CONSISTENCY)
  {
    trace(TRACE_INFORMATION, "-> Unparsing AST to Petri net ...\n");
    // choose Petri net patterns
    if (globals::parameters[P_COMMUNICATIONONLY] == true)
    globals::AST->unparse(kc::pseudoPrinter, kc::petrinetsmall);
    else
    globals::AST->unparse(kc::pseudoPrinter, kc::petrinetnew);

    // calculate maximum occurences
    PN.calculate_max_occurrences();
    if (modus == M_CONSISTENCY)
    {
      unsigned int pos = file->rfind(".bpel", file->length());
      unsigned int pos2 = file->rfind("/", file->length());
      string prefix = "";
      if (pos == (file->length() - 5))
      {
        prefix = file->substr(pos2 + 1, pos - pos2 - 1) + "_";
      }
      // apply structural reduction rules?
      if (globals::parameters[P_REDUCE])
      {
        trace(TRACE_INFORMATION, "-> Structurally simplifying Petri Net ...\n");
        PN.reduce();
      }
      PN.addPrefix(prefix);
      PN2.compose(PN);
      PN = PetriNet();

      globals::AST = NULL;
      }
    }
}

// Final Output of the result
void final_output( PetriNet PN2)
{
  if (modus == M_CONSISTENCY)
    PN = PN2;

  if (modus == M_PETRINET || modus == M_CONSISTENCY)
  {
    // apply structural reduction rules?
    if ( globals::parameters[P_REDUCE] )
    {
      trace(TRACE_INFORMATION, "-> Structurally simplifying Petri Net ...\n");
      PN.reduce();
    }

    // now the net will not change any more, thus the nodes are re-enumerated
    // and the maximal occurrences of the nodes are calculated.
    PN.reenumerate();
//  PN.calculate_max_occurrences();
    cerr << PN.information() << endl;

    // create oWFN output ?
    if (formats[F_OWFN])
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_OWFN]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for oWFN ...\n");
      PN.set_format(FORMAT_OWFN);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create LoLA output ?
    if ( formats[F_LOLA] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_LOLA]);
      }
      if (modus == M_CONSISTENCY)
      {
	PN.makeChannelsInternal();
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for LoLA ...\n");
      PN.set_format(FORMAT_LOLA);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }

      if (modus == M_CONSISTENCY || modus == M_PETRINET)
      {
	if (globals::output_filename != "")
	{
	  output = openOutput(globals::output_filename + ".task");
	}
	string comment = "{ AG EF (";
	string formula = "FORMULA\n  ALLPATH ALWAYS EXPATH EVENTUALLY (";
	string andStr = "";

        set< Place * > finalPlaces = PN.getFinalPlaces();
	for (set< Place * >::iterator place = finalPlaces.begin(); place != finalPlaces.end(); place++)
	{
	  comment += andStr + (*place)->nodeFullName();
	  formula += andStr + (*place)->nodeShortName() + " > 0";
       	  andStr = " AND ";
	}
	comment += ") }";
	formula += ")";
	(*output) << comment << endl << endl;
	(*output) << formula << endl << endl;
	if (globals::output_filename != "")
	{
	  closeOutput(output);
	  output = NULL;
	}
      }
    }

    // create PNML output ?
    if ( formats[F_PNML] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_PNML]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for PNML ...\n");
      PN.set_format(FORMAT_PNML);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create PEP output ?
    if ( formats[F_PEP] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_PEP]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for PEP ...\n");
      PN.set_format(FORMAT_PEP);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create INA output ?
    if ( formats[F_INA] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_INA]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for INA ...\n");
      PN.set_format(FORMAT_INA);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create SPIN output ?
    if ( formats[F_SPIN] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_SPIN]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for SPIN ...\n");
      PN.set_format(FORMAT_SPIN);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create APNN output ?
    if ( formats[F_APNN] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_APNN]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for APNN ...\n");
      PN.set_format(FORMAT_APNN);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }

    // create dot output ?
    if ( formats[F_DOT] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_DOT]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net for dot ...\n");
      PN.set_format(FORMAT_DOT);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;

#ifdef HAVE_DOT
	string systemcall = "dot -q -Tpng -o" + globals::output_filename + ".png " + globals::output_filename + "." + suffixes[F_DOT];
	trace(TRACE_INFORMATION, "Invoking dot with the following options:\n");
	trace(TRACE_INFORMATION, systemcall + "\n\n");
	system(systemcall.c_str());
#endif
      }
    }

    // create info file ?
    if ( formats[F_INFO] )
    {
      if (globals::output_filename != "")
      {
	output = openOutput(globals::output_filename + "." + suffixes[F_INFO]);
      }
      trace(TRACE_INFORMATION, "-> Printing Petri net information ...\n");
      PN.set_format(FORMAT_INFO);
      (*output) << PN;
      if (globals::output_filename != "")
      {
	closeOutput(output);
	output = NULL;
      }
    }
  }
}

/******************************************************************************
 * main() function
 *****************************************************************************/

/*!
 * \brief entry point of BPEL2oWFN
 *
 * Controls the behaviour of input and output.
 *
 * \param argc	number of command line arguments
 * \param argv	array with command line arguments
 *
 * \returns 0 if everything went well
 * \returns 1 if an error occurred
 *
 * \todo This function is definitly too long. It should be partitioned!
 */
int main( int argc, char *argv[])
{
  // initilization of variables
  PetriNet PN2 = PetriNet();

  // analyzation of the commandline
  analyze_cl(argc,argv);

  // parsing all inputfiles
  set< string >::iterator file = inputfiles.begin();
  do
  {
    open_file(file);

    // invoke Bison parser
    trace(TRACE_INFORMATION, "Parsing " + globals::filename + " ...\n");
    int error = frontend_parse();

    if (!error)
    {
      trace(TRACE_INFORMATION, "Parsing of " + globals::filename + " complete.\n");
      close_file(file);
      finish_AST();
      // create output for this file
      single_output(file, PN2);

    }
    else /* parse error */
    {
      cleanup();
      return error;
    }

    file++;

  } while (modus == M_CONSISTENCY && file != inputfiles.end());

  trace(TRACE_INFORMATION, "All files have been parsed.\n");

  final_output(PN2);

  // everything went fine
  return 0;
}

/*!
 * \defgroup frontend Front End
 * \defgroup patterns Petri Net Patterns
 */
<|endoftext|>


<commit_before>#ifndef _C4_ERROR_HPP_
#define _C4_ERROR_HPP_

#include "c4/config.hpp"

/** @def C4_ERROR_THROWS_EXCEPTION if this is defined and exceptions are
 * enabled, then calls to C4_ERROR() will throw an exception */

 /** @def C4_NOEXCEPT evaluates to noexcept when C4_ERROR might be called
 * and exceptions are disabled. */

#ifdef C4_ERROR_THROWS_EXCEPTION
#   define C4_NOEXCEPT
#else
#   define C4_NOEXCEPT noexcept
#endif

//-----------------------------------------------------------------------------

#ifdef __clang__
    /* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
     * variadic macros is not portable, but works in clang, gcc, msvc, icc.
     * clang requires switching off compiler warnings for pedantic mode.
     * @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
#   pragma clang diagnostic push
#   pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
#elif defined(__GNUC__)
    /* GCC also issues a warning for zero-args calls to variadic macros.
     * This warning is switched on with -pedantic and apparently there is no
     * easy way to turn it off as with clang. But marking this as a system
     * header works.
     * @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
     * @see http://stackoverflow.com/questions/35587137/ */
#   pragma GCC system_header
#endif

//-----------------------------------------------------------------------------

C4_BEGIN_NAMESPACE(c4)

using error_callback_type = void (*)();

void set_error_callback(error_callback_type cb);
error_callback_type get_error_callback();

void report_error    (                                              const char *fmt, ...);
void report_error_fl (const char *file, int line,                   const char *fmt, ...);
void report_error_flf(const char *file, int line, const char *func, const char *fmt, ...);

void report_warning    (                                              const char *fmt, ...);
void report_warning_fl (const char *file, int line,                   const char *fmt, ...);
void report_warning_flf(const char *file, int line, const char *func, const char *fmt, ...);

/** Raise an error, and report a printf-formatted message.
 * If an error callback was set, it will be called.
 * @see set_error_callback() */
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)

#   define C4_ERROR(msg, ...)                                           \
    c4::report_error_flf(__FILE__, __LINE__, C4_PRETTY_FUNC, msg, ## __VA_ARGS__)

#elif defined(C4_ERROR_SHOWS_FILELINE)

#   define C4_ERROR(msg, ...)                                       \
    c4::report_error_fl(__FILE__, __LINE__, msg, ## __VA_ARGS__)

#elif ! defined(C4_ERROR_SHOWS_FUNC)

#   define C4_ERROR(msg, ...)                   \
    c4::report_error(msg, ## __VA_ARGS__)

#else
#   error not implemented
#endif

/** Report a warning with a printf-formatted message. */
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)

#   define C4_WARNING(msg, ...)                                         \
    c4::report_warning_flf(__FILE__, __LINE__, C4_PRETTY_FUNC, msg, ## __VA_ARGS__)

#elif defined(C4_ERROR_SHOWS_FILELINE)
#   define C4_WARNING(msg, ...)                                 \
    c4::report_warning_fl(__FILE__, __LINE__, msg, ## __VA_ARGS__)

#elif ! defined(C4_ERROR_SHOWS_FUNC)
#   define C4_WARNING(msg, ...)                 \
    c4::report_warning(msg, ## __VA_ARGS__)

#else
#   error not implemented
#endif

/** Check that a condition is true, or raise an error when not
 *  true. Unlike C4_ASSERT, this check is not omitted in non-debug
 *  builds.
 *  @see C4_ASSERT */
#define C4_CHECK(cond)                          \
    if(C4_UNLIKELY(!(cond)))                    \
    {                                           \
        C4_ERROR("check failed: %s", #cond);    \
    }

/** like C4_CHECK(), and additionally log a printf-style message.
 * @see C4_CHECK */
#define C4_CHECK_MSG(cond, fmt, ...)                                \
    if(C4_UNLIKELY(!(cond)))                                        \
    {                                                               \
        C4_ERROR("check failed: %s\n" fmt, #cond, ## __VA_ARGS__);  \
    }

// assertions - only in debug builds
#ifdef NDEBUG // turn off assertions
#   define C4_ASSERT(cond)
#   define C4_ASSERT_MSG(cond, fmt, ...)
#else
#   define C4_ASSERT(cond) C4_CHECK(cond)
#   define C4_ASSERT_MSG(cond, fmt, ...) C4_CHECK_MSG(cond, fmt, ## __VA_ARGS__)
#endif

// Extreme assertion: can be switched off independently of the regular assertion.
// Use eg for bounds checking in hot code.
#ifdef C4_USE_XASSERT
#   define C4_XASSERT(cond) C4_CHECK(cond)
#   define C4_XASSERT_MSG(cond, fmt, ...) C4_CHECK_MSG(cond, fmt, ## __VA_ARGS__)
#else
#   define C4_XASSERT(cond)
#   define C4_XASSERT_MSG(cond, fmt, ...)
#endif

// Common error conditions
#define C4_NOT_IMPLEMENTED() C4_ERROR("NOT IMPLEMENTED")
#define C4_NOT_IMPLEMENTED_MSG(msg, ...) C4_ERROR("NOT IMPLEMENTED: " msg, ## __VA_ARGS__)

#define C4_NEVER_REACH() C4_UNREACHABLE(); C4_ERROR("never reach this point")
#define C4_NEVER_REACH_MSG(msg, ...) C4_UNREACHABLE(); C4_ERROR("never reach this point: " msg, ## __VA_ARGS__)

C4_END_NAMESPACE(c4)

#ifdef __clang__
#   pragma clang diagnostic pop
#endif

#endif /* _C4_ERROR_HPP_ */
<commit_msg>add scoped error callback<commit_after>#ifndef _C4_ERROR_HPP_
#define _C4_ERROR_HPP_

#include "c4/config.hpp"

/** @def C4_ERROR_THROWS_EXCEPTION if this is defined and exceptions are
 * enabled, then calls to C4_ERROR() will throw an exception */

 /** @def C4_NOEXCEPT evaluates to noexcept when C4_ERROR might be called
 * and exceptions are disabled. */

#ifdef C4_ERROR_THROWS_EXCEPTION
#   define C4_NOEXCEPT
#else
#   define C4_NOEXCEPT noexcept
#endif

//-----------------------------------------------------------------------------

#ifdef __clang__
    /* NOTE: using , ## __VA_ARGS__ to deal with zero-args calls to
     * variadic macros is not portable, but works in clang, gcc, msvc, icc.
     * clang requires switching off compiler warnings for pedantic mode.
     * @see http://stackoverflow.com/questions/32047685/variadic-macro-without-arguments */
#   pragma clang diagnostic push
#   pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // warning: token pasting of ',' and __VA_ARGS__ is a GNU extension
#elif defined(__GNUC__)
    /* GCC also issues a warning for zero-args calls to variadic macros.
     * This warning is switched on with -pedantic and apparently there is no
     * easy way to turn it off as with clang. But marking this as a system
     * header works.
     * @see https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
     * @see http://stackoverflow.com/questions/35587137/ */
#   pragma GCC system_header
#endif

//-----------------------------------------------------------------------------

C4_BEGIN_NAMESPACE(c4)

using error_callback_type = void (*)();

void set_error_callback(error_callback_type cb);
error_callback_type get_error_callback();

void report_error    (                                              const char *fmt, ...);
void report_error_fl (const char *file, int line,                   const char *fmt, ...);
void report_error_flf(const char *file, int line, const char *func, const char *fmt, ...);

void report_warning    (                                              const char *fmt, ...);
void report_warning_fl (const char *file, int line,                   const char *fmt, ...);
void report_warning_flf(const char *file, int line, const char *func, const char *fmt, ...);

//-----------------------------------------------------------------------------
struct ScopedErrorCallback
{
    error_callback_type m_original;

    explicit ScopedErrorCallback(error_callback_type cb)
        : m_original(get_error_callback())
    {
        set_error_callback(cb);
    }
    ~ScopedErrorCallback()
    {
        set_error_callback(m_original);
    }
};

//-----------------------------------------------------------------------------
/** Raise an error, and report a printf-formatted message.
 * If an error callback was set, it will be called.
 * @see set_error_callback() */
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)

#   define C4_ERROR(msg, ...)                                           \
    c4::report_error_flf(__FILE__, __LINE__, C4_PRETTY_FUNC, msg, ## __VA_ARGS__)

#elif defined(C4_ERROR_SHOWS_FILELINE)

#   define C4_ERROR(msg, ...)                                       \
    c4::report_error_fl(__FILE__, __LINE__, msg, ## __VA_ARGS__)

#elif ! defined(C4_ERROR_SHOWS_FUNC)

#   define C4_ERROR(msg, ...)                   \
    c4::report_error(msg, ## __VA_ARGS__)

#else
#   error not implemented
#endif

/** Report a warning with a printf-formatted message. */
#if defined(C4_ERROR_SHOWS_FILELINE) && defined(C4_ERROR_SHOWS_FUNC)

#   define C4_WARNING(msg, ...)                                         \
    c4::report_warning_flf(__FILE__, __LINE__, C4_PRETTY_FUNC, msg, ## __VA_ARGS__)

#elif defined(C4_ERROR_SHOWS_FILELINE)
#   define C4_WARNING(msg, ...)                                 \
    c4::report_warning_fl(__FILE__, __LINE__, msg, ## __VA_ARGS__)

#elif ! defined(C4_ERROR_SHOWS_FUNC)
#   define C4_WARNING(msg, ...)                 \
    c4::report_warning(msg, ## __VA_ARGS__)

#else
#   error not implemented
#endif

/** Check that a condition is true, or raise an error when not
 *  true. Unlike C4_ASSERT, this check is not omitted in non-debug
 *  builds.
 *  @see C4_ASSERT */
#define C4_CHECK(cond)                          \
    if(C4_UNLIKELY(!(cond)))                    \
    {                                           \
        C4_ERROR("check failed: %s", #cond);    \
    }

/** like C4_CHECK(), and additionally log a printf-style message.
 * @see C4_CHECK */
#define C4_CHECK_MSG(cond, fmt, ...)                                \
    if(C4_UNLIKELY(!(cond)))                                        \
    {                                                               \
        C4_ERROR("check failed: %s\n" fmt, #cond, ## __VA_ARGS__);  \
    }

// assertions - only in debug builds
#ifdef NDEBUG // turn off assertions
#   define C4_ASSERT(cond)
#   define C4_ASSERT_MSG(cond, fmt, ...)
#else
#   define C4_ASSERT(cond) C4_CHECK(cond)
#   define C4_ASSERT_MSG(cond, fmt, ...) C4_CHECK_MSG(cond, fmt, ## __VA_ARGS__)
#endif

// Extreme assertion: can be switched off independently of the regular assertion.
// Use eg for bounds checking in hot code.
#ifdef C4_USE_XASSERT
#   define C4_XASSERT(cond) C4_CHECK(cond)
#   define C4_XASSERT_MSG(cond, fmt, ...) C4_CHECK_MSG(cond, fmt, ## __VA_ARGS__)
#else
#   define C4_XASSERT(cond)
#   define C4_XASSERT_MSG(cond, fmt, ...)
#endif

// Common error conditions
#define C4_NOT_IMPLEMENTED() C4_ERROR("NOT IMPLEMENTED")
#define C4_NOT_IMPLEMENTED_MSG(msg, ...) C4_ERROR("NOT IMPLEMENTED: " msg, ## __VA_ARGS__)
#define C4_NOT_IMPLEMENTED_IF(condition) if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED"); }
#define C4_NOT_IMPLEMENTED_IF_MSG(condition, msg, ...) if(C4_UNLIKELY(condition)) { C4_ERROR("NOT IMPLEMENTED: " msg, ## __VA_ARGS__); }

#define C4_NEVER_REACH() C4_UNREACHABLE(); C4_ERROR("never reach this point")
#define C4_NEVER_REACH_MSG(msg, ...) C4_UNREACHABLE(); C4_ERROR("never reach this point: " msg, ## __VA_ARGS__)

C4_END_NAMESPACE(c4)

#ifdef __clang__
#   pragma clang diagnostic pop
#endif

#endif /* _C4_ERROR_HPP_ */
<|endoftext|>


<commit_before>#include "Kick.hpp"

#include <stdio.h>
#include <algorithm>

using namespace std;

const float Min_Segment = 1.5 * Ball_Diameter; //Tuning Required (Anthony)

Gameplay::Behaviors::Kick::Kick(GameplayModule *gameplay):
    SingleRobotBehavior(gameplay)
{
	setTargetGoal();

        //Whether or not the shot is feasible
        hasShot = false;
        //The segment of the best shot
        _shotSegment = Geometry2d::Segment(Geometry2d::Point(0,0), Geometry2d::Point(0,0));
	restart();
}

bool Gameplay::Behaviors::Kick::run()
{
	if (!robot || !robot->visible)
	{
		return false;
	}

        //Only end the behavior is the ball can't be seen and the robot doesn't have it
        //This prevents the behavior from stopping when the robot blocks the ball
        if(!ball().valid && !robot->hasBall)
        {
            return false;
        }

        //If the ball is being blocked set its location to the location of the robot
        //Accounting for the direction the robot is facing
        Geometry2d::Point ballPos;

        if(!ball().valid)
        {
           float x = Robot_Radius * sin(robot->angle * DegreesToRadians);
           float y = Robot_Radius * cos(robot->angle * DegreesToRadians);
           Geometry2d::Point pt = Geometry2d::Point(x, y);
           ballPos = robot->pos + pt;
        }
        else
        {
            ballPos = ball().pos;
        }

        //Get the best ublocked area in the target to aim at
        WindowEvaluator e = WindowEvaluator(state());
        e.run(ballPos, _target);
        Window *w = e.best;

        //The target to use
        Geometry2d::Segment target;

        //Prevents the segfault from using a non existent window
        if(w != NULL)
        {
            if(w->segment.length() < Min_Segment)
            {
                hasShot = false;
            }
            else
            {
                hasShot = true;
            }

            target = w->segment;
            _shotSegment = target;
        }
        else
        {
            hasShot = false;
            target = _target;

            //There is not shot therefore set the best segment to a single point
            _shotSegment = Geometry2d::Segment(Geometry2d::Point(0,0), Geometry2d::Point(0,0));
        }

	// Some calculations depend on the order of the target endpoints.
	// Ensure that t0 x t1 > 0.
	// We have to do this each frame since the ball may move to the other side of the target.
	//FIXME - Actually, doesn't that mean the kick/pass is done?
	//FIXME - What about kicking towards a point?  cross product is zero...
	if ((target.pt[0] - ballPos).cross(target.pt[1] - ballPos) < 0)
	{
		swap(target.pt[0], target.pt[1]);
	}

	// State transitions
	switch (_state)
	{
		case State_Approach1:
                {
                        Geometry2d::Point targetCenter = target.center();

                        // Vector from ball to center of target
			Geometry2d::Point toTarget = targetCenter - ballPos;

                        // Robot position relative to the ball
			Geometry2d::Point relPos = robot->pos - ballPos;

                        //The Point to compute with
                        Geometry2d::Point point = target.pt[0];

			//Behind the ball: move to the nearest line containing the ball and a target endpoint.
			//the robot is behind the ball, while the target vectors all point in *front* of the ball.
			if (toTarget.cross(relPos) < 0)
			{
				// Above the center line: nearest endpoint-line includes target.pt[1]
				point = target.pt[1];
	               	}

                        //Change state when the robot is in the right location
                        //facing the right direction
                        Geometry2d::Point b = (point - ballPos + robot->pos).normalized();

                        float angleError = b.dot(Geometry2d::Point::direction(robot->angle * DegreesToRadians));
			bool nearBall = robot->pos.nearPoint(ballPos, Robot_Radius + Ball_Radius + 0.25);

                        //angleError is greater than because cos(0) is 1 which is perfect
                        if (nearBall && angleError > cos(15 * DegreesToRadians))
			{
				_state = State_Approach2;
			}
			break;
                }

		case State_Approach2:
                {
                        if (robot->hasBall && robot->charged())
			{
				robot->addText("Aim");
				_state = State_Aim;
				_lastError = INFINITY;
			}

			bool nearBall = robot->pos.nearPoint(ballPos, Robot_Radius + Ball_Radius + 0.30);

                        //Go back to state one if needed
                        if(!nearBall)
                        {
                            _state = State_Approach1;
                        }

			break;
                }

		case State_Aim:
			if (!robot->hasBall)
			{
				_state = State_Approach2;
			} else {
				state()->drawLine(ballPos, target.pt[0], Qt::red);
				state()->drawLine(ballPos, target.pt[1], Qt::white);

				Geometry2d::Point rd = Geometry2d::Point::direction(robot->angle * DegreesToRadians);

				_kickSegment = Geometry2d::Segment(robot->pos, robot->pos + rd * Field_Length);
				state()->drawLine(robot->pos, target.center(), Qt::gray);
				float error = acos(rd.dot((target.center() - robot->pos).normalized())) * RadiansToDegrees;

                                //The distance between the trajectory and the target center
                                float distOff = _kickSegment.distTo(target.center());

                                //The width of half the target
                                float width = target.pt[0].distTo(target.center());

                                robot->addText(QString("Aim %1").arg(error));

				if (!isinf(_lastError))
				{
					//FIXME - Depends on t0 x t1 > 0
					bool inT0 = (target.pt[0] - ballPos).cross(rd) > 0;
					bool inT1 = rd.cross(target.pt[1] - ballPos) > 0;
					robot->addText(QString("in %1 %2").arg(inT0).arg(inT1));

                                        //How close to the center line printout
                                        robot->addText(QString("Width %1 Distance %2").arg(width).arg(distOff));

                                        //If the tarjectory is within the target bounds
                                        if (inT0 && inT1)
                                        {
                                            //Shoot if the shot is getting worse or the shot is
                                            //very good (within half of the width of half the window) (Tuning required)
                                            if((error > _lastError) || (distOff < (width * .5)))
		                            {
						// Past the best position
						_state = State_Kick;
					    }
                                        }
				}
				_lastError = error;
			}
			break;

		case State_Kick:

			if (!robot->charged())
			{
				_state = State_Done;
			}

                        //If the robot loses the ball whilst trying to kick before the kick is done
                        //go back to approach1 to reacquire the ball
                        else if(!robot->hasBall)
                        {
                            _state = State_Approach1;
                        }
			break;

		case State_Done:
			break;
	}

	switch (_state)
	{
		case State_Approach1:
                {
                        robot->addText("Approach1");

                        Geometry2d::Point targetCenter = target.center();

			// Vector from ball to center of target
			Geometry2d::Point toTarget = targetCenter - ballPos;

                        // Robot position relative to the ball
			Geometry2d::Point relPos = robot->pos - ballPos;

                        //The Point to compute with
                        Geometry2d::Point point = target.pt[0];

			//Behind the ball: move to the nearest line containing the ball and a target endpoint.
			//the robot is behind the ball, while the target vectors all point in *front* of the ball.
			if (toTarget.cross(relPos) < 0)
			{
				// Above the center line: nearest endpoint-line includes target.pt[1]
				point = target.pt[1];
	               	}

                        //Face that point and move to the appropriate line
                        robot->move(ballPos + (ballPos -
                                    point).normalized() * (Robot_Radius +
                                        Ball_Radius + .07));
                        robot->face(point - ballPos + robot->pos);

		        state()->drawLine(ballPos, point, Qt::red);

			//FIXME - Real robots overshoot and hit the ball in this state.  This shouldn't be necessary.
                        //Hopefully moving the target point back and pivoting whilst moving will prevent the ball
                        //from getting hit thus there shouldn't need to be a dribbler
			robot->dribble(127);

			robot->avoidBall = true;
			break;
                }

		case State_Approach2:
			robot->addText("Approach2");
			robot->move(ballPos);

                        //Should this face be ballPos or the quanity found in Approach1?
			robot->face(ballPos);
			robot->dribble(127);
			break;

		case State_Aim:
		{
			Geometry2d::Point targetCenter = target.center();

			// Vector from ball to center of target
			Geometry2d::Point toTarget = targetCenter - ballPos;

			// Robot position relative to the ball
			Geometry2d::Point relPos = robot->pos - ballPos;

			// True if the robot is in front of the ball
			bool inFrontOfBall = toTarget.perpCCW().cross(relPos) > 0;

			MotionCmd::PivotType dir;
			if (inFrontOfBall)
			{
				// Move behind the ball
				dir = (toTarget.cross(relPos) > 0) ? MotionCmd::CCW : MotionCmd::CW;
			} else {
				// Behind the ball: move to the nearest line containing the ball and a target endpoint.
				// Note that the robot is behind the ball, while the target vectors all point in *front* of the ball.
				//FIXME - These assume t0 x t1 > 0.  Enforce this here or above.
				if (toTarget.cross(relPos) > 0)
				{
					// Below the center line: nearest endpoint-line includes target.pt[0]
					dir = (target.pt[0] - ballPos).cross(relPos) > 0 ? MotionCmd::CW : MotionCmd::CCW;
				} else {
					// Above the center line: nearest endpoint-line includes target.pt[1]
					dir = (target.pt[1] - ballPos).cross(relPos) > 0 ? MotionCmd::CCW : MotionCmd::CW;
				}
			}

			robot->dribble(127);
			robot->pivot(ballPos, dir);
			state()->drawLine(_kickSegment);
			break;
		}

		case State_Kick:
			robot->addText("Kick");
                        if(hasShot)
                        {
                            robot->move(ballPos);
		            robot->face(ballPos);
			    robot->dribble(127);
			    robot->kick(255);
                        }
			state()->drawLine(_kickSegment);
                        break;

		case State_Done:
			robot->addText("Done");
			state()->drawLine(_kickSegment);
			break;
	}

	return _state != State_Done;
}

void Gameplay::Behaviors::Kick::restart()
{
	_state = State_Approach1;
}

void Gameplay::Behaviors::Kick::setTargetGoal()
{
        //Set the target to be a little inside of the goal posts to prevent noise errors from
        //causing a post shot
	setTarget(Geometry2d::Segment(
		Geometry2d::Point((Field_GoalWidth / 2 - Ball_Diameter), Field_Length),
		Geometry2d::Point((-Field_GoalWidth / 2 + Ball_Diameter), Field_Length)));
}

void Gameplay::Behaviors::Kick::setTarget(const Geometry2d::Segment& seg)
{
	_target = seg;
}
<commit_msg>Fixed a threshold error that was too tight and caused a end zone<commit_after>#include "Kick.hpp"

#include <stdio.h>
#include <algorithm>

using namespace std;

const float Min_Segment = 1.5 * Ball_Diameter; //Tuning Required (Anthony)

Gameplay::Behaviors::Kick::Kick(GameplayModule *gameplay):
    SingleRobotBehavior(gameplay)
{
	setTargetGoal();

        //Whether or not the shot is feasible
        hasShot = false;
        //The segment of the best shot
        _shotSegment = Geometry2d::Segment(Geometry2d::Point(0,0), Geometry2d::Point(0,0));
	restart();
}

bool Gameplay::Behaviors::Kick::run()
{
	if (!robot || !robot->visible)
	{
		return false;
	}

        //Only end the behavior is the ball can't be seen and the robot doesn't have it
        //This prevents the behavior from stopping when the robot blocks the ball
        if(!ball().valid && !robot->hasBall)
        {
            return false;
        }

        //If the ball is being blocked set its location to the location of the robot
        //Accounting for the direction the robot is facing
        Geometry2d::Point ballPos;

        if(!ball().valid)
        {
           float x = Robot_Radius * sin(robot->angle * DegreesToRadians);
           float y = Robot_Radius * cos(robot->angle * DegreesToRadians);
           Geometry2d::Point pt = Geometry2d::Point(x, y);
           ballPos = robot->pos + pt;
        }
        else
        {
            ballPos = ball().pos;
        }

        //Get the best ublocked area in the target to aim at
        WindowEvaluator e = WindowEvaluator(state());
        e.run(ballPos, _target);
        Window *w = e.best;

        //The target to use
        Geometry2d::Segment target;

        //Prevents the segfault from using a non existent window
        if(w != NULL)
        {
            if(w->segment.length() < Min_Segment)
            {
                hasShot = false;
            }
            else
            {
                hasShot = true;
            }

            target = w->segment;
            _shotSegment = target;
        }
        else
        {
            hasShot = false;
            target = _target;

            //There is not shot therefore set the best segment to a single point
            _shotSegment = Geometry2d::Segment(Geometry2d::Point(0,0), Geometry2d::Point(0,0));
        }

	// Some calculations depend on the order of the target endpoints.
	// Ensure that t0 x t1 > 0.
	// We have to do this each frame since the ball may move to the other side of the target.
	//FIXME - Actually, doesn't that mean the kick/pass is done?
	//FIXME - What about kicking towards a point?  cross product is zero...
	if ((target.pt[0] - ballPos).cross(target.pt[1] - ballPos) < 0)
	{
		swap(target.pt[0], target.pt[1]);
	}

	// State transitions
	switch (_state)
	{
		case State_Approach1:
                {
                        Geometry2d::Point targetCenter = target.center();

                        // Vector from ball to center of target
			Geometry2d::Point toTarget = targetCenter - ballPos;

                        // Robot position relative to the ball
			Geometry2d::Point relPos = robot->pos - ballPos;

                        //The Point to compute with
                        Geometry2d::Point point = target.pt[0];

			//Behind the ball: move to the nearest line containing the ball and a target endpoint.
			//the robot is behind the ball, while the target vectors all point in *front* of the ball.
			if (toTarget.cross(relPos) < 0)
			{
				// Above the center line: nearest endpoint-line includes target.pt[1]
				point = target.pt[1];
	               	}

                        //Change state when the robot is in the right location
                        //facing the right direction
                        Geometry2d::Point b = (point - ballPos + robot->pos).normalized();

                        float angleError = b.dot(Geometry2d::Point::direction(robot->angle * DegreesToRadians));
			bool nearBall = robot->pos.nearPoint(ballPos, Robot_Radius + Ball_Radius + 0.25);

                        //angleError is greater than because cos(0) is 1 which is perfect
                        if (nearBall && angleError > cos(20 * DegreesToRadians))
			{
				_state = State_Approach2;
			}
			break;
                }

		case State_Approach2:
                {
                        if (robot->hasBall && robot->charged())
			{
				robot->addText("Aim");
				_state = State_Aim;
				_lastError = INFINITY;
			}

			bool nearBall = robot->pos.nearPoint(ballPos, Robot_Radius + Ball_Radius + 0.30);

                        //Go back to state one if needed
                        if(!nearBall)
                        {
                            _state = State_Approach1;
                        }

			break;
                }

		case State_Aim:
			if (!robot->hasBall)
			{
				_state = State_Approach2;
			} else {
				state()->drawLine(ballPos, target.pt[0], Qt::red);
				state()->drawLine(ballPos, target.pt[1], Qt::white);

				Geometry2d::Point rd = Geometry2d::Point::direction(robot->angle * DegreesToRadians);

				_kickSegment = Geometry2d::Segment(robot->pos, robot->pos + rd * Field_Length);
				state()->drawLine(robot->pos, target.center(), Qt::gray);
				float error = acos(rd.dot((target.center() - robot->pos).normalized())) * RadiansToDegrees;

                                //The distance between the trajectory and the target center
                                float distOff = _kickSegment.distTo(target.center());

                                //The width of half the target
                                float width = target.pt[0].distTo(target.center());

                                robot->addText(QString("Aim %1").arg(error));

				if (!isinf(_lastError))
				{
					//FIXME - Depends on t0 x t1 > 0
					bool inT0 = (target.pt[0] - ballPos).cross(rd) > 0;
					bool inT1 = rd.cross(target.pt[1] - ballPos) > 0;
					robot->addText(QString("in %1 %2").arg(inT0).arg(inT1));

                                        //How close to the center line printout
                                        robot->addText(QString("Width %1 Distance %2").arg(width).arg(distOff));

                                        //If the tarjectory is within the target bounds
                                        if (inT0 && inT1)
                                        {
                                            //Shoot if the shot is getting worse or the shot is
                                            //very good (within half of the width of half the window) (Tuning required)
                                            if((error > _lastError) || (distOff < (width * .5)))
		                            {
						// Past the best position
						_state = State_Kick;
					    }
                                        }
				}
				_lastError = error;
			}
			break;

		case State_Kick:

			if (!robot->charged())
			{
				_state = State_Done;
			}

                        //If the robot loses the ball whilst trying to kick before the kick is done
                        //go back to approach1 to reacquire the ball
                        else if(!robot->hasBall)
                        {
                            _state = State_Approach1;
                        }
			break;

		case State_Done:
			break;
	}

	switch (_state)
	{
		case State_Approach1:
                {
                        robot->addText("Approach1");

                        Geometry2d::Point targetCenter = target.center();

			// Vector from ball to center of target
			Geometry2d::Point toTarget = targetCenter - ballPos;

                        // Robot position relative to the ball
			Geometry2d::Point relPos = robot->pos - ballPos;

                        //The Point to compute with
                        Geometry2d::Point point = target.pt[0];

			//Behind the ball: move to the nearest line containing the ball and a target endpoint.
			//the robot is behind the ball, while the target vectors all point in *front* of the ball.
			if (toTarget.cross(relPos) < 0)
			{
				// Above the center line: nearest endpoint-line includes target.pt[1]
				point = target.pt[1];
	               	}

                        //Face that point and move to the appropriate line
                        robot->move(ballPos + (ballPos -
                                    point).normalized() * (Robot_Radius +
                                        Ball_Radius + .07));
                        robot->face(point - ballPos + robot->pos);

		        state()->drawLine(ballPos, point, Qt::red);

			//FIXME - Real robots overshoot and hit the ball in this state.  This shouldn't be necessary.
                        //Hopefully moving the target point back and pivoting whilst moving will prevent the ball
                        //from getting hit thus there shouldn't need to be a dribbler
			robot->dribble(127);

			robot->avoidBall = true;
			break;
                }

		case State_Approach2:
			robot->addText("Approach2");
                        robot->move(ballPos);

                        //Should this face be ballPos or the quanity found in Approach1?
			robot->face(ballPos);
			robot->dribble(127);
			break;

		case State_Aim:
		{
			Geometry2d::Point targetCenter = target.center();

			// Vector from ball to center of target
			Geometry2d::Point toTarget = targetCenter - ballPos;

			// Robot position relative to the ball
			Geometry2d::Point relPos = robot->pos - ballPos;

			// True if the robot is in front of the ball
			bool inFrontOfBall = toTarget.perpCCW().cross(relPos) > 0;

			MotionCmd::PivotType dir;
			if (inFrontOfBall)
			{
				// Move behind the ball
				dir = (toTarget.cross(relPos) > 0) ? MotionCmd::CCW : MotionCmd::CW;
			} else {
				// Behind the ball: move to the nearest line containing the ball and a target endpoint.
				// Note that the robot is behind the ball, while the target vectors all point in *front* of the ball.
				//FIXME - These assume t0 x t1 > 0.  Enforce this here or above.
				if (toTarget.cross(relPos) > 0)
				{
					// Below the center line: nearest endpoint-line includes target.pt[0]
					dir = (target.pt[0] - ballPos).cross(relPos) > 0 ? MotionCmd::CW : MotionCmd::CCW;
				} else {
					// Above the center line: nearest endpoint-line includes target.pt[1]
					dir = (target.pt[1] - ballPos).cross(relPos) > 0 ? MotionCmd::CCW : MotionCmd::CW;
				}
			}

			robot->dribble(127);

                        //Robot has trouble handling a moving ball when trying to pivot (I don't know how to fix this)
			robot->pivot(ballPos, dir);
			state()->drawLine(_kickSegment);
			break;
		}

		case State_Kick:
			robot->addText("Kick");
                        if(hasShot)
                        {
                            robot->move(ballPos);
		            robot->face(ballPos);
			    robot->dribble(127);
			    robot->kick(255);
                        }
			state()->drawLine(_kickSegment);
                        break;

		case State_Done:
			robot->addText("Done");
			state()->drawLine(_kickSegment);
			break;
	}

	return _state != State_Done;
}

void Gameplay::Behaviors::Kick::restart()
{
	_state = State_Approach1;
}

void Gameplay::Behaviors::Kick::setTargetGoal()
{
        //Set the target to be a little inside of the goal posts to prevent noise errors from
        //causing a post shot
	setTarget(Geometry2d::Segment(
		Geometry2d::Point((Field_GoalWidth / 2 - Ball_Diameter), Field_Length),
		Geometry2d::Point((-Field_GoalWidth / 2 + Ball_Diameter), Field_Length)));
}

void Gameplay::Behaviors::Kick::setTarget(const Geometry2d::Segment& seg)
{
	_target = seg;
}
<|endoftext|>


<commit_before>//===- IVUsers.cpp - Induction Variable Users -------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements bookkeeping for "interesting" users of expressions
// computed from induction variables.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "iv-users"
#include "llvm/Analysis/IVUsers.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

char IVUsers::ID = 0;
static RegisterPass<IVUsers>
X("iv-users", "Induction Variable Users", false, true);

Pass *llvm::createIVUsersPass() {
  return new IVUsers();
}

/// containsAddRecFromDifferentLoop - Determine whether expression S involves a
/// subexpression that is an AddRec from a loop other than L.  An outer loop
/// of L is OK, but not an inner loop nor a disjoint loop.
static bool containsAddRecFromDifferentLoop(const SCEV *S, Loop *L) {
  // This is very common, put it first.
  if (isa<SCEVConstant>(S))
    return false;
  if (const SCEVCommutativeExpr *AE = dyn_cast<SCEVCommutativeExpr>(S)) {
    for (unsigned int i=0; i< AE->getNumOperands(); i++)
      if (containsAddRecFromDifferentLoop(AE->getOperand(i), L))
        return true;
    return false;
  }
  if (const SCEVAddRecExpr *AE = dyn_cast<SCEVAddRecExpr>(S)) {
    if (const Loop *newLoop = AE->getLoop()) {
      if (newLoop == L)
        return false;
      // if newLoop is an outer loop of L, this is OK.
      if (!LoopInfo::isNotAlreadyContainedIn(L, newLoop))
        return false;
    }
    return true;
  }
  if (const SCEVUDivExpr *DE = dyn_cast<SCEVUDivExpr>(S))
    return containsAddRecFromDifferentLoop(DE->getLHS(), L) ||
           containsAddRecFromDifferentLoop(DE->getRHS(), L);
#if 0
  // SCEVSDivExpr has been backed out temporarily, but will be back; we'll
  // need this when it is.
  if (const SCEVSDivExpr *DE = dyn_cast<SCEVSDivExpr>(S))
    return containsAddRecFromDifferentLoop(DE->getLHS(), L) ||
           containsAddRecFromDifferentLoop(DE->getRHS(), L);
#endif
  if (const SCEVCastExpr *CE = dyn_cast<SCEVCastExpr>(S))
    return containsAddRecFromDifferentLoop(CE->getOperand(), L);
  return false;
}

/// getSCEVStartAndStride - Compute the start and stride of this expression,
/// returning false if the expression is not a start/stride pair, or true if it
/// is.  The stride must be a loop invariant expression, but the start may be
/// a mix of loop invariant and loop variant expressions.  The start cannot,
/// however, contain an AddRec from a different loop, unless that loop is an
/// outer loop of the current loop.
static bool getSCEVStartAndStride(const SCEV *&SH, Loop *L, Loop *UseLoop,
                                  const SCEV *&Start, const SCEV *&Stride,
                                  ScalarEvolution *SE, DominatorTree *DT) {
  const SCEV *TheAddRec = Start;   // Initialize to zero.

  // If the outer level is an AddExpr, the operands are all start values except
  // for a nested AddRecExpr.
  if (const SCEVAddExpr *AE = dyn_cast<SCEVAddExpr>(SH)) {
    for (unsigned i = 0, e = AE->getNumOperands(); i != e; ++i)
      if (const SCEVAddRecExpr *AddRec =
             dyn_cast<SCEVAddRecExpr>(AE->getOperand(i))) {
        if (AddRec->getLoop() == L)
          TheAddRec = SE->getAddExpr(AddRec, TheAddRec);
        else
          return false;  // Nested IV of some sort?
      } else {
        Start = SE->getAddExpr(Start, AE->getOperand(i));
      }
  } else if (isa<SCEVAddRecExpr>(SH)) {
    TheAddRec = SH;
  } else {
    return false;  // not analyzable.
  }

  const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(TheAddRec);
  if (!AddRec || AddRec->getLoop() != L) return false;

  // Use getSCEVAtScope to attempt to simplify other loops out of
  // the picture.
  const SCEV *AddRecStart = AddRec->getStart();
  AddRecStart = SE->getSCEVAtScope(AddRecStart, UseLoop);
  const SCEV *AddRecStride = AddRec->getStepRecurrence(*SE);

  // FIXME: If Start contains an SCEVAddRecExpr from a different loop, other
  // than an outer loop of the current loop, reject it.  LSR has no concept of
  // operating on more than one loop at a time so don't confuse it with such
  // expressions.
  if (containsAddRecFromDifferentLoop(AddRecStart, L))
    return false;

  Start = SE->getAddExpr(Start, AddRecStart);

  // If stride is an instruction, make sure it dominates the loop preheader.
  // Otherwise we could end up with a use before def situation.
  if (!isa<SCEVConstant>(AddRecStride)) {
    BasicBlock *Preheader = L->getLoopPreheader();
    if (!AddRecStride->dominates(Preheader, DT))
      return false;

    DEBUG(errs() << "[" << L->getHeader()->getName()
                 << "] Variable stride: " << *AddRec << "\n");
  }

  Stride = AddRecStride;
  return true;
}

/// IVUseShouldUsePostIncValue - We have discovered a "User" of an IV expression
/// and now we need to decide whether the user should use the preinc or post-inc
/// value.  If this user should use the post-inc version of the IV, return true.
///
/// Choosing wrong here can break dominance properties (if we choose to use the
/// post-inc value when we cannot) or it can end up adding extra live-ranges to
/// the loop, resulting in reg-reg copies (if we use the pre-inc value when we
/// should use the post-inc value).
static bool IVUseShouldUsePostIncValue(Instruction *User, Instruction *IV,
                                       Loop *L, LoopInfo *LI, DominatorTree *DT,
                                       Pass *P) {
  // If the user is in the loop, use the preinc value.
  if (L->contains(User->getParent())) return false;

  BasicBlock *LatchBlock = L->getLoopLatch();

  // Ok, the user is outside of the loop.  If it is dominated by the latch
  // block, use the post-inc value.
  if (DT->dominates(LatchBlock, User->getParent()))
    return true;

  // There is one case we have to be careful of: PHI nodes.  These little guys
  // can live in blocks that are not dominated by the latch block, but (since
  // their uses occur in the predecessor block, not the block the PHI lives in)
  // should still use the post-inc value.  Check for this case now.
  PHINode *PN = dyn_cast<PHINode>(User);
  if (!PN) return false;  // not a phi, not dominated by latch block.

  // Look at all of the uses of IV by the PHI node.  If any use corresponds to
  // a block that is not dominated by the latch block, give up and use the
  // preincremented value.
  unsigned NumUses = 0;
  for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
    if (PN->getIncomingValue(i) == IV) {
      ++NumUses;
      if (!DT->dominates(LatchBlock, PN->getIncomingBlock(i)))
        return false;
    }

  // Okay, all uses of IV by PN are in predecessor blocks that really are
  // dominated by the latch block.  Use the post-incremented value.
  return true;
}

/// AddUsersIfInteresting - Inspect the specified instruction.  If it is a
/// reducible SCEV, recursively add its users to the IVUsesByStride set and
/// return true.  Otherwise, return false.
bool IVUsers::AddUsersIfInteresting(Instruction *I) {
  if (!SE->isSCEVable(I->getType()))
    return false;   // Void and FP expressions cannot be reduced.

  // LSR is not APInt clean, do not touch integers bigger than 64-bits.
  if (SE->getTypeSizeInBits(I->getType()) > 64)
    return false;

  if (!Processed.insert(I))
    return true;    // Instruction already handled.

  // Get the symbolic expression for this instruction.
  const SCEV *ISE = SE->getSCEV(I);
  if (isa<SCEVCouldNotCompute>(ISE)) return false;

  // Get the start and stride for this expression.
  Loop *UseLoop = LI->getLoopFor(I->getParent());
  const SCEV *Start = SE->getIntegerSCEV(0, ISE->getType());
  const SCEV *Stride = Start;

  if (!getSCEVStartAndStride(ISE, L, UseLoop, Start, Stride, SE, DT))
    return false;  // Non-reducible symbolic expression, bail out.

  SmallPtrSet<Instruction *, 4> UniqueUsers;
  for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
       UI != E; ++UI) {
    Instruction *User = cast<Instruction>(*UI);
    if (!UniqueUsers.insert(User))
      continue;

    // Do not infinitely recurse on PHI nodes.
    if (isa<PHINode>(User) && Processed.count(User))
      continue;

    // Descend recursively, but not into PHI nodes outside the current loop.
    // It's important to see the entire expression outside the loop to get
    // choices that depend on addressing mode use right, although we won't
    // consider references ouside the loop in all cases.
    // If User is already in Processed, we don't want to recurse into it again,
    // but do want to record a second reference in the same instruction.
    bool AddUserToIVUsers = false;
    if (LI->getLoopFor(User->getParent()) != L) {
      if (isa<PHINode>(User) || Processed.count(User) ||
          !AddUsersIfInteresting(User)) {
        DOUT << "FOUND USER in other loop: " << *User
             << "   OF SCEV: " << *ISE << "\n";
        AddUserToIVUsers = true;
      }
    } else if (Processed.count(User) ||
               !AddUsersIfInteresting(User)) {
      DOUT << "FOUND USER: " << *User
           << "   OF SCEV: " << *ISE << "\n";
      AddUserToIVUsers = true;
    }

    if (AddUserToIVUsers) {
      IVUsersOfOneStride *StrideUses = IVUsesByStride[Stride];
      if (!StrideUses) {    // First occurrence of this stride?
        StrideOrder.push_back(Stride);
        StrideUses = new IVUsersOfOneStride(Stride);
        IVUses.push_back(StrideUses);
        IVUsesByStride[Stride] = StrideUses;
      }

      // Okay, we found a user that we cannot reduce.  Analyze the instruction
      // and decide what to do with it.  If we are a use inside of the loop, use
      // the value before incrementation, otherwise use it after incrementation.
      if (IVUseShouldUsePostIncValue(User, I, L, LI, DT, this)) {
        // The value used will be incremented by the stride more than we are
        // expecting, so subtract this off.
        const SCEV *NewStart = SE->getMinusSCEV(Start, Stride);
        StrideUses->addUser(NewStart, User, I);
        StrideUses->Users.back().setIsUseOfPostIncrementedValue(true);
        DOUT << "   USING POSTINC SCEV, START=" << *NewStart<< "\n";
      } else {
        StrideUses->addUser(Start, User, I);
      }
    }
  }
  return true;
}

IVUsers::IVUsers()
 : LoopPass(&ID) {
}

void IVUsers::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<LoopInfo>();
  AU.addRequired<DominatorTree>();
  AU.addRequired<ScalarEvolution>();
  AU.setPreservesAll();
}

bool IVUsers::runOnLoop(Loop *l, LPPassManager &LPM) {

  L = l;
  LI = &getAnalysis<LoopInfo>();
  DT = &getAnalysis<DominatorTree>();
  SE = &getAnalysis<ScalarEvolution>();

  // Find all uses of induction variables in this loop, and categorize
  // them by stride.  Start by finding all of the PHI nodes in the header for
  // this loop.  If they are induction variables, inspect their uses.
  for (BasicBlock::iterator I = L->getHeader()->begin(); isa<PHINode>(I); ++I)
    AddUsersIfInteresting(I);

  return false;
}

/// getReplacementExpr - Return a SCEV expression which computes the
/// value of the OperandValToReplace of the given IVStrideUse.
const SCEV *IVUsers::getReplacementExpr(const IVStrideUse &U) const {
  // Start with zero.
  const SCEV *RetVal = SE->getIntegerSCEV(0, U.getParent()->Stride->getType());
  // Create the basic add recurrence.
  RetVal = SE->getAddRecExpr(RetVal, U.getParent()->Stride, L);
  // Add the offset in a separate step, because it may be loop-variant.
  RetVal = SE->getAddExpr(RetVal, U.getOffset());
  // For uses of post-incremented values, add an extra stride to compute
  // the actual replacement value.
  if (U.isUseOfPostIncrementedValue())
    RetVal = SE->getAddExpr(RetVal, U.getParent()->Stride);
  // Evaluate the expression out of the loop, if possible.
  if (!L->contains(U.getUser()->getParent())) {
    const SCEV *ExitVal = SE->getSCEVAtScope(RetVal, L->getParentLoop());
    if (ExitVal->isLoopInvariant(L))
      RetVal = ExitVal;
  }
  return RetVal;
}

void IVUsers::print(raw_ostream &OS, const Module *M) const {
  OS << "IV Users for loop ";
  WriteAsOperand(OS, L->getHeader(), false);
  if (SE->hasLoopInvariantBackedgeTakenCount(L)) {
    OS << " with backedge-taken count "
       << *SE->getBackedgeTakenCount(L);
  }
  OS << ":\n";

  for (unsigned Stride = 0, e = StrideOrder.size(); Stride != e; ++Stride) {
    std::map<const SCEV *, IVUsersOfOneStride*>::const_iterator SI =
      IVUsesByStride.find(StrideOrder[Stride]);
    assert(SI != IVUsesByStride.end() && "Stride doesn't exist!");
    OS << "  Stride " << *SI->first->getType() << " " << *SI->first << ":\n";

    for (ilist<IVStrideUse>::const_iterator UI = SI->second->Users.begin(),
         E = SI->second->Users.end(); UI != E; ++UI) {
      OS << "    ";
      WriteAsOperand(OS, UI->getOperandValToReplace(), false);
      OS << " = ";
      OS << *getReplacementExpr(*UI);
      if (UI->isUseOfPostIncrementedValue())
        OS << " (post-inc)";
      OS << " in ";
      UI->getUser()->print(OS);
      OS << '\n';
    }
  }
}

void IVUsers::print(std::ostream &o, const Module *M) const {
  raw_os_ostream OS(o);
  print(OS, M);
}

void IVUsers::dump() const {
  print(errs());
}

void IVUsers::releaseMemory() {
  IVUsesByStride.clear();
  StrideOrder.clear();
  Processed.clear();
}

void IVStrideUse::deleted() {
  // Remove this user from the list.
  Parent->Users.erase(this);
  // this now dangles!
}
<commit_msg>Fix more missing newlines.<commit_after>//===- IVUsers.cpp - Induction Variable Users -------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements bookkeeping for "interesting" users of expressions
// computed from induction variables.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "iv-users"
#include "llvm/Analysis/IVUsers.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Type.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
using namespace llvm;

char IVUsers::ID = 0;
static RegisterPass<IVUsers>
X("iv-users", "Induction Variable Users", false, true);

Pass *llvm::createIVUsersPass() {
  return new IVUsers();
}

/// containsAddRecFromDifferentLoop - Determine whether expression S involves a
/// subexpression that is an AddRec from a loop other than L.  An outer loop
/// of L is OK, but not an inner loop nor a disjoint loop.
static bool containsAddRecFromDifferentLoop(const SCEV *S, Loop *L) {
  // This is very common, put it first.
  if (isa<SCEVConstant>(S))
    return false;
  if (const SCEVCommutativeExpr *AE = dyn_cast<SCEVCommutativeExpr>(S)) {
    for (unsigned int i=0; i< AE->getNumOperands(); i++)
      if (containsAddRecFromDifferentLoop(AE->getOperand(i), L))
        return true;
    return false;
  }
  if (const SCEVAddRecExpr *AE = dyn_cast<SCEVAddRecExpr>(S)) {
    if (const Loop *newLoop = AE->getLoop()) {
      if (newLoop == L)
        return false;
      // if newLoop is an outer loop of L, this is OK.
      if (!LoopInfo::isNotAlreadyContainedIn(L, newLoop))
        return false;
    }
    return true;
  }
  if (const SCEVUDivExpr *DE = dyn_cast<SCEVUDivExpr>(S))
    return containsAddRecFromDifferentLoop(DE->getLHS(), L) ||
           containsAddRecFromDifferentLoop(DE->getRHS(), L);
#if 0
  // SCEVSDivExpr has been backed out temporarily, but will be back; we'll
  // need this when it is.
  if (const SCEVSDivExpr *DE = dyn_cast<SCEVSDivExpr>(S))
    return containsAddRecFromDifferentLoop(DE->getLHS(), L) ||
           containsAddRecFromDifferentLoop(DE->getRHS(), L);
#endif
  if (const SCEVCastExpr *CE = dyn_cast<SCEVCastExpr>(S))
    return containsAddRecFromDifferentLoop(CE->getOperand(), L);
  return false;
}

/// getSCEVStartAndStride - Compute the start and stride of this expression,
/// returning false if the expression is not a start/stride pair, or true if it
/// is.  The stride must be a loop invariant expression, but the start may be
/// a mix of loop invariant and loop variant expressions.  The start cannot,
/// however, contain an AddRec from a different loop, unless that loop is an
/// outer loop of the current loop.
static bool getSCEVStartAndStride(const SCEV *&SH, Loop *L, Loop *UseLoop,
                                  const SCEV *&Start, const SCEV *&Stride,
                                  ScalarEvolution *SE, DominatorTree *DT) {
  const SCEV *TheAddRec = Start;   // Initialize to zero.

  // If the outer level is an AddExpr, the operands are all start values except
  // for a nested AddRecExpr.
  if (const SCEVAddExpr *AE = dyn_cast<SCEVAddExpr>(SH)) {
    for (unsigned i = 0, e = AE->getNumOperands(); i != e; ++i)
      if (const SCEVAddRecExpr *AddRec =
             dyn_cast<SCEVAddRecExpr>(AE->getOperand(i))) {
        if (AddRec->getLoop() == L)
          TheAddRec = SE->getAddExpr(AddRec, TheAddRec);
        else
          return false;  // Nested IV of some sort?
      } else {
        Start = SE->getAddExpr(Start, AE->getOperand(i));
      }
  } else if (isa<SCEVAddRecExpr>(SH)) {
    TheAddRec = SH;
  } else {
    return false;  // not analyzable.
  }

  const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(TheAddRec);
  if (!AddRec || AddRec->getLoop() != L) return false;

  // Use getSCEVAtScope to attempt to simplify other loops out of
  // the picture.
  const SCEV *AddRecStart = AddRec->getStart();
  AddRecStart = SE->getSCEVAtScope(AddRecStart, UseLoop);
  const SCEV *AddRecStride = AddRec->getStepRecurrence(*SE);

  // FIXME: If Start contains an SCEVAddRecExpr from a different loop, other
  // than an outer loop of the current loop, reject it.  LSR has no concept of
  // operating on more than one loop at a time so don't confuse it with such
  // expressions.
  if (containsAddRecFromDifferentLoop(AddRecStart, L))
    return false;

  Start = SE->getAddExpr(Start, AddRecStart);

  // If stride is an instruction, make sure it dominates the loop preheader.
  // Otherwise we could end up with a use before def situation.
  if (!isa<SCEVConstant>(AddRecStride)) {
    BasicBlock *Preheader = L->getLoopPreheader();
    if (!AddRecStride->dominates(Preheader, DT))
      return false;

    DEBUG(errs() << "[" << L->getHeader()->getName()
                 << "] Variable stride: " << *AddRec << "\n");
  }

  Stride = AddRecStride;
  return true;
}

/// IVUseShouldUsePostIncValue - We have discovered a "User" of an IV expression
/// and now we need to decide whether the user should use the preinc or post-inc
/// value.  If this user should use the post-inc version of the IV, return true.
///
/// Choosing wrong here can break dominance properties (if we choose to use the
/// post-inc value when we cannot) or it can end up adding extra live-ranges to
/// the loop, resulting in reg-reg copies (if we use the pre-inc value when we
/// should use the post-inc value).
static bool IVUseShouldUsePostIncValue(Instruction *User, Instruction *IV,
                                       Loop *L, LoopInfo *LI, DominatorTree *DT,
                                       Pass *P) {
  // If the user is in the loop, use the preinc value.
  if (L->contains(User->getParent())) return false;

  BasicBlock *LatchBlock = L->getLoopLatch();

  // Ok, the user is outside of the loop.  If it is dominated by the latch
  // block, use the post-inc value.
  if (DT->dominates(LatchBlock, User->getParent()))
    return true;

  // There is one case we have to be careful of: PHI nodes.  These little guys
  // can live in blocks that are not dominated by the latch block, but (since
  // their uses occur in the predecessor block, not the block the PHI lives in)
  // should still use the post-inc value.  Check for this case now.
  PHINode *PN = dyn_cast<PHINode>(User);
  if (!PN) return false;  // not a phi, not dominated by latch block.

  // Look at all of the uses of IV by the PHI node.  If any use corresponds to
  // a block that is not dominated by the latch block, give up and use the
  // preincremented value.
  unsigned NumUses = 0;
  for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
    if (PN->getIncomingValue(i) == IV) {
      ++NumUses;
      if (!DT->dominates(LatchBlock, PN->getIncomingBlock(i)))
        return false;
    }

  // Okay, all uses of IV by PN are in predecessor blocks that really are
  // dominated by the latch block.  Use the post-incremented value.
  return true;
}

/// AddUsersIfInteresting - Inspect the specified instruction.  If it is a
/// reducible SCEV, recursively add its users to the IVUsesByStride set and
/// return true.  Otherwise, return false.
bool IVUsers::AddUsersIfInteresting(Instruction *I) {
  if (!SE->isSCEVable(I->getType()))
    return false;   // Void and FP expressions cannot be reduced.

  // LSR is not APInt clean, do not touch integers bigger than 64-bits.
  if (SE->getTypeSizeInBits(I->getType()) > 64)
    return false;

  if (!Processed.insert(I))
    return true;    // Instruction already handled.

  // Get the symbolic expression for this instruction.
  const SCEV *ISE = SE->getSCEV(I);
  if (isa<SCEVCouldNotCompute>(ISE)) return false;

  // Get the start and stride for this expression.
  Loop *UseLoop = LI->getLoopFor(I->getParent());
  const SCEV *Start = SE->getIntegerSCEV(0, ISE->getType());
  const SCEV *Stride = Start;

  if (!getSCEVStartAndStride(ISE, L, UseLoop, Start, Stride, SE, DT))
    return false;  // Non-reducible symbolic expression, bail out.

  SmallPtrSet<Instruction *, 4> UniqueUsers;
  for (Value::use_iterator UI = I->use_begin(), E = I->use_end();
       UI != E; ++UI) {
    Instruction *User = cast<Instruction>(*UI);
    if (!UniqueUsers.insert(User))
      continue;

    // Do not infinitely recurse on PHI nodes.
    if (isa<PHINode>(User) && Processed.count(User))
      continue;

    // Descend recursively, but not into PHI nodes outside the current loop.
    // It's important to see the entire expression outside the loop to get
    // choices that depend on addressing mode use right, although we won't
    // consider references ouside the loop in all cases.
    // If User is already in Processed, we don't want to recurse into it again,
    // but do want to record a second reference in the same instruction.
    bool AddUserToIVUsers = false;
    if (LI->getLoopFor(User->getParent()) != L) {
      if (isa<PHINode>(User) || Processed.count(User) ||
          !AddUsersIfInteresting(User)) {
        DOUT << "FOUND USER in other loop: " << *User << '\n'
             << "   OF SCEV: " << *ISE << "\n";
        AddUserToIVUsers = true;
      }
    } else if (Processed.count(User) ||
               !AddUsersIfInteresting(User)) {
      DOUT << "FOUND USER: " << *User << '\n'
           << "   OF SCEV: " << *ISE << "\n";
      AddUserToIVUsers = true;
    }

    if (AddUserToIVUsers) {
      IVUsersOfOneStride *StrideUses = IVUsesByStride[Stride];
      if (!StrideUses) {    // First occurrence of this stride?
        StrideOrder.push_back(Stride);
        StrideUses = new IVUsersOfOneStride(Stride);
        IVUses.push_back(StrideUses);
        IVUsesByStride[Stride] = StrideUses;
      }

      // Okay, we found a user that we cannot reduce.  Analyze the instruction
      // and decide what to do with it.  If we are a use inside of the loop, use
      // the value before incrementation, otherwise use it after incrementation.
      if (IVUseShouldUsePostIncValue(User, I, L, LI, DT, this)) {
        // The value used will be incremented by the stride more than we are
        // expecting, so subtract this off.
        const SCEV *NewStart = SE->getMinusSCEV(Start, Stride);
        StrideUses->addUser(NewStart, User, I);
        StrideUses->Users.back().setIsUseOfPostIncrementedValue(true);
        DOUT << "   USING POSTINC SCEV, START=" << *NewStart<< "\n";
      } else {
        StrideUses->addUser(Start, User, I);
      }
    }
  }
  return true;
}

IVUsers::IVUsers()
 : LoopPass(&ID) {
}

void IVUsers::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<LoopInfo>();
  AU.addRequired<DominatorTree>();
  AU.addRequired<ScalarEvolution>();
  AU.setPreservesAll();
}

bool IVUsers::runOnLoop(Loop *l, LPPassManager &LPM) {

  L = l;
  LI = &getAnalysis<LoopInfo>();
  DT = &getAnalysis<DominatorTree>();
  SE = &getAnalysis<ScalarEvolution>();

  // Find all uses of induction variables in this loop, and categorize
  // them by stride.  Start by finding all of the PHI nodes in the header for
  // this loop.  If they are induction variables, inspect their uses.
  for (BasicBlock::iterator I = L->getHeader()->begin(); isa<PHINode>(I); ++I)
    AddUsersIfInteresting(I);

  return false;
}

/// getReplacementExpr - Return a SCEV expression which computes the
/// value of the OperandValToReplace of the given IVStrideUse.
const SCEV *IVUsers::getReplacementExpr(const IVStrideUse &U) const {
  // Start with zero.
  const SCEV *RetVal = SE->getIntegerSCEV(0, U.getParent()->Stride->getType());
  // Create the basic add recurrence.
  RetVal = SE->getAddRecExpr(RetVal, U.getParent()->Stride, L);
  // Add the offset in a separate step, because it may be loop-variant.
  RetVal = SE->getAddExpr(RetVal, U.getOffset());
  // For uses of post-incremented values, add an extra stride to compute
  // the actual replacement value.
  if (U.isUseOfPostIncrementedValue())
    RetVal = SE->getAddExpr(RetVal, U.getParent()->Stride);
  // Evaluate the expression out of the loop, if possible.
  if (!L->contains(U.getUser()->getParent())) {
    const SCEV *ExitVal = SE->getSCEVAtScope(RetVal, L->getParentLoop());
    if (ExitVal->isLoopInvariant(L))
      RetVal = ExitVal;
  }
  return RetVal;
}

void IVUsers::print(raw_ostream &OS, const Module *M) const {
  OS << "IV Users for loop ";
  WriteAsOperand(OS, L->getHeader(), false);
  if (SE->hasLoopInvariantBackedgeTakenCount(L)) {
    OS << " with backedge-taken count "
       << *SE->getBackedgeTakenCount(L);
  }
  OS << ":\n";

  for (unsigned Stride = 0, e = StrideOrder.size(); Stride != e; ++Stride) {
    std::map<const SCEV *, IVUsersOfOneStride*>::const_iterator SI =
      IVUsesByStride.find(StrideOrder[Stride]);
    assert(SI != IVUsesByStride.end() && "Stride doesn't exist!");
    OS << "  Stride " << *SI->first->getType() << " " << *SI->first << ":\n";

    for (ilist<IVStrideUse>::const_iterator UI = SI->second->Users.begin(),
         E = SI->second->Users.end(); UI != E; ++UI) {
      OS << "    ";
      WriteAsOperand(OS, UI->getOperandValToReplace(), false);
      OS << " = ";
      OS << *getReplacementExpr(*UI);
      if (UI->isUseOfPostIncrementedValue())
        OS << " (post-inc)";
      OS << " in ";
      UI->getUser()->print(OS);
      OS << '\n';
    }
  }
}

void IVUsers::print(std::ostream &o, const Module *M) const {
  raw_os_ostream OS(o);
  print(OS, M);
}

void IVUsers::dump() const {
  print(errs());
}

void IVUsers::releaseMemory() {
  IVUsesByStride.clear();
  StrideOrder.clear();
  Processed.clear();
}

void IVStrideUse::deleted() {
  // Remove this user from the list.
  Parent->Users.erase(this);
  // this now dangles!
}
<|endoftext|>