387 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			387 lines
		
	
	
	
		
			6.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Header$ */
 | 
						|
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
 | 
						|
/*  I N L I N E   S U B S T I T U T I O N
 | 
						|
 *
 | 
						|
 *  I L _ A U X . C
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include "../share/types.h"
 | 
						|
#include "il.h"
 | 
						|
#include "../share/debug.h"
 | 
						|
#include "../share/get.h"
 | 
						|
#include "../share/put.h"
 | 
						|
#include "../share/alloc.h"
 | 
						|
#include "../share/global.h"
 | 
						|
#include "../share/lset.h"
 | 
						|
#include "../share/map.h"
 | 
						|
#include "../../../h/em_spec.h"
 | 
						|
#include "../../../h/em_mnem.h"
 | 
						|
#include "../../../h/em_pseu.h"
 | 
						|
#include "il_aux.h"
 | 
						|
 | 
						|
 | 
						|
int tsize(type)
 | 
						|
	int type;
 | 
						|
{
 | 
						|
	/* Determine the size of a variable of the
 | 
						|
	 *  given type.
 | 
						|
	 */
 | 
						|
 | 
						|
	switch(type) {
 | 
						|
		case SINGLE:	return ws;
 | 
						|
		case DOUBLE:	return 2*ws;
 | 
						|
		case POINTER:	return ps;
 | 
						|
		default:	assert(FALSE);
 | 
						|
	}
 | 
						|
	/* NOTREACHED */
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
line_p duplicate(lnp)
 | 
						|
	line_p lnp;
 | 
						|
{
 | 
						|
	/* Make a duplicate of an EM instruction.
 | 
						|
	 * Pseudos may not be passed as argument.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p l;
 | 
						|
 | 
						|
	l = newline(TYPE(lnp));
 | 
						|
	l->l_instr = INSTR(lnp);
 | 
						|
	switch(TYPE(l)) {
 | 
						|
		case OPNO:
 | 
						|
			break;
 | 
						|
		case OPSHORT:
 | 
						|
			SHORT(l) = SHORT(lnp);
 | 
						|
			break;
 | 
						|
		case OPOFFSET:
 | 
						|
			OFFSET(l) = OFFSET(lnp);
 | 
						|
			break;
 | 
						|
		case OPINSTRLAB:
 | 
						|
			INSTRLAB(l) = INSTRLAB(lnp);
 | 
						|
			break;
 | 
						|
		case OPOBJECT:
 | 
						|
			OBJ(l) = OBJ(lnp);
 | 
						|
			break;
 | 
						|
		case OPPROC:
 | 
						|
			PROC(l) = PROC(lnp);
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			assert(FALSE); /* cannot copy pseudo */
 | 
						|
	}
 | 
						|
	return l;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
 | 
						|
line_p copy_expr(l1)
 | 
						|
	line_p l1;
 | 
						|
{
 | 
						|
	/* copy the expression */
 | 
						|
 | 
						|
	line_p head, tail, l, lnp;
 | 
						|
 | 
						|
	head = (line_p) 0;
 | 
						|
	for (lnp = l1; lnp != (line_p) 0; lnp = lnp->l_next) {
 | 
						|
		l = duplicate(lnp);
 | 
						|
		if (head == (line_p) 0) {
 | 
						|
			head = tail = l;
 | 
						|
			PREV(l) = (line_p) 0;
 | 
						|
		} else {
 | 
						|
			tail->l_next = l;
 | 
						|
			PREV(l) = tail;
 | 
						|
			tail = l;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return head;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
rem_call(c)
 | 
						|
	call_p c;
 | 
						|
{
 | 
						|
	actual_p act, nexta;
 | 
						|
	call_p   nc,nextc;
 | 
						|
	line_p   l,   nextl;
 | 
						|
 | 
						|
	for (act = c->cl_actuals; act != (actual_p) 0; act = nexta) {
 | 
						|
		nexta = act->ac_next;
 | 
						|
		for (l = act->ac_exp; l != (line_p) 0; l = nextl) {
 | 
						|
			nextl = l->l_next;
 | 
						|
			oldline(l);
 | 
						|
		}
 | 
						|
		oldactual(act);
 | 
						|
	}
 | 
						|
	nc = c->cl_car;
 | 
						|
	oldcall(c);
 | 
						|
	for (; nc != (call_p) 0; nc = nextc) {
 | 
						|
		/* Take care of nested calls */
 | 
						|
		nextc = nc->cl_cdr;
 | 
						|
		rem_call(nc);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* rem_graph */
 | 
						|
 | 
						|
STATIC short remlines(l)
 | 
						|
	line_p l;
 | 
						|
{
 | 
						|
 | 
						|
	register line_p lnp;
 | 
						|
	line_p next;
 | 
						|
 | 
						|
	for (lnp = l; lnp != (line_p) 0; lnp = next) {
 | 
						|
		next = lnp->l_next;
 | 
						|
		oldline(lnp);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
remunit(kind,p,l)
 | 
						|
	short    kind;
 | 
						|
	proc_p   p;
 | 
						|
	line_p   l;
 | 
						|
{
 | 
						|
	register bblock_p b;
 | 
						|
	bblock_p next;
 | 
						|
	Lindex   pi;
 | 
						|
 | 
						|
	if (kind == LDATA) {
 | 
						|
		remlines(l);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	for (b = p->p_start; b != (bblock_p) 0; b = next) {
 | 
						|
		next = b->b_next;
 | 
						|
		remlines(b->b_start);
 | 
						|
		Ldeleteset(b->b_loops);
 | 
						|
		Ldeleteset(b->b_succ);
 | 
						|
		Ldeleteset(b->b_pred);
 | 
						|
		oldbblock(b);
 | 
						|
	}
 | 
						|
	for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
 | 
						|
					 pi = Lnext(pi,p->p_loops)) {
 | 
						|
		oldloop(Lelem(pi));
 | 
						|
	}
 | 
						|
	Ldeleteset(p->p_loops);
 | 
						|
	oldmap(lmap,llength);
 | 
						|
	oldmap(lbmap,llength);
 | 
						|
	oldmap(bmap,blength);
 | 
						|
	oldmap(lpmap,lplength);
 | 
						|
}
 | 
						|
remcc(head)
 | 
						|
	calcnt_p head;
 | 
						|
{
 | 
						|
	calcnt_p cc, next;
 | 
						|
 | 
						|
	for (cc = head; cc != (calcnt_p) 0; cc = next) {
 | 
						|
		next = cc->cc_next;
 | 
						|
		oldcalcnt(cc);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* Extra I/O routines */
 | 
						|
 | 
						|
call_p getcall(cf)
 | 
						|
	FILE *cf;
 | 
						|
{
 | 
						|
	/* read a call from the call-file */
 | 
						|
 | 
						|
	call_p c;
 | 
						|
	proc_p voided;
 | 
						|
	actual_p act,*app;
 | 
						|
	short n,m;
 | 
						|
 | 
						|
	curinp = cf;
 | 
						|
	c = newcall();
 | 
						|
	n = getshort(); /* void nesting level */
 | 
						|
	if (feof(curinp)) return (call_p) 0;
 | 
						|
	c->cl_caller = pmap[getshort()];
 | 
						|
	c->cl_id     = getshort();
 | 
						|
	c->cl_proc   = pmap[getshort()];
 | 
						|
	c->cl_looplevel = getbyte();
 | 
						|
	c->cl_flags = getbyte();
 | 
						|
	c->cl_ratio  = getshort();
 | 
						|
	app = &c->cl_actuals;
 | 
						|
	n = getshort();
 | 
						|
	while(n--) {
 | 
						|
		act = newactual();
 | 
						|
		m = getshort();
 | 
						|
		act->ac_size = getoff();
 | 
						|
		act->ac_inl = getbyte();
 | 
						|
		act->ac_exp = getlines(cf,m,&voided);
 | 
						|
		*app = act;
 | 
						|
		app = &act->ac_next;
 | 
						|
	}
 | 
						|
	*app = (actual_p) 0;
 | 
						|
	return c;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
line_p get_text(lf,p_out)
 | 
						|
	FILE *lf;
 | 
						|
	proc_p *p_out;
 | 
						|
{
 | 
						|
	/* Read the EM text of one unit
 | 
						|
	 * If it is a procedure, set p_out to
 | 
						|
	 * the proc. just read. Else set p_out
 | 
						|
	 * to 0.
 | 
						|
	 */
 | 
						|
 | 
						|
	line_p dumhead, l, lprev;
 | 
						|
	loop_p *oldlpmap = lpmap;
 | 
						|
	line_p *oldlmap = lmap;
 | 
						|
	short oldllength = llength;
 | 
						|
	short oldlastlabid = lastlabid;
 | 
						|
 | 
						|
	curinp = lf;
 | 
						|
	*p_out = (proc_p) 0;
 | 
						|
	dumhead = newline(OPNO);
 | 
						|
	/* The list of instructions is preceeded by a dummy
 | 
						|
	 * line, to simplify list manipulation
 | 
						|
	 */
 | 
						|
	dumhead->l_instr = op_nop; /* just for fun */
 | 
						|
	lprev = dumhead;
 | 
						|
	for (;;) {
 | 
						|
		l = read_line(p_out);
 | 
						|
		if (feof(curinp)) return (line_p) 0;
 | 
						|
		lprev->l_next = l;
 | 
						|
		PREV(l) = lprev;
 | 
						|
		if (INSTR(l) == ps_end) break;
 | 
						|
		if (INSTR(l) == ps_mes) {
 | 
						|
			message(l);
 | 
						|
		}
 | 
						|
		lprev = l;
 | 
						|
	}
 | 
						|
	/* The tables that map labels to instructions
 | 
						|
	 * and labels to basic blocks are not used.
 | 
						|
	 */
 | 
						|
	if (*p_out != (proc_p) 0) {
 | 
						|
		oldmap(lmap,llength);
 | 
						|
		oldmap(lbmap,llength);
 | 
						|
		lmap = oldlmap;
 | 
						|
		lpmap = oldlpmap;
 | 
						|
	}
 | 
						|
	llength = oldllength;
 | 
						|
	lastlabid = oldlastlabid;
 | 
						|
	return dumhead;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
calcnt_p getcc(ccf,p)
 | 
						|
	FILE *ccf;
 | 
						|
	proc_p p;
 | 
						|
{
 | 
						|
	/* Get call-count info of procedure p */
 | 
						|
 | 
						|
	calcnt_p head,cc,*ccp;
 | 
						|
	short i;
 | 
						|
 | 
						|
	fseek(ccf,p->p_extend->px_il.p_ccaddr,0);
 | 
						|
	curinp = ccf;
 | 
						|
	head = (calcnt_p) 0;
 | 
						|
	ccp = &head;
 | 
						|
	for (i = getshort(); i != (short) 0; i--) {
 | 
						|
		cc = *ccp = newcalcnt();
 | 
						|
		cc->cc_proc = pmap[getshort()];
 | 
						|
		cc->cc_count = getshort();
 | 
						|
		ccp = &cc->cc_next;
 | 
						|
	}
 | 
						|
	return head;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/* The following routines are only used by the Inline Substitution phase */
 | 
						|
 | 
						|
 | 
						|
STATIC putactuals(alist,cfile)
 | 
						|
	actual_p alist;
 | 
						|
	FILE     *cfile;
 | 
						|
{
 | 
						|
	/* output a list of actual parameters */
 | 
						|
 | 
						|
	actual_p a,next;
 | 
						|
	line_p l;
 | 
						|
	int count;
 | 
						|
 | 
						|
	count = 0;
 | 
						|
	for (a = alist; a != (actual_p) 0; a = a->ac_next) count++;
 | 
						|
	outshort(count); /* number of actuals */
 | 
						|
	for (a = alist; a != (actual_p) 0; a = next) {
 | 
						|
		next = a->ac_next;
 | 
						|
		count = 0;
 | 
						|
		for (l = a->ac_exp; l != (line_p) 0; l= l->l_next) count++;
 | 
						|
		outshort(count); /* length of actual */
 | 
						|
		outoff(a->ac_size);
 | 
						|
		outbyte(a->ac_inl);
 | 
						|
		count = putlines(a->ac_exp,cfile);
 | 
						|
		oldactual(a);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
putcall(c,cfile,level)
 | 
						|
	call_p c;
 | 
						|
	FILE   *cfile;
 | 
						|
	short  level;
 | 
						|
{
 | 
						|
	/* output a call */
 | 
						|
 | 
						|
	call_p nc,nextc;
 | 
						|
 | 
						|
 | 
						|
	curoutp = cfile;
 | 
						|
	outshort(level);  /* nesting level */
 | 
						|
	outshort(c->cl_caller->p_id);	/* calling proc */
 | 
						|
	outshort(c->cl_id);
 | 
						|
	outshort(c->cl_proc->p_id);	/* called proc */
 | 
						|
	outbyte(c->cl_looplevel);
 | 
						|
	outbyte(c->cl_flags);
 | 
						|
	outshort(c->cl_ratio);
 | 
						|
	putactuals(c->cl_actuals,cfile);
 | 
						|
	nc = c->cl_car;
 | 
						|
	oldcall(c);
 | 
						|
	for (; nc != (call_p) 0; nc = nextc) {
 | 
						|
		/* take care of nested calls */
 | 
						|
		nextc = nc->cl_cdr;
 | 
						|
		putcall(nc,cfile,level+1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
long putcc(head,ccf)
 | 
						|
	calcnt_p head;
 | 
						|
	FILE     *ccf;
 | 
						|
{
 | 
						|
	/* Write call-count information to file ccf.
 | 
						|
	 * Return the disk address of the info written.
 | 
						|
	 */
 | 
						|
 | 
						|
	calcnt_p cc;
 | 
						|
	long addr;
 | 
						|
	short cnt;
 | 
						|
 | 
						|
	addr = ftell(ccf);
 | 
						|
	curoutp = ccf;
 | 
						|
	cnt = 0;
 | 
						|
	for (cc = head; cc != (calcnt_p) 0;cc = cc->cc_next) cnt++;
 | 
						|
	outshort(cnt);
 | 
						|
	for (cc = head; cc != (calcnt_p) 0; cc = cc->cc_next) {
 | 
						|
		outproc(cc->cc_proc);
 | 
						|
		outshort(cc->cc_count);
 | 
						|
	}
 | 
						|
	return addr;
 | 
						|
}
 |