Initial revision
This commit is contained in:
parent
f01e1431b0
commit
9f778655a6
133
util/ego/il/Makefile
Normal file
133
util/ego/il/Makefile
Normal 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
312
util/ego/il/il.c
Normal 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
69
util/ego/il/il.h
Normal 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
177
util/ego/il/il1_anal.c
Normal 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
17
util/ego/il/il1_anal.h
Normal 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
208
util/ego/il/il1_aux.c
Normal 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
38
util/ego/il/il1_aux.h
Normal 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
138
util/ego/il/il1_cal.c
Normal 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
31
util/ego/il/il1_cal.h
Normal 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
141
util/ego/il/il1_formal.c
Normal 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
11
util/ego/il/il1_formal.h
Normal 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
718
util/ego/il/il2_aux.c
Normal 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
36
util/ego/il/il2_aux.h
Normal 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
63
util/ego/il/il3_aux.c
Normal 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
15
util/ego/il/il3_aux.h
Normal 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
583
util/ego/il/il3_change.c
Normal 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
41
util/ego/il/il3_change.h
Normal 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
121
util/ego/il/il3_subst.c
Normal 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
17
util/ego/il/il3_subst.h
Normal 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
182
util/ego/il/il_aux.c
Normal 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
30
util/ego/il/il_aux.h
Normal 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.
|
||||
*/
|
Loading…
Reference in a new issue