#include <stdio.h>
//#include <strings.h>
#include <string.h>
#include "opt.h"
#include "analysis.h"
#include "misc.h"
#include "vars.h"
#include "io.h"
#include "vect.h"

#include <assert.h> // wso

//#define PRINT_ASM // enable this only when you want to print out assembly into stdout

#define MAXLOOPLEVELS 10

int totnuminsts;               /* total static instructions */
int totnummems;                /* total static memory references */
int totinsts[MAXLOOPLEVELS];   /* total static insts at each loop nest level */
int totmems[MAXLOOPLEVELS];    /* total static mems at each loop nest level */

/* insttypes are used to identify the type of each instruction */
/*struct instinfo {
  char *mneumonic;            // mneumonic of instruction
  enum insttype type;         // instruction class:    
  ARITH_INST,
  BRANCH_INST,
  CALL_INST,
  CMP_INST,
  CONV_INST,
  JUMP_INST,
  LOAD_INST,
  MOV_INST,
  RESTORE_INST,
  RETURN_INST,
  SAVE_INST,
  STORE_INST,
  COMMENT_LINE,
  DEFINE_LINE
  int numargs;                 // number of arguments
  int numdstregs;              // number of consecutive registers associated with the destination
  int numsrcregs;             // number of consecutive registers associated with each source
  int setscc;                  // condition codes set? 
  // wso: Not used in any part of source: always set to 0 for PISA
  // sparc uses CMP instruction to set condition register then use bg,bne,bl,ble..
  // BUT, PISA has FCC. Use this for FCC
  TRUE=1 FALSE=0
  int datatype;                // datatype of instruction
  INT_TYPE=1 FLOAT_TYPE=2 DOUBLE_TYPE 3=3

  };*/

struct instinfo insttypes[] = {
// ===== CAT 1: Control =====
//JUMP_INST
  {"j", JUMP_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"jr", JUMP_INST, 1, 0, 1, FALSE, INT_TYPE},
//CALL_INST??
  {"jal", CALL_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"jalr", CALL_INST, 1, 0, 1, FALSE, INT_TYPE},
//BRANCH_INST
  {"beq", BRANCH_INST, 3, 0, 1, FALSE, INT_TYPE},
  {"bne", BRANCH_INST, 3, 0, 1, FALSE, INT_TYPE},
  {"blez", BRANCH_INST, 2, 0, 1, FALSE, INT_TYPE},
  {"bgtz", BRANCH_INST, 2, 0, 1, FALSE, INT_TYPE},
  {"bltz", BRANCH_INST, 2, 0, 1, FALSE, INT_TYPE},
  {"bgez", BRANCH_INST, 2, 0, 1, FALSE, INT_TYPE},
  {"bc1f", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bc1t", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
// ===== CAT 2: Load/Store =====
//LOAD_INST
  {"lb", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"lbu", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"lh", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"lhu", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"lw", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"dlw", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"l.s", LOAD_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"l.d", LOAD_INST, 2, 1, 1, FALSE, DOUBLE_TYPE},
  {"lwl", LOAD_INST, 1, 0, 1, FALSE, INT_TYPE},
  {"lwr", LOAD_INST, 1, 0, 1, FALSE, INT_TYPE},
//STORE_INST
  {"sb", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"sh", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"sw", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"dsw", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"dsz", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"s.s", STORE_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"s.d", STORE_INST, 2, 1, 1, FALSE, DOUBLE_TYPE},
  {"swl", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"swr", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},

// ===== CAT 3: Integer Arithmetic =====
//ARITH_INST
  {"add", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"addi", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"addu", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"addiu", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"sub", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"subu", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  // uses $HI, $LOW as dst regs
  {"mult", ARITH_INST, 2, 0, 1, FALSE, INT_TYPE}, 
  {"multu", ARITH_INST, 2, 0, 1, FALSE, INT_TYPE},
  {"div", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE}, // 2 parameters in the manual but 3 in reality
  {"divu", ARITH_INST, 2, 0, 1, FALSE, INT_TYPE},
  {"mfhi", ARITH_INST, 1, 0, 1, FALSE, INT_TYPE},
  {"mthi", ARITH_INST, 1, 0, 1, FALSE, INT_TYPE},
  {"mflo", ARITH_INST, 1, 0, 1, FALSE, INT_TYPE},
  {"mtlo", ARITH_INST, 1, 0, 1, FALSE, INT_TYPE},
  // logical & bitwise
  {"and", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"andi", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"or", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"ori", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"xor", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"xori", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"nor", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"sll", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"slly", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"srl", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"srlv", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"sra", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"srav", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  // compare (before branch)
  {"slt", CMP_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"slti", CMP_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"sltu", CMP_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"sltiu", CMP_INST, 3, 1, 1, FALSE, INT_TYPE},

// Psedo-instructions: http://www.cs.wisc.edu/~lenz/WISC.html
  {"move", MOV_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"la", ARITH_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"li", ARITH_INST, 2, 1, 1, FALSE, INT_TYPE},

// ===== CAT 4: Floating Point Arithmetic =====
//ARITH_INST
  {"add.s", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"add.d", ARITH_INST, 3, 1, 1, FALSE, DOUBLE_TYPE},
  {"sub.s", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"sub.d", ARITH_INST, 3, 1, 1, FALSE, DOUBLE_TYPE},
  {"mul.s", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"mul.d", ARITH_INST, 3, 1, 1, FALSE, DOUBLE_TYPE},
  {"div.s", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"div.d", ARITH_INST, 3, 1, 1, FALSE, DOUBLE_TYPE},
  {"abs.s", ARITH_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"abs.d", ARITH_INST, 2, 1, 1, FALSE, DOUBLE_TYPE},
//CONV_INST
  {"mov.s", CONV_INST, 2, 1, 1, FALSE, 0},
  {"mov.d", CONV_INST, 2, 1, 1, FALSE, 0},
  {"neg.s", CONV_INST, 2, 1, 1, FALSE, 0},
  {"neg.d", CONV_INST, 2, 1, 1, FALSE, 0},
  {"cvt.s.d", CONV_INST, 2, 1, 1, FALSE, 0},
  {"cvt.s.w", CONV_INST, 2, 1, 1, FALSE, 0},
  {"cvt.d.s", CONV_INST, 2, 1, 1, FALSE, 0},
  {"cvt.d.w", CONV_INST, 2, 1, 1, FALSE, 0},
  {"cvt.w.s", CONV_INST, 2, 1, 1, FALSE, 0},
  {"cvt.w.d", CONV_INST, 2, 1, 1, FALSE, 0},
//CMP_INST
  {"c.eq.s", CMP_INST, 2, 0, 1, TRUE, FLOAT_TYPE},
  {"c.eq.d", CMP_INST, 2, 0, 1, TRUE, DOUBLE_TYPE},
  {"c.lt.s", CMP_INST, 2, 0, 1, TRUE, FLOAT_TYPE},
  {"c.lt.d", CMP_INST, 2, 0, 1, TRUE, DOUBLE_TYPE},
  {"c.le.s", CMP_INST, 2, 0, 1, TRUE, FLOAT_TYPE},
  {"c.eq.d", CMP_INST, 2, 0, 1, TRUE, DOUBLE_TYPE},
//others
  {"sqrt.s", ARITH_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"sqrt.d", ARITH_INST, 2, 1, 1, FALSE, DOUBLE_TYPE},

// ===== CAT 5: Miscellaneous =====
// MISC_INST
  {"nop", MISC_INST, 0, 0, 0, FALSE, 0},
  {"syscall", MISC_INST, 0, 0, 0, FALSE, 0},
  {"break", MISC_INST, 1, 0, 0, FALSE, 0},
  {"lui", MISC_INST, 1, 0, 0, FALSE, 0},
//CONV_INST
  {"mfc1", CONV_INST, 2, 1, 1, FALSE, 0},
  {"mtc1", CONV_INST, 2, 1, 1, FALSE, 0},

// ===== Not exist =====
//RESTORE_INST
//RETURN_INST
//SAVE_INST
#if 0 // sparc
  {"add", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"addcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"and", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"andcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"andn", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"andncc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"ba", JUMP_INST, 1, 0, 0, FALSE, 0},
  {"ba,a", JUMP_INST, 1, 0, 0, FALSE, 0},
  {"be", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bg", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bge", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bgeu", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bgu", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bl", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"ble", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bleu", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"blu", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"bne", BRANCH_INST, 1, 0, 0, FALSE, INT_TYPE},
  {"call", CALL_INST, 2, 0, 1, FALSE, 0},
  {"cmp", CMP_INST, 2, 0, 1, TRUE, INT_TYPE},
  {"fadds", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"faddd", ARITH_INST, 3, 2, 2, FALSE, DOUBLE_TYPE},
  {"fbe", BRANCH_INST, 1, 0, 0, FALSE, DOUBLE_TYPE},
  {"fbg", BRANCH_INST, 1, 0, 0, FALSE, DOUBLE_TYPE},
  {"fbge", BRANCH_INST, 1, 0, 0, FALSE, DOUBLE_TYPE},
  {"fbl", BRANCH_INST, 1, 0, 0, FALSE, DOUBLE_TYPE},
  {"fble", BRANCH_INST, 1, 0, 0, FALSE, DOUBLE_TYPE},
  {"fbne", BRANCH_INST, 1, 0, 0, FALSE, DOUBLE_TYPE},
  {"fdivs", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"fdivd", ARITH_INST, 3, 2, 2, FALSE, DOUBLE_TYPE},
  {"fdtoi", CONV_INST, 2, 1, 2, FALSE, 0},
  {"fdtos", CONV_INST, 2, 1, 2, FALSE, 0},
  {"fitos", CONV_INST, 2, 1, 1, FALSE, 0},
  {"fitod", CONV_INST, 2, 2, 1, FALSE, 0},
  {"fmovs", MOV_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"fmovd", MOV_INST, 2, 2, 2, FALSE, DOUBLE_TYPE},
  {"fmuls", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"fmuld", ARITH_INST, 3, 2, 2, FALSE, DOUBLE_TYPE},
  {"fnegs", ARITH_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"fstod", CONV_INST, 2, 2, 1, FALSE, 0},
  {"fstoi", CONV_INST, 2, 1, 1, FALSE, 0},
  {"fsubs", ARITH_INST, 3, 1, 1, FALSE, FLOAT_TYPE},
  {"fsubd", ARITH_INST, 3, 2, 2, FALSE, DOUBLE_TYPE},
  {"ld", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"ldd", LOAD_INST, 2, 2, 1, FALSE, DOUBLE_TYPE},
  {"ldf", LOAD_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"ldsb", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"ldsh", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"ldub", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"lduh", LOAD_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"mov", MOV_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"or", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"orcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"orn", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"orncc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"restore", RESTORE_INST, 0, 0, 0, FALSE, 0},
  {"restore", RESTORE_INST, 3, 1, 1, FALSE, 0},
  {"ret", RETURN_INST, 0, 0, 0, FALSE, 0},
  {"retl", RETURN_INST, 0, 0, 0, FALSE, 0},
  {"save", SAVE_INST, 3, 1, 1, FALSE, 0},
  {"sdiv", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"sdivcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"sethi", ARITH_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"sll", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"smul", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"smulcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"sra", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"srl", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"st", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"stb", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"std", STORE_INST, 2, 1, 2, FALSE, DOUBLE_TYPE},
  {"stf", STORE_INST, 2, 1, 1, FALSE, FLOAT_TYPE},
  {"sth", STORE_INST, 2, 1, 1, FALSE, INT_TYPE},
  {"sub", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"subcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"umul", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"umulcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"udiv", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"udivcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"xor", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"xorcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
  {"xnor", ARITH_INST, 3, 1, 1, FALSE, INT_TYPE},
  {"xnorcc", ARITH_INST, 3, 1, 1, TRUE, INT_TYPE},
#endif
  {"", 0, 0, 0, 0, 0, 0}
};

struct bblk *top = (struct bblk *) NULL;  /* top block in the function    */
struct bblk *bot = (struct bblk *) NULL;  /* end block in the function    */
char funcname[MAXFIELD];                  /* name of the current function */
short functype;                           /* type of the current function */
int numpeeprules;                         /* number of peephole rules     */
int numrulesapplied[MAXRULES];            /* count each rule is applied   */

/* wso: global variable list */
struct globalinfo* globals = (struct globalinfo*) NULL;

/* wso: local variable list */
struct localinfo* locals = (struct localinfo*) NULL;
int local_framsize = 0;

/*
 * classifyinst - classify an instruction
 */
void classifyinst(short numitems, itemarray items, enum insttype *type,
                  int *instinfonum, int *numdstregs, int *numsrcregs)
{
  int i;

  /* search through the list of known instructions */
  for (i = 0; insttypes[i].mneumonic[0]; i++)
    if (numitems-1 == insttypes[i].numargs &&
	strcmp(insttypes[i].mneumonic, items[0]) == 0) {
      *type = insttypes[i].type;
      *instinfonum = i;
      *numdstregs = insttypes[i].numdstregs;
      *numsrcregs = insttypes[i].numsrcregs;
      return;
    }
  fprintf(stderr, "classifyinst - %s is unknown instruction\n", items[0]);
  quit(1);
}

/*
 * reclassifyinsts - reclassify the instructions
 */
void reclassifyinsts()
{
  struct bblk *cblk;
  struct assemline *ptr;
  extern struct bblk *top;

  for (cblk = top; cblk; cblk = cblk->down) {
    for (ptr = cblk->lines; ptr; ptr = ptr->next)
      if (INST(ptr->type))
	setupinstinfo(ptr);
  }
}

/*
 * makeinstitems - make the items associated with an instruction
 */
void makeinstitems(char *text, short *numitems, itemarray *items, int strip)
{
  int i, j, commas, tabs;
  char args[4][MAXFIELD], inst[MAXLINE];

// wso: sometimes space is inserted instead of tab (E.g. addiu $2,$0,305)      
// so don't strip..(don't remove spaces)
//   strip = FALSE; // din't verified yet..

  /* strip out the blanks */
  j = 0;
  strcpy(inst, text);
  for (i = 0; text[i]; i++)
    if (text[i] != ' ' || !strip)
      inst[j++] = text[i];
  inst[j] = '\0';

  /* replace the commas with tabs */
  commas = 0;
  tabs = 0;
  for (i = 0; inst[i]; i++)
    if (inst[i] == '\t')
      tabs++;
    else if (tabs == 2 && inst[i] == ',') {
      commas++;
      inst[i] = '\t';
    }
      
  /* setup the arguments in the instruction */
  if (commas == 2 &&
      sscanf(inst, "\t%s\t%s\t%s\t%s", args[0], args[1], args[2], args[3])
      == 4)
    *numitems = 4;
  else if (commas == 1 &&
	   sscanf(inst, "\t%s\t%s\t%s", args[0], args[1], args[2]) == 3)
    *numitems = 3;
  else if (commas == 0 &&
	   sscanf(inst, "\t%s\t%s", args[0], args[1]) == 2)
    *numitems = 2;
  else if (commas == 0 && sscanf(inst, "\t%s", args[0]) == 1)
    *numitems = 1;
  else if (commas == 0 && sscanf(inst, "%s = %s", args[0], args[1]) == 2)
    *numitems = 2;
  *items = (itemarray) alloc(*numitems * sizeof(char *));
  for (i = 0; i < *numitems; i++)
    (*items)[i] = allocstring(args[i]);
}

/*
 * setupinstinfo - setup instruction information
 */
void setupinstinfo(struct assemline *ptr)
{
  int numdstregs, numsrcregs;

  makeinstitems(ptr->text, &ptr->numitems, &ptr->items, TRUE);
  classifyinst(ptr->numitems, ptr->items, &ptr->type, &ptr->instinfonum,
	       &numdstregs, &numsrcregs);
#if 0 // setuses must be modified if it is used.
  setsuses(ptr->text, ptr->type, ptr->instinfonum, ptr->items, ptr->numitems,
	   ptr->sets, ptr->uses, numdstregs, numsrcregs);
#endif
}

// wso: read global variables and construct symbol table.
// restriction - can read only integer global
/* 
 * readinglobals - read in global variables and store into globals
 */
int readinglobals(FILE* fin)
{
  char *status;
  char line[MAXLINE]; // items[2][MAXFIELD];
  char name[32];
  int value;
  struct globalinfo* temp;
  int global_read = FALSE;
   
  while ((status = fgets(line, MAXLINE, fin))) {
#ifdef PRINT_ASM
    printf("%s", line);
#endif
    if ( sscanf(line, "\t.word\t%d\n", &value) == 1 ) // \t.word\t5\n
    {
      // name, and value are stored (this happend at different iteration)
      //assert(global_read);
      if (global_read)  // Take one global per one word : there is a chance that multiple word for one global but just ignore this case.
      {
	// allocate new global variable
	temp = globals;
	globals = (struct globalinfo *) alloc(sizeof(struct globalinfo));
	assert(globals);
	globals->name = allocstring(name);
	globals->value = value;
	globals->next = temp;
	//(debug)//fprintf(stderr, "global: name=%s, value=%d\n", globals->name, globals->value);
      }

      global_read = FALSE;
    }

    if ( sscanf(line, "\t.globl\t%s\n", name) == 1 ) // \t.globl\tx\n
    {
      // name stored
      global_read = TRUE;
    }

// begining of code section
    if ( strcmp(line, "\t.text\n") == 0 ) 
      break;
  }
  if (!status)
    return 0;

  return 1;
}


/*
 * readinfunc - read in the function and store the instructions into basic
 *              blocks
 */
int readinfunc(FILE* fin)
{
  //int n;
  struct assemline *ptr;
  struct bblk *tblk;
  char line[MAXLINE]; // items[2][MAXFIELD];
  char *status;
  extern int numvars;
  //extern struct varinfo vars[];
// wso
  char strtmp[32];

  /* print out a pending switch to the data segment */
  //sparc// printf("\t.seg\t\"data\"\n");

  /* read in and dump out directives until read the text segment */
  while ((status = fgets(line, MAXLINE, fin))) {
#ifdef PRINT_ASM
    printf("%s", line);
#endif
// begining of the function
    //sparc//if (strcmp(line, "\t.seg\t\"text\"\n") == 0)
    if ( sscanf(line, "\t.ent\t%s\n", strtmp) == 1 ) // wso: E.g. \t.ent\tmain\n
      break;
  }
  if (!status)
    return 0;
#if 0 // sparc
  /* check if we are at the beginning of a function */
  fgets(line, MAXLINE, fin);
  if (strcmp(line, "\t.align\t8\n") != 0) {
    fprintf(stderr, "expecting\n\t.align\t8\n and got\n%s", line);
    quit(1);
  }
  printf("%s", line);
  fgets(line, MAXLINE, fin);
  if (strncmp(line, "\t.global", 8) != 0) {
    fprintf(stderr, "expecting\n\t.global\t%%s\n and got\n%s", line);
    quit(1);
  }
  printf("%s", line);
  fgets(line, MAXLINE, fin);
  if (sscanf(line, "\t.proc\t%d", &n) != 1) {
    fprintf(stderr, "expecting\n\t.proc\n and got\n%s", line);
    quit(1);
  }
#endif
// read func name
  //(buggy: do not print here) //printf("%s", line);
  fgets(line, MAXLINE, fin);
  if (line[strlen(line)-2] != ':') {
    fprintf(stderr, "readinfunc - expecting label and got\n%s", line);
    quit(1);
  }
  /* setup function name and type */
  strcpy(funcname, line);
  funcname[strlen(funcname)-2] = '\0';
  assert( strcmp(funcname, strtmp) == 0 ); // wso: make sure function name match.
#if 0 // sparc
  switch (n) {
  case 0:
    functype = 0;
    break;

  case 6:
    functype = FLOAT_TYPE;
    break;

  case 7:
    functype = DOUBLE_TYPE;
    break;

  default:
    functype = INT_TYPE;
    break;
  }
#endif
  /* read in the instructions for the function */
  top = bot = newblk(funcname);
  numvars = 0;
  while ((status = fgets(line, MAXLINE, fin))) {
    line[strlen(line)-1] = '\0';

// wso: delete comments if any. comments start with #. Also have to delete any tabs before comments.
    {
      int pos=0;
      while (line[pos++] != '\0')
      {
	if (line[pos] == '#')
	{
	  while (line[--pos] == '\t');
	  line[++pos] = '\0'; // replace the first TAB before comments into NULL
	  break;
	}
      }
      // if whole line comments, then skip
      if (line[0] == ' ') continue;
  
    }

// wso: empty line.. (with -g)
    if (line[0] == '\0') continue;



    /* check if we are at the end of the function */
    //sparc//if (strcmp(line, "\t.seg\t\"data\"") == 0) {
    if ( sscanf(line, "\t.end\t%s", strtmp) == 1) {

      assert( strcmp(funcname, strtmp) == 0 ); // wso: make sure function name match.

      /* clean up last empty block */
      if (!bot->lines) {
	tblk = bot;
	bot = bot->up;
	deleteblk(tblk);
      }
      return 1;
    }

#if 0 // sparc
      /* ignore nop instructions */
    if (strcmp(line, "\tnop") == 0)
      continue;
#endif

#if 0 // sparc
      /* store a comment line */
    else if (line[0] == '!') {
      ptr = insline(bot, (struct assemline *) NULL, line);
      ptr->type = COMMENT_LINE;
    }
#endif

// wso: .frame/.mask/.fmask at the beginning of function (Q. NEEDED?)
    else if ( (line[0] == '\t') && (line[1] == '.') ) {
      //continue; // ignore
      // or treat them as comment lines.. (keep them but do not use.)
// wso: This code should exist to output valid assmelby, but cause an error line729 loop_bound_analysis.c
// so from now one don't care about output valid assmelby.
#if 0 
      ptr = insline(bot, (struct assemline *) NULL, line);
      ptr->type = COMMENT_LINE;
#endif 

// wso: read .frame and .def for constructing local symbol table
// -O0 -g
// .frame $fp, 56, $31 --> store stack size 56
// .def	x;	.val	-40;	.scl	1;	.type	0x4;	.endef
// -O1/O2/O3 -g
// .frame	$sp,40,$31		# vars= 16, regs= 1/0, args= 16, extra= 0
// .def	x;	.val	9;	.scl	4;	.type	0x4;	.endef
      if ( line[2] == 'f' && line[3] == 'r' && line[4] == 'a' && line[5] == 'm' && line[6] == 'e')
      {
        char str1[8], str2[8]; 
        int value;
        // replace ',' to '\t': sscanf can not use ',' as delimeter.
        int pos=0;
        while (line[pos++] != '\0')
        {
          if (line[pos] == ',') line[pos] = '\t';
        }
        if (sscanf(line, "\t.frame\t%s\t%d\t%s", str1, &value, str2) == 3)
        {
          local_framsize = value;
        }        
      }
      else if ( line[2] == 'd' && line[3] == 'e' && line[4] == 'f')
      {
        char name[32]; 
        int value, value2, value3;
        struct localinfo* temp;
        // replace ';' to ' ': sscanf can not use ',' as delimeter.
        int pos=0;
        while (line[pos++] != '\0')
        {
          if (line[pos] == ';') line[pos] = ' ';
        }
        if (sscanf(line, "\t.def\t%s \t.val\t%d \t.scl\t\t%d \t.type\t0x%x \t.endif", name, &value, &value2, &value3) == 4)
        {
        	temp = locals;
        	locals = (struct localinfo *) alloc(sizeof(struct localinfo));
        	assert(locals);
        	locals->name = allocstring(name);
        	locals->value = value;
        	locals->next = temp;
        }

      }

    }

#if 0 // sparc
      /* store a define line */
    else if (sscanf(line, "%s = %s", items[0], items[1]) == 2) {
      ptr = insline(bot, (struct assemline *) NULL, line);
      ptr->type = DEFINE_LINE;
      makeinstitems(ptr->text, &ptr->numitems, &ptr->items, 0);
      if (numvars == MAXVARS) {
	fprintf(stderr, "readinfunc - too many variables in %s\n",
		funcname);
	quit(1);
      }
      vars[numvars].name = allocstring(ptr->items[0]);
      vars[numvars].type = 0;
      vars[numvars].indirect = 0;
      numvars++;
    }
#endif

    /* if a label, then start a new block */
    //sparc//else if (line[0] == '.' && line[1] == 'L') {
    else if (line[0] == '$' && line[1] == 'L') {
      line[strlen(line)-1] = '\0';
      if (bot->lines || bot->label) {
	tblk = newblk(line);
	tblk->up = bot;
	bot->down = tblk;
	bot = tblk;
      }
      else
	assignlabel(bot, line);
    }

    /* else an instruction */
    else {
      ptr = insline(bot, (struct assemline *) NULL, line);
      setupinstinfo(ptr);
      if ((TOC(ptr->type) && ptr->type != RETURN_INST) ||
	  ptr->type == RESTORE_INST) {
	tblk = newblk((char *) NULL);
	tblk->up = bot;
	bot->down = tblk;
	bot = tblk;
      }
    }
  }
  if (!status) {
    fprintf(stderr, "unexpected end of file after function\n");
    quit(1);
  }

  /* clean up last empty block */
  if (!bot->lines) {
    tblk = bot;
    bot = bot->up;
    deleteblk(tblk);
  }

  /* indicate that a function was read in */
  return 1;
}

/* wso: 11/06/2005
 * dumglobals - dumps global variables
 */
void dumpglobals()
{
  struct globalinfo *global;

  fprintf(stdout, "# global info\n");
  for (global = globals; global; global = global->next)
  {
    fprintf(stdout, "# global %s = %d\n", global->name, global->value);
  }
}

/* wso: 11/06/2005
 * dumplocals - dumps local variables
 */
void dumplocals()
{
  struct localinfo *local;

  fprintf(stdout, "# local info\n");
  fprintf(stdout, "# local framesize = %d\n", local_framsize);
  for (local = locals; local; local = local->next)
  {
    if (local->value >0) // register type
      fprintf(stdout, "# local %s -> $%d\n", local->name, local->value);
    else
      fprintf(stdout, "# local %s -> %d($fp)\n", local->name, local->value + local_framsize);
  }
}

/* wso: 11/06/2005
 * getlocalname - return name of local variables
 */
char* getlocalname(char* str)
{
  struct localinfo *local;

  int value;
  if (str[0] == '$') { // register type E.g $15
    value = atoi(&str[1]);
  }
  else { // stack type E.g. 16($fp)
    int pos = -1;
    while (str[++pos] == '(') str[pos] = '\0';
    value = atoi(&str[0]);
    value -= local_framsize;
  }

  for (local = locals; local; local = local->next)
  {
    if (local->value == value) return local->name;
  }
  return NULL;
}



/*
 * dumpblk - dumps the information for a block
 */
void dumpblk(FILE *fout, struct bblk *cblk)
{

#ifdef PRINT_ASM // wso

  int i;
  struct blist *bptr;
  struct assemline *ptr;
  char vartext[MAXVARLINE], new[MAXLINE];
#define COMMENT_START 20
#define USES_START    (COMMENT_START+13)
#define DEADS_START   (USES_START+14)

// wso: sparc comment ! ==> PISA comment #

  /* print out predecessor and successor information */
  fprintf(fout, "#\n");
  fprintf(fout, "# block %d\n", cblk->num);
  fprintf(fout, "# preds:");
  for (bptr = cblk->preds; bptr; bptr = bptr->next)
    fprintf(fout, " %d", bptr->ptr->num);
  fprintf(fout, "\n");
  fprintf(fout, "# succs:");
  for (bptr = cblk->succs; bptr; bptr = bptr->next)
    fprintf(fout, " %d", bptr->ptr->num);
  fprintf(fout, "\n");
  fprintf(fout, "#  doms:");
  bdump(fout, cblk->dom);
  fprintf(fout, "\n");
  fprintf(fout, "#   ins=");
  dumpvarstate(vartext, cblk->ins);
  fprintf(fout, "%s\n", vartext);
  fprintf(fout, "#  outs=");
  dumpvarstate(vartext, cblk->outs);
  fprintf(fout, "%s\n", vartext);
  fprintf(fout, "#\n");

  /* print out label */
  if (cblk->label)
    fprintf(fout, "%s:\n", cblk->label);

  /* for each assembly line in the block */
  for (ptr = cblk->lines; ptr; ptr = ptr->next) {

    /* print out the text of the assembly line */
    fprintf(fout, "%s", ptr->text);

    /* if the line contains an instruction */
    if (INST(ptr->type)) {

      /* line up sets after the instruction */
      new[0] = '\0';
      for (i = 1; ptr->text[i]; i++)
	if (ptr->text[i] == '\t') {
	  i++;
	  break;
	}
      if (!ptr->text[i])
	fprintf(fout, "\t");
      i = strlen(&ptr->text[i]);
      for (; i < COMMENT_START; i++)
	strcat(new, " ");
      fprintf(fout, new);

#if 0 // wso: not going to use..
      /* print out the sets */
      if (ptr->type == CALL_INST) {
	strcpy(vartext, "scratch");
	fprintf(fout, "# sets=%s", vartext);
      }
      else if (ptr->type == SAVE_INST || ptr->type == RESTORE_INST) {
	strcpy(vartext, "window");
	fprintf(fout, "# sets=%s", vartext);
      }
      else {
	dumpvarstate(vartext, ptr->sets);
	fprintf(fout, "# sets=%s", vartext);
      }

      /* line up uses after the sets */
      new[0] = '\0';
      for (i = COMMENT_START+strlen("sets=")+strlen(vartext);
	   i < USES_START; i++)
	strcat(new, " ");
      fprintf(fout, new);

      /* print out the uses */
      dumpvarstate(vartext, ptr->uses);
      fprintf(fout, "uses=%s", vartext);

      /* line up deads after the uses */
      new[0] = '\0';
      for (i = USES_START+strlen("uses=")+strlen(vartext);
	   i < DEADS_START; i++)
	strcat(new, " ");
      fprintf(fout, new);

      /* print out the deads */
      dumpvarstate(vartext, ptr->deads);
      fprintf(fout, "deads=%s", vartext);
#endif
    }

    /* print out the carriage return */
    fprintf(fout, "\n");

#if 0 // sparc: wso: add nop for branch delay slot
    if ((ptr->type == CALL_INST || ptr->type == BRANCH_INST ||
	 ptr->type == RETURN_INST) && !ptr->next)
      fprintf(fout, "\tnop\n");
#endif

  }
#endif // PRINT_ASM

}

/*
 * dumpoutblks - dumps a range of blocks to a file pointer
 */
void dumpoutblks(FILE *fout, unsigned int num1, unsigned int num2)
{
  struct bblk *cblk;
  void dumpblk(FILE *, struct bblk *);
  extern struct bblk *top;
 
  /* find the start block */
  for (cblk = top; cblk; cblk = cblk->down)
    if (cblk->num == num1)
      break;
 
  /* check if no more blocks */
  if (!cblk) {
    fprintf(fout, "no blocks in the range %d to %d\n", num1, num2);
    return;
  }
 
  /* print each block in the range */
  for (; cblk; cblk = cblk->down)
    if (cblk->num <= num2)
      dumpblk(fout, cblk);
    else
      break;
}

/*
 * dumpblks - diagnostic function to dump out a range of blocks
 */
void dumpblks(int num1, int num2)
{
  dumpoutblks(stderr, num1, num2);
}

/*
 * dumpfunc - write out the function to stdout
 */
void dumpfunc()
{
  struct bblk *cblk;

  /* dump out loop information */
  dumploops(stdout);

  /* print out each block in the program */
  for (cblk = top; cblk; cblk = cblk->down)
    dumpblk(stdout, cblk);

// wso: print end of function
#ifdef PRINT_ASM
  printf("\t.end\t%s\n", funcname);
#endif

}

/*
 * dumpruleusage - dump out how many times each rule was applied
 */
void dumpruleusage()
{
  int i;

  /* print out which peephole optimization rules were applied */
  fprintf(stderr, "\nnumpeeprules = %d\n", numpeeprules);
  for (i = 0; i < numpeeprules; i++)
    if (numrulesapplied[i] > 0)
      fprintf(stderr, "peephole rule %d applied %d times\n",
	      i+1, numrulesapplied[i]);
}

/*
 * dumpfunccounts - dump out the number of instructions and memory references
 *                  for the function
 */
void dumpfunccounts()
{
  int i, numinsts, nummems;
  int insts[MAXLOOPLEVELS];
  int mems[MAXLOOPLEVELS];
  struct bblk *cblk;
  struct assemline *ptr;
  static int first = TRUE;

  numinsts = nummems = 0;
  for (i = 0; i < MAXLOOPLEVELS; i++)
    insts[i] = mems[i] = 0;
  for (cblk = top; cblk; cblk = cblk->down)
    for (ptr = cblk->lines; ptr; ptr = ptr->next)
      if (INST(ptr->type)) {
	numinsts++;
	insts[cblk->loopnest]++;
	if (ptr->type == LOAD_INST || ptr->type == STORE_INST) {
	  nummems++;
	  mems[cblk->loopnest]++;
	}
      }
  if (first) {
    fprintf(stderr, "function     level instructions memory refs\n");
    fprintf(stderr, "------------ ----- ------------ -----------\n");
    first = FALSE;
  }
  fprintf(stderr, "%-12s total %12d %11d\n", funcname, numinsts, nummems);
  totnuminsts += numinsts;
  totnummems += nummems;
  if (insts[1] > 0)
    for (i = 0; i < MAXLOOPLEVELS && insts[i] > 0; i++) {
      totinsts[i] += insts[i];
      totmems[i] += mems[i];
      fprintf(stderr, "             %5d %12d %11d\n", i, insts[i], mems[i]);
    }
}

/*
 * dumptotalcounts - dump out the number of instructions and memory references
 *                   for the entire file
 */
void dumptotalcounts()
{
  int i;

  fprintf(stderr, "------------ ----- ------------ -----------\n");
  fprintf(stderr, "%-12s total %12d %11d\n", "program", 
	  totnuminsts, totnummems);
  if (totinsts[1] > 0)
    for (i = 0; i < MAXLOOPLEVELS && totinsts[i] > 0; i++) {
      fprintf(stderr, "             %5d %12d %11d\n", 
	      i, totinsts[i], totmems[i]);
    }
}

/* wso: 11/20/2005
 * utility functions for dumploop_dotloop
 * is_inc_type_add: check operaiton type is add or sub or others
 * find_deploop: find dependent (outer) loop if any
 */

int is_inc_type_add(char* inc_type)
{

  if (!inc_type) return 0;
  
	  if (  (strcmp(inc_type,"add")   == 0) ||
	      (strcmp(inc_type,"addi")  == 0) ||
	      (strcmp(inc_type,"addu")  == 0) ||
	      (strcmp(inc_type,"addiu") == 0) ) return 1;
    else if (
	      (strcmp(inc_type,"sub")   == 0) ||
		   (strcmp(inc_type,"subu")  == 0)  ) return -1;
    else return 0;
}

#define SIGN (is_inc_type_add(lptr->inc_type))
// determines sign of inc_value

struct loopnode * find_deploop(struct loopnode* lptr)
{
  int i;
  struct loopnode* dep_loop_ptr;

  if (!lptr) return NULL;
  
  // If it has no dependent loop 
  dep_loop_ptr = NULL;
  for (i=0; i<lptr->count; i++) {
    if (lptr->dependent[i]) { dep_loop_ptr = lptr->nested_ptr[i]; break; }
  }
  return dep_loop_ptr;
}

/* wso: 11/06/2005
 * dumploops_dotloop - wso: dump loop information for pcompiler
 */
void dumploops_dotloop(FILE *fout)
{
  struct loopnode *lptr;
  int loopno;
  struct loopnode* loopptrs[256];////struct loopnode ** loopptrs; // 11/27: use static array instead of dynamic: Limit 256 loops in a function
  int i;
//  int loop_no = 1;
  // register number usage:
  // 1-10: reserved for local and global variables (1: outermost loop/ increase by nested levels)
  // 11-..: for loop
  int loop_reg = 11;
  int loop_var = 1;

// wso: now only works for rectangular loops
  fprintf(fout, "-3\n");
  fprintf(fout, "%s\n", funcname);

  /* bviyer: MODIFIED suchh that we need to print oiut the loop increments
   * not just the loop bound twice
   */
#if 0  
  for (lptr = loops; lptr; lptr = lptr->next)
  {
    fprintf(fout, "! loop %d\n", loop_no);
     
    fprintf(fout, "%d %d -1 -1\n", lptr->loop_bound, lptr->loop_bound); //lptr->inc_value);
    loop_no++;
  }
#endif
  // Loop orders are reverse! Need to traverse in a reverse way
  loopno = 0;
  for (lptr = loops; lptr; lptr = lptr->next)
  {
    loopno++;
  }
  ////loopptrs = (struct loopnode **) alloc(loopno * sizeof(struct loopnode *));
  i = loopno;
  for (lptr = loops; lptr; lptr = lptr->next)
  {
    loopptrs[--i] = lptr;
    lptr->loop_no = i+1; // reverse loop numbers
  }

  // Now loopptrs are inoder.  
  for (i = 0; i < loopno; i++)
  {
    lptr = loopptrs[i];
    loop_var = lptr->header->loopnest; // 1..2..3
    
    fprintf(fout, "! loop %d\n", lptr->loop_no);

  // unpredictable loop:
    if (!lptr->predictable) {
      fprintf(fout, "Unpredictiable\n");
      continue; // skip this loop
    }

  // Rectangular loops
    if (lptr->rectangular) {
      // Constant: <min iterations> <max iterations> -1 -1
      if ( (lptr->init_val_type == LOOP_CONSTANT) && (lptr->final_val_type == LOOP_CONSTANT)) {
        fprintf(fout, "%d %d -1 -1\n", lptr->loop_bound, lptr->loop_bound); //lptr->inc_value);
      }
// Parameteric: -4 reg <init value> <final value> <increment> s -2 <var name> <var name> -1 -1
      // E.g. -4 r[11] 0 r[8] 1 s -2 .1_iter1 .1_iter1 -1 -1
      else {
      // Make sure + and <
      if (!( is_inc_type_add(lptr->inc_type) )) {// && lptr->compare_type == LT)) {// result is NE
        fprintf(fout, "Can not analyze: inc_op is not add/sub\n"); // or rel_op is not LT/GT.\n");
        continue; // skip this loop
      }
      if (lptr->init_val_type == LOOP_CONSTANT)
      {
        fprintf(fout, "-4 r[%d] %d r[%d] %d s -2 ", loop_reg++, lptr->init_val, loop_var, lptr->inc_value*SIGN);
#if 0 // 11/22 dont need global symbol either
        if (lptr->final_val_type == LOOP_GLOBAL) {
          fprintf(fout, "%s %s -1 -1\n", lptr->final_val_reg, lptr->final_val_reg);
        }
        else { //if (lptr->final_val_type == LOOP_REGISTER) {
#if 0 // 11/22: tried to use orignal symbol but, it is not possible for -O1/2/3 because registers are reused.
          char* lname;
          if ((lname = getlocalname(lptr->final_val_reg)))
            fprintf(fout, "%s %s -1 -1\n", lname, lname);
          else
#endif
            fprintf(fout, ".iter%d .iter%d -1 -1\n", lptr->loop_no, lptr->loop_no);
        }
#else
        fprintf(fout, ".iter%d .iter%d -1 -1\n", lptr->loop_no, lptr->loop_no);
#endif
      }
      else if (lptr->final_val_type == LOOP_CONSTANT)
      {
        fprintf(fout, "-4 r[%d] r[%d] %d %d s -2 ", loop_reg++, loop_var, lptr->final_val, lptr->inc_value*SIGN);
#if 0
        if (lptr->init_val_type == LOOP_GLOBAL) {
          fprintf(fout, "%s %s -1 -1\n", lptr->init_val_reg, lptr->init_val_reg);
        }
        else { //if (lptr->final_val_type == LOOP_REGISTER) {
#if 0 // 11/22: sane as above
          char* lname;
          if ((lname = getlocalname(lptr->init_val_reg)))
            fprintf(fout, "%s %s -1 -1\n", lname, lname);
          else
#endif
            fprintf(fout, ".iter%d .iter%d -1 -1\n", lptr->loop_no, lptr->loop_no);
        }
#else
        fprintf(fout, ".iter%d .iter%d -1 -1\n", lptr->loop_no, lptr->loop_no);
#endif
      }
      else { // both init and final are variables: possible??
        fprintf(fout, "Can not analyze: loop init, final both are variables\n");
      }
    }
    }
  // Non rectangular: either outer loop or inner loop
    else {

      struct loopnode* dep_loop_ptr, *ter_dep_loop_ptr, *tmp_loop_ptr;
      // If it has no dependent loop 
      dep_loop_ptr = find_deploop(lptr);

      // Outer loop
      if (dep_loop_ptr == NULL) {
        // -4 r[reg_num] <initial_val> <final_val> <inc_value> s <min_iterations> <max_iterations> -1 -1
        // E.g. -4 r[15] 0 10 1 s 10 10 -1 -1
        if (!( is_inc_type_add(lptr->inc_type) )) {
          fprintf(fout, "Can not analyze: inc_op is not add/sub\n");
          continue; // skip this loop
        }
        // Both must be constants
        if ( (lptr->init_val_type == LOOP_CONSTANT) && (lptr->final_val_type == LOOP_CONSTANT)) {
          fprintf(fout, "-4 r[%d] %d %d %d s %d %d -1 -1\n", 
            loop_reg++, lptr->init_val, lptr->final_val, lptr->inc_value*SIGN, lptr->loop_bound, lptr->loop_bound);
        }
        else {
          //fprintf(fout, "Can not analyze: Non-rectangular loops must be constant iterations.\n");
          // 11/22: allow parametric
      // code from above
      if (!( is_inc_type_add(lptr->inc_type) )) {// && lptr->compare_type == LT)) {// result is NE
        fprintf(fout, "Can not analyze: inc_op is not add/sub\n");
        continue; // skip this loop
      }
      if (lptr->init_val_type == LOOP_CONSTANT)
      {
        fprintf(fout, "-4 r[%d] %d r[%d] %d s -2 ", loop_reg++, lptr->init_val, loop_var, lptr->inc_value*SIGN);
        fprintf(fout, ".iter%d .iter%d -1 -1\n", lptr->loop_no, lptr->loop_no);
      }
      else if (lptr->final_val_type == LOOP_CONSTANT)
      {
        fprintf(fout, "-4 r[%d] r[%d] %d %d s -2 ", loop_reg++, loop_var, lptr->final_val, lptr->inc_value*SIGN);
        fprintf(fout, ".iter%d .iter%d -1 -1\n", lptr->loop_no, lptr->loop_no);
      }
      else {
        fprintf(fout, "Can not analyze: loop init, final both are variables\n");
      }
          
        }

      }

      // Inner loop: outerloop = dep_loop_ptr;
      else {
        //-3 <iter_mode> <initial_rtl> <inner_loop_limit> <rel_op>
        //<inner_loop_inc> <dependant_outer_loop_number> <c/r><outer_init_val>
        //<c/r><outer_max_value> <outer_loop_inc> -1 -1
        // E.g. -3 0 r[16]+0 10 4 1 1 c0 c10 1 -1 -1
        if (!( is_inc_type_add(lptr->inc_type) )) {
          fprintf(fout, "Can not analyze: inc_op is not add/sub\n");
          continue; // skip this loop
        }

        // find outer-most loop (when rectangular loops are nested more than 2 levels)
        ter_dep_loop_ptr = dep_loop_ptr;
        while ((tmp_loop_ptr = find_deploop(ter_dep_loop_ptr))) {
          ter_dep_loop_ptr = tmp_loop_ptr;
        }


        // case : dep. loop also has dependent loop: init final value comes from ter_dep_loop_ptr
        if (lptr->init_val_type == LOOP_CONSTANT) {

          if (ter_dep_loop_ptr->final_val_type == LOOP_CONSTANT 
            && ter_dep_loop_ptr->init_val_type == LOOP_CONSTANT) {

            fprintf(fout, "-3 0 r[%d]+%d %d %d %d %d c%d c%d %d -1 -1\n", 
              loop_reg++, 
              lptr->init_val, 
              ter_dep_loop_ptr->final_val, 
              lptr->compare_type, 
              lptr->inc_value*SIGN, 
              dep_loop_ptr->loop_no, 
              ((dep_loop_ptr->init_val_type==LOOP_CONSTANT)? dep_loop_ptr->init_val : ter_dep_loop_ptr->init_val),
              ((dep_loop_ptr->final_val_type==LOOP_CONSTANT)? dep_loop_ptr->final_val : ter_dep_loop_ptr->final_val), 
              dep_loop_ptr->inc_value*SIGN);
          }
          else if (ter_dep_loop_ptr->init_val_type == LOOP_CONSTANT) {
            // case: dep. loop final value is parametric: local or global: finalvalue -> .iter
            fprintf(fout, "-3 0 r[%d]+%d .iter%d %d %d %d c%d c.iter%d %d -1 -1\n", 
              loop_reg++, 
              lptr->init_val, 
              ter_dep_loop_ptr->loop_no, //final_val, 
              lptr->compare_type, 
              lptr->inc_value*SIGN, 
              dep_loop_ptr->loop_no, 
              ((dep_loop_ptr->init_val_type==LOOP_CONSTANT)? dep_loop_ptr->init_val : ter_dep_loop_ptr->init_val),
              ter_dep_loop_ptr->loop_no, //final_val, 
              dep_loop_ptr->inc_value*SIGN);
          }
          else {//if (ter_dep_loop_ptr->final_val_type == LOOP_CONSTANT) {

            fprintf(fout, "-3 0 r[%d]+%d .iter%d %d %d %d c.iter%d c%d %d -1 -1\n", 
              loop_reg++, 
              lptr->init_val, 
              ter_dep_loop_ptr->loop_no, //final_val, 
              lptr->compare_type, 
              lptr->inc_value*SIGN, 
              dep_loop_ptr->loop_no, 
              ter_dep_loop_ptr->loop_no,//dep_loop_ptr->init_val,
              ((dep_loop_ptr->final_val_type==LOOP_CONSTANT)? dep_loop_ptr->final_val : ter_dep_loop_ptr->final_val), 
              dep_loop_ptr->inc_value*SIGN);
          }

        }
        else if (lptr->final_val_type == LOOP_CONSTANT) {

          if (ter_dep_loop_ptr->final_val_type == LOOP_CONSTANT 
            && ter_dep_loop_ptr->init_val_type == LOOP_CONSTANT) {

            fprintf(fout, "-3 0 r[%d]+%d %d %d %d %d c%d c%d %d -1 -1\n", 
              loop_reg++, 
              ter_dep_loop_ptr->init_val, 
              lptr->final_val, 
              lptr->compare_type, 
              lptr->inc_value*SIGN, 
              dep_loop_ptr->loop_no, 
              ((dep_loop_ptr->init_val_type==LOOP_CONSTANT)? dep_loop_ptr->init_val : ter_dep_loop_ptr->init_val),
              ((dep_loop_ptr->final_val_type==LOOP_CONSTANT)? dep_loop_ptr->final_val : ter_dep_loop_ptr->final_val), 
              dep_loop_ptr->inc_value*SIGN);
          }
          else if (ter_dep_loop_ptr->init_val_type == LOOP_CONSTANT) {

            fprintf(fout, "-3 0 r[%d]+.iter%d %d %d %d %d c.iter%d c%d %d -1 -1\n", 
              loop_reg++, 
              ter_dep_loop_ptr->loop_no,
              lptr->final_val, 
              lptr->compare_type, 
              lptr->inc_value*SIGN, 
              dep_loop_ptr->loop_no, 
              dep_loop_ptr->loop_no,
              ((dep_loop_ptr->final_val_type==LOOP_CONSTANT)? dep_loop_ptr->final_val : ter_dep_loop_ptr->final_val), 
              dep_loop_ptr->inc_value*SIGN);
          }
          else {//if (ter_dep_loop_ptr->final_val_type == LOOP_CONSTANT) {

            fprintf(fout, "-3 0 r[%d]+.iter%d %d %d %d %d c.iter%d c%d %d -1 -1\n", 
              loop_reg++, 
              ter_dep_loop_ptr->loop_no,
              lptr->final_val, 
              lptr->compare_type, 
              lptr->inc_value*SIGN, 
              dep_loop_ptr->loop_no, 
              dep_loop_ptr->loop_no,
              ((dep_loop_ptr->final_val_type==LOOP_CONSTANT)? dep_loop_ptr->final_val : ter_dep_loop_ptr->final_val), 
              dep_loop_ptr->inc_value*SIGN);
          }
        }
        else {
          fprintf(fout, "Can not analyze: loop init, final both are variables\n");
        }

      }

    }
    
  }

  ////free(loopptrs);

}

/* wso: 11/06/2005
 * dumploops_info - wso: dump loop information for debug
 */
void dumploops_info(FILE *fout)
{
  struct loopnode *lptr;
  int loopno;
  struct loopnode* loopptrs[256]; ////struct loopnode ** loopptrs;
  int i;
  //int j;

  // Loop orders are reverse! Need to traverse in a reverse way
  loopno = 0;
  for (lptr = loops; lptr; lptr = lptr->next)
  {
    loopno++;
  }
  ////loopptrs = (struct loopnode **) alloc(loopno * sizeof(struct loopnode *));
  i = loopno;
  for (lptr = loops; lptr; lptr = lptr->next)
  {
    loopptrs[--i] = lptr;
    lptr->loop_no = i+1; // reverse loop numbers
  }

  // Now loopptrs are inoder.  
  for (i = 0; i < loopno; i++)
  {
    lptr = loopptrs[i];
    // add tab for nested loop
    //for (j=0; j<lptr->header->loopnest; j++) fprintf("\t");
    fprintf(fout, "loop %d ", lptr->loop_no);
    fprintf(fout, ": nest = %d\n", lptr->header->loopnest);
    fprintf(fout, "  predictable = %d rectangular = %d\n", lptr->predictable, lptr->rectangular);
    if (lptr->init_val_type == LOOP_CONSTANT) fprintf(fout, "  init = %d", lptr->init_val);
    else fprintf(fout, "  init = %s", lptr->init_val_reg);
    if (lptr->final_val_type == LOOP_CONSTANT) fprintf(fout, "  final = %d", lptr->final_val);
    else fprintf(fout, "  final = %s", lptr->final_val_reg);
    if (lptr->init_val_type == LOOP_CONSTANT && lptr->final_val_type == LOOP_CONSTANT) 
      fprintf(fout, "  bound = %d", lptr->loop_bound);
    fprintf(fout, "\n");

    fprintf(fout, "  comp_type = ");
    switch (lptr->compare_type)
    {
      case EQ:  fprintf(fout, "EQ");      break;
      case NE:  fprintf(fout, "NE");      break;
      case GT:  fprintf(fout, "GT");      break;
      case LT:  fprintf(fout, "LT");      break;
      case GE:  fprintf(fout, "GE");      break;
      case LE:  fprintf(fout, "LE");      break;
    }
    fprintf(fout, " inc_type = %s", lptr->inc_type);
    fprintf(fout, " inc_val = %d", lptr->inc_value);
    fprintf(fout, " inc_reg = %s", lptr->loop_var_addr);
    fprintf(fout, "\n");
    
    
  }

  ////free(loopptrs);
}


