1994-06-24 11:31:16 +00:00
|
|
|
/* $Id$ */
|
1987-03-09 19:15:41 +00:00
|
|
|
/*
|
|
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
|
|
*/
|
1984-11-26 14:14:55 +00:00
|
|
|
|
|
|
|
/* I N L I N E S U B S T I T U T I O N
|
|
|
|
*
|
|
|
|
* I L _ A U X . C
|
|
|
|
*/
|
|
|
|
|
1984-11-29 11:03:19 +00:00
|
|
|
#include <stdio.h>
|
1991-03-05 12:44:05 +00:00
|
|
|
#include <em_spec.h>
|
|
|
|
#include <em_mnem.h>
|
|
|
|
#include <em_pseu.h>
|
1984-11-26 14:14:55 +00:00
|
|
|
#include "../share/types.h"
|
|
|
|
#include "il.h"
|
|
|
|
#include "../share/debug.h"
|
1984-11-29 11:03:19 +00:00
|
|
|
#include "../share/get.h"
|
|
|
|
#include "../share/put.h"
|
1984-11-26 14:14:55 +00:00
|
|
|
#include "../share/alloc.h"
|
|
|
|
#include "../share/global.h"
|
|
|
|
#include "../share/lset.h"
|
|
|
|
#include "../share/map.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);
|
|
|
|
}
|
|
|
|
}
|
1984-11-29 11:03:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
}
|