/*
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 */
#ifndef NORCSID
static char rcsid[]= "$Id$";
#endif

#include "param.h"
#include "instruct.h"
#include "pseudo.h"
#include "varinfo.h"
#include "set.h"
#include "expr.h"
#include "iocc.h"
#include <cgg_cg.h>
#include "extern.h"

extern int niops;
extern iocc_t iops[];
extern inproc;

extern set_t l_sets[];
extern inst_t l_instances[];

extern expr_t subreg_expr(),regno_expr();

struct varinfo * setcoco(n) {
	struct varinfo *vi;
	
	NEW(vi,struct varinfo);
	vi->vi_next = VI_NULL;
	vi->vi_int[0] = INSSETCC;
	vi->vi_int[1] = n;
	return(vi);
}

struct varinfo * generase(n) {
	struct varinfo *vi;

	NEW(vi,struct varinfo);
	vi->vi_next = VI_NULL;
	vi->vi_int[0] = INSERASE;
	vi->vi_int[1] = n;
	return(vi);
}

struct varinfo * genremove(n) {
	struct varinfo *vi;

	NEW(vi,struct varinfo);
	vi->vi_next = VI_NULL;
	vi->vi_int[0] = INSREMOVE;
	vi->vi_int[1] = n;
	return(vi);
}

onlyreg(argno) {
	register bitno;
	register short *sp;
	
	if (! argno) argno++;
	sp = l_sets[tokpatset[argno-1]].set_val;
	for(bitno=nregs;bitno<nregs+ntokens;bitno++)
		if (BIT(sp,bitno))
			return(0);
	return(1);
}

makescratch(argno) {
	set_t s;

	if (! argno) argno++;
	if (tokpatro[argno-1])
		error("Instruction destroys %%%d, not allowed here",argno);
	s = l_sets[tokpatset[argno-1]];
	BIC(s.set_val,0);
	tokpatset[argno-1] = setlookup(s);
}

struct varinfo *gen_inst(ident,star) char *ident; {
	register struct varinfo *vi,*retval,*eravi;
	register instr_p ip;
	register struct operand *op;
	register i;
	register inst_p insta;
	
	if (star && !inproc)
		error("Variable instruction only allowed inside proc");
	for (ip=l_instr;ip<l_instr+ninstr;ip++) {
		if(strcmp(ident,ip->i_name))
			continue;
		if (ip->i_nops!=niops)
			continue;
		for(i=0,op=ip->i_oplist;i<niops;i++,op=op->o_next) {
			if (!subset(iops[i].in_set,l_sets[op->o_setno].set_val,SETSIZE))
				goto cont;
		}
		goto found;		/* oh well, one more won't hurt */
	    cont:;
	}
	error("Such an \"%s\" does not exist",ident);
	return(0);
found:
	NEW(vi,struct varinfo);
	vi->vi_int[0] = ip-l_instr;
	vi->vi_int[1] = star;
	vi->vi_next=0;
	retval = vi;
	for(i=0;i<niops;i++) {
		NEW(vi->vi_vi,struct varinfo);
		vi=vi->vi_vi;
		vi->vi_int[0] = iops[i].in_index;
	}
	vi->vi_vi = 0;
	vi = retval;
	for(i=0,op=ip->i_oplist;i<niops;i++,op=op->o_next) {
	    if(op->o_adorn&AD_CC) {
		vi->vi_next = setcoco(iops[i].in_index);
		vi=vi->vi_next;
	    }
	    switch(op->o_adorn&AD_RWMASK) {
	    default:
		/* Nothing possible to do */
		break;
	    case AD_RO:
		/* It might be possible to do something
		 * here but not now.
		 */
		break;
	    case AD_RW:
	    case AD_WO:
		/* Treated the same for now */
		insta = &l_instances[iops[i].in_index];
		switch(insta->in_which) {
		case IN_COPY:
			if(insta->in_info[1]==0 && !onlyreg(insta->in_info[0]))
				break;
			makescratch(insta->in_info[0]);
			vi->vi_next = generase(
			               ex_lookup(
				        EX_SUBREG,insta->in_info[0],
					          insta->in_info[1]
				       )
				      );
			vi = vi->vi_next;
			break;
		case IN_MEMB:
			vi->vi_next = generase(
				       ex_lookup(
				        EX_TOKFIELD,insta->in_info[0],
					            insta->in_info[1]
				       )
				      );
			vi=vi->vi_next;
			break;
		case IN_RIDENT:
			vi->vi_next = generase(
				       ex_lookup(
				        EX_REG,insta->in_info[0],0
				       )
				      );
			vi = vi->vi_next;
			break;
		case IN_ALLOC:
			vi->vi_next = generase(
				       ex_lookup(
				        EX_ALLREG,insta->in_info[0]+1,
						  insta->in_info[1]
				       )
				      );
			vi = vi->vi_next;
			break;
		case IN_S_DESCR:
		case IN_D_DESCR:
			{ int temp;

			temp=ex_lookup(EX_REGVAR,insta->in_info[1],0);
			vi->vi_next = generase(temp);
			vi = vi->vi_next;
			vi->vi_next = genremove(temp);
			vi = vi->vi_next;
			break;
			}
		}
		break;
	    }
	}
	for (eravi=ip->i_erases;eravi != VI_NULL;eravi=eravi->vi_next) {
		if (eravi->vi_int[0] < 0)
			vi->vi_next = setcoco(0);
		else {
			vi->vi_next = generase(eravi->vi_int[0]);
			vi=vi->vi_next;
			vi->vi_next = genremove(eravi->vi_int[0]);
		}
		vi=vi->vi_next;
	}
	return(retval);
}