ack/util/ego/cf/cf_succ.c

258 lines
6 KiB
C

/* $Header$ */
/*
* (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 "../share/types.h"
#include "../share/def.h"
#include "../share/debug.h"
#include "../share/global.h"
#include "../share/lset.h"
#include "../share/cset.h"
#include "../../../h/em_spec.h"
#include "../../../h/em_pseu.h"
#include "../../../h/em_flag.h"
#include "../../../h/em_mnem.h"
#include "cf.h"
#include "../share/map.h"
extern char em_flag[];
STATIC 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 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 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;
}
}
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);
}
}
}
}
}
}