17bc9cdef7
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.
237 lines
4.6 KiB
C
237 lines
4.6 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".
|
|
*/
|
|
/*
|
|
* L O C A L S . C
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <em_mnem.h>
|
|
#include <em_spec.h>
|
|
#include <em_pseu.h>
|
|
#include <em_mes.h>
|
|
#include "types.h"
|
|
#include "debug.h"
|
|
#include "global.h"
|
|
#include "lset.h"
|
|
#include "cset.h"
|
|
#include "def.h"
|
|
#include "get.h"
|
|
#include "utils.h"
|
|
#include "alloc.h"
|
|
#include "locals.h"
|
|
|
|
|
|
short nrglobals;
|
|
short nrlocals;
|
|
local_p *locals; /* dynamic array */
|
|
|
|
STATIC void localvar(offset off, short size, local_p *locs, bool reg,
|
|
offset score)
|
|
{
|
|
/* process a reference to a local variable.
|
|
* A local is characterized by a (offset,size) pair.
|
|
* We first collect all locals in a list, sorted
|
|
* by offset. Later we will construct a table
|
|
* out of this list.
|
|
*/
|
|
|
|
local_p lc, x, *prevp;
|
|
|
|
prevp = locs;
|
|
for (lc = *locs; lc != (local_p) 0; lc = lc->lc_next) {
|
|
if (lc->lc_off == off && lc->lc_size == size) {
|
|
if (reg) {
|
|
REGVAR(lc); /* register variable */
|
|
lc->lc_score = score;
|
|
}
|
|
return; /* local already present */
|
|
}
|
|
if (lc->lc_off > off) break;
|
|
prevp = &lc->lc_next;
|
|
}
|
|
/* the local was not seen before; create an entry
|
|
* for it in the list.
|
|
*/
|
|
x = *prevp = newlocal();
|
|
x->lc_off = off;
|
|
x->lc_size = size;
|
|
x->lc_next = lc;
|
|
if (reg) {
|
|
REGVAR(x);
|
|
x->lc_score = score;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
STATIC void check_message(line_p l, local_p *locs)
|
|
{
|
|
/* See if l is a register message */
|
|
|
|
arg_p arg;
|
|
|
|
arg = ARG(l);
|
|
if (aoff(arg,0) == ms_reg && arg->a_next != (arg_p) 0) {
|
|
localvar(aoff(arg,1), (short) aoff(arg,2), locs, TRUE,
|
|
aoff(arg,4));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC void check_local_use(line_p l, local_p *locs)
|
|
{
|
|
short sz;
|
|
|
|
switch(INSTR(l)) {
|
|
case op_lol:
|
|
case op_stl:
|
|
case op_inl:
|
|
case op_del:
|
|
case op_zrl:
|
|
sz = ws;
|
|
break;
|
|
case op_ldl:
|
|
case op_sdl:
|
|
sz = 2 * ws;
|
|
break;
|
|
case op_lil:
|
|
case op_sil:
|
|
sz = ps;
|
|
break;
|
|
case ps_mes:
|
|
check_message(l,locs);
|
|
/* fall through .. */
|
|
default:
|
|
return;
|
|
}
|
|
if (l->l_next && INSTR(l->l_next) == op_nop) {
|
|
/* volatile */
|
|
return;
|
|
}
|
|
localvar(off_set(l),sz,locs,FALSE,(offset) 0);
|
|
}
|
|
|
|
|
|
void make_localtab(proc_p p)
|
|
{
|
|
/* Make a table of local variables.
|
|
* This table is used to associate a
|
|
* unique number with a local. If two
|
|
* locals overlap (e.g. LDL 4 and LDL 2)
|
|
* none of them is considered any further,
|
|
* i.e. we don't compute ud-info for them.
|
|
*/
|
|
|
|
local_p prev = 0, next, lc;
|
|
local_p locallist = (local_p) 0;
|
|
short cnt = 0;
|
|
offset x, ill_zone = 0;
|
|
register bblock_p b;
|
|
register line_p l;
|
|
|
|
/* first make a list of all locals used */
|
|
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) {
|
|
check_local_use(l,&locallist);
|
|
}
|
|
}
|
|
/* Now remove overlapping locals, count useful ones on the fly */
|
|
for (lc = locallist; lc != (local_p) 0; lc = lc->lc_next) {
|
|
if (ill_zone != 0 && lc->lc_off < ill_zone) {
|
|
/* this local overlaps with a previous one */
|
|
BADLC(lc);
|
|
if (!IS_BADLC(prev)) {
|
|
BADLC(prev);
|
|
cnt--;
|
|
}
|
|
} else {
|
|
cnt++;
|
|
}
|
|
x = lc->lc_off + lc->lc_size;
|
|
if (ill_zone == 0 || x > ill_zone) {
|
|
ill_zone = x;
|
|
}
|
|
prev = lc;
|
|
}
|
|
/* Now we know how many local variables there are */
|
|
nrlocals = cnt;
|
|
locals = (local_p *) newmap(cnt);
|
|
cnt = 1;
|
|
for (lc = locallist; lc != (local_p) 0; lc = next) {
|
|
next = lc->lc_next;
|
|
if (IS_BADLC(lc)) {
|
|
oldlocal(lc);
|
|
} else {
|
|
locals[cnt++] = lc;
|
|
lc->lc_next = (local_p) 0;
|
|
}
|
|
}
|
|
assert (cnt == nrlocals+1);
|
|
}
|
|
|
|
|
|
|
|
void find_local(offset off, short *nr_out, bool *found_out)
|
|
{
|
|
/* Try to find the local variable at the given
|
|
* offset. Return its local-number.
|
|
*/
|
|
|
|
short v;
|
|
|
|
for (v = 1; v <= nrlocals; v++) {
|
|
if (locals[v]->lc_off > off) break;
|
|
if (locals[v]->lc_off == off) {
|
|
*found_out = TRUE;
|
|
*nr_out = v;
|
|
return;
|
|
}
|
|
}
|
|
*found_out = FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
void var_nr(line_p l, short *nr_out, bool *found_out)
|
|
{
|
|
/* Determine the number of the variable referenced
|
|
* by EM instruction l.
|
|
*/
|
|
|
|
offset off = 0;
|
|
short nr;
|
|
|
|
switch(TYPE(l)) {
|
|
case OPOBJECT:
|
|
/* global variable */
|
|
if (OBJ(l)->o_globnr == 0) {
|
|
/* We don't maintain ud-info for this var */
|
|
*found_out = FALSE;
|
|
} else {
|
|
*nr_out = GLOB_TO_VARNR(OBJ(l)->o_globnr);
|
|
*found_out = TRUE;
|
|
}
|
|
return;
|
|
case OPSHORT:
|
|
off = (offset) SHORT(l);
|
|
break;
|
|
case OPOFFSET:
|
|
off = OFFSET(l);
|
|
break;
|
|
default:
|
|
assert(FALSE);
|
|
}
|
|
/* Its's a local variable */
|
|
find_local(off,&nr,found_out);
|
|
if (*found_out) {
|
|
*nr_out = LOC_TO_VARNR(nr);
|
|
}
|
|
}
|