ack/util/ego/cf/cf_succ.c
George Koehler 17bc9cdef7 More void, fewer clang warnings in util/ego
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.
2019-11-01 15:27:16 -04:00

259 lines
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".
*/
/* C O N T R O L F L O W
*
* C F _ S U C C . C
*/
#include <stdio.h>
#include <em_spec.h>
#include <em_pseu.h>
#include <em_flag.h>
#include <em_mnem.h>
#include "../share/types.h"
#include "../share/def.h"
#include "../share/debug.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/cset.h"
#include "cf.h"
#include "cf_succ.h"
#include "../share/map.h"
extern char em_flag[];
STATIC void succeeds(succ,pred)
bblock_p succ, pred;
{
assert(pred != (bblock_p) 0);
if (succ != (bblock_p) 0) {
Ladd(succ, &pred->b_succ);
Ladd(pred, &succ->b_pred);
}
}
#define IS_RETURN(i) (i == op_ret || i == op_rtt)
#define IS_CASE_JUMP(i) (i == op_csa || i == op_csb)
#define IS_UNCOND_JUMP(i) (i <= sp_lmnem && (em_flag[i-sp_fmnem] & EM_FLO) == FLO_T)
#define IS_COND_JUMP(i) (i <= sp_lmnem && (em_flag[i-sp_fmnem] & EM_FLO) == FLO_C)
#define TARGET(lnp) (lbmap[INSTRLAB(lnp)])
#define ATARGET(arg) (lbmap[arg->a_a.a_instrlab])
STATIC arg_p skip_const(arg)
arg_p arg;
{
assert(arg != (arg_p) 0);
switch(arg->a_type) {
case ARGOFF:
case ARGICN:
case ARGUCN:
break;
default:
error("bad case descriptor");
}
return arg->a_next;
}
STATIC arg_p use_label(arg,b)
arg_p arg;
bblock_p b;
{
if (arg->a_type == ARGINSTRLAB) {
/* arg is a non-null label */
succeeds(ATARGET(arg),b);
}
return arg->a_next;
}
STATIC void case_flow(instr,desc,b)
short instr;
line_p desc;
bblock_p b;
{
/* Analyse the case descriptor (given as a ROM pseudo instruction).
* Every instruction label appearing in the descriptor
* heads a basic block that is a successor of the block
* in which the case instruction appears (b).
*/
register arg_p arg;
assert(instr == op_csa || instr == op_csb);
assert(TYPE(desc) == OPLIST);
arg = ARG(desc);
arg = use_label(arg,b);
/* See if there is a default label. If so, then
* its block is a successor of b. Set arg to
* next argument.
*/
if (instr == op_csa) {
arg = skip_const(arg); /* skip lower bound */
arg = skip_const(arg); /* skip lower-upper bound */
while (arg != (arg_p) 0) {
/* All following arguments are case labels
* or zeroes.
*/
arg = use_label(arg,b);
}
} else {
/* csb instruction */
arg = skip_const(arg); /* skip #entries */
while (arg != (arg_p) 0) {
/* All following arguments are alternatively
* an index and an instruction label (possibly 0).
*/
arg = skip_const(arg); /* skip index */
arg = use_label(arg,b);
}
}
}
STATIC line_p case_descr(lnp)
line_p lnp;
{
/* lnp is the instruction just before a csa or csb,
* so it is the instruction that pushes the address
* of a case descriptor on the stack. Find that
* descriptor, i.e. a rom pseudo instruction.
* Note that this instruction will always be part
* of the procedure in which the csa/csb occurs.
*/
register line_p l;
dblock_p d;
obj_p obj;
dblock_id id;
if (lnp == (line_p) 0 || (INSTR(lnp)) != op_lae) {
error("cannot find 'lae descr' before csa/csb");
}
/* We'll first find the ROM and its dblock_id */
obj = OBJ(lnp);
if (obj->o_off != (offset) 0) {
error("bad 'lae descr' before csa/csb");
/* We require a descriptor to be an entire rom,
* not part of a rom.
*/
}
d = obj->o_dblock;
assert(d != (dblock_p) 0);
if (d->d_pseudo != DROM) {
error("case descriptor must be in rom");
}
id = d->d_id;
/* We'll use the dblock_id to find the defining occurrence
* of the rom in the EM text (i.e. a rom pseudo). As all
* pseudos appear at the beginning of a procedure, we only
* have to look in its first basic block.
*/
assert(curproc != (proc_p) 0);
assert(curproc->p_start != (bblock_p) 0);
l = curproc->p_start->b_start; /* first instruction of curproc */
while (l != (line_p) 0) {
if ((INSTR(l)) == ps_sym &&
SHORT(l) == id) {
/* found! */
assert((INSTR(l->l_next)) == ps_rom);
return l->l_next;
}
l = l->l_next;
}
error("cannot find rom pseudo for case descriptor");
/* NOTREACHED */
}
STATIC void last2_instrs(b,last_out,prev_out)
bblock_p b;
line_p *last_out,*prev_out;
{
/* Determine the last and one-but-last instruction
* of basic block b. An end-pseudo is not regarded
* as an instruction. If the block contains only 1
* instruction, prev_out is 0.
*/
register line_p l1,l2;
l2 = b->b_start; /* first instruction of b */
assert(l2 != (line_p) 0); /* block can not be empty */
if ((l1 = l2->l_next) == (line_p) 0 || INSTR(l1) == ps_end) {
*last_out = l2; /* single instruction */
*prev_out = (line_p) 0;
} else {
while(l1->l_next != (line_p) 0 && INSTR(l1->l_next) != ps_end) {
l2 = l1;
l1 = l1->l_next;
}
*last_out = l1;
*prev_out = l2;
}
}
void control_flow(head)
bblock_p head;
{
/* compute the successor and predecessor relation
* for every basic block.
*/
register bblock_p b;
line_p lnp, prev;
short instr;
for (b = head; b != (bblock_p) 0; b = b->b_next) {
/* for every basic block, in textual order, do */
last2_instrs(b, &lnp, &prev);
/* find last and one-but-last instruction */
instr = INSTR(lnp);
/* The last instruction of the basic block
* determines the set of successors of the block.
*/
if (IS_CASE_JUMP(instr)) {
case_flow(instr,case_descr(prev),b);
/* If lnp is a csa or csb, then the instruction
* just before it (i.e. prev) must be the
* instruction that pushes the address of the
* case descriptor. This descriptor is found
* and analysed in order to build the successor
* and predecessor sets of b.
*/
} else {
if (!IS_RETURN(instr)) {
if (IS_UNCOND_JUMP(instr)) {
if (instr != op_gto) {
succeeds(TARGET(lnp),b);
}
} else {
if (IS_COND_JUMP(instr)) {
succeeds(TARGET(lnp),b);
succeeds(b->b_next, b);
/* Textually next block is
* a successor of b.
*/
} else {
/* normal instruction */
succeeds(b->b_next, b);
}
}
}
}
}
}