/*
 * main driver for the program
 */
#include <stdio.h>
#include "opt.h"
#include "io.h"
#include "flow.h"
#include "analysis.h"
#include "opts.h"

#if 0
int swb = FALSE;  /* reverse branches flag             */
int swc = FALSE;  /* branch chaining flag              */
int swd = FALSE;  /* dead assignment elimination flag  */
int swe = FALSE;  /* local cse flag                    */
#ifdef FILLSLOTS
int swf = FALSE;  /* fill delay slots flag             */
#endif
int swm = FALSE;  /* code motion flag                  */
int swo = FALSE;  /* copy propagation flag             */
int swp = FALSE;  /* peephole optimization flag        */
int swr = FALSE;  /* register allocation flag          */
int swu = FALSE;  /* unreachable code elimination flag */

/*
 * checkflags - check the optimization flags
 */
void checkflags(char *flags)
{
   int i;

   if (flags[0] != '-') {
      fprintf(stderr,
              "checkflags - optimization flags should begin with '-'\n");
      quit(1);
   }
   for (i = 1; flags[i]; i++)
      switch (flags[i]) {
         case 'B':
            swb = TRUE;
            break;

         case 'C':
            swc = TRUE;
            break;

         case 'D':
            swd = TRUE;
            break;

         case 'E':
            swe = TRUE;
            break;

#ifdef FILLSLOTS
         case 'F':
            swf = TRUE;
            break;
#endif

         case 'M':
            swm = TRUE;
            break;

         case 'O':
            swo = TRUE;
            break;

         case 'P':
            swp = TRUE;
            break;

         case 'R':
            swr = TRUE;
            break;

         case 'U':
            swu = TRUE;
            break;

         default:
            fprintf(stderr, "%c is an invalid optimization flag\n", flags[i]);
            quit(1);
      }
}
#endif

/*
 * main - main function for the assembly optimizer
 */
int main(int argc, char *argv[])
{
  FILE* fin, *fout;
  char name_fout[64];
  int pos;
#if 0 // wso
   /* read in peephole optimization rules */
   readinrules();
#endif

#if 0 // wso
   /* check for flags */
   if (argc == 1)
#ifdef FILLSLOTS
      checkflags("-BCDEFMOPRU");
#else
      checkflags("-BCDEMOPRU");
#endif
   else if (argc == 2)
      checkflags(argv[1]);
   else {
      fprintf(stderr, "main - wrong number of arguments\n");
      quit(1);
   }
#else
  if (argc != 2) {
      fprintf(stderr, "usage: loopbound <input assembly file>\n");
      quit(1);
  }
#endif

   fin = fopen(argv[1], "r");
   strcpy(name_fout, argv[1]);
   pos = 0;
   while (1) { if (name_fout[pos++] == '.') break; }
   name_fout[pos++] = 'l'; 
   name_fout[pos++] = 'o'; 
   name_fout[pos++] = 'o'; 
   name_fout[pos++] = 'p'; 
   name_fout[pos++] = '\0'; 
   fout = fopen(name_fout, "w");

   /* wso : process global variables in the file */
   readinglobals(fin);
   //dumpglobals();

   /* process each function in the file */
   while (readinfunc(fin)) {

      /* setup the control flow between the basic blocks */
      setupcontrolflow();

#if 0 // wso
      /* perform branch optimizations */
      if (swc)
         remvbranchchains();
      if (swb)
         reversebranches();

      /* remove unreachable code */
      if (swu)
         unreachablecodeelim();
#endif

      /* find the loops in the function */
      numberblks();
      findloops();
      find_simple_loop_bounds();
#if 0 // wso
      /* allocate variables to registers */
      if (swr)
         regalloc(&changes);

      /* perform local common subexpression elimination */
      if (swe)
         localcse(&changes);

      /* perform copy propagation */
      if (swo) {
         calclivevars();
         calcdeadvars();
         copyprop(&changes);
      }

      /* calculate live variable information */
      calclivevars();

      /* remove dead assignments */
      if (swd)
         deadasgelim();

      /* apply peephole optimization rules */
      calcdeadvars();
      if (swp) {
         applypeeprules(&changes);
         if (changes) {
            calclivevars();
            calcdeadvars();
         }
      }

      /* repeatedly apply loop-invariant code motion as long as there
         are changes */
      do {
         anychanges = FALSE;
         if (swm) {
            codemotion(&anychanges);
            if (swe) {
               changes = FALSE;
               localcse(&changes);
               if (swo) {
                  calclivevars();
                  calcdeadvars();
                  copyprop(&changes);
                  if (swd) {
                     calclivevars();
                     deadasgelim();
                  }
               }
               if (changes)
                  anychanges = TRUE;
            }
            if (anychanges) {
               calclivevars();
               calcdeadvars();
               changes = FALSE;
               if (swp) {
                  applypeeprules(&changes);
                  if (changes) {
                     calclivevars();
                     calcdeadvars();
                  }
               }
            }
         }
      }
      while (anychanges);
#endif

#ifdef FILLSLOTS
      /* fill delay slots */
      if (swf)
         filldelayslots();
#endif

      /* dump out the assembly code */
      //dumplocals();
      //dumpfunc();

      /* dump out dot loop file */
      dumploops_info(stdout);
      dumploops_dotloop(fout);
      //dumploops_info(stderr);
      //dumploops_dotloop(stderr);


#if 0 // wso
      /* dump out counts */
      dumpfunccounts();
#endif
   }

#if 0 // wso
   /* dump out total counts */
   dumptotalcounts();

   /* dump out rule usage */
   dumpruleusage();
#endif

   fclose(fin);
   fclose(fout);

   quit(0);

   return 0;
}
