1994-06-24 11:31:16 +00:00
|
|
|
/* $Id$ */
|
1987-03-09 19:15:41 +00:00
|
|
|
/*
|
|
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
|
|
*/
|
1984-11-26 13:43:22 +00:00
|
|
|
/* C O N T R O L F L O W
|
|
|
|
*
|
|
|
|
* M A I N R O U T I N E
|
|
|
|
*/
|
|
|
|
|
2006-07-22 00:46:16 +00:00
|
|
|
#include <stdlib.h>
|
1984-11-26 13:43:22 +00:00
|
|
|
#include <stdio.h>
|
1991-03-05 12:16:17 +00:00
|
|
|
#include <em_mnem.h>
|
|
|
|
#include <em_pseu.h>
|
|
|
|
#include <em_spec.h>
|
|
|
|
#include <em_flag.h>
|
|
|
|
#include <em_mes.h>
|
1984-11-26 13:43:22 +00:00
|
|
|
#include "../share/types.h"
|
|
|
|
#include "../share/debug.h"
|
|
|
|
#include "../share/map.h"
|
|
|
|
#include "../share/files.h"
|
|
|
|
#include "../share/global.h"
|
|
|
|
#include "../share/alloc.h"
|
|
|
|
#include "../share/lset.h"
|
|
|
|
#include "../share/cset.h"
|
|
|
|
#include "../share/get.h"
|
|
|
|
#include "../share/put.h"
|
1985-02-11 09:51:02 +00:00
|
|
|
#include "../share/def.h"
|
2019-10-31 22:05:22 +00:00
|
|
|
#include "../share/utils.h"
|
1984-11-26 13:43:22 +00:00
|
|
|
#include "cf.h"
|
|
|
|
#include "cf_succ.h"
|
|
|
|
#include "cf_idom.h"
|
|
|
|
#include "cf_loop.h"
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
#define newcfbx() (bext_p) newstruct(bext_cf)
|
|
|
|
#define oldcfbx(x) oldstruct(bext_cf, x)
|
1984-11-26 13:43:22 +00:00
|
|
|
|
1985-02-11 09:51:02 +00:00
|
|
|
extern char em_flag[];
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
STATIC cset lpi_set; /* set of procedures used in LPI instruction */
|
|
|
|
STATIC cset cai_set; /* set of all procedures doing a CAI */
|
1984-11-29 10:51:16 +00:00
|
|
|
|
|
|
|
/* The procedure getbblocks reads the EM textfile and
|
|
|
|
* partitions every procedure into a number of basic blocks.
|
|
|
|
*/
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
#define LABEL0 0
|
|
|
|
#define LABEL 1
|
|
|
|
#define NORMAL 2
|
|
|
|
#define JUMP 3
|
|
|
|
#define END 4
|
|
|
|
#define AFTERPRO 5
|
|
|
|
#define INIT 6
|
1984-11-29 10:51:16 +00:00
|
|
|
|
|
|
|
/* These global variables are used by getbblocks and nextblock. */
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
STATIC bblock_p b, *bp; /* b is the current basic block, bp is
|
1984-11-29 10:51:16 +00:00
|
|
|
* the address where the next block has
|
|
|
|
* to be linked.
|
|
|
|
*/
|
2016-08-21 17:34:54 +00:00
|
|
|
STATIC line_p lnp, *lp; /* lnp is the current line, lp is
|
1984-11-29 10:51:16 +00:00
|
|
|
* the address where the next line
|
|
|
|
* has to be linked.
|
|
|
|
*/
|
2016-08-21 17:34:54 +00:00
|
|
|
STATIC short state; /* We use a finite state machine with the
|
1984-11-29 10:51:16 +00:00
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
|
2019-10-31 22:05:22 +00:00
|
|
|
STATIC void nextblock()
|
1984-11-29 10:51:16 +00:00
|
|
|
{
|
|
|
|
/* 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
|
2016-08-21 17:34:54 +00:00
|
|
|
fprintf(stderr, "new basic block, id = %d\n", lastbid);
|
1984-11-29 10:51:16 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
STATIC short kind(lnp)
|
2016-08-21 17:34:54 +00:00
|
|
|
line_p lnp;
|
1984-11-29 10:51:16 +00:00
|
|
|
{
|
|
|
|
/* determine if lnp is a label, branch, end or otherwise */
|
|
|
|
|
|
|
|
short instr;
|
2016-08-21 17:34:54 +00:00
|
|
|
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;
|
1984-11-29 10:51:16 +00:00
|
|
|
}
|
|
|
|
|
1990-05-30 11:31:32 +00:00
|
|
|
STATIC line_p doread_line(p_out)
|
2016-08-21 17:34:54 +00:00
|
|
|
proc_p* p_out;
|
1990-05-30 11:31:32 +00:00
|
|
|
{
|
|
|
|
/* read a line, and check pseudos for procedure addresses */
|
|
|
|
|
|
|
|
register line_p lnp = read_line(p_out);
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
if (lnp && TYPE(lnp) == OPLIST && INSTR(lnp) != ps_mes)
|
|
|
|
{
|
1990-05-30 11:31:32 +00:00
|
|
|
register arg_p arg = ARG(lnp);
|
2016-08-21 17:34:54 +00:00
|
|
|
|
|
|
|
while (arg)
|
|
|
|
{
|
|
|
|
if (arg->a_type == ARGPROC)
|
|
|
|
{
|
1990-05-30 11:31:32 +00:00
|
|
|
Cadd(arg->a_a.a_proc->p_id, &lpi_set);
|
|
|
|
arg->a_a.a_proc->p_flags1 |= PF_LPI;
|
|
|
|
}
|
|
|
|
arg = arg->a_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lnp;
|
|
|
|
}
|
1984-11-29 10:51:16 +00:00
|
|
|
|
2019-10-31 22:05:22 +00:00
|
|
|
STATIC bool
|
|
|
|
getbblocks(FILE *fp, short *kind_out, short *n_out, bblock_p *g_out,
|
|
|
|
line_p *l_out)
|
1984-11-29 10:51:16 +00:00
|
|
|
{
|
2016-08-21 17:34:54 +00:00
|
|
|
bblock_p head = (bblock_p)0;
|
|
|
|
line_p headl = (line_p)0;
|
1984-11-29 10:51:16 +00:00
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
curproc = (proc_p)0;
|
1984-11-29 10:51:16 +00:00
|
|
|
/* 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.).
|
|
|
|
*/
|
|
|
|
curinp = fp;
|
2016-08-21 17:34:54 +00:00
|
|
|
lastbid = (block_id)0; /* block identier */
|
|
|
|
state = INIT; /* initial state */
|
1984-11-29 10:51:16 +00:00
|
|
|
bp = &head;
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
#ifdef TRACE
|
2016-08-21 17:34:54 +00:00
|
|
|
fprintf(stderr, "state = %d\n", state);
|
1984-11-29 10:51:16 +00:00
|
|
|
#endif
|
2016-08-21 17:34:54 +00:00
|
|
|
switch (state)
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
case LABEL0:
|
|
|
|
nextblock();
|
2016-08-21 17:34:54 +00:00
|
|
|
/* Fall through !! */
|
1984-11-29 10:51:16 +00:00
|
|
|
case LABEL:
|
|
|
|
lbmap[INSTRLAB(lnp)] = b;
|
|
|
|
/* The lbmap table contains for each
|
|
|
|
* label_id the basic block of that label.
|
|
|
|
*/
|
1990-05-30 11:31:32 +00:00
|
|
|
lnp = doread_line(&curproc);
|
1984-11-29 10:51:16 +00:00
|
|
|
state = kind(lnp);
|
2016-08-21 17:34:54 +00:00
|
|
|
if (state != END)
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
*lp = lnp;
|
|
|
|
lp = &lnp->l_next;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NORMAL:
|
1990-05-30 11:31:32 +00:00
|
|
|
lnp = doread_line(&curproc);
|
2016-08-21 17:34:54 +00:00
|
|
|
if ((state = kind(lnp)) == LABEL)
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
/* If we come accross a label
|
|
|
|
* here, it must be the beginning
|
|
|
|
* of a new basic block.
|
|
|
|
*/
|
|
|
|
state = LABEL0;
|
2016-08-21 17:34:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (state != END)
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
*lp = lnp;
|
|
|
|
lp = &lnp->l_next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case JUMP:
|
1990-05-30 11:31:32 +00:00
|
|
|
lnp = doread_line(&curproc);
|
2016-08-21 17:34:54 +00:00
|
|
|
/* fall through ... */
|
1984-11-29 10:51:16 +00:00
|
|
|
case AFTERPRO:
|
2016-08-21 17:34:54 +00:00
|
|
|
switch (state = kind(lnp))
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
case LABEL:
|
|
|
|
state = LABEL0;
|
|
|
|
break;
|
|
|
|
case JUMP:
|
|
|
|
case NORMAL:
|
|
|
|
nextblock();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case END:
|
|
|
|
*lp = lnp;
|
|
|
|
#ifdef TRACE
|
2016-08-21 17:34:54 +00:00
|
|
|
fprintf(stderr, "at end of proc, %d blocks\n", lastbid);
|
1984-11-29 10:51:16 +00:00
|
|
|
#endif
|
2016-08-21 17:34:54 +00:00
|
|
|
if (head == (bblock_p)0)
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
*kind_out = LDATA;
|
|
|
|
*l_out = headl;
|
2016-08-21 17:34:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
*kind_out = LTEXT;
|
|
|
|
*g_out = head;
|
2016-08-21 17:34:54 +00:00
|
|
|
*n_out = (short)lastbid;
|
1984-11-29 10:51:16 +00:00
|
|
|
/* number of basic blocks */
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
case INIT:
|
1990-05-30 11:31:32 +00:00
|
|
|
lnp = doread_line(&curproc);
|
2016-08-21 17:34:54 +00:00
|
|
|
if (feof(curinp))
|
|
|
|
return FALSE;
|
|
|
|
if (INSTR(lnp) == ps_pro)
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
state = AFTERPRO;
|
2016-08-21 17:34:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1984-11-29 10:51:16 +00:00
|
|
|
state = NORMAL;
|
|
|
|
headl = lnp;
|
|
|
|
lp = &lnp->l_next;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-31 22:05:22 +00:00
|
|
|
STATIC void interproc_analysis(p)
|
2016-08-21 17:34:54 +00:00
|
|
|
proc_p p;
|
1984-11-26 13:43:22 +00:00
|
|
|
{
|
|
|
|
/* Interprocedural analysis of a procedure p determines:
|
|
|
|
* - all procedures called by p (the 'call graph')
|
|
|
|
* - the set of objects changed by p (directly)
|
|
|
|
* - whether p does a load-indirect (loi,lof etc.)
|
|
|
|
* - whether p does a store-indirect (sti, stf etc.)
|
|
|
|
* The changed/used variables information will be
|
|
|
|
* transitively closed, i.e. if P calls Q and Q changes
|
|
|
|
* a variable X, the P changes X too.
|
|
|
|
* (The same applies for used variables and for use/store
|
|
|
|
* indirect).
|
|
|
|
* The transitive closure will be computed by main
|
|
|
|
* after all procedures have been processed.
|
|
|
|
*/
|
|
|
|
|
|
|
|
bblock_p b;
|
2016-08-21 17:34:54 +00:00
|
|
|
line_p lnp;
|
1984-11-26 13:43:22 +00:00
|
|
|
bool inloop;
|
|
|
|
|
|
|
|
/* Allocate memory for structs and sets */
|
|
|
|
|
|
|
|
p->p_use = newuse();
|
|
|
|
p->p_change = newchange();
|
|
|
|
p->p_change->c_ext = Cempty_set(olength);
|
|
|
|
p->p_calling = Cempty_set(plength);
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
for (b = p->p_start; b != (bblock_p)0; b = b->b_next)
|
|
|
|
{
|
|
|
|
inloop = (Lnrelems(b->b_loops) > 0);
|
|
|
|
for (lnp = b->b_start; lnp != (line_p)0; lnp = lnp->l_next)
|
|
|
|
{
|
|
|
|
/* for all instructions of p do */
|
|
|
|
switch (INSTR(lnp))
|
|
|
|
{
|
|
|
|
case op_cal:
|
|
|
|
Cadd(PROC(lnp)->p_id, &p->p_calling);
|
|
|
|
/* add called proc to p_calling */
|
|
|
|
if (inloop)
|
|
|
|
{
|
|
|
|
CALLED_IN_LOOP(PROC(lnp));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case op_cai:
|
|
|
|
Cadd(p->p_id, &cai_set);
|
|
|
|
break;
|
|
|
|
case op_lpi:
|
|
|
|
Cadd(PROC(lnp)->p_id, &lpi_set);
|
|
|
|
/* All procedures that have their names used
|
1984-11-26 13:43:22 +00:00
|
|
|
* in an lpi instruction, may be called via
|
|
|
|
* a cai instruction.
|
|
|
|
*/
|
2016-08-21 17:34:54 +00:00
|
|
|
PROC(lnp)->p_flags1 |= PF_LPI;
|
|
|
|
break;
|
|
|
|
case op_ste:
|
|
|
|
case op_sde:
|
|
|
|
case op_ine:
|
|
|
|
case op_dee:
|
|
|
|
case op_zre:
|
|
|
|
Cadd(OBJ(lnp)->o_id, &p->p_change->c_ext);
|
|
|
|
/* Add changed object to c_ext */
|
|
|
|
break;
|
|
|
|
case op_lil:
|
|
|
|
case op_lof:
|
|
|
|
case op_loi:
|
|
|
|
case op_los:
|
|
|
|
case op_lar:
|
|
|
|
p->p_use->u_flags |= UF_INDIR;
|
|
|
|
/* p does a load-indirect */
|
|
|
|
break;
|
|
|
|
case op_sil:
|
|
|
|
case op_stf:
|
|
|
|
case op_sti:
|
|
|
|
case op_sts:
|
|
|
|
case op_sar:
|
|
|
|
p->p_change->c_flags |= CF_INDIR;
|
|
|
|
/* p does a store-indirect */
|
|
|
|
break;
|
|
|
|
case op_blm:
|
|
|
|
case op_bls:
|
|
|
|
p->p_use->u_flags |= UF_INDIR;
|
|
|
|
p->p_change->c_flags |= CF_INDIR;
|
|
|
|
/* p does both */
|
|
|
|
break;
|
|
|
|
case op_mon:
|
|
|
|
printf("mon not yet implemented\n");
|
|
|
|
break;
|
|
|
|
case op_lxl:
|
|
|
|
case op_lxa:
|
|
|
|
curproc->p_flags1 |= PF_ENVIRON;
|
|
|
|
break;
|
|
|
|
case op_lor:
|
|
|
|
case op_str:
|
|
|
|
if (SHORT(lnp) == 0)
|
|
|
|
{
|
|
|
|
curproc->p_flags1 |= PF_ENVIRON;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ps_mes:
|
|
|
|
if (aoff(ARG(lnp), 0) == ms_gto)
|
|
|
|
{
|
|
|
|
ENTERED_WITH_GTO(curproc);
|
|
|
|
}
|
|
|
|
break;
|
1987-10-02 12:43:54 +00:00
|
|
|
}
|
1984-11-26 13:43:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-31 22:05:22 +00:00
|
|
|
STATIC void cf_cleanproc(p)
|
2016-08-21 17:34:54 +00:00
|
|
|
proc_p p;
|
1984-11-26 13:43:22 +00:00
|
|
|
{
|
|
|
|
/* Remove the extended data structures of p */
|
|
|
|
|
|
|
|
register bblock_p b;
|
|
|
|
register Lindex pi;
|
|
|
|
loop_p lp;
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
for (b = p->p_start; b != (bblock_p)0; b = b->b_next)
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
oldcfbx(b->b_extend);
|
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
for (pi = Lfirst(p->p_loops); pi != (Lindex)0; pi = Lnext(pi,
|
|
|
|
p->p_loops))
|
|
|
|
{
|
|
|
|
lp = (loop_p)Lelem(pi);
|
1984-11-26 13:43:22 +00:00
|
|
|
oldcflpx(lp->lp_extend);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
#define CH_CHANGE_INDIR(ch) ((ch->c_flags & CF_INDIR) != 0)
|
|
|
|
#define USE_INDIR(us) ((us->u_flags & UF_INDIR) != 0)
|
|
|
|
#define CALLS_UNKNOWN(p) (p->p_flags1 & (byte)PF_CALUNKNOWN)
|
|
|
|
#define ENVIRON(p) (p->p_flags1 & (byte)PF_ENVIRON)
|
1984-11-26 13:43:22 +00:00
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
STATIC bool add_info(q, p)
|
|
|
|
proc_p q,
|
|
|
|
p;
|
1984-11-26 13:43:22 +00:00
|
|
|
{
|
|
|
|
/* Determine the consequences for used/changed variables info
|
|
|
|
* of the fact that p calls q. If e.g. q changes a variable X
|
|
|
|
* then p changes this variable too. This routine is an
|
|
|
|
* auxiliary routine of the transitive closure process.
|
|
|
|
* The returned value indicates if there was any change in
|
|
|
|
* the information of p.
|
|
|
|
*/
|
|
|
|
|
|
|
|
change_p chp, chq;
|
2016-08-21 17:34:54 +00:00
|
|
|
use_p usp, usq;
|
|
|
|
bool diff = FALSE;
|
1984-11-26 13:43:22 +00:00
|
|
|
|
|
|
|
chp = p->p_change;
|
|
|
|
chq = q->p_change;
|
|
|
|
usp = p->p_use;
|
|
|
|
usq = q->p_use;
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
if (!BODY_KNOWN(q))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
/* q is a procedure of which the body is not available
|
|
|
|
* as EM text.
|
|
|
|
*/
|
2016-08-21 17:34:54 +00:00
|
|
|
if (CALLS_UNKNOWN(p))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
return FALSE;
|
|
|
|
/* p already called an unknown procedure */
|
2016-08-21 17:34:54 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
p->p_flags1 |= PF_CALUNKNOWN;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
if (CALLS_UNKNOWN(q))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
/* q calls a procedure of which the body is not available
|
|
|
|
* as EM text.
|
|
|
|
*/
|
2016-08-21 17:34:54 +00:00
|
|
|
if (!CALLS_UNKNOWN(p))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
p->p_flags1 |= PF_CALUNKNOWN;
|
|
|
|
diff = TRUE;
|
|
|
|
}
|
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
if (IS_CALLED_IN_LOOP(p) && !IS_CALLED_IN_LOOP(q))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
CALLED_IN_LOOP(q);
|
|
|
|
diff = TRUE;
|
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
if (!Cis_subset(chq->c_ext, chp->c_ext))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
/* q changes global variables (objects) that
|
|
|
|
* p did not (yet) change. Add all variables
|
|
|
|
* changed by q to the c_ext set of p.
|
|
|
|
*/
|
|
|
|
Cjoin(chq->c_ext, &chp->c_ext);
|
|
|
|
diff = TRUE;
|
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
if (CH_CHANGE_INDIR(chq) && !CH_CHANGE_INDIR(chp))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
/* q does a change-indirect (sil etc.)
|
|
|
|
* and p did not (yet).
|
|
|
|
*/
|
|
|
|
chp->c_flags |= CF_INDIR;
|
|
|
|
diff = TRUE;
|
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
if (USE_INDIR(usq) && !USE_INDIR(usp))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
/* q does a use-indirect (lil etc.)
|
|
|
|
* and p dis not (yet).
|
|
|
|
*/
|
|
|
|
usp->u_flags |= UF_INDIR;
|
|
|
|
diff = TRUE;
|
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
if (ENVIRON(q) && !ENVIRON(p))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
/* q uses or changes local variables in its
|
|
|
|
* environment while p does not (yet).
|
|
|
|
*/
|
|
|
|
p->p_flags1 |= PF_ENVIRON;
|
|
|
|
diff = TRUE;
|
|
|
|
}
|
|
|
|
return diff;
|
|
|
|
}
|
|
|
|
|
2019-10-31 22:05:22 +00:00
|
|
|
STATIC void trans_clos(head)
|
2016-08-21 17:34:54 +00:00
|
|
|
proc_p head;
|
1984-11-26 13:43:22 +00:00
|
|
|
{
|
|
|
|
/* Compute the transitive closure of the used/changed
|
|
|
|
* variable information.
|
|
|
|
*/
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
register proc_p p, q;
|
1984-11-26 13:43:22 +00:00
|
|
|
Cindex i;
|
|
|
|
bool changes = TRUE;
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
while (changes)
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
changes = FALSE;
|
2016-08-21 17:34:54 +00:00
|
|
|
for (p = head; p != (proc_p)0; p = p->p_next)
|
|
|
|
{
|
|
|
|
if (!BODY_KNOWN(p))
|
|
|
|
continue;
|
|
|
|
for (i = Cfirst(p->p_calling); i != (Cindex)0;
|
|
|
|
i = Cnext(i, p->p_calling))
|
|
|
|
{
|
|
|
|
q = pmap[Celem(i)];
|
|
|
|
if (add_info(q, p))
|
|
|
|
{
|
|
|
|
changes = TRUE;
|
|
|
|
}
|
1984-11-26 13:43:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-31 22:05:22 +00:00
|
|
|
STATIC void indir_calls()
|
1984-11-26 13:43:22 +00:00
|
|
|
{
|
|
|
|
Cindex i;
|
|
|
|
proc_p p;
|
|
|
|
|
2016-08-21 17:34:54 +00:00
|
|
|
for (i = Cfirst(cai_set); i != (Cindex)0; i = Cnext(i, cai_set))
|
|
|
|
{
|
|
|
|
p = pmap[Celem(i)]; /* p does a CAI */
|
1984-11-26 13:43:22 +00:00
|
|
|
Cjoin(lpi_set, &p->p_calling);
|
|
|
|
}
|
|
|
|
Cdeleteset(lpi_set);
|
|
|
|
Cdeleteset(cai_set);
|
|
|
|
}
|
|
|
|
|
2019-10-31 22:05:22 +00:00
|
|
|
int main(argc, argv) int argc;
|
2016-08-21 17:34:54 +00:00
|
|
|
char* argv[];
|
1984-11-26 13:43:22 +00:00
|
|
|
{
|
2016-08-21 17:34:54 +00:00
|
|
|
FILE* f, *f2, *gf2; /* The EM input, EM output, basic block output */
|
1984-11-26 13:43:22 +00:00
|
|
|
bblock_p g;
|
|
|
|
short n, kind;
|
|
|
|
line_p l;
|
|
|
|
|
2016-08-21 20:01:19 +00:00
|
|
|
/* The names of the input files of every phase are passed as
|
|
|
|
* arguments to the phase. First come the input file names,
|
|
|
|
* then the output file names. We use a one-letter convention
|
|
|
|
* to denote the type of file:
|
|
|
|
* p: procedure table file
|
|
|
|
* d: data table file
|
|
|
|
* l: EM text file (lines of EM instructions)
|
|
|
|
* b: basic block file (Control Flow Graph file)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* The input file names */
|
|
|
|
|
|
|
|
char* pname_in = argv[1];
|
|
|
|
char* dname_in = argv[2];
|
|
|
|
char* lname_in = argv[3];
|
|
|
|
char* bname_in = argv[4];
|
|
|
|
|
|
|
|
/* The output file names */
|
|
|
|
|
|
|
|
char* pname_out = argv[5];
|
|
|
|
char* dname_out = argv[6];
|
|
|
|
char* lname_out = argv[7];
|
|
|
|
char* bname_out = argv[8];
|
|
|
|
|
1984-11-26 13:43:22 +00:00
|
|
|
linecount = 0;
|
2016-08-21 20:01:19 +00:00
|
|
|
fproc = getptable(pname_in); /* proc table */
|
|
|
|
fdblock = getdtable(dname_in); /* data block table */
|
1984-11-26 13:43:22 +00:00
|
|
|
lpi_set = Cempty_set(plength);
|
|
|
|
cai_set = Cempty_set(plength);
|
2016-08-21 20:01:19 +00:00
|
|
|
if ((f = fopen(lname_in, "r")) == NULL)
|
2016-08-21 17:34:54 +00:00
|
|
|
{
|
2016-08-21 20:01:19 +00:00
|
|
|
error("cannot open %s", lname_in);
|
1984-11-26 13:43:22 +00:00
|
|
|
}
|
2016-08-21 20:01:19 +00:00
|
|
|
if ((f2 = fopen(lname_out, "w")) == NULL)
|
2016-08-21 17:34:54 +00:00
|
|
|
{
|
2016-08-21 20:01:19 +00:00
|
|
|
error("cannot open %s", lname_out);
|
1984-11-26 13:43:22 +00:00
|
|
|
}
|
2016-08-21 20:01:19 +00:00
|
|
|
if ((gf2 = fopen(bname_out, "w")) == NULL)
|
2016-08-21 17:34:54 +00:00
|
|
|
{
|
2016-08-21 20:01:19 +00:00
|
|
|
error("cannot open %s", bname_out);
|
1984-11-26 13:43:22 +00:00
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
while (getbblocks(f, &kind, &n, &g, &l))
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
/* read EM text of one unit and
|
|
|
|
* (if it is a procedure)
|
|
|
|
* partition it into n basic blocks.
|
|
|
|
*/
|
2016-08-21 17:34:54 +00:00
|
|
|
if (kind == LDATA)
|
|
|
|
{
|
|
|
|
putunit(LDATA, (proc_p)0, l, gf2, f2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1984-11-26 13:43:22 +00:00
|
|
|
curproc->p_start = g;
|
|
|
|
/* The global variable curproc points to the
|
|
|
|
* current procedure. It is set by getbblocks
|
|
|
|
*/
|
|
|
|
control_flow(g); /* compute pred and succ */
|
2016-08-21 17:34:54 +00:00
|
|
|
dominators(g, n); /* compute immediate dominators */
|
1984-11-26 13:43:22 +00:00
|
|
|
loop_detection(curproc); /* compute loops */
|
|
|
|
interproc_analysis(curproc);
|
|
|
|
/* Interprocedural analysis */
|
|
|
|
cf_cleanproc(curproc);
|
2016-08-21 17:34:54 +00:00
|
|
|
putunit(LTEXT, curproc, (line_p)0, gf2, f2);
|
1984-11-26 13:43:22 +00:00
|
|
|
/* output control flow graph + text */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
fclose(f2);
|
|
|
|
fclose(gf2);
|
|
|
|
indir_calls();
|
|
|
|
trans_clos(fproc);
|
|
|
|
/* Compute transitive closure of used/changed
|
|
|
|
* variables information for every procedure.
|
|
|
|
*/
|
2016-08-21 20:01:19 +00:00
|
|
|
if ((f = fopen(dname_out, "w")) == NULL)
|
2016-08-21 17:34:54 +00:00
|
|
|
{
|
2016-08-21 20:01:19 +00:00
|
|
|
error("cannot open %s", dname_out);
|
1984-11-26 13:43:22 +00:00
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
putdtable(fdblock, f);
|
2016-08-21 20:01:19 +00:00
|
|
|
if ((f = fopen(pname_out, "w")) == NULL)
|
2016-08-21 17:34:54 +00:00
|
|
|
{
|
2016-08-21 20:01:19 +00:00
|
|
|
error("cannot open %s", pname_out);
|
1984-11-26 13:43:22 +00:00
|
|
|
}
|
2016-08-21 17:34:54 +00:00
|
|
|
putptable(fproc, f, TRUE);
|
1984-11-26 13:43:22 +00:00
|
|
|
exit(0);
|
|
|
|
}
|