Most warnings are for functions implicitly returning int. Change most
of these functions to return void. (Traditional K&R C had no void
type, but C89 has it.)
Add prototypes to most function declarations in headers. This is
easy, because ego declares most of its extern functions, and the
comments listed most parameters. There were a few outdated or missing
declarations, and a few .c files that failed to include an .h with the
declarations.
Add prototypes to a few function definitions in .c files. Most
functions still have traditional K&R definitions. Most STATIC
functions still don't have prototypes, because they have no earlier
declaration where I would have added the prototype.
Change some prototypes in util/ego/share/alloc.h. Functions newmap()
and oldmap() handle an array of pointers to something; change the
array's type from `short **` to `void **`. Callers use casts to go
between `void **` and the correct type, like `line_p *`. Function
oldtable() takes a `short *`, not a `short **`; I added the wrong type
in 5bbbaf4
.
Make a few other changes to silence warnings. There are a few places
where clang wants extra parentheses in the code.
Edit util/ego/ra/build.lua to add the missing dependency on ra*.h; I
needed this to prevent crashes from ra.
424 lines
8.8 KiB
C
424 lines
8.8 KiB
C
/* $Id$ */
|
|
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
/* P U T . C */
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <em_pseu.h>
|
|
#include <em_spec.h>
|
|
#include "types.h"
|
|
#include "global.h"
|
|
#include "debug.h"
|
|
#include "def.h"
|
|
#include "map.h"
|
|
#include "lset.h"
|
|
#include "cset.h"
|
|
#include "alloc.h"
|
|
#include "put.h"
|
|
|
|
FILE *curoutp;
|
|
|
|
|
|
/* The output can be either 'typed' or 'untyped'. Typed data
|
|
* consists of a value preceded by a byte specifying what kind
|
|
* of value it is (e.g. 2 bytes constant, 4 bytes constant,
|
|
* proc-id, lab-id, string etc.). Untyped data consists
|
|
* of the value only. We use typed data for the EM text and
|
|
* untyped data for all other files.
|
|
*/
|
|
|
|
/* putlines */
|
|
|
|
STATIC void putstr(argb_p);
|
|
STATIC void outlab(lab_id);
|
|
STATIC void outobject(obj_p);
|
|
|
|
STATIC void putargs(arg_p ap)
|
|
{
|
|
while (ap != (arg_p) 0) {
|
|
outbyte((byte) ap->a_type & BMASK);
|
|
switch(ap->a_type) {
|
|
case ARGOFF:
|
|
outoff(ap->a_a.a_offset);
|
|
break;
|
|
case ARGINSTRLAB:
|
|
outlab(ap->a_a.a_instrlab);
|
|
break;
|
|
case ARGOBJECT:
|
|
outobject(ap->a_a.a_obj);
|
|
break;
|
|
case ARGPROC:
|
|
outproc(ap->a_a.a_proc);
|
|
break;
|
|
case ARGSTRING:
|
|
putstr(&ap->a_a.a_string);
|
|
break;
|
|
case ARGICN:
|
|
case ARGUCN:
|
|
case ARGFCN:
|
|
outshort(ap->a_a.a_con.ac_length);
|
|
putstr(&ap->a_a.a_con.ac_con);
|
|
break;
|
|
}
|
|
ap = ap->a_next;
|
|
}
|
|
outbyte((byte) ARGCEND);
|
|
}
|
|
|
|
|
|
|
|
STATIC void putstr(argb_p abp) {
|
|
argb_p tbp;
|
|
int length;
|
|
|
|
length = 0;
|
|
tbp = abp;
|
|
while (tbp!= (argb_p) 0) {
|
|
length += tbp->ab_index;
|
|
tbp = tbp->ab_next;
|
|
}
|
|
outshort(length);
|
|
while (abp != (argb_p) 0) {
|
|
for (length=0;length<abp->ab_index;length++)
|
|
outbyte( (byte) abp->ab_contents[length] );
|
|
abp = abp->ab_next;
|
|
}
|
|
}
|
|
|
|
|
|
void outoff(offset off) {
|
|
|
|
outshort( (short) (off&0177777L) );
|
|
outshort( (short) (off>>16) );
|
|
}
|
|
|
|
|
|
void outshort(short i) {
|
|
|
|
outbyte( (byte) (i&BMASK) );
|
|
outbyte( (byte) (i>>8) );
|
|
}
|
|
|
|
|
|
STATIC void outint(int i)
|
|
{
|
|
/* Write an integer to the output file. This routine is
|
|
* only used when outputting a bitvector-set. We expect an
|
|
* integer to be either a short or a long.
|
|
*/
|
|
|
|
if (sizeof(int) == sizeof(short)) {
|
|
outshort(i);
|
|
} else {
|
|
assert (sizeof(int) == sizeof(offset));
|
|
outoff((offset) i);
|
|
}
|
|
}
|
|
|
|
STATIC void outlab(lab_id lid) {
|
|
outshort((short) lid);
|
|
}
|
|
|
|
|
|
STATIC void outobject(obj_p obj) {
|
|
outshort((short) obj->o_id);
|
|
}
|
|
|
|
|
|
void outproc(proc_p p) {
|
|
outshort((short) p->p_id);
|
|
}
|
|
|
|
|
|
short putlines(line_p l, FILE *lf)
|
|
{
|
|
/* Output the list of em instructions headed by l.
|
|
* Return the number of instruction written.
|
|
*/
|
|
|
|
register line_p lnp;
|
|
line_p next;
|
|
short instr;
|
|
short count= 0;
|
|
|
|
curoutp = lf; /* Set f to the EM-text output file */
|
|
for (lnp = l; lnp != (line_p) 0; lnp = next) {
|
|
VL(lnp);
|
|
count++;
|
|
next = lnp->l_next;
|
|
instr = INSTR(lnp);
|
|
outbyte((byte) instr);
|
|
outbyte((byte) TYPE(lnp));
|
|
switch(TYPE(lnp)) {
|
|
case OPSHORT:
|
|
outshort(SHORT(lnp));
|
|
break;
|
|
case OPOFFSET:
|
|
outoff(OFFSET(lnp));
|
|
break;
|
|
case OPINSTRLAB:
|
|
outlab(INSTRLAB(lnp));
|
|
break;
|
|
case OPOBJECT:
|
|
outobject(OBJ(lnp));
|
|
break;
|
|
case OPPROC:
|
|
outproc(PROC(lnp));
|
|
break;
|
|
case OPLIST:
|
|
putargs(ARG(lnp));
|
|
break;
|
|
}
|
|
oldline(lnp);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* putdtable */
|
|
|
|
#define outmark(m) outbyte((byte) m)
|
|
|
|
|
|
STATIC void putobjects(obj_p obj)
|
|
{
|
|
while (obj != (obj_p) 0) {
|
|
outmark(MARK_OBJ);
|
|
outshort(obj->o_id);
|
|
outoff(obj->o_size);
|
|
outoff(obj->o_off);
|
|
obj = obj->o_next;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
STATIC void putvalues(arg_p arg)
|
|
{
|
|
while (arg != (arg_p) 0) {
|
|
assert(arg->a_type == ARGOFF);
|
|
outmark(MARK_ARG);
|
|
outoff(arg->a_a.a_offset);
|
|
arg = arg->a_next;
|
|
}
|
|
}
|
|
void putdtable(dblock_p head, FILE *df)
|
|
{
|
|
/* Write the datablock table to the data block file df. */
|
|
|
|
register dblock_p dbl;
|
|
register obj_p obj;
|
|
dblock_p next;
|
|
register short n = 0;
|
|
|
|
curoutp = df; /* set f to the data block output file */
|
|
/* Count the number of objects */
|
|
for (dbl = head; dbl != (dblock_p) 0; dbl = dbl->d_next) {
|
|
for (obj = dbl->d_objlist; obj != (obj_p) 0;
|
|
obj = obj->o_next) {
|
|
n++;
|
|
}
|
|
}
|
|
outshort(n); /* The table is preceded by #objects . */
|
|
for (dbl = head; dbl != (dblock_p) 0; dbl = next) {
|
|
next = dbl->d_next;
|
|
outmark(MARK_DBLOCK);
|
|
outshort(dbl->d_id);
|
|
outbyte(dbl->d_pseudo);
|
|
outoff(dbl->d_size);
|
|
outshort(dbl->d_fragmnr);
|
|
outbyte(dbl->d_flags1);
|
|
putobjects(dbl->d_objlist);
|
|
putvalues(dbl->d_values);
|
|
olddblock(dbl);
|
|
}
|
|
fclose(curoutp);
|
|
if (omap != (obj_p *) 0) {
|
|
oldmap((void **) omap,olength); /* release memory for omap */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* putptable */
|
|
|
|
|
|
|
|
STATIC void outcset(cset s)
|
|
{
|
|
/* A 'compact' set is represented externally as a row of words
|
|
* (its bitvector) preceded by its length.
|
|
*/
|
|
|
|
register short i;
|
|
|
|
outshort(s->v_size);
|
|
for (i = 0; i <= DIVWL(s->v_size - 1); i++) {
|
|
outint(s->v_bits[i]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void putptable(proc_p head, FILE *pf, bool all)
|
|
{
|
|
register proc_p p;
|
|
proc_p next;
|
|
register short n = 0;
|
|
/* Write the proc table */
|
|
|
|
curoutp = pf;
|
|
/* Determine the number of procs */
|
|
for (p = head; p != (proc_p) 0; p = p->p_next) {
|
|
n++;
|
|
}
|
|
outshort(n); /* The table is preceded by its length. */
|
|
outshort ((all?1:0)); /* if all=false, only some of the attributes
|
|
are written. */
|
|
for (p = head; p != (proc_p) 0; p = next) {
|
|
next = p->p_next;
|
|
outshort(p->p_id);
|
|
outbyte(p->p_flags1);
|
|
if (p->p_flags1 & PF_BODYSEEN) {
|
|
/* If we have no access to the EM text of the
|
|
* body of a procedure, we have no information
|
|
* about it whatsoever, so there is nothing
|
|
* to output in that case.
|
|
*/
|
|
outshort(p->p_nrlabels);
|
|
outoff(p->p_localbytes);
|
|
outoff(p->p_nrformals);
|
|
if (all) {
|
|
outcset(p->p_change->c_ext);
|
|
outshort(p->p_change->c_flags);
|
|
outshort(p->p_use->u_flags);
|
|
outcset(p->p_calling);
|
|
Cdeleteset(p->p_change->c_ext);
|
|
oldchange(p->p_change);
|
|
olduse(p->p_use);
|
|
Cdeleteset(p->p_calling);
|
|
}
|
|
}
|
|
oldproc(p);
|
|
}
|
|
fclose(curoutp);
|
|
if (pmap != (proc_p *) 0) {
|
|
oldmap((void **) pmap,plength); /* release memory for pmap */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* putunit */
|
|
|
|
STATIC void outloop(void *vp)
|
|
{
|
|
loop_p l = vp;
|
|
|
|
outshort((short) l->lp_id);
|
|
}
|
|
|
|
|
|
STATIC void outblock(void *vp)
|
|
{
|
|
bblock_p b = vp;
|
|
|
|
if (b == (bblock_p) 0) {
|
|
outshort((short) 0);
|
|
} else {
|
|
outshort((short) b->b_id);
|
|
}
|
|
}
|
|
|
|
|
|
STATIC void outlset(lset s, void (*p)(void *))
|
|
{
|
|
/* A 'long' set is represented externally as a
|
|
* a sequence of elements terminated by a 0 word.
|
|
* The procedural parameter p is a routine that
|
|
* prints an id (proc_id, obj_id etc.).
|
|
*/
|
|
|
|
register Lindex i;
|
|
|
|
for (i = Lfirst(s); i != (Lindex) 0; i = Lnext(i,s)) {
|
|
(*p)(Lelem(i));
|
|
}
|
|
outshort((short) 0);
|
|
}
|
|
|
|
|
|
|
|
void putunit(short kind, proc_p p, line_p l, FILE *gf, FILE *lf)
|
|
{
|
|
register bblock_p b;
|
|
register short n = 0;
|
|
Lindex pi;
|
|
bblock_p nextb;
|
|
loop_p lp;
|
|
|
|
curoutp = gf;
|
|
if (kind == LDATA) {
|
|
outshort(0); /* No basic blocks */
|
|
n = putlines(l,lf);
|
|
curoutp = gf;
|
|
outshort(n);
|
|
return;
|
|
}
|
|
/* Determine the number of basic blocks */
|
|
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
|
n++;
|
|
}
|
|
outshort(n); /* # basic blocks */
|
|
outshort(Lnrelems(p->p_loops)); /* # loops */
|
|
for (b = p->p_start; b != (bblock_p) 0; b = b->b_next) {
|
|
n = putlines(b->b_start,lf);
|
|
curoutp = gf;
|
|
outblock(b); /* put its block_id */
|
|
outshort(n); /* #instructions of the block */
|
|
outlset(b->b_succ, outblock); /* put succ set */
|
|
outlset(b->b_pred, outblock); /* put pred set */
|
|
outblock(b->b_idom); /* put id of immediate dominator */
|
|
outlset(b->b_loops, outloop); /* put loop set */
|
|
outshort(b->b_flags);
|
|
}
|
|
/* The Control Flow Graph of every procedure is followed
|
|
* by a description of the loops of the procedure.
|
|
* Every loop contains an id, an entry block and a level.
|
|
*/
|
|
for (pi = Lfirst(p->p_loops); pi != (Lindex) 0;
|
|
pi = Lnext(pi,p->p_loops)) {
|
|
lp = (loop_p) Lelem(pi);
|
|
outloop(lp); /* id */
|
|
outshort(lp->lp_level); /* nesting level */
|
|
outblock(lp->lp_entry); /* loop entry block */
|
|
outblock(lp->lp_end);
|
|
oldloop(lp);
|
|
}
|
|
Ldeleteset(p->p_loops);
|
|
/* We will now release the memory of the basic blocks.
|
|
* Note that it would be incorrect to release a basic block
|
|
* after it has been written, because there may be references
|
|
* to it from other (later) blocks.
|
|
*/
|
|
for (b = p->p_start; b != (bblock_p) 0; b = nextb) {
|
|
Ldeleteset(b->b_loops);
|
|
Ldeleteset(b->b_succ);
|
|
Ldeleteset(b->b_pred);
|
|
/* Must read b->b_next before releasing b */
|
|
nextb = b->b_next;
|
|
oldbblock(b);
|
|
}
|
|
/* Release the memory for the lmap, lbmap, bmap, lpmap tables */
|
|
if (lmap != (line_p *) 0) oldmap((void **) lmap,llength);
|
|
if (lbmap != (bblock_p *) 0) oldmap((void **) lbmap,llength);
|
|
if (bmap != (bblock_p *) 0) oldmap((void **) bmap,blength);
|
|
if (lpmap != (loop_p *) 0) oldmap((void **) lpmap,lplength);
|
|
curoutp = lf;
|
|
}
|