|
@@ -0,0 +1,911 @@
|
|
|
+/* S H A R E D F I L E
|
|
|
+ *
|
|
|
+ * G E T . C
|
|
|
+ */
|
|
|
+
|
|
|
+#include <stdio.h>
|
|
|
+#include "types.h"
|
|
|
+#include "def.h"
|
|
|
+#include "debug.h"
|
|
|
+#include "global.h"
|
|
|
+#include "lset.h"
|
|
|
+#include "cset.h"
|
|
|
+#include "get.h"
|
|
|
+#include "alloc.h"
|
|
|
+#include "map.h"
|
|
|
+#include "aux.h"
|
|
|
+#include "../../../h/em_spec.h"
|
|
|
+#include "../../../h/em_mnem.h"
|
|
|
+#include "../../../h/em_pseu.h"
|
|
|
+#include "../../../h/em_mes.h"
|
|
|
+#include "../../../h/em_flag.h"
|
|
|
+
|
|
|
+extern char em_flag[];
|
|
|
+
|
|
|
+
|
|
|
+/* global variables */
|
|
|
+
|
|
|
+static FILE *f;
|
|
|
+STATIC block_id lastbid; /* block identifying number */
|
|
|
+STATIC lab_id lastlabid; /* last label identifier */
|
|
|
+
|
|
|
+/* creating new identifying numbers, i.e. numbers that did not
|
|
|
+ * appear in the input.
|
|
|
+ */
|
|
|
+
|
|
|
+bblock_p freshblock()
|
|
|
+{
|
|
|
+ bblock_p b;
|
|
|
+ b = newbblock();
|
|
|
+ b->b_id = ++lastbid;
|
|
|
+ return b;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+lab_id freshlabel()
|
|
|
+{
|
|
|
+ curproc->p_nrlabels++;
|
|
|
+ return ++lastlabid;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* local routines */
|
|
|
+
|
|
|
+#define getbyte() getc(f)
|
|
|
+
|
|
|
+#define getmark() getbyte()
|
|
|
+
|
|
|
+STATIC short getshort() {
|
|
|
+ register int l_byte, h_byte;
|
|
|
+
|
|
|
+ l_byte = getbyte();
|
|
|
+ h_byte = getbyte();
|
|
|
+ if ( h_byte>=128 ) h_byte -= 256 ;
|
|
|
+ return l_byte | (h_byte*256) ;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+STATIC offset getoff() {
|
|
|
+ register long l;
|
|
|
+ register int h_byte;
|
|
|
+
|
|
|
+ l = getbyte();
|
|
|
+ l |= ((unsigned) getbyte())*256 ;
|
|
|
+ l |= getbyte()*256L*256L ;
|
|
|
+ h_byte = getbyte() ;
|
|
|
+ if ( h_byte>=128 ) h_byte -= 256 ;
|
|
|
+ return l | (h_byte*256L*256*256L) ;
|
|
|
+}
|
|
|
+
|
|
|
+STATIC int getint()
|
|
|
+{
|
|
|
+ /* Read an integer from the input file. This routine is
|
|
|
+ * only used when reading a bitvector-set. We expect an
|
|
|
+ * integer to be either a short or a long.
|
|
|
+ */
|
|
|
+
|
|
|
+ if (sizeof(int) == sizeof(short)) {
|
|
|
+ return getshort();
|
|
|
+ } else {
|
|
|
+ assert (sizeof(int) == sizeof(offset));
|
|
|
+ return getoff();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* getptable */
|
|
|
+
|
|
|
+loop_p getloop(id)
|
|
|
+ loop_id id;
|
|
|
+{
|
|
|
+ /* Map a loop identifier onto a loop struct.
|
|
|
+ * If no struct was alocated yet for this identifier then
|
|
|
+ * allocate one now and update the loop-map table.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ assert (id > 0 && id <=lplength);
|
|
|
+ if (lpmap[id] == (loop_p) 0) {
|
|
|
+ lpmap[id] = newloop();
|
|
|
+ lpmap[id]->lp_id = id;
|
|
|
+ }
|
|
|
+ return (lpmap[id]);
|
|
|
+}
|
|
|
+
|
|
|
+bblock_p getblock(id)
|
|
|
+ block_id id;
|
|
|
+{
|
|
|
+ /* Map a basic block identifier onto a block struct
|
|
|
+ * If no struct was alocated yet for this identifier then
|
|
|
+ * allocate one now and update the block-map table.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ assert (id >= 0 && id <=blength);
|
|
|
+ if (id == 0) return (bblock_p) 0;
|
|
|
+ if (bmap[id] == (bblock_p) 0) {
|
|
|
+ bmap[id] = newbblock();
|
|
|
+ bmap[id]->b_id = id;
|
|
|
+ }
|
|
|
+ return (bmap[id]);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+lset getlset(p)
|
|
|
+ char *((*p) ());
|
|
|
+{
|
|
|
+ /* Read a 'long' set. Such a set is represented externally
|
|
|
+ * as a sequence of identifying numbers terminated by a 0.
|
|
|
+ * The procedural parameter p maps such a number onto a
|
|
|
+ * pointer to a struct (bblock_p, loop_p etc.).
|
|
|
+ */
|
|
|
+
|
|
|
+ lset s;
|
|
|
+ int id;
|
|
|
+
|
|
|
+ s = Lempty_set();
|
|
|
+ while (id = getshort()) {
|
|
|
+ Ladd( (*p) (id), &s);
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+cset getcset()
|
|
|
+{
|
|
|
+ /* Read a 'compact' set. Such a set is represented externally
|
|
|
+ * a row of bytes (its bitvector) preceded by its length.
|
|
|
+ */
|
|
|
+
|
|
|
+ cset s;
|
|
|
+ register short i;
|
|
|
+
|
|
|
+ s = Cempty_set(getshort());
|
|
|
+ for (i = 0; i <= DIVWL(s->v_size-1);i++) {
|
|
|
+ s->v_bits[i] = getint();
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+proc_p getptable(pname)
|
|
|
+ char *pname;
|
|
|
+{
|
|
|
+ short i;
|
|
|
+ proc_p head, p, *pp;
|
|
|
+ short all;
|
|
|
+
|
|
|
+ if ((f = fopen(pname,"r")) == NULL) {
|
|
|
+ error("cannot open %s",pname);
|
|
|
+ }
|
|
|
+
|
|
|
+ plength = getshort(); /* table is preceded by its length */
|
|
|
+ assert(plength >= 0);
|
|
|
+ assert(plength < 1000); /* See if its a reasonable number */
|
|
|
+ pmap = (proc_p *) newmap(plength); /* allocate the pmap table */
|
|
|
+
|
|
|
+ all = getshort();
|
|
|
+ head = (proc_p) 0;
|
|
|
+ pp = &head;
|
|
|
+ for (i = 0; i < plength; i++) {
|
|
|
+ if (feof(f)) {
|
|
|
+ error("unexpected eof %s", pname);
|
|
|
+ }
|
|
|
+ p = newproc();
|
|
|
+ p->p_id = getshort();
|
|
|
+ assert(p->p_id > 0 && p->p_id <= plength);
|
|
|
+ pmap[p->p_id] = p;
|
|
|
+ p->p_flags1 = getbyte();
|
|
|
+ if (p->p_flags1 & PF_BODYSEEN) {
|
|
|
+ p->p_nrlabels = getshort();
|
|
|
+ p->p_localbytes = getoff();
|
|
|
+ p->p_nrformals = getoff();
|
|
|
+ if (all) {
|
|
|
+ p->p_change = newchange();
|
|
|
+ p->p_change->c_ext = getcset();
|
|
|
+ p->p_change->c_flags = getshort();
|
|
|
+ p->p_use = newuse();
|
|
|
+ p->p_use->u_flags = getshort();
|
|
|
+ p->p_calling = getcset();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *pp = p;
|
|
|
+ pp = &(p->p_next);
|
|
|
+ }
|
|
|
+ fclose(f);
|
|
|
+ OUTTRACE("have read proc table of length %d",plength);
|
|
|
+ return head; /* pointer to first structure of list */
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/* getdtable */
|
|
|
+
|
|
|
+dblock_p getdtable(dname)
|
|
|
+ char *dname;
|
|
|
+{
|
|
|
+ /* Read the data block table. Every data block may
|
|
|
+ * have a list of objects and a list of values (arguments),
|
|
|
+ * each of which is also represented by a structure.
|
|
|
+ * So the input file contains a mixture of dblock,
|
|
|
+ * obj and arg records, each one having its own
|
|
|
+ * attributes. A mark indicates which one comes next.
|
|
|
+ * We assume that the syntactic structure of the input
|
|
|
+ * is correct.
|
|
|
+ */
|
|
|
+
|
|
|
+ dblock_p head, d, *dp;
|
|
|
+ obj_p obj, *op;
|
|
|
+ arg_p arg, *ap;
|
|
|
+ /* dp, op an ap tell how the next dblock/obj/arg
|
|
|
+ * has to be linked.
|
|
|
+ */
|
|
|
+ int n;
|
|
|
+
|
|
|
+ head = (dblock_p) 0;
|
|
|
+ dp = &head;
|
|
|
+ if ((f = fopen(dname,"r")) == NULL) {
|
|
|
+ error("cannot open %s", dname);
|
|
|
+ }
|
|
|
+ olength = getshort();
|
|
|
+ assert(olength >= 0);
|
|
|
+ assert(olength < 5000); /* See if its a reasonable number */
|
|
|
+ /* total number of objects */
|
|
|
+ omap = (obj_p *) newmap(olength); /* allocate omap table */
|
|
|
+
|
|
|
+ while (TRUE) {
|
|
|
+ n = getmark();
|
|
|
+ if (feof(f)) break;
|
|
|
+ switch(n) {
|
|
|
+ case MARK_DBLOCK:
|
|
|
+ d = *dp = newdblock();
|
|
|
+ op = &d->d_objlist;
|
|
|
+ ap = &d->d_values;
|
|
|
+ dp = &d->d_next;
|
|
|
+ d->d_id = getshort();
|
|
|
+ d->d_pseudo = getbyte();
|
|
|
+ d->d_size = getoff();
|
|
|
+ d->d_fragmnr = getshort();
|
|
|
+ d->d_flags1 = getbyte();
|
|
|
+ break;
|
|
|
+ case MARK_OBJ:
|
|
|
+ obj = *op = newobject();
|
|
|
+ op = &obj->o_next;
|
|
|
+ obj->o_dblock = d;
|
|
|
+ obj->o_id = getshort();
|
|
|
+ assert(obj->o_id >0);
|
|
|
+ assert(obj->o_id <= olength);
|
|
|
+ omap[obj->o_id] = obj;
|
|
|
+ obj->o_size = getoff();
|
|
|
+ obj->o_off = getoff();
|
|
|
+ break;
|
|
|
+ case MARK_ARG:
|
|
|
+ arg = *ap = newarg(ARGOFF);
|
|
|
+ ap = &arg->a_next;
|
|
|
+ arg->a_a.a_offset = getoff();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ assert(FALSE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ OUTTRACE("have read data table, %d objects",olength);
|
|
|
+ return head;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+/* getbblocks */
|
|
|
+
|
|
|
+STATIC argstring(length,abp)
|
|
|
+ short length;
|
|
|
+ register argb_p abp;
|
|
|
+{
|
|
|
+
|
|
|
+ while (length--) {
|
|
|
+ if (abp->ab_index == NARGBYTES)
|
|
|
+ abp = abp->ab_next = newargb();
|
|
|
+ abp->ab_contents[abp->ab_index++] = getbyte();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+STATIC arg_p readargs()
|
|
|
+{
|
|
|
+ /* Read a list of arguments and allocate structures
|
|
|
+ * for them. Return a pointer to the head of the list.
|
|
|
+ */
|
|
|
+
|
|
|
+ arg_p head, arg, *ap;
|
|
|
+ byte t;
|
|
|
+ short length;
|
|
|
+
|
|
|
+ ap = &head;
|
|
|
+ for (;;) {
|
|
|
+ /* every argument list is terminated by an
|
|
|
+ * ARGCEND byte in Intermediate Code.
|
|
|
+ */
|
|
|
+ t = getbyte();
|
|
|
+ if (t == (byte) ARGCEND) {
|
|
|
+ return head;
|
|
|
+ }
|
|
|
+ arg = *ap = newarg(t);
|
|
|
+ ap = &arg->a_next;
|
|
|
+ switch((short) t) {
|
|
|
+ case ARGOFF:
|
|
|
+ arg->a_a.a_offset = getoff();
|
|
|
+ break;
|
|
|
+ case ARGINSTRLAB:
|
|
|
+ arg->a_a.a_instrlab = getshort();
|
|
|
+ break;
|
|
|
+ case ARGOBJECT:
|
|
|
+ arg->a_a.a_obj = omap[getshort()];
|
|
|
+ /* Read an object identifier (o_id)
|
|
|
+ * and use the omap table to obtain
|
|
|
+ * a pointer to the rigth obj struct.
|
|
|
+ */
|
|
|
+ break;
|
|
|
+ case ARGPROC:
|
|
|
+ arg->a_a.a_proc = pmap[getshort()];
|
|
|
+ /* Read a procedure identifier (p_id) */
|
|
|
+ break;
|
|
|
+ case ARGSTRING:
|
|
|
+ length = getshort();
|
|
|
+ argstring(length, &arg->a_a.a_string);
|
|
|
+ break;
|
|
|
+ case ARGICN:
|
|
|
+ case ARGUCN:
|
|
|
+ case ARGFCN:
|
|
|
+ length = getshort();
|
|
|
+ arg->a_a.a_con.ac_length = length;
|
|
|
+ /* size of the constant */
|
|
|
+ argstring(getshort(),
|
|
|
+ &arg->a_a.a_con.ac_con);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ assert(FALSE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+STATIC line_p read_line(p_out)
|
|
|
+ proc_p *p_out;
|
|
|
+{
|
|
|
+ /* Read a line of EM code (i.e. one instruction)
|
|
|
+ * and its arguments (if any).
|
|
|
+ * In Intermediate Code, the first byte is the
|
|
|
+ * instruction code and the second byte denotes the kind
|
|
|
+ * of operand(s) that follow.
|
|
|
+ */
|
|
|
+
|
|
|
+ line_p lnp;
|
|
|
+ byte instr;
|
|
|
+
|
|
|
+ instr = getbyte();
|
|
|
+ if (feof(f)) return (line_p) 0;
|
|
|
+ lnp = newline(getbyte());
|
|
|
+ linecount++;
|
|
|
+ lnp->l_instr = instr;
|
|
|
+ switch(TYPE(lnp)) {
|
|
|
+ /* read the operand(s) */
|
|
|
+ case OPSHORT:
|
|
|
+ SHORT(lnp) = getshort();
|
|
|
+ break;
|
|
|
+ case OPOFFSET:
|
|
|
+ OFFSET(lnp) = getoff();
|
|
|
+ break;
|
|
|
+ case OPINSTRLAB:
|
|
|
+ INSTRLAB(lnp) = getshort();
|
|
|
+ if (instr == op_lab) {
|
|
|
+ /* defining occurrence of an
|
|
|
+ * instruction label.
|
|
|
+ */
|
|
|
+ lmap[INSTRLAB(lnp)] = lnp;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case OPOBJECT:
|
|
|
+ OBJ(lnp) = omap[getshort()];
|
|
|
+ break;
|
|
|
+ case OPPROC:
|
|
|
+ PROC(lnp) = pmap[getshort()];
|
|
|
+ if ((instr & BMASK) == ps_pro) {
|
|
|
+ /* enter new procedure: allocate a
|
|
|
+ * label map and a label-block map table.
|
|
|
+ */
|
|
|
+ *p_out = PROC(lnp);
|
|
|
+ llength = (*p_out)->p_nrlabels;
|
|
|
+ lmap = (line_p *) newmap(llength);
|
|
|
+ /* maps lab_id to line structure */
|
|
|
+ lbmap = (bblock_p *) newmap(llength);
|
|
|
+ /* maps lab_id to bblock structure */
|
|
|
+ lastlabid = llength;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case OPLIST:
|
|
|
+ ARG(lnp) = readargs();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ assert(TYPE(lnp) == OPNO);
|
|
|
+ }
|
|
|
+ return lnp;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+STATIC message(lnp)
|
|
|
+ line_p lnp;
|
|
|
+{
|
|
|
+ /* See if lnp is some useful message.
|
|
|
+ * (e.g. a message telling that a certain local variable
|
|
|
+ * will never be referenced indirectly, so it may be put
|
|
|
+ * in a register. If so, add it to the mesregs set.)
|
|
|
+ */
|
|
|
+
|
|
|
+ assert(ARG(lnp)->a_type == ARGOFF);
|
|
|
+ switch((int) aoff(ARG(lnp),0)) {
|
|
|
+ case ms_reg:
|
|
|
+ if (ARG(lnp)->a_next != (arg_p) 0) {
|
|
|
+ /* take only "mes 3" with further arguments */
|
|
|
+ Ladd(lnp,&mesregs);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case ms_err:
|
|
|
+ error("ms_err encountered");
|
|
|
+ case ms_opt:
|
|
|
+ error("ms_opt encountered");
|
|
|
+ case ms_emx:
|
|
|
+ ws = aoff(ARG(lnp),1);
|
|
|
+ ps = aoff(ARG(lnp),2);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+STATIC line_p getlines(lf,n,p_out,collect_mes)
|
|
|
+ FILE *lf;
|
|
|
+ int n;
|
|
|
+ proc_p *p_out;
|
|
|
+ bool collect_mes;
|
|
|
+{
|
|
|
+ /* Read n lines of EM text and doubly link them.
|
|
|
+ * Also process messages.
|
|
|
+ */
|
|
|
+
|
|
|
+ line_p head, *pp, l, lprev;
|
|
|
+
|
|
|
+ f = lf; /* EM input file */
|
|
|
+ pp = &head;
|
|
|
+ lprev = (line_p) 0;
|
|
|
+ while (n--) {
|
|
|
+ l = *pp = read_line(p_out);
|
|
|
+ PREV(l) = lprev;
|
|
|
+ pp = &l->l_next;
|
|
|
+ lprev = l;
|
|
|
+ if (collect_mes && INSTR(l) == ps_mes) {
|
|
|
+ message(l);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *pp = (line_p) 0;
|
|
|
+ return head;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+bool getunit(gf,lf,kind_out,g_out,l_out,p_out,collect_mes)
|
|
|
+ FILE *gf,*lf;
|
|
|
+ short *kind_out;
|
|
|
+ bblock_p *g_out;
|
|
|
+ line_p *l_out;
|
|
|
+ proc_p *p_out;
|
|
|
+ bool collect_mes;
|
|
|
+{
|
|
|
+ /* Read control flow graph (gf) and EM text (lf) of the next procedure.
|
|
|
+ * A pointer to the proctable entry of the read procedure is
|
|
|
+ * returned via p_out.
|
|
|
+ * This routine also constructs the bmap and lpmap tables.
|
|
|
+ * Note that we allocate structs for basic blocks and loops
|
|
|
+ * at their first reference rather than at when we read them.
|
|
|
+ */
|
|
|
+
|
|
|
+ int n,i;
|
|
|
+ bblock_p head, *pp, b;
|
|
|
+ loop_p lp;
|
|
|
+
|
|
|
+ f = gf;
|
|
|
+ blength = getshort(); /* # basic blocks in this procedure */
|
|
|
+ if (feof(f)) return FALSE;
|
|
|
+ if (blength == 0) {
|
|
|
+ /* data unit */
|
|
|
+ *kind_out = LDATA;
|
|
|
+ n = getshort();
|
|
|
+ *l_out = getlines(lf,n,p_out,collect_mes);
|
|
|
+ return TRUE;
|
|
|
+ }
|
|
|
+ *kind_out = LTEXT;
|
|
|
+ bmap = (bblock_p *) newmap(blength); /* maps block_id on bblock_p */
|
|
|
+ lplength = getshort(); /* # loops in this procedure */
|
|
|
+ lpmap = (loop_p *) newmap(lplength); /* maps loop_id on loop_p */
|
|
|
+
|
|
|
+ /* Read the basic blocks and the EM text */
|
|
|
+ pp = &head; /* we use a pointer-to-a-pointer to link the structs */
|
|
|
+ for (i = 0; i < blength; i++) {
|
|
|
+ b = getblock(getshort());
|
|
|
+ n = getshort(); /* #instructions in the block */
|
|
|
+ b->b_succ = getlset(getblock);
|
|
|
+ b->b_pred = getlset(getblock);
|
|
|
+ b->b_idom = getblock(getshort());
|
|
|
+ b->b_loops = getlset(getloop);
|
|
|
+ b->b_flags = getshort();
|
|
|
+ b->b_start = getlines(lf,n,p_out,collect_mes); /* read EM text */
|
|
|
+ *pp = b;
|
|
|
+ pp = &b->b_next;
|
|
|
+ f = gf;
|
|
|
+ }
|
|
|
+ lastbid = blength; /* last block_id */
|
|
|
+
|
|
|
+ /* read the information about loops */
|
|
|
+ curproc->p_loops = Lempty_set();
|
|
|
+ for (i = 0; i < lplength; i++) {
|
|
|
+ lp = getloop(getshort());
|
|
|
+ lp->lp_level = getshort(); /* nesting level */
|
|
|
+ lp->lp_entry = getblock(getshort()); /* entry block of the loop */
|
|
|
+ lp->lp_end = getblock(getshort()); /* tail of back edge of loop */
|
|
|
+ Ladd(lp,&curproc->p_loops);
|
|
|
+ }
|
|
|
+ *g_out = head;
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* The procedure getbblocks is used only by the Control Flow phase.
|
|
|
+ * It reads the EM textfile and partitions every procedure into
|
|
|
+ * a number of basic blocks.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+#define LABEL0 0
|
|
|
+#define LABEL 1
|
|
|
+#define NORMAL 2
|
|
|
+#define JUMP 3
|
|
|
+#define END 4
|
|
|
+#define AFTERPRO 5
|
|
|
+#define INIT 6
|
|
|
+
|
|
|
+
|
|
|
+/* These global variables are used by getbblocks and nextblock. */
|
|
|
+
|
|
|
+STATIC bblock_p b, *bp; /* b is the current basic block, bp is
|
|
|
+ * the address where the next block has
|
|
|
+ * to be linked.
|
|
|
+ */
|
|
|
+STATIC line_p lnp, *lp; /* lnp is the current line, lp is
|
|
|
+ * the address where the next line
|
|
|
+ * has to be linked.
|
|
|
+ */
|
|
|
+STATIC short state; /* We use a finite state machine with the
|
|
|
+ * following states:
|
|
|
+ * LABEL0: after the first (successive)
|
|
|
+ * instruction label.
|
|
|
+ * LABEL1: after at least two successive
|
|
|
+ * instruction labels.
|
|
|
+ * NORMAL: after a normal instruction.
|
|
|
+ * JUMP: after a branch (conditional,
|
|
|
+ * unconditional or CSA/CSB).
|
|
|
+ * END: after an END pseudo
|
|
|
+ * AFTERPRO: after we've read a PRO pseudo
|
|
|
+ * INIT: initial state
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+STATIC nextblock()
|
|
|
+{
|
|
|
+ /* allocate a new basic block structure and
|
|
|
+ * set b, bp and lp.
|
|
|
+ */
|
|
|
+
|
|
|
+ b = *bp = freshblock();
|
|
|
+ bp = &b->b_next;
|
|
|
+ b->b_start = lnp;
|
|
|
+ b->b_succ = Lempty_set();
|
|
|
+ b->b_pred = Lempty_set();
|
|
|
+ b->b_extend = newcfbx(); /* basic block extension for CF */
|
|
|
+ b->b_extend->bx_cf.bx_bucket = Lempty_set();
|
|
|
+ b->b_extend->bx_cf.bx_semi = 0;
|
|
|
+ lp = &lnp->l_next;
|
|
|
+#ifdef TRACE
|
|
|
+ fprintf(stderr,"new basic block, id = %d\n",lastbid);
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+STATIC short kind(lnp)
|
|
|
+ line_p lnp;
|
|
|
+{
|
|
|
+ /* determine if lnp is a label, branch, end or otherwise */
|
|
|
+
|
|
|
+ short instr;
|
|
|
+ byte flow;
|
|
|
+
|
|
|
+ if ((instr = INSTR(lnp)) == op_lab) return (short) LABEL;
|
|
|
+ if (instr == ps_end) return (short) END;
|
|
|
+ if (instr > sp_lmnem) return (short) NORMAL; /* pseudo */
|
|
|
+ if ((flow = (em_flag[instr-sp_fmnem] & EM_FLO)) == FLO_C ||
|
|
|
+ flow == FLO_T) return (short) JUMP; /* conditional/uncond. jump */
|
|
|
+ return (short) NORMAL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+bool getbblocks(fp,kind_out,n_out,g_out,l_out)
|
|
|
+ FILE *fp;
|
|
|
+ short *kind_out;
|
|
|
+ short *n_out;
|
|
|
+ bblock_p *g_out;
|
|
|
+ line_p *l_out;
|
|
|
+{
|
|
|
+ bblock_p head = (bblock_p) 0;
|
|
|
+ line_p headl = (line_p) 0;
|
|
|
+
|
|
|
+ curproc = (proc_p) 0;
|
|
|
+ /* curproc will get a value when we encounter a PRO pseudo.
|
|
|
+ * If there is no such pseudo, we're reading only data
|
|
|
+ * declarations or messages (outside any proc.).
|
|
|
+ */
|
|
|
+ f = fp;
|
|
|
+ lastbid = (block_id) 0; /* block identier */
|
|
|
+ state = INIT; /* initial state */
|
|
|
+ bp = &head;
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+#ifdef TRACE
|
|
|
+ fprintf(stderr,"state = %d\n",state);
|
|
|
+#endif
|
|
|
+ switch(state) {
|
|
|
+ case LABEL0:
|
|
|
+ nextblock();
|
|
|
+ /* Fall through !! */
|
|
|
+ case LABEL:
|
|
|
+ lbmap[INSTRLAB(lnp)] = b;
|
|
|
+ /* The lbmap table contains for each
|
|
|
+ * label_id the basic block of that label.
|
|
|
+ */
|
|
|
+ lnp = read_line(&curproc);
|
|
|
+ state = kind(lnp);
|
|
|
+ if (state != END) {
|
|
|
+ *lp = lnp;
|
|
|
+ lp = &lnp->l_next;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case NORMAL:
|
|
|
+ lnp = read_line(&curproc);
|
|
|
+ if ( (state = kind(lnp)) == LABEL) {
|
|
|
+ /* If we come accross a label
|
|
|
+ * here, it must be the beginning
|
|
|
+ * of a new basic block.
|
|
|
+ */
|
|
|
+ state = LABEL0;
|
|
|
+ } else {
|
|
|
+ if (state != END) {
|
|
|
+ *lp = lnp;
|
|
|
+ lp = &lnp->l_next;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case JUMP:
|
|
|
+ lnp = read_line(&curproc);
|
|
|
+ /* fall through ... */
|
|
|
+ case AFTERPRO:
|
|
|
+ switch(state = kind(lnp)) {
|
|
|
+ case LABEL:
|
|
|
+ state = LABEL0;
|
|
|
+ break;
|
|
|
+ case JUMP:
|
|
|
+ case NORMAL:
|
|
|
+ nextblock();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case END:
|
|
|
+ *lp = lnp;
|
|
|
+#ifdef TRACE
|
|
|
+ fprintf(stderr,"at end of proc, %d blocks\n",lastbid);
|
|
|
+#endif
|
|
|
+ if (head == (bblock_p) 0) {
|
|
|
+ *kind_out = LDATA;
|
|
|
+ *l_out = headl;
|
|
|
+ } else {
|
|
|
+ *kind_out = LTEXT;
|
|
|
+ *g_out = head;
|
|
|
+ *n_out = (short) lastbid;
|
|
|
+ /* number of basic blocks */
|
|
|
+ }
|
|
|
+ return TRUE;
|
|
|
+ case INIT:
|
|
|
+ lnp = read_line(&curproc);
|
|
|
+ if (feof(f)) return FALSE;
|
|
|
+ if (INSTR(lnp) == ps_pro) {
|
|
|
+ state = AFTERPRO;
|
|
|
+ } else {
|
|
|
+ state = NORMAL;
|
|
|
+ headl = lnp;
|
|
|
+ lp = &lnp->l_next;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* The following routines are only used by the Inline Substitution phase */
|
|
|
+
|
|
|
+call_p getcall(cf)
|
|
|
+ FILE *cf;
|
|
|
+{
|
|
|
+ /* read a call from the call-file */
|
|
|
+
|
|
|
+ call_p c;
|
|
|
+ proc_p voided;
|
|
|
+ actual_p act,*app;
|
|
|
+ short n,m;
|
|
|
+
|
|
|
+ f = cf;
|
|
|
+ c = newcall();
|
|
|
+ n = getshort(); /* void nesting level */
|
|
|
+ if (feof(f)) return (call_p) 0;
|
|
|
+ c->cl_caller = pmap[getshort()];
|
|
|
+ c->cl_id = getshort();
|
|
|
+ c->cl_proc = pmap[getshort()];
|
|
|
+ c->cl_looplevel = getbyte();
|
|
|
+ c->cl_flags = getbyte();
|
|
|
+ c->cl_ratio = getshort();
|
|
|
+ app = &c->cl_actuals;
|
|
|
+ n = getshort();
|
|
|
+ while(n--) {
|
|
|
+ act = newactual();
|
|
|
+ m = getshort();
|
|
|
+ act->ac_size = getoff();
|
|
|
+ act->ac_inl = getbyte();
|
|
|
+ act->ac_exp = getlines(cf,m,&voided);
|
|
|
+ *app = act;
|
|
|
+ app = &act->ac_next;
|
|
|
+ }
|
|
|
+ *app = (actual_p) 0;
|
|
|
+ return c;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+line_p get_text(lf,p_out)
|
|
|
+ FILE *lf;
|
|
|
+ proc_p *p_out;
|
|
|
+{
|
|
|
+ /* Read the EM text of one unit
|
|
|
+ * If it is a procedure, set p_out to
|
|
|
+ * the proc. just read. Else set p_out
|
|
|
+ * to 0.
|
|
|
+ */
|
|
|
+
|
|
|
+ line_p dumhead, l, lprev;
|
|
|
+ loop_p *oldlpmap = lpmap;
|
|
|
+ line_p *oldlmap = lmap;
|
|
|
+ short oldllength = llength;
|
|
|
+ short oldlastlabid = lastlabid;
|
|
|
+
|
|
|
+ f = lf;
|
|
|
+ *p_out = (proc_p) 0;
|
|
|
+ dumhead = newline(OPNO);
|
|
|
+ /* The list of instructions is preceeded by a dummy
|
|
|
+ * line, to simplify list manipulation
|
|
|
+ */
|
|
|
+ dumhead->l_instr = op_nop; /* just for fun */
|
|
|
+ lprev = dumhead;
|
|
|
+ for (;;) {
|
|
|
+ l = read_line(p_out);
|
|
|
+ if (feof(f)) return (line_p) 0;
|
|
|
+ lprev->l_next = l;
|
|
|
+ PREV(l) = lprev;
|
|
|
+ if (INSTR(l) == ps_end) break;
|
|
|
+ if (INSTR(l) == ps_mes) {
|
|
|
+ message(l);
|
|
|
+ }
|
|
|
+ lprev = l;
|
|
|
+ }
|
|
|
+ /* The tables that map labels to instructions
|
|
|
+ * and labels to basic blocks are not used.
|
|
|
+ */
|
|
|
+ if (*p_out != (proc_p) 0) {
|
|
|
+ oldmap(lmap,llength);
|
|
|
+ oldmap(lbmap,llength);
|
|
|
+ lmap = oldlmap;
|
|
|
+ lpmap = oldlpmap;
|
|
|
+ }
|
|
|
+ llength = oldllength;
|
|
|
+ lastlabid = oldlastlabid;
|
|
|
+ return dumhead;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+calcnt_p getcc(ccf,p)
|
|
|
+ FILE *ccf;
|
|
|
+ proc_p p;
|
|
|
+{
|
|
|
+ /* Get call-count info of procedure p */
|
|
|
+
|
|
|
+ calcnt_p head,cc,*ccp;
|
|
|
+ short i;
|
|
|
+
|
|
|
+ fseek(ccf,p->p_extend->px_il.p_ccaddr,0);
|
|
|
+ f = ccf;
|
|
|
+ head = (calcnt_p) 0;
|
|
|
+ ccp = &head;
|
|
|
+ for (i = getshort(); i != (short) 0; i--) {
|
|
|
+ cc = *ccp = newcalcnt();
|
|
|
+ cc->cc_proc = pmap[getshort()];
|
|
|
+ cc->cc_count = getshort();
|
|
|
+ ccp = &cc->cc_next;
|
|
|
+ }
|
|
|
+ return head;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* The following routine is only used by the Compact Assembly generation phase,
|
|
|
+ * which does not read basic blocks.
|
|
|
+ */
|
|
|
+
|
|
|
+line_p get_ca_lines(lf,p_out)
|
|
|
+ FILE *lf;
|
|
|
+ proc_p *p_out;
|
|
|
+{
|
|
|
+ /* Read lines of EM text and link them.
|
|
|
+ * Register messages are outputted immediately after the PRO.
|
|
|
+ */
|
|
|
+
|
|
|
+ line_p head, *pp, l;
|
|
|
+ line_p headm, *mp;
|
|
|
+ arg_p a;
|
|
|
+
|
|
|
+ f = lf; /* EM input file */
|
|
|
+ pp = &head;
|
|
|
+ mp = &headm;
|
|
|
+ headm = (line_p) 0;
|
|
|
+ while (TRUE) {
|
|
|
+ l = read_line(p_out);
|
|
|
+ if (feof(f)) break;
|
|
|
+ assert (l != (line_p) 0);
|
|
|
+ if (INSTR(l) == ps_end && INSTR(head) != ps_pro) {
|
|
|
+ /* Delete end pseudo after data-unit */
|
|
|
+ oldline(l);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (INSTR(l) == ps_mes && l->l_a.la_arg->a_a.a_offset == ms_reg) {
|
|
|
+ /* l is a register message */
|
|
|
+ if (l->l_a.la_arg->a_next == (arg_p) 0) {
|
|
|
+ /* register message without arguments */
|
|
|
+ oldline(l);
|
|
|
+ } else {
|
|
|
+ *mp = l;
|
|
|
+ mp = &l->l_next;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ *pp = l;
|
|
|
+ pp = &l->l_next;
|
|
|
+ }
|
|
|
+ if (INSTR(l) == ps_end) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *pp = (line_p) 0;
|
|
|
+ if (INSTR(head) == ps_pro) {
|
|
|
+ /* append register message without arguments to list */
|
|
|
+ l = newline(OPLIST);
|
|
|
+ l->l_instr = ps_mes;
|
|
|
+ a = ARG(l) = newarg(ARGOFF);
|
|
|
+ a->a_a.a_offset = ms_reg;
|
|
|
+ *mp = l;
|
|
|
+ l->l_next = head->l_next;
|
|
|
+ head->l_next = headm;
|
|
|
+ } else {
|
|
|
+ assert(headm == (line_p) 0);
|
|
|
+ }
|
|
|
+ return head;
|
|
|
+}
|