/* next_use.c */
/* author: Edward A. Green */
/* description: functions for derriving the next-use information */
/*              from a stored program.    */

#include "proj3.h"


void  next_use(BLOCK *blocks)
{
	MOD  *use;      /* pointers to current structure analyzed */
	MOD  *mod;      /* " */
	CODE *code;     /* " */
	BLOCK *blk;     /* " */
	CODE *code_end; /* pointer to end of current function block */
	int bb_num;     /* current basic block number */
	char *var[2];   /* pointers into quad field data */

	MOD *next_use_list = NULL;  /* dynamic next-use table */

	/* list of opcodes that modify quad field 2 */
	char *mod2[] = {"[]=", ""};


	/* list of opcodes that modify quad field 4 */
	char *mod4[] = {"ADD", "DI",  "DIV", "MOD", "MOV",
			"MUL", "PULL", "SUB", "[]",  ""};

	/* list of opcodes that use quad field 2 */
	char *use2[] = {"ADD", "DI", "DIV", "JGZ", "JZ",
			"MOD", "MOV", "MUL", "SUB", "[]", ""};

	/* list of opcodes that use quad field 3 */
	char *use3[] = {"ADD", "DI", "DIV", "MOD", "MUL", "SUB",
			"[]", "[]=", ""};

	/* list of opcodes that use quad field 4 */
	char *use4[] = {"PUSH", "[]=", ""};

	SYMTBL *sym_look_up(BLOCK *blk, char *var);
	MOD *next_use_find(MOD *next_use_list, char *s);
	void clear_next_use(MOD *list);
	char *strsave(char *x);

	/* check each statement from end to start of b. b. */
	/* separate case for each quad statement command */
	/* fill in use and mod entry for each statement (code) */

	/* until the block structure is exhausted... */
	blocks->last->next=NULL;
	for (blk=blocks; blk!=NULL; blk=blk->next)
	  {
	  /* work subprogram block from back to front */
	  code_end=blk->lead->last;     /* save end of code for block */
	  blk->lead->last=NULL;         /* set sentinal for linked list */
	  code=code_end;                /* start at the end of the code */
	  while (code!=NULL)
	    {
	    bb_num=code->basic;           /* consider each basic block */
	    clear_next_use(next_use_list);
	    next_use_list=NULL;
	    while (code->basic==bb_num)
	      {
	      int i,n;

	      /* do modified variables 1st */
	      var[0]=NULL;
	      for (i=0; strlen(mod2[i])>0; i++)
		if (!strcmp(mod2[i],code->flds[1])) var[0]=code->flds[2];
	      for (i=0; strlen(mod4[i])>0; i++)
		if (!strcmp(mod4[i],code->flds[1])) var[0]=code->flds[4];

	      if (var[0]!=NULL && !(var[0][0]>='0' && var[0][0]<='9'))
		{
		next_use_list=next_use_find(next_use_list,var[0]);
		if (NULL==(code->mod=(MOD *)malloc(sizeof(MOD))))
		  {
		  printf("out of room in next_use (mod\n");
		  exit(1);
		  }
		code->mod->var=strsave(var[0]);
		code->mod->next_line=next_use_list->next_line;
		code->mod->next=NULL;
		next_use_list->next_line=-1;
		}

	      /* now do use variables */
	      var[0]=NULL;
	      var[1]=NULL;
	      n=0;
	      for (i=0; strlen(use2[i])>0; i++)
		if (!strcmp(use2[i],code->flds[1])) var[n++]=code->flds[2];
	      for (i=0; strlen(use3[i])>0; i++)
		if (!strcmp(use3[i],code->flds[1])) var[n++]=code->flds[3];
	      for (i=0; strlen(use4[i])>0; i++)
		if (!strcmp(use4[i],code->flds[1])) var[n++]=code->flds[4];

	      for (i=0; i<n; i++)
		{
		if (!(var[i][0]>='0' && var[i][0]<='9'))
		  {
		  next_use_list=next_use_find(next_use_list,var[i]);
		  next_use_list->next_line=code->line;
		  if (NULL==(use=(MOD *)malloc(sizeof(MOD))))
		    {
		    printf("out of room in next_use (use)\n");
		    exit(1);
		    }
		  use->var=strsave(var[i]);
		  use->next=NULL;
		  if (code->used==NULL) code->used=use;
		  else code->used->next=use;
		  }
		}
	      if (code->last!=NULL) code=code->last;
	      else bb_num=code->basic+1;
	      }
              if (code->last==NULL) code=code->last;
	    }
	  blk->lead->last=code_end;
	  }
	blocks->last->next=blocks;
}

/* If you can't find s, add it to the list */
/* Return the pointer to the data's entry */
MOD *next_use_find(MOD *next_use_list, char *s)
{
	MOD *rv;
	MOD *pre;
	char *strsave(char *x);

	/* use move to front */
	rv=next_use_list;
	pre=NULL;
	while (rv!=NULL && strcmp(rv->var,s))
	  {
	  pre=rv;
	  rv=rv->next;
	  }
	if (rv!=NULL)
	  {
	  if (pre!=NULL)
	    {
	    pre->next=rv->next;
	    rv->next=next_use_list;
	    }
	  return(rv);
	  }

	if (NULL==(rv=(MOD *)malloc(sizeof(MOD))))
	  {
	  printf("no room in function next_use_find\n");
	  exit(1);
	  }
	rv->var=strsave(s);
	rv->next_line=-1;
	rv->next=next_use_list;
	return(rv);
}


/* FREE UP NEXT-USE MEMORY */
void clear_next_use(MOD *list)
{
	MOD *hold;

	while (list!=NULL)
	  {
	  if (list->var!=NULL) free(list->var);
	  hold=list->next;
	  free(list);
	  list=hold;
	  }
	return;
}

/* DUMP NEXT-USE INFORMATION IN A BLOCK */
void dump_next_use(BLOCK *blocks)
{
	MOD *use;
	MOD *mod;
	CODE *code;
	SYMTBL *symtbl, *parms;
	BLOCK *blk;
	int i;

	blocks->last->next=NULL;
	printf("********************\n");
	printf("** Next-use table **\n");
	printf("********************\n\n");
	printf("**stmt\tblock\tmod(next use)\tused\n");
	printf("**----\t-----\t-------------\t----\n");
	for (blk=blocks; blk!=NULL; blk=blk->next)
	  {
	  blk->lead->last->next=NULL;
	  for (code=blk->lead; code!=NULL; code=code->next)
	    {
	    printf("**%d\t%d\t", code->line, code->basic);
	    if (code->mod!=NULL)
	      printf("%s(%d)\t\t",code->mod->var,code->mod->next_line);
	    else printf("\t\t");
	    for (use=code->used; use!=NULL; use=use->next)
	      {
	      printf("%s",use->var);
	      if (use->next!=NULL) printf(", ");
	      }
	    printf("\n");
	    }
	  blk->lead->last->next=blk->lead;
	  }
	blocks->last->next=blocks;
}

