Initial revision

This commit is contained in:
bal 1984-11-26 14:14:55 +00:00
parent f01e1431b0
commit 9f778655a6
21 changed files with 3081 additions and 0 deletions

133
util/ego/il/Makefile Normal file
View file

@ -0,0 +1,133 @@
EMH=../../../h
EML=../../../lib
CFLAGS=-DVERBOSE
SHARE=../share
IL=.
OBJECTS=il.o il1_anal.o il1_cal.o il1_formal.o il1_aux.o il2_aux.o \
il3_change.o il3_subst.o il3_aux.o il_aux.o
SHOBJECTS=$(SHARE)/get.o $(SHARE)/put.o $(SHARE)/alloc.o $(SHARE)/global.o $(SHARE)/debug.o $(SHARE)/files.o $(SHARE)/map.o $(SHARE)/lset.o $(SHARE)/cset.o $(SHARE)/parser.o $(SHARE)/aux.o $(SHARE)/go.o
SRC=il.h il1_anal.h il1_cal.h il1_formal.h il1_aux.h il2_aux.h il3_subst.h il3_change.h il3_aux.h il_aux.h \
il.c il1_anal.c il1_cal.c il1_formal.c il1_aux.c il2_aux.c il3_subst.c il3_change.c il3_aux.c il_aux.c
.c.o:
cc $(CFLAGS) -c $<
all: $(OBJECTS)
il: \
$(OBJECTS) $(SHOBJECTS)
cc -o il -i $(OBJECTS) $(SHOBJECTS) $(EML)/em_data.a
lpr:
pr $(SRC) | lpr
dumpflop:
tar -uf /mnt/ego/il/il.tarf $(SRC)
# the next lines are generated automatically
# AUTOAUTOAUTOAUTOAUTOAUTO
il.o: ../../../h/em_mnem.h
il.o: ../../../h/em_pseu.h
il.o: ../share/alloc.h
il.o: ../share/debug.h
il.o: ../share/files.h
il.o: ../share/get.h
il.o: ../share/global.h
il.o: ../share/lset.h
il.o: ../share/map.h
il.o: ../share/put.h
il.o: ../share/types.h
il.o: il.h
il.o: il1_anal.h
il.o: il2_aux.h
il.o: il3_subst.h
il1_anal.o: ../../../h/em_mnem.h
il1_anal.o: ../../../h/em_pseu.h
il1_anal.o: ../share/alloc.h
il1_anal.o: ../share/debug.h
il1_anal.o: ../share/global.h
il1_anal.o: ../share/lset.h
il1_anal.o: ../share/put.h
il1_anal.o: ../share/types.h
il1_anal.o: il.h
il1_anal.o: il1_anal.h
il1_anal.o: il1_aux.h
il1_anal.o: il1_cal.h
il1_anal.o: il1_formal.h
il1_anal.o: il_aux.h
il1_aux.o: ../../../h/em_spec.h
il1_aux.o: ../share/alloc.h
il1_aux.o: ../share/debug.h
il1_aux.o: ../share/global.h
il1_aux.o: ../share/lset.h
il1_aux.o: ../share/types.h
il1_aux.o: il.h
il1_aux.o: il1_aux.h
il1_aux.o: il_aux.h
il1_cal.o: ../../../h/em_mnem.h
il1_cal.o: ../../../h/em_spec.h
il1_cal.o: ../share/alloc.h
il1_cal.o: ../share/debug.h
il1_cal.o: ../share/global.h
il1_cal.o: ../share/lset.h
il1_cal.o: ../share/parser.h
il1_cal.o: ../share/types.h
il1_cal.o: il.h
il1_cal.o: il1_aux.h
il1_cal.o: il1_cal.h
il1_formal.o: ../share/alloc.h
il1_formal.o: ../share/debug.h
il1_formal.o: ../share/global.h
il1_formal.o: ../share/lset.h
il1_formal.o: ../share/types.h
il1_formal.o: il.h
il1_formal.o: il1_aux.h
il1_formal.o: il1_formal.h
il2_aux.o: ../../../h/em_mnem.h
il2_aux.o: ../../../h/em_spec.h
il2_aux.o: ../share/alloc.h
il2_aux.o: ../share/debug.h
il2_aux.o: ../share/get.h
il2_aux.o: ../share/global.h
il2_aux.o: ../share/lset.h
il2_aux.o: ../share/types.h
il2_aux.o: il.h
il2_aux.o: il2_aux.h
il2_aux.o: il_aux.h
il3_aux.o: ../share/alloc.h
il3_aux.o: ../share/debug.h
il3_aux.o: ../share/global.h
il3_aux.o: ../share/types.h
il3_aux.o: il.h
il3_aux.o: il3_aux.h
il3_aux.o: il_aux.h
il3_change.o: ../../../h/em_mes.h
il3_change.o: ../../../h/em_mnem.h
il3_change.o: ../../../h/em_pseu.h
il3_change.o: ../../../h/em_spec.h
il3_change.o: ../share/alloc.h
il3_change.o: ../share/debug.h
il3_change.o: ../share/def.h
il3_change.o: ../share/get.h
il3_change.o: ../share/global.h
il3_change.o: ../share/lset.h
il3_change.o: ../share/put.h
il3_change.o: ../share/types.h
il3_change.o: il.h
il3_change.o: il3_aux.h
il3_change.o: il3_change.h
il3_change.o: il_aux.h
il3_subst.o: ../../../h/em_mnem.h
il3_subst.o: ../share/alloc.h
il3_subst.o: ../share/debug.h
il3_subst.o: ../share/get.h
il3_subst.o: ../share/global.h
il3_subst.o: ../share/lset.h
il3_subst.o: ../share/types.h
il3_subst.o: il.h
il3_subst.o: il3_aux.h
il3_subst.o: il3_change.h
il3_subst.o: il3_subst.h
il_aux.o: ../../../h/em_spec.h
il_aux.o: ../share/alloc.h
il_aux.o: ../share/debug.h
il_aux.o: ../share/global.h
il_aux.o: ../share/lset.h
il_aux.o: ../share/map.h
il_aux.o: ../share/types.h
il_aux.o: il.h
il_aux.o: il_aux.h

312
util/ego/il/il.c Normal file
View file

@ -0,0 +1,312 @@
/* I N L I N E S U B S T I T U T I O N */
#include <stdio.h>
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/files.h"
#include "../../../h/em_mnem.h"
#include "../../../h/em_pseu.h"
#include "../share/map.h"
#include "il1_anal.h"
#include "il2_aux.h"
#include "il3_subst.h"
#include "../share/get.h"
#include "../share/put.h"
#include "../share/go.h"
int calnr;
calcnt_p cchead; /* call-count info of current proc */
STATIC short space = 0;
STATIC char cname[] = "/usr/tmp/ego.i1.XXXXXX";
STATIC char ccname[] = "/usr/tmp/ego.i2.XXXXXX";
/* For debugging only */
STATIC char sname[] = "/usr/tmp/ego.i3.XXXXXX";
int Ssubst;
#ifdef VERBOSE
int Senv,Srecursive,Slocals,Sinstrlab,Sparsefails,Spremoved,Scals;
int Sbig_caller,Sdispensable,Schangedcallee,Sbigcallee,Sspace,Szeroratio;
#endif
/* P A S S 1
*
* Pass 1 reads and analyses the EM text and the CFG.
* It determines for every procedure if it may be expanded
* in line and how it uses its formal parameters.
* It also collects all calls appearing in the program and
* recognizes the actual parameters of every call.
* The call descriptors are put in a file (calfile).
*/
pass1(lnam,bnam,cnam)
char *lnam, *bnam, *cnam;
{
FILE *f, *gf, *cf, *ccf; /* The EM input, the basic block graph,
* the call-list file and the calcnt file.
*/
long laddr;
bblock_p g;
short kind;
line_p l;
f = openfile(lnam,"r");
gf = openfile(bnam,"r");
cf = openfile(cnam,"w");
ccf = openfile(ccname,"w");
mesregs = Lempty_set();
apriori(fproc);
/* use information from the procedure table to
* see which calls certainly cannot be expanded.
*/
while(TRUE) {
laddr = ftell(f);
if (!getunit(gf,f,&kind,&g,&l,&curproc,TRUE)) break;
/* Read the control flow graph and EM text of
* one procedure and analyze it.
*/
if (kind == LDATA) {
remunit(LDATA,(proc_p) 0,l);
continue;
}
/* OUTTRACE("flow graph of proc %d read",curproc->p_id); */
assert(INSTR(g->b_start) == ps_pro);
curproc->p_start = g;
curproc->P_LADDR = laddr;
/* address of em text in em-file */
/* address of graph in basic block file */
curproc->P_SIZE = proclength(curproc); /* #instructions */
if (BIG_PROC(curproc)) {
/* curproc is too large to be expanded in line */
UNSUITABLE(curproc);
}
calnr = 0;
anal_proc(curproc,cf,ccf);
/* OUTTRACE("proc %d processed",curproc->p_id); */
remunit(LTEXT,curproc,(line_p) 0);
/* remove control flow graph + text */
/* OUTTRACE("graph of proc %d removed",curproc->p_id); */
Ldeleteset(mesregs);
mesregs = Lempty_set();
}
fclose(f);
fclose(gf);
fclose(cf);
fclose(ccf);
}
/* P A S S 2
*
* Pass 2 reads the calfile and determines which calls should
* be expanded in line. It does not use the EM text.
*/
STATIC char cname2[] = "/usr/tmp/ego.i4.XXXXXX";
pass2(cnam,space)
char *cnam;
short space;
{
FILE *cf, *cf2, *ccf;
call_p c,a;
cf = openfile(cnam,"r");
cf2 = openfile(cname2,"w");
ccf = openfile(ccname,"r");
while ((c = getcall(cf)) != (call_p) 0) {
/* process all calls */
if (SUITABLE(c->cl_proc)) {
/* called proc. may be put in line */
anal_params(c);
/* see which parameters may be put in line */
assign_ratio(c); /* assign a rank */
a = abstract(c); /* abstract essential info */
append_abstract(a,a->cl_caller);
/* put it in call-list of calling proc. */
putcall(c,cf2,(short) 0);
} else {
rem_call(c);
}
}
select_calls(fproc,ccf,space);
fclose(cf); unlink(cnam);
fclose(cf2);
fclose(ccf); unlink(ccname);
cf2 = openfile(cname2,"r");
add_actuals(fproc,cf2);
cleancals(fproc); /* remove calls that were not selected */
/* add actual parameters to each selected call */
fclose(cf2); unlink(cname2);
}
/* P A S S 3
*
* pass 3 reads the substitution file and performs all
* substitutions described in that file. It reads the
* original EM text and produced a new (optimized)
* EM textfile.
*/
pass3(lnam,lnam2)
char *lnam,*lnam2;
{
bool verbose = TRUE;
FILE *lfile, *lfilerand, *lfile2, *sfile;
call_p c,next;
line_p l,startscan,cal;
short lastcid; /* last call-id seen */
lfile = openfile(lnam, "r");
lfilerand = openfile(lnam, "r");
lfile2 = openfile(lnam2,"w");
if (verbose) {
sfile = openfile(sname,"w");
}
mesregs = Lempty_set();
while ((l = get_text(lfile,&curproc)) != (line_p) 0) {
if (curproc == (proc_p) 0) {
/* Just a data-unit; no real instructions */
putlines(l->l_next,lfile2);
oldline(l);
continue;
}
if (IS_DISPENSABLE(curproc)) {
liquidate(curproc,l->l_next);
} else {
startscan = l->l_next;
lastcid = 0;
for (c = curproc->P_CALS; c != (call_p) 0; c = next) {
next = c->cl_cdr;
cal = scan_to_cal(startscan,c->cl_id - lastcid);
assert (cal != (line_p) 0);
startscan = scan_to_cal(cal->l_next,1);
/* next CAL */
lastcid = c->cl_id;
/* next CAL after current one */
substitute(lfilerand,c,cal,l->l_next);
if (verbose) {
putcall(c,sfile,0);
} else {
rem_call(c);
}
}
}
putlines(l->l_next,lfile2);
Ldeleteset(mesregs);
mesregs = Lempty_set();
oldline(l);
}
fclose(lfile);
fclose(lfile2);
if (verbose) {
fclose(sfile);
unlink(sname);
}
}
STATIC il_extptab(ptab)
proc_p ptab;
{
/* Allocate space for extension of proctable entries.
* Also, initialise some of the fields just allocated.
*/
register proc_p p;
for (p = ptab; p != (proc_p) 0; p = p->p_next) {
p->p_extend = newilpx();
p->P_ORGLABELS = p->p_nrlabels;
p->P_ORGLOCALS = p->p_localbytes;
}
}
STATIC il_cleanptab(ptab)
proc_p ptab;
{
/* De-allocate space for extensions */
register proc_p p;
for (p = ptab; p != (proc_p) 0; p = p->p_next) {
oldilpx(p->p_extend);
}
}
#ifdef VERBOSE
Sdiagnostics()
{
/* print statictical information */
fprintf(stderr,"STATISTICS:\n");
fprintf(stderr,"Info about procedures:\n");
fprintf(stderr,"environment accessed: %d\n",Senv);
fprintf(stderr,"recursive: %d\n",Srecursive);
fprintf(stderr,"too many locals: %d\n",Slocals);
fprintf(stderr,"instr. lab in data block: %d\n",Sinstrlab);
fprintf(stderr,"procedures removed: %d\n",Spremoved);
fprintf(stderr,"\nInfo about calls:\n");
fprintf(stderr,"total number of calls: %d\n",Scals);
fprintf(stderr,"total number of calls substituted: %d\n",Ssubst);
fprintf(stderr,"parser failed: %d\n",Sparsefails);
fprintf(stderr,"caller too big: %d\n",Sbig_caller);
fprintf(stderr,"caller dispensable: %d\n",Sdispensable);
fprintf(stderr,"callee is changed: %d\n",Schangedcallee);
fprintf(stderr,"callee too big: %d\n",Sbigcallee);
fprintf(stderr,"no space available: %d\n",Sspace);
fprintf(stderr,"zero ratio: %d\n",Szeroratio);
}
#endif
il_flags(p)
char *p;
{
if (*p++ == 's') {
while (*p != '\0') {
space = 10*space +*p++ -'0';
}
}
}
main(argc,argv)
int argc;
char *argv[];
{
FILE *f;
go(argc,argv,no_action,no_action,no_action,il_flags);
il_extptab(fproc); /* add extended data structures */
mktemp(cname);
mktemp(ccname);
mktemp(sname);
mktemp(cname2);
pass1(lname,bname,cname); /* grep calls, analyse procedures */
pass2(cname,space); /* select calls to be expanded */
pass3(lname,lname2); /* do substitutions */
f = openfile(dname2,"w");
il_cleanptab(fproc); /* remove extended data structures */
putdtable(fdblock,f);
f = openfile(pname2,"w");
putptable(fproc,f,FALSE);
report("inline substitutions",Ssubst);
#ifdef VERBOSE
if (verbose_flag) {
Sdiagnostics();
}
#endif
#ifdef DEBUG
core_usage();
#endif
exit(0);
}

69
util/ego/il/il.h Normal file
View file

@ -0,0 +1,69 @@
/* I N T E R N A L D A T A S T R U C T U R E S O F
*
* I N L I N E S U B S T I T U T I O N
*
*/
extern int calnr;
extern calcnt_p cchead; /* calcnt info of current proc */
/* Macro's for extended data structures */
#define P_CALS p_extend->px_il.p_cals
#define P_SIZE p_extend->px_il.p_size
#define P_FORMALS p_extend->px_il.p_formals
#define P_NRCALLED p_extend->px_il.p_nrcalled
#define P_CCADDR p_extend->px_il.p_ccaddr
#define P_LADDR p_extend->px_il.p_laddr
#define P_ORGLABELS p_extend->px_il.p_orglabels
#define P_ORGLOCALS p_extend->px_il.p_orglocals
/* flags2: */
#define PF_UNSUITABLE 01
#define PF_NO_INLPARS 02
#define PF_FALLTHROUGH 04
#define PF_DISPENSABLE 010
#define PF_CHANGED 020
/* kinds of usages: */
#define USE 0
#define CHANGE 1
#define ADDRESS 2
/* We do not expand calls if:
* - the called procedure has to many local variables
* - the calling procedure is already very large
* - the called procedure is to large.
*/
#define MANY_LOCALS(p) (p->p_localbytes > LOCAL_THRESHOLD)
#define LOCAL_THRESHOLD 200
#define BIG_CALLER(p) (p->P_SIZE > CALLER_THRESHOLD)
#define CALLER_THRESHOLD 500
#define BIG_PROC(p) (p->P_SIZE > CALLEE_THRESHOLD)
#define CALLEE_THRESHOLD 100
#define FALLTHROUGH(p) (p->p_flags2 & PF_FALLTHROUGH)
#define DISPENSABLE(p) p->p_flags2 |= PF_DISPENSABLE
#define IS_DISPENSABLE(p) (p->p_flags2 & PF_DISPENSABLE)
#define SELECTED(c) c->cl_flags |= CLF_SELECTED
#define IS_SELECTED(c) (c->cl_flags & CLF_SELECTED)
#define EVER_EXPANDED(c) c->cl_flags |= CLF_EVER_EXPANDED
#define IS_EVER_EXPANDED(c) (c->cl_flags & CLF_EVER_EXPANDED)
#define UNSUITABLE(p) p->p_flags2 |= PF_UNSUITABLE
#define SUITABLE(p) (!(p->p_flags2&PF_UNSUITABLE))
#define INLINE_PARS(p) (!(p->p_flags2&PF_NO_INLPARS))
#define PARAMS_UNKNOWN(p) (p->p_nrformals == UNKNOWN_SIZE)
extern int Ssubst;
#ifdef VERBOSE
extern int Senv,Srecursive,Slocals,Sinstrlab,Sparsefails,Spremoved,Scals;
extern int Sbig_caller,Sdispensable,Schangedcallee,Sbigcallee,Sspace,Szeroratio;
#endif

177
util/ego/il/il1_anal.c Normal file
View file

@ -0,0 +1,177 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ A N A L . C
*/
#include <stdio.h>
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/aux.h"
#include "../../../h/em_mnem.h"
#include "../../../h/em_pseu.h"
#include "il1_aux.h"
#include "il1_formal.h"
#include "il1_cal.h"
#include "il1_anal.h"
#include "il_aux.h"
#include "../share/put.h"
#define BODY_KNOWN(p) (p->p_flags1 & (byte) PF_BODYSEEN)
#define ENVIRON(p) (p->p_flags1 & (byte) PF_ENVIRON)
#define RETURN_BLOCK(b) (Lnrelems(b->b_succ) == 0)
#define LAST_BLOCK(b) (b->b_next == (bblock_p) 0)
/* Daisy chain recursion not yet accounted for: */
#define RECURSIVE(p) (Cis_elem(p->p_id,p->p_calling))
/*
#define CALLS_UNKNOWN(p) (p->p_flags1 & (byte) PF_CALUNKNOWN)
*/
#define CALLS_UNKNOWN(p) (FALSE)
apriori(proctab)
proc_p proctab;
{
/* For every procedure, see if we can determine
* from the information provided by the previous
* phases of the optimizer that it cannot or should not
* be expanded in line. This will reduce the length
* of the call list.
*/
register proc_p p;
for (p = proctab; p != (proc_p) 0; p = p->p_next) {
if (!BODY_KNOWN(p) ||
ENVIRON(p) || RECURSIVE(p) ||
PARAMS_UNKNOWN(p) || MANY_LOCALS(p)) {
UNSUITABLE(p);
#ifdef VERBOSE
if (BODY_KNOWN(p)) {
if (ENVIRON(p)) Senv++;
if (RECURSIVE(p)) Srecursive++;
if (MANY_LOCALS(p)) Slocals++;
}
#endif
}
}
}
STATIC check_labels(p,arglist)
proc_p p;
arg_p arglist;
{
/* Check if any of the arguments contains an instruction
* label; if so, make p unsuitable.
*/
arg_p arg;
for (arg = arglist; arg != (arg_p) 0; arg = arg->a_next) {
if (arg->a_type == ARGINSTRLAB) {
UNSUITABLE(p);
#ifdef VERBOSE
Sinstrlab++;
#endif
break;
}
}
}
STATIC anal_instr(p,b,cf)
proc_p p;
bblock_p b;
FILE *cf;
{
/* Analyze the instructions of block b
* within procedure p.
* See which parameters are used, changed
* or have their address taken. Recognize
* the actual parameter expressions of
* the CAL instructions.
*/
register line_p l;
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
switch(INSTR(l)) {
case op_cal:
anal_cal(p,l,b,cf);
break;
case op_stl:
case op_inl:
case op_del:
case op_zrl:
formal(p,b,off_set(l),SINGLE,CHANGE);
/* see if the local is a parameter.
* If so, it is a one-word parameter
* that is stored into.
*/
break;
case op_sdl:
formal(p,b,off_set(l),DOUBLE,CHANGE);
break;
case op_lol:
formal(p,b,off_set(l),SINGLE,USE);
break;
case op_ldl:
formal(p,b,off_set(l),DOUBLE,USE);
break;
case op_sil:
case op_lil:
formal(p,b,off_set(l),POINTER,USE);
break;
case op_lal:
formal(p,b,off_set(l),UNKNOWN,ADDRESS);
break;
case ps_rom:
case ps_con:
case ps_bss:
case ps_hol:
check_labels(p,ARG(l));
break;
}
}
}
anal_proc(p,cf,ccf)
proc_p p;
FILE *cf,*ccf;
{
/* Analyze a procedure; use information
* stored in its basic blocks or in
* its instructions.
*/
register bblock_p b;
bool fallthrough = TRUE;
cchead = (calcnt_p) 0;
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
if (RETURN_BLOCK(b) && !LAST_BLOCK(b)) {
fallthrough = FALSE;
/* p contains a RET instruction somewhere
* in the middle of its code.
*/
}
anal_instr(p,b,cf); /* analyze instructions */
}
if (fallthrough) {
p->p_flags2 |= PF_FALLTHROUGH;
}
rem_indir_acc(p);
/* don't expand formal that may be accessed indirectly */
p->P_CCADDR = putcc(cchead,ccf);
/* write calcnt info and remember disk address */
remcc(cchead);
}

17
util/ego/il/il1_anal.h Normal file
View file

@ -0,0 +1,17 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ A N A L . H
*/
extern apriori(); /* (proc_p proctab)
* For every procedure, see if we can determine
* from the information provided by the previous
* phases of the optimizer that it cannot or should not
* be expanded in line. This will reduce the length
* of the call list.
*/
extern anal_proc(); /* (proc_p p, FILE *cf, *cff)
* Analyse a procedure. See which formal parameters
* it uses and which procedures it calls.
* cf and ccf are the call-file and the call-count file.
*/

208
util/ego/il/il1_aux.c Normal file
View file

@ -0,0 +1,208 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ A U X . C
*/
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../../../h/em_spec.h"
#include "il_aux.h"
#include "il1_aux.h"
#define CHANGE_INDIR(p) (p->p_change->c_flags & CF_INDIR)
#define USE_INDIR(p) (p->p_use->u_flags & UF_INDIR)
#define IS_INSTR(c) (c >= sp_fmnem && c <= sp_lmnem)
bool same_size(t1,t2)
int t1, t2;
{
/* See if the two types have the same size */
return tsize(t1) == tsize(t2);
}
STATIC bool is_reg(off,s)
offset off;
int s;
{
/* See if there is a register message
* for the local or parameter at offset off
* and size s.
*/
Lindex i;
arg_p arg;
for (i = Lfirst(mesregs); i != (Lindex) 0; i = Lnext(i,mesregs)) {
arg = ((line_p) Lelem(i))->l_a.la_arg->a_next;
if (arg->a_a.a_offset == off &&
arg->a_next->a_a.a_offset == s) {
return TRUE;
}
}
return FALSE;
}
rem_actuals(acts)
actual_p acts;
{
/* remove the actual-list */
actual_p a,next;
for (a = acts; a != (actual_p) 0; a = next) {
next = a->ac_next;
/* REMOVE CODE OF a->ac_exp HERE */
oldactual(a);
}
}
remov_formals(p)
proc_p p;
{
/* Remove the list of formals of p */
formal_p f, next;
for (f = p->P_FORMALS; f != (formal_p) 0; f = next) {
next = f->f_next;
oldformal(f);
}
p->P_FORMALS = (formal_p) 0;
}
rem_indir_acc(p)
proc_p p;
{
/* Formals that may be accessed indirectly
* cannot be expanded in line, so they are
* removed from the formals list.
*/
formal_p prev, f, next;
if (!USE_INDIR(p) && !CHANGE_INDIR(p)) return;
/* Any formal for which we don't have
* a register message is now doomed.
*/
prev = (formal_p) 0;
for (f = p->P_FORMALS; f != (formal_p) 0; f = next) {
next = f->f_next;
if (!is_reg(f->f_offset,tsize(f->f_type))) {
if (prev == (formal_p) 0) {
p->P_FORMALS = next;
} else {
prev->f_next = next;
}
oldformal(f);
}
}
}
bool par_overlap(off1,t1,off2,t2)
offset off1,off2;
int t1,t2;
{
/* See if the parameter at offset off1 and type t1
* overlaps the paramete at offset off2 and type t2.
*/
if (off1 > off2) {
return off2 + tsize(t2) > off1;
} else {
if (off2 > off1) {
return off1 + tsize(t1) > off2;
} else {
return TRUE;
}
}
}
short looplevel(b)
bblock_p b;
{
/* determine the loop nesting level of basic block b;
* this is the highest nesting level of all blocks
* that b is part of.
* Note that the level of a loop is 0 for outer loops,
* so a block inside a loop with nesting level N has
* looplevel N+1.
*/
Lindex i;
short max = 0;
for (i = Lfirst(b->b_loops); i != (Lindex)0; i = Lnext(i,b->b_loops)) {
if (((loop_p) Lelem(i))->lp_level >= max) {
max = ((loop_p) Lelem(i))->lp_level + 1;
}
}
return max;
}
short proclength(p)
proc_p p;
{
/* count the number of EM instructions of p */
register short cnt;
register bblock_p b;
register line_p l;
cnt = 0;
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
for (l = b->b_start; l != (line_p) 0; l = l->l_next) {
if (IS_INSTR(INSTR(l))) {
/* skip pseudo instructions */
cnt++;
}
}
}
return cnt;
}
line_p copy_code(l1,l2)
line_p l1,l2;
{
/* copy the code between l1 and l2 */
line_p head, tail, l, lnp;
head = (line_p) 0;
for (lnp = l1; ; 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;
}
if (lnp == l2) break;
}
return head;
}

38
util/ego/il/il1_aux.h Normal file
View file

@ -0,0 +1,38 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ A U X . H
*/
extern bool same_size(); /* (int t1,t2)
* See if the two types t1 and t2 have
* the same size.
*/
extern rem_actuals(); /* (actual_p atcs)
* remove an actual-list from core.
*/
extern remov_formals(); /* (proc_p p)
* Remove the formals-list of p from core.
*/
extern rem_indir_acc(); /* (proc_p p)
* Remove formal that may be accessed
* indirectly from formal lists of p
*/
extern bool par_overlap(); /* (offset off1, int t1, offset off2, int t2)
* See if the formal at offset off1 and type t1
* overlaps the formal at offset off2
* and type t2.
*/
extern short looplevel(); /* (bblock_p b)
* Determine the loop nesting level of b.
*/
extern short proclength(); /* (proc_p p)
* Determine the number of EM instructions
* in p. Do not count pseudos.
*/
extern line_p copy_code(); /* (line_p l1,l2)
* copy the code between l1 and l2.
* Pseudos may not be contained in
* the list of instructions. If l1==l2
* the result is only one instruction.
*/

138
util/ego/il/il1_cal.c Normal file
View file

@ -0,0 +1,138 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ C A L . C
*/
#include <stdio.h>
#include "../share/types.h"
#include "il.h"
#include "il1_cal.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../../../h/em_spec.h"
#include "../../../h/em_mnem.h"
#include "il1_aux.h"
#include "../share/parser.h"
STATIC actual_p acts, *app;
#define INIT_ACTS() {acts = (actual_p) 0; app = &acts;}
#define APPEND_ACTUAL(a) {*app = a; app = &a->ac_next;}
STATIC make_actual(l1,l2,size)
line_p l1,l2;
offset size;
{
/* Allocate a struct for a new actual parameter
* expression, the code of which extends from
* l1 to l2.
*/
actual_p a;
a = newactual();
a->ac_exp = copy_code(l1,l2);
a->ac_size = size;
APPEND_ACTUAL(a); /* append it to actual-list */
}
STATIC bool chck_asp(p,l)
proc_p p;
line_p l;
{
/* We require a call to a procedure p that has n formal
* parameters to be followed by an 'asp n' instruction
* (i.e. the caller should remove the actual parameters).
*/
return (p->p_nrformals == 0 || (l != (line_p) 0 &&INSTR(l) == op_asp &&
TYPE(l) == OPSHORT && SHORT(l) == p->p_nrformals));
}
STATIC inc_count(caller,callee)
proc_p caller, callee;
{
/* Update the call-count information.
* Record the fact that there is one more call
* to 'callee', appearing in 'caller'.
*/
calcnt_p cc;
if (!SUITABLE(caller)) return;
/* if the calling routine is never expanded in line
* we do not need call-count information.
*/
for (cc = cchead; cc != (calcnt_p) 0; cc = cc->cc_next) {
if (cc->cc_proc == callee) {
cc->cc_count++;
/* #calls to callee from caller */
return;
}
}
/* This is the first call from caller to callee.
* Allocate a new calcnt struct.
*/
cc = newcalcnt();
cc->cc_proc = callee;
cc->cc_count = 1;
cc->cc_next = cchead; /* insert it at front of list */
cchead = cc;
}
anal_cal(p,call,b,cf)
proc_p p;
line_p call;
bblock_p b;
FILE *cf;
{
/* Analyze a call instruction. If the called
* routine may be expanded in line, try to
* recognize the actual parameter expressions of
* the call and extend the call list.
*/
call_p c;
line_p lnp;
proc_p callee;
#ifdef VERBOSE
Scals++;
#endif
calnr++;
callee = PROC(call);
if (SUITABLE(callee)) {
/* The called procedure may be expanded */
callee->P_NRCALLED++; /* #calls to callee from anywhere */
INIT_ACTS();
if (parse(PREV(call),callee->p_nrformals,&lnp,0,make_actual) &&
chck_asp(callee,call->l_next)) {
/* succeeded in recognizing the actuals */
c = newcall();
c->cl_caller = p;
c->cl_id = calnr;
c->cl_proc = callee;
c->cl_looplevel = (byte) looplevel(b);
if (c->cl_looplevel > 0 && IS_FIRM(b)) {
c->cl_flags |= CLF_FIRM;
}
c->cl_actuals = acts;
inc_count(p,callee);
/* update call-count info */
putcall(c,cf,(short) 0); /* write the call to the calfile */
} else {
#ifdef VERBOSE
Sparsefails++;
#endif
rem_actuals(acts);
}
}
}

31
util/ego/il/il1_cal.h Normal file
View file

@ -0,0 +1,31 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ C A L . C
*/
struct class {
byte src_class;
byte res_class;
};
typedef struct class *class_p;
extern struct class classtab[];
#define NOCLASS 0
#define CLASS1 1
#define CLASS2 2
#define CLASS3 3
#define CLASS4 4
#define CLASS5 5
#define CLASS6 6
#define CLASS7 7
#define CLASS8 8
#define CLASS9 9
extern anal_cal(); /* (line_p call, bblock_p b)
* analyze a call instruction;
* try to recognize the actual parameter
* expressions.
*/

141
util/ego/il/il1_formal.c Normal file
View file

@ -0,0 +1,141 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ F O R M A L . C
*/
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "il1_aux.h"
#include "il1_formal.h"
#define NOT_USED(f) (!(f->f_flags & USEMASK))
#define USED_ONCE(f) f->f_flags |= FF_ONCEUSED
#define USED_OFTEN(f) f->f_flags |= FF_OFTENUSED
#define BADFORMAL(f) f->f_flags |= FF_BAD
#define OUTSIDE_LOOP(b) (Lnrelems(b->b_loops) == 0)
#define IS_FORMAL(x) (x >= 0)
formal_p find_formal(p,type,off)
proc_p p;
int type;
offset off;
{
/* Find a formal parameter of p
* If the formal overlaps with an existing formal
* or has an unknown type (i.e. its address is used)
* 0 is returned.
*/
formal_p f,prev,nf;
if (type == UNKNOWN) return (formal_p) 0;
prev = (formal_p) 0;
for (f = p->P_FORMALS; f != (formal_p) 0; f = f->f_next) {
if (f->f_offset >= off) break;
prev = f;
}
if (f != (formal_p) 0 && f->f_offset == off) {
return (same_size(f->f_type,type) ? f : (formal_p) 0);
}
if (f != (formal_p) 0 && par_overlap(off,type,f->f_offset,f->f_type)) {
return (formal_p) 0;
}
if (prev != (formal_p) 0 && par_overlap(prev->f_offset,prev->f_type,
off,type)) {
return (formal_p) 0;
}
nf = newformal();
nf->f_type = type;
nf->f_offset = off;
if (prev == (formal_p) 0) {
p->P_FORMALS = nf;
} else {
prev->f_next = nf;
}
nf->f_next = f;
return nf;
}
STATIC no_inl_pars(p)
proc_p p;
{
/* p may not have any in line parameters */
p->p_flags2 |= PF_NO_INLPARS;
remov_formals(p);
}
STATIC inc_use(f,b)
formal_p f;
bblock_p b;
{
/* Increment the use count of formal f.
* The counter has only three states: not used,
* used once, used more than once.
* We count the number of times the formal
* is used dynamically (rather than statically),
* so if it is used in a loop, the counter
* is always set to more than once.
*/
if (NOT_USED(f) && OUTSIDE_LOOP(b)) {
USED_ONCE(f);
} else {
USED_OFTEN(f);
}
}
formal(p,b,off,type,usage)
proc_p p;
bblock_p b;
offset off;
int type,
usage;
{
/* Analyze a reference to a parameter of p
* (occurring within basic block b).
* The parameter has offset off. If this
* offset is less than 0, it is not a
* parameter, but a local.
* The type can be SINGLE (1 word), DOUBLE
* (2 words), POINTER or UNKNOWN.
*/
formal_p f;
if (!IS_FORMAL(off) || !SUITABLE(p) || !INLINE_PARS(p)) return;
/* We are not interested in formal parameters of
* proccedures that will never be expanded in line,
* or whose parameters will not be expanded in line.
*/
f = find_formal(p,type,off);
/* Find the formal; if not found, create one;
* if inconsistent with previous formals (e.g.
* overlapping formals) then return 0;
* also fills in its type.
*/
if (f == (formal_p) 0) {
no_inl_pars(p);
/* parameters of p may not be expanded in line */
} else {
if (usage == CHANGE) {
/* don't expand f in line */
BADFORMAL(f);
} else {
inc_use(f,b); /* increment use count */
}
}
}

11
util/ego/il/il1_formal.h Normal file
View file

@ -0,0 +1,11 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 1 _ F O R M A L . C
*/
extern formal(); /* (proc_p p; bblock_p b; offset off;
* int type, usage)
* Analyze a reference to a parameter of p.
* The type denotes its size (single,double,
* pointer).
*/

718
util/ego/il/il2_aux.c Normal file
View file

@ -0,0 +1,718 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 2 _ A U X . C
*/
#include <stdio.h>
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../../../h/em_spec.h"
#include "../../../h/em_mnem.h"
#include "il_aux.h"
#include "il2_aux.h"
#include "../share/get.h"
#include "../share/aux.h"
#define CHANGE_INDIR(p) (p->p_change->c_flags & CF_INDIR)
#define USE_INDIR(p) (p->p_use->u_flags & UF_INDIR)
#define OFTEN_USED(f) ((f->f_flags&FF_OFTENUSED) == FF_OFTENUSED)
#define CHANGE_EXT(p) (Cnrelems(p->p_change->c_ext) > 0)
#define NOT_INLINE(a) (a->ac_inl = FALSE)
#define INLINE(a) (a->ac_inl = TRUE)
#define CHANGED(p) p->p_flags2 |= PF_CHANGED
#define IS_CHANGED(p) (p->p_flags2 & PF_CHANGED)
STATIC bool match_pars(fm,act)
formal_p fm;
actual_p act;
{
/* Check if every actual parameter has the same
* size as its corresponding formal. If not, the
* actual parameters should not be expanded in line.
*/
while (act != (actual_p) 0) {
if (fm == (formal_p) 0 || tsize(fm->f_type) != act->ac_size) {
return FALSE;
}
act = act->ac_next;
fm = fm->f_next;
}
return (fm == (formal_p) 0 ? TRUE : FALSE);
}
STATIC bool change_act(p,act)
proc_p p;
actual_p act;
{
/* See if a call to p migth change any of the
* operands of the actual parameter expression.
* If the parameter is to be expanded in line,
* we must be sure its value does not depend
* on the point in the program where it is
* evaluated.
*/
line_p l;
for (l = act->ac_exp; l != (line_p) 0; l = l->l_next) {
switch(INSTR(l)) {
case op_lil:
case op_lof:
case op_loi:
case op_los:
case op_ldf:
return TRUE;
/* assume worst case */
case op_lol:
case op_ldl:
if (CHANGE_INDIR(p)) {
return TRUE;
}
break;
case op_loe:
case op_lde:
if (CHANGE_INDIR(p) || CHANGE_EXT(p)) {
return TRUE;
}
break;
}
}
return FALSE;
}
STATIC bool is_simple(expr)
line_p expr;
{
/* See if expr is something simple, i.e. a constant or
* a variable. So the expression must consist of
* only one instruction.
*/
if (expr->l_next == (line_p) 0) {
switch(INSTR(expr)) {
case op_loc:
case op_ldc:
case op_lol:
case op_ldl:
case op_loe:
case op_lde:
return TRUE;
}
}
return FALSE;
}
STATIC bool too_expensive(fm,act)
formal_p fm;
actual_p act;
{
/* If the formal parameter is used often and the
* actual parameter is not something simple
* (i.e. an expression, not a constant or variable)
* it may be too expensive too expand the parameter
* in line.
*/
return (OFTEN_USED(fm) && !is_simple(act->ac_exp));
}
anal_params(c)
call_p c;
{
/* Determine which of the actual parameters of a
* call may be expanded in line.
*/
proc_p p;
actual_p act;
formal_p form;
int inlpars = 0;
p = c->cl_proc; /* the called procedure */
if (!INLINE_PARS(p) || !match_pars(p->P_FORMALS, c->cl_actuals)) {
for (act = c->cl_actuals; act != (actual_p) 0;
act = act->ac_next) {
NOT_INLINE(act);
}
return; /* "# of inline pars." field in cl_flags remains 0 */
}
for (act = c->cl_actuals, form = p->P_FORMALS; act != (actual_p) 0;
act = act->ac_next, form = form->f_next) {
if (form->f_flags & FF_BAD ||
change_act(p,act) || too_expensive(form,act)) {
NOT_INLINE(act);
} else {
INLINE(act);
inlpars++;
}
}
if (inlpars > 15) inlpars = 15; /* We've only got 4 bits! */
c->cl_flags |= inlpars; /* number of inline parameters */
}
STATIC short space_saved(c)
call_p c;
{
/* When a call gets expanded in line, the total size of the
* code usually gets incremented, because we have to
* duplicate the text of the called routine. However, we save
* ourselves a CAL instruction and possibly anASP instruction
* (if the called procedure has parameters). Moreover, if we
* can put some parameters in line, we don't have to push
* their results on the stack before doing the call, so we
* save some code here too. The routine estimates the amount of
* code saved, expressed in number of EM instructions.
*/
return (1 + (c->cl_flags & CLF_INLPARS) + (c->cl_proc->p_nrformals>0));
}
STATIC short param_score(c)
call_p c;
{
/* If a call has an inline parameter that is a constant,
* chances are high that other optimization techniques
* can do further optimizations, especially if the constant
* happens to be "0". So the call gets extra points for this.
*/
register actual_p act;
line_p l;
short score = 0;
for (act = c->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
if (act->ac_inl) {
l = act->ac_exp;
if (l->l_next == (line_p) 0 &&
(INSTR(l) == op_loc || INSTR(l) == op_ldc)) {
score += (off_set(l) == (offset) 0 ? 2 : 1);
/* 0's count for two! */
}
}
}
return score;
}
assign_ratio(c)
call_p c;
{
/* This routine is one of the most important ones
* of the inline substitution phase. It assigns a number
* (a 'ratio') to a call, indicating how desirable
* it is to expand the call in line.
* Currently, a very simplified straightforward heuristic
* is used.
*/
short ll, loopfact, ratio;
ll = c->cl_proc->P_SIZE - space_saved(c);
if (ll <= 0) ll = 1;
ratio = 1000 / ll;
if (ratio == 0) ratio = 1;
/* Add points if the called procedure falls through
* it's end (no BRA needed) or has formal parameters
* (ASP can be deleted).
*/
if (c->cl_proc->p_flags2 & PF_FALLTHROUGH) {
ratio += 10;
}
if (c->cl_proc->p_nrformals > 0) {
ratio += 10;
}
if (c->cl_caller->p_localbytes == 0) {
ratio -= 10;
}
ratio += (10 *param_score(c));
/* Extra points for constants as parameters */
if (ratio <= 0) ratio = 1;
ll = c->cl_looplevel+1;
if (ll == 1 && !IS_CALLED_IN_LOOP(c->cl_caller)) ll = 0;
/* If the call is not in a loop and the called proc. is never called
* in a loop, ll is set to 0.
*/
loopfact = (ll > 3 ? 10 : ll*ll);
ratio *= loopfact;
if (c->cl_flags & CLF_FIRM) {
ratio = 2*ratio;
}
c->cl_ratio = ratio;
}
call_p abstract(c)
call_p c;
{
/* Abstract information from the call that is essential
* for choosing the calls that will be expanded.
* Put the information is an 'abstracted call'.
*/
call_p a;
a = newcall();
a->cl_caller = c->cl_caller;
a->cl_id = c->cl_id;
a->cl_proc = c->cl_proc;
a->cl_looplevel = c->cl_looplevel;
a->cl_ratio = c->cl_ratio;
a->cl_flags = c->cl_flags;
return a;
}
STATIC adjust_counts(callee,ccf)
proc_p callee;
FILE *ccf;
{
/* A call to callee is expanded in line;
* the text of callee is not removed, so
* every proc called by callee gets its
* P_NRCALLED field incremented.
*/
calcnt_p cc, head;
head = getcc(ccf,callee); /* get calcnt info of called proc */
for (cc = head; cc != (calcnt_p) 0; cc = cc->cc_next) {
cc->cc_proc->P_NRCALLED += cc->cc_count;
}
remcc(head); /* remove calcnt info */
}
STATIC bool is_dispensable(callee,ccf)
proc_p callee;
FILE *ccf;
{
/* A call to callee is expanded in line.
* Decrement its P_NRCALLED field and see if
* it can now be removed because it is no
* longer called. Procedures that ever have
* their address taken (via LPI) will never
* be removed, as they might be called indirectly.
*/
if ((--callee->P_NRCALLED) == 0 &&
(callee->p_flags1 & PF_LPI) == 0) {
DISPENSABLE(callee);
OUTTRACE("procedure %d can be removed",callee->p_id);
#ifdef VERBOSE
Spremoved++;
#endif
return TRUE;
} else {
adjust_counts(callee,ccf);
return FALSE;
}
}
STATIC call_p nested_calls(a)
call_p a;
{
/* Get a list of all calls that will appear in the
* EM text if the call 'a' is expanded in line.
* These are the calls in the P_CALS list of the
* called procedure.
*/
call_p c, cp, head, *cpp;
head = (call_p) 0;
cpp = &head;
for (c = a->cl_proc->P_CALS; c != (call_p) 0; c = c->cl_cdr) {
cp = abstract(c);
cp->cl_looplevel += a->cl_looplevel;
cp->cl_flags = (byte) 0;
if (a->cl_flags & CLF_FIRM) {
cp->cl_flags |= CLF_FIRM;
}
assign_ratio(cp);
*cpp = cp;
cpp = &cp->cl_cdr;
}
return head;
}
STATIC call_p find_origin(c)
call_p c;
{
/* c is a nested call. Find the original call.
* This origional must be in the P_CALS list
* of the calling procedure.
*/
register call_p x;
for (x = c->cl_caller->P_CALS; x != (call_p) 0; x = x->cl_cdr) {
if (x->cl_id == c->cl_id) return x;
}
assert(FALSE);
/* NOTREACHED */
}
STATIC selected(a)
call_p a;
{
/* The call a is selected for in line expansion.
* Mark the call as being selected and get the
* calls nested in it; these will be candidates
* too now.
*/
SELECTED(a);
EVER_EXPANDED(find_origin(a));
a->cl_car = nested_calls(a);
}
STATIC compare(x,best,space)
call_p x, *best;
short space;
{
/* See if x is better than the current best choice */
if (x != (call_p) 0 && !IS_CHANGED(x->cl_proc) &&
x->cl_proc->P_SIZE - space_saved(x) <= space) {
if ((*best == (call_p) 0 && x->cl_ratio != 0) ||
(*best != (call_p) 0 && x->cl_ratio > (*best)->cl_ratio )) {
*best = x;
}
}
}
STATIC call_p best_one(list,space)
call_p list;
short space;
{
/* Find the best candidate of the list
* that has not already been selected. The
* candidate must fit in the given space.
* We look in the cdr as well as in the car
* direction.
*/
call_p best = (call_p) 0;
call_p x,c;
for (c = list; c != (call_p) 0; c = c->cl_cdr) {
if (IS_SELECTED(c)) {
compare(best_one(c->cl_car,space),&best,space);
} else {
compare(c,&best,space);
}
}
return best;
}
STATIC singles(cals)
call_p cals;
{
/* If a procedure is only called once, this call
* will be expanded in line, because it costs
* no extra space.
*/
call_p c;
for (c = cals; c != (call_p) 0; c = c->cl_cdr) {
if (IS_SELECTED(c)) {
singles(c->cl_car);
} else {
if (c->cl_proc->P_NRCALLED == 1 &&
!IS_CHANGED(c->cl_proc) &&
(c->cl_proc->p_flags1 & PF_LPI) == 0) {
c->cl_proc->P_NRCALLED = 0;
SELECTED(c);
EVER_EXPANDED(find_origin(c));
DISPENSABLE(c->cl_proc);
CHANGED(c->cl_caller);
OUTTRACE("procedure %d can be removed",
c->cl_proc->p_id);
#ifdef VERBOSE
Spremoved++;
#endif
}
}
}
}
STATIC single_calls(proclist)
proc_p proclist;
{
proc_p p;
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
if (!BIG_CALLER(p) && !IS_DISPENSABLE(p)) {
/* Calls appearing in a large procedure or in
* a procedure that was already eliminated
* are not considered.
*/
singles(p->P_CALS);
}
}
}
select_calls(proclist,ccf,space)
proc_p proclist;
FILE *ccf;
short space ;
{
/* Select all calls that are to be expanded in line. */
proc_p p,chp;
call_p best, x;
for (;;) {
best = (call_p) 0;
chp = (proc_p) 0; /* the changed procedure */
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
if (!BIG_CALLER(p) && !IS_DISPENSABLE(p)) {
/* Calls appearing in a large procedure or in
* a procedure that was already eliminated
* are not considered.
*/
x = best_one(p->P_CALS,space);
compare(x,&best,space);
if (x == best) chp = p;
}
}
if (best == (call_p) 0) break;
if (!is_dispensable(best->cl_proc,ccf)) {
space -= (best->cl_proc->P_SIZE - space_saved(best));
}
selected(best);
CHANGED(chp);
}
single_calls(proclist);
#ifdef VERBOSE
Sstat(proclist,space);
#endif
}
STATIC nonnested_calls(cfile)
FILE *cfile;
{
register call_p c,a;
while((c = getcall(cfile)) != (call_p) 0) {
/* find the call in the call list of the caller */
for (a = c->cl_caller->P_CALS;
a != (call_p) 0 && c->cl_id != a->cl_id; a = a->cl_cdr);
assert(a != (call_p) 0 && a->cl_proc == c->cl_proc);
if (IS_EVER_EXPANDED(a)) {
a->cl_actuals = c->cl_actuals;
c->cl_actuals = (actual_p) 0;
}
rem_call(c);
}
}
STATIC copy_pars(src,dest)
call_p src, dest;
{
/* Copy the actual parameters of src to dest. */
actual_p as,ad, *app;
app = &dest->cl_actuals;
for (as = src->cl_actuals; as != (actual_p) 0; as = as->ac_next) {
ad = newactual();
ad->ac_exp = copy_expr(as->ac_exp);
ad->ac_size = as->ac_size;
ad->ac_inl = as->ac_inl;
*app = ad;
app = &ad->ac_next;
}
}
STATIC nest_pars(cals)
call_p cals;
{
/* Recursive auxiliary procedure of add_actuals. */
call_p c,org;
for (c = cals; c != (call_p) 0; c = c->cl_cdr) {
if (IS_SELECTED(c)) {
org = find_origin(c);
copy_pars(org,c);
nest_pars(c->cl_car);
}
}
}
add_actuals(proclist,cfile)
proc_p proclist;
FILE *cfile;
{
/* Fetch the actual parameters of all selected calls.
* For all non-nested calls (i.e. those calls that
* appeared originally in the EM text), we get the
* parameters from the cal-file.
* For nested calls (i.e. calls
* that are a result of in line substitution) we
* get the parameters from the original call.
*/
proc_p p;
call_p a;
nonnested_calls(cfile);
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
for (a = p->P_CALS; a != (call_p) 0; a = a->cl_cdr) {
nest_pars(a->cl_car);
}
}
}
STATIC clean(cals)
call_p *cals;
{
call_p c,next,*cpp;
/* Recursive auxiliary routine of cleancals */
cpp = cals;
for (c = *cpp; c != (call_p) 0; c = next) {
next = c->cl_cdr;
if (IS_SELECTED(c)) {
clean(&c->cl_car);
cpp = &c->cl_cdr;
} else {
assert(c->cl_car == (call_p) 0);
oldcall(c);
*cpp = next;
}
}
}
cleancals(proclist)
proc_p proclist;
{
/* Remove all calls in the P_CALS list of p
* that were not selected for in line expansion.
*/
register proc_p p;
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
clean(&p->P_CALS);
}
}
append_abstract(a,p)
call_p a;
proc_p p;
{
/* Append an abstract of a call-descriptor to
* the call-list of procedure p.
*/
call_p c;
if (p->P_CALS == (call_p) 0) {
p->P_CALS = a;
} else {
for (c = p->P_CALS; c->cl_cdr != (call_p) 0; c = c->cl_cdr);
c->cl_cdr = a;
}
}
#ifdef VERBOSE
/* At the end, we traverse the entire call-list, to see why the
* remaining calls were not expanded inline.
*/
Sstatist(list,space)
call_p list;
short space;
{
call_p c;
for (c = list; c != (call_p) 0; c = c->cl_cdr) {
if (IS_SELECTED(c)) {
Sstatist(c->cl_car,space);
} else {
if (IS_CHANGED(c->cl_proc)) Schangedcallee++;
else if (BIG_PROC(c->cl_proc)) Sbigcallee++;
else if (c->cl_proc->P_SIZE > space) Sspace++;
else if (c->cl_ratio == 0) Szeroratio++;
else assert(FALSE);
}
}
}
Sstat(proclist,space)
proc_p proclist;
short space;
{
proc_p p;
for (p = proclist; p != (proc_p) 0; p = p->p_next) {
if (BIG_CALLER(p)) Sbig_caller++;
else if (IS_DISPENSABLE(p)) Sdispensable++;
else Sstatist(p->P_CALS,space);
}
}
#endif

36
util/ego/il/il2_aux.h Normal file
View file

@ -0,0 +1,36 @@
extern anal_params(); /* (call_p c)
* See which parameters of the call
* may be expanded in line.
*/
extern assign_ratio(); /* (call_p c)
* Assigna ratio number to the call,
* indicating how desirable it is to
* expand the call in line.
*/
extern call_p abstract(); /* (call_p c)
* Abstract essential information from
* the call.
*/
extern select_calls(); /* (call_p alist; FILE *ccf;short space)
* Select the best calls to be expanded.
* Every procedure gets a list of
* selected calls appearing in it.
* space is the amount of space that the
* program is allowed to grow
* (expressed in number of EM instructions).
*/
extern cleancals(); /* (proc_p plist)
* Remove all calls that were not selected.
*/
extern add_actuals(); /* (proc_p plist; FILE *cfile)
* Add the actual parameters to the descriptor abstracts
* of the selected calls.
* the calfile contains the full descriptors of all
* calls.
* These two are combined to yield a file of full
* descriptors of the selected calls.
*/
extern append_abstract(); /* (call_p a; proc_p p)
* Put the call-descriptor abstract in the p_cals
* list of p.
*/

63
util/ego/il/il3_aux.c Normal file
View file

@ -0,0 +1,63 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 3 _ A U X . C
*/
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "il_aux.h"
#include "il3_aux.h"
line_p last_line(lines)
line_p lines;
{
/* Determine the last line of a list */
register line_p l;
assert (l != (line_p) 0);
for (l = lines; l->l_next != (line_p) 0; l = l->l_next);
return l;
}
app_list(list,l)
line_p list,l;
{
/* Append the list after line l */
line_p llast;
assert(l != (line_p) 0);
assert (list != (line_p) 0);
llast = last_line(list);
llast->l_next = l->l_next;
if (l->l_next != (line_p) 0) {
PREV(l->l_next) = llast;
}
l->l_next = list;
PREV(list) = l;
}
rem_line(l)
line_p l;
{
/* Remove a line from the list */
if (PREV(l) != (line_p) 0) {
PREV(l)->l_next = l->l_next;
}
if (l->l_next != (line_p) 0) {
PREV(l->l_next) = PREV(l);
}
oldline(l);
}

15
util/ego/il/il3_aux.h Normal file
View file

@ -0,0 +1,15 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 3 _ A U X . H
*/
extern line_p last_line(); /* (line_p list)
* Find the last line of a list.
*/
extern app_list(); /* (line_p list,l)
* Put list after l
*/
extern rem_line(); /* (line_p l)
* Remove a line from a (doubly linked)
* list.
*/

583
util/ego/il/il3_change.c Normal file
View file

@ -0,0 +1,583 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 3 _ C H A N G E . C
*/
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/def.h"
#include "../share/lset.h"
#include "../share/aux.h"
#include "../../../h/em_mnem.h"
#include "../../../h/em_pseu.h"
#include "../../../h/em_spec.h"
#include "../../../h/em_mes.h"
#include "../share/get.h"
#include "../share/put.h"
#include "il_aux.h"
#include "il3_change.h"
#include "il3_aux.h"
/* chg_callseq */
STATIC line_p par_expr(l,expr)
line_p l, expr;
{
/* Find the first line of the expression of which
* l is the last line; expr contains a pointer
* to a copy of that expression; effectively we
* just have to tally lines.
*/
line_p lnp;
for (lnp = expr->l_next; lnp != (line_p) 0; lnp = lnp->l_next) {
assert(l != (line_p) 0);
l = PREV(l);
}
return l;
}
STATIC rem_text(l1,l2)
line_p l1,l2;
{
/* Remove the lines from l1 to l2 (inclusive) */
line_p l, lstop;
l = PREV(l1);
lstop = l2->l_next;
while (l->l_next != lstop) {
rem_line(l->l_next);
}
}
STATIC store_tmp(p,l,size)
proc_p p;
line_p l;
offset size;
{
/* Emit code to store a 'size'-byte value in a new
* temporary local variable in the stack frame of p.
* Put this code after line l.
*/
line_p lnp;
lnp = int_line(tmplocal(p,size)); /* line with operand temp. */
if (size == ws) {
lnp->l_instr = op_stl; /* STL temp. */
} else {
if (size == 2*ws) {
lnp->l_instr = op_sdl; /* SDL temp. */
} else {
/* emit 'LAL temp; STI size' */
lnp->l_instr = op_lal;
appnd_line(lnp,l);
l = lnp;
assert ((short) size == size);
lnp = newline(OPSHORT);
SHORT(lnp) = size;
lnp->l_instr = op_sti;
}
}
appnd_line(lnp,l);
}
STATIC chg_actuals(c,cal)
call_p c;
line_p cal;
{
/* Change the actual parameter expressions of the call. */
actual_p act;
line_p llast,lfirst,l;
llast = PREV(cal);
for (act = c->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
lfirst = par_expr(llast,act->ac_exp);
/* the code from lfirst to llast is a parameter expression */
if (act->ac_inl) {
/* in line parameter; remove it */
l = llast;
llast = PREV(lfirst);
rem_text(lfirst,l);
} else {
store_tmp(curproc,llast,act->ac_size);
/* put a "STL tmp" -like instruction after the code */
llast = PREV(lfirst);
}
}
}
STATIC rm_callpart(c,cal)
call_p c;
line_p cal;
{
/* Remove the call part, consisting of a CAL,
* an optional ASP and an optional LFR.
*/
line_p l;
l= PREV(cal);
rem_line(cal);
if (c->cl_proc->p_nrformals > 0) {
/* called procedure has parameters */
assert (INSTR(l->l_next) == op_asp);
rem_line(l->l_next);
}
if (INSTR(l->l_next) == op_lfr) {
rem_line(l->l_next);
}
}
chg_callseq(c,cal,l_out)
call_p c;
line_p cal,*l_out;
{
/* Change the calling sequence. The actual parameter
* expressions are changed (in line parameters are
* removed, all other ones now store their result
* in a temporary local of the caller);
* the sequence "CAL ; ASP ; LFR" is removed.
*/
chg_actuals(c,cal);
*l_out = PREV(cal); /* last instr. of new parameter part */
rm_callpart(c,cal);
}
/* make_label */
line_p make_label(l,p)
line_p l;
proc_p p;
{
/* Make sure that the instruction after l
* contains an instruction label. If this is
* not already the case, create a new label.
*/
line_p lab;
if (l->l_next != (line_p) 0 && INSTR(l->l_next) == op_lab) {
return l->l_next;
}
lab = newline(OPINSTRLAB);
lab->l_instr = op_lab;
p->p_nrlabels++;
INSTRLAB(lab) = p->p_nrlabels;
appnd_line(lab,l);
return lab;
}
/* modify */
STATIC act_info(off,acts,ab_off,act_out,off_out)
offset off, ab_off, *off_out;
actual_p acts, *act_out;
{
/* Find the actual parameter that corresponds to
* the formal parameter with the given offset.
* Return it via act_out. If the actual is not
* an in-line actual, determine which temporary
* local is used for it; return the offset of that
* local via off_out.
*/
offset sum = 0, tmp = 0;
actual_p act;
for (act = acts; act != (actual_p) 0; act = act->ac_next) {
if (!act->ac_inl) {
tmp -= act->ac_size;
}
if (sum >= off) {
/* found */
*act_out = act;
if (!act->ac_inl) {
*off_out = tmp + sum - off + ab_off;
} else {
assert (sum == off);
}
return;
}
sum += act->ac_size;
}
assert(FALSE);
}
STATIC store_off(off,l)
offset off;
line_p l;
{
if (TYPE(l) == OPSHORT) {
assert ((short) off == off);
SHORT(l) = (short) off;
} else {
OFFSET(l) = off;
}
}
STATIC inl_actual(l,expr)
line_p l, expr;
{
/* Expand an actual parameter in line.
* A LOL or LDL instruction is replaced
* by an expression.
* A SIL or LIL is replaced by the expression
* followed by a STI or LOI.
*/
line_p e, lnp, s;
short instr;
instr = INSTR(l);
assert(expr != (line_p) 0);
e = copy_expr(expr); /* make a copy of expr. */
if (instr == op_sil || instr == op_lil) {
s = int_line((offset) ws);
s->l_instr = (instr == op_sil ? op_sti : op_loi);
appnd_line(s,last_line(e));
} else {
assert(instr == op_lol || instr == op_ldl);
}
lnp = PREV(l);
rem_line(l);
app_list(e,lnp);
}
STATIC localref(l,c,ab_off,lb_off)
line_p l;
call_p c;
offset ab_off, lb_off;
{
/* Change a reference to a local variable or parameter
* of the called procedure.
*/
offset off, tmpoff;
actual_p act;
off = off_set(l);
if (off < 0) {
/* local variable, only the offset changes */
store_off(lb_off + off,l);
} else {
act_info(off,c->cl_actuals,ab_off,&act,&tmpoff); /* find actual */
if (act->ac_inl) {
/* inline actual parameter */
inl_actual(l,act->ac_exp);
} else {
/* parameter stored in temporary local */
store_off(tmpoff,l);
}
}
}
STATIC chg_mes(l,c,ab_off,lb_off)
line_p l;
call_p c;
offset ab_off, lb_off;
{
/* The register messages of the called procedure
* must be changed. If the message applies to a
* local variable or to a parameter that is not
* expanded in line, the offset of the variable
* is changed; else the entire message is deleted.
*/
offset off, tmpoff;
actual_p act;
arg_p arg;
arg = ARG(l);
switch ((int) arg->a_a.a_offset) {
case ms_reg:
if ((arg = arg->a_next) != (arg_p) 0) {
/* "mes 3" without further argument is not changed */
off = arg->a_a.a_offset;
if (off < 0) {
/* local variable */
arg->a_a.a_offset += lb_off;
} else {
act_info(off,c->cl_actuals,ab_off,&act,&tmpoff);
if (act->ac_inl) {
/* in line actual */
rem_line(l);
} else {
arg->a_a.a_offset = tmpoff;
}
}
}
break;
case ms_par:
rem_line(l);
break;
}
}
STATIC chg_ret(l,c,lab)
line_p l,lab;
call_p c;
{
/* Change the RET instruction appearing in the
* expanded text of a call. If the called procedure
* falls through, the RET is just deleted; else it
* is replaced by a branch.
*/
line_p lnp, bra;
lnp = PREV(l);
rem_line(l);
if (!FALLTHROUGH(c->cl_proc)) {
bra = newline(OPINSTRLAB);
bra->l_instr = op_bra;
INSTRLAB(bra) = INSTRLAB(lab);
appnd_line(bra,lnp);
}
}
STATIC mod_instr(l,c,lab,ab_off,lb_off,lab_off)
line_p l,lab;
call_p c;
offset ab_off,lb_off;
int lab_off;
{
if (TYPE(l) == OPINSTRLAB) {
INSTRLAB(l) += lab_off;
} else {
switch(INSTR(l)) {
case op_stl:
case op_inl:
case op_del:
case op_zrl:
case op_sdl:
case op_lol:
case op_ldl:
case op_sil:
case op_lil:
case op_lal:
localref(l,c,ab_off,lb_off);
break;
case op_ret:
chg_ret(l,c,lab);
break;
case ps_pro:
case ps_end:
case ps_sym:
case ps_hol:
case ps_bss:
case ps_con:
case ps_rom:
rem_line(l);
break;
case ps_mes:
chg_mes(l,c,ab_off,lb_off);
break;
}
}
}
modify(text,c,lab,ab_off,lb_off,lab_off)
line_p text,lab;
call_p c;
offset ab_off,lb_off;
int lab_off;
{
/* Modify the EM text of the called procedure.
* References to locals and parameters are
* changed; RETs are either deleted or replaced
* by a BRA to the given label; PRO and END pseudos
* are removed; instruction labels are changed, in
* order to make them different from any label used
* by the caller; some messages need to be changed too.
* Note that the first line of the text is a dummy instruction.
*/
register line_p l;
line_p next;
for (l = text->l_next; l != (line_p) 0; l = next) {
next = l->l_next;
/* This is rather tricky. An instruction like
* LOL 2 may be replaced by a number of instructions
* (if the parameter is expanded in line). This inserted
* code, however, should not be modified!
*/
mod_instr(l,c,lab,ab_off,lb_off,lab_off);
}
}
mod_actuals(nc,c,lab,ab_off,lb_off,lab_off)
call_p nc,c;
line_p lab;
offset ab_off,lb_off;
int lab_off;
{
actual_p act;
line_p l, next, dum;
dum = newline(OPNO);
PREV(dum) = (line_p) 0;
for (act = nc->cl_actuals; act != (actual_p) 0; act = act->ac_next) {
l = act->ac_exp;
assert(l != (line_p) 0);
/* Insert a dummy instruction before l */
dum->l_next = l;
PREV(l) = dum;
while(l != (line_p) 0) {
next = l->l_next;
mod_instr(l,c,lab,ab_off,lb_off,lab_off);
l = next;
}
act->ac_exp = dum->l_next;
PREV(dum->l_next) = (line_p) 0;
}
oldline(dum);
}
/* insert */
STATIC line_p first_nonpseudo(l)
line_p l;
{
/* Find the first non-pseudo instruction of
* a list of instructions.
*/
while (l != (line_p) 0 && INSTR(l) >= sp_fpseu &&
INSTR(l) <= ps_last) l = l->l_next;
return l;
}
insert(text,l,firstline)
line_p text,l,firstline;
{
/* Insert the modified EM text of the called
* routine in the calling routine. Pseudos are
* put after the pseudos of the caller; all
* normal instructions are put at the place
* where the CAL originally was.
*/
line_p l1,l2,lastpseu;
l1 = text->l_next;
oldline(text); /* remove dummy head instruction */
if (l1 == (line_p) 0) return; /* no text at all! */
l2 = first_nonpseudo(l1);
if (l2 == (line_p) 0) {
/* modified code consists only of pseudos */
app_list(l1,PREV(first_nonpseudo(firstline)));
} else {
if (l1 == l2) {
/* no pseudos */
app_list(l2,l);
} else {
lastpseu = PREV(first_nonpseudo(firstline));
PREV(l2)->l_next = (line_p) 0; /* cut link */
app_list(l2,l); /* insert normal instructions */
app_list(l1,lastpseu);
}
}
}
liquidate(p,text)
proc_p p;
line_p text;
{
/* All calls to procedure p were expanded in line, so
* p is no longer needed. However, we must not throw away
* any data declarations appearing in p.
* The proctable entry of p is not removed, as we do not
* want to create holes in this table; however the PF_BODYSEEN
* flag is cleared, so p gets the same status as a procedure
* whose body is unmkown.
*/
line_p l, nextl, lastkept = (line_p) 0;
call_p c, nextc;
for (l = text; l != (line_p) 0; l = nextl) {
nextl = l->l_next;
switch(INSTR(l)) {
case ps_sym:
case ps_hol:
case ps_bss:
case ps_con:
case ps_rom:
lastkept = l;
break;
default:
rem_line(l);
}
}
if (lastkept != (line_p) 0) {
/* There were some data declarations in p,
* so we'll turn p into a data-unit; we'll
* have to append an end-pseudo for this
* purpose.
*/
lastkept->l_next = newline(OPNO);
lastkept->l_next->l_instr = (byte) ps_end;
}
/* There may be some calls in the body of p that
* ought to be expanded in line. As p is removed
* anyway, there is no use in really performing
* these substitutions, so the call-descriptors
* are just thrown away.
*/
for (c = p->P_CALS; c != (call_p) 0; c = nextc) {
nextc = c->cl_cdr;
rem_call(c);
}
/* change the proctable entry */
p->p_flags1 &= (byte) ~PF_BODYSEEN;
oldchange(p->p_change);
olduse(p->p_use);
}

41
util/ego/il/il3_change.h Normal file
View file

@ -0,0 +1,41 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 3 _ C H A N G E . C
*/
extern chg_callseq(); /* (call_p c; line_p cal, *l_out)
* Change the calling sequence of
* the call c. The parameters are
* changed and the sequence
* CAL - ASP - LFR is removed.
* cal points to the CAL instruction
* l_out indicates where the expanded
* text of the called routine must
* be put.
*/
extern line_p make_label(); /* (line_p l; proc_p p)
* Make sure that the instruction after
* l contains a label. If this is not
* already the case, create a new label.
*/
extern modify(); /* (line_p text; call_p c; line_p lab;
* offset ab_off, lb_off; int lab_off)
* Modify the EM text of the called
* procedure.
*/
extern mod_actuals(); /* (call_p nc,c; line_p lab;
* offset ab_off, lb_off; int lab_off)
* Modify the actual parameters of the
* call nc the same way as the text of
* call c would be modified.
*/
extern insert(); /* (line_p text,l,firstline)
* Insert the modified EM text.
* Pseudos are put after the pseudos
* of the caller.
*/
extern liquidate(); /* (proc_p p; line_p text)
* All calls to p were expanded in line,
* so p is no longer needed.
*/

121
util/ego/il/il3_subst.c Normal file
View file

@ -0,0 +1,121 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 3 _ S U B S T . C
*/
#include <stdio.h>
#include "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/get.h"
#include "../../../h/em_mnem.h"
#include "il3_aux.h"
#include "il3_change.h"
#include "il3_subst.h"
STATIC line_p fetch_text(lf,c)
FILE *lf;
call_p c;
{
/* Read the EM text of the called procedure.
* We use random access I/O here.
*/
line_p l;
proc_p p;
lset savmes;
savmes = mesregs;
mesregs = Lempty_set();
fseek(lf,c->cl_proc->P_LADDR,0);
l = get_text(lf,&p);
assert (p == c->cl_proc);
Ldeleteset(mesregs);
mesregs = savmes;
return l;
}
line_p scan_to_cal(lines,n)
line_p lines;
short n;
{
/* Find the n-th CAL instruction */
register line_p l;
for (l = lines; l != (line_p) 0; l = l->l_next) {
if (INSTR(l) == op_cal) {
if (--n == 0) return l;
}
}
return (line_p) 0; /* CAL not found */
}
substitute(lf,c,cal,firstline)
FILE *lf;
call_p c;
line_p cal,firstline;
{
/* Perform in line substitution of the call described
* by c. The EM text of the called routine is fetched
* and modified, the calling sequence is changed,
* the modified routine is put at the place of the call
* and all global information (proctable etc.) is kept
* up to date.
*/
line_p l, text, lab;
offset ab_off, lb_off;
line_p startscan, ncal;
short lastcid;
call_p nc;
Ssubst++;
ab_off = - curproc->p_localbytes;
/* offset of temporaries for parameters
* that are not expanded in line.
*/
chg_callseq(c,cal,&l);
/* Change the calling sequence; l points to the place
* where the expanded text must be put
*/
text = fetch_text(lf,c); /* fetch EM text of called routine */
lb_off = - curproc->p_localbytes;
/* offset of temps. for locals of called proc. */
curproc->p_localbytes += c->cl_proc->P_ORGLOCALS;
/* locals of called routine are put in stack frame of caller */
if (!FALLTHROUGH(c->cl_proc)) {
/* The called proc contains one or more RETurns
* somewhere in the middle of its text; these
* should be changed into a jump to the end
* of the text. We create a label for this
* purpose (if there was no one already).
*/
lab = make_label(l,curproc);
}
modify(text,c,lab,ab_off,lb_off,curproc->p_nrlabels);
curproc->p_nrlabels += c->cl_proc->P_ORGLABELS;
insert(text,l,firstline);
/* insert text; instructions are put after l, pseudos
* are put at beginning of caller.
*/
/* Now take care of the nested calls */
startscan = l->l_next;
lastcid = 0;
for (nc = c->cl_car; nc != (call_p) 0; nc = nc->cl_cdr) {
mod_actuals(nc,c,lab,ab_off,lb_off,curproc->p_nrlabels);
ncal = scan_to_cal(startscan,nc->cl_id - lastcid);
assert(ncal != (line_p) 0);
startscan = scan_to_cal(ncal->l_next,1);
lastcid = nc->cl_id;
substitute(lf,nc,ncal,firstline);
}
}

17
util/ego/il/il3_subst.h Normal file
View file

@ -0,0 +1,17 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L 3 _ S U B S T . H
*/
extern line_p scan_to_cal(); /* (line_p lines; short n)
* Find the n-th cal instruction.
*/
extern substitute(); /* (FILE *lf;call_p c; line_ pcal,firstline)
* Perform in line substitution of the call described
* by c. The EM text of the called routine is fetched
* and modified, the calling sequence is changed,
* the modified routine is put at the place of the call
* and all global information (proctable etc.) is kept
* up to date.
*/

182
util/ego/il/il_aux.c Normal file
View file

@ -0,0 +1,182 @@
/* 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 "../share/types.h"
#include "il.h"
#include "../share/debug.h"
#include "../share/alloc.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/map.h"
#include "../../../h/em_spec.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;
loop_p lp;
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);
}
}

30
util/ego/il/il_aux.h Normal file
View file

@ -0,0 +1,30 @@
/* I N L I N E S U B S T I T U T I O N
*
* I L _ A U X . H
*/
extern int tsize(); /* (int type)
* Determine the size of a variable of
* the given type.
*/
extern line_p duplicate(); /* (line_p lnp)
* Make a duplicate of the given EM
* instruction. Pseudos may not be
* passed as argumnets.
*/
extern line_p copy_expr(); /* (line_p l1)
* copy the expression l1.
* Pseudos may not be contained in
* the list of instructions.
*/
extern rem_call(); /* (call_p c)
* Remove a call from main memory.
*/
extern rem_graph(); /* (proc_p p)
* Remove the CFG and EM text of
* a procedure from core.
*/
extern remcc(); /* (calcnt_p head)
* Remove call-count info from core.
*/