home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.cs.arizona.edu
/
ftp.cs.arizona.edu.tar
/
ftp.cs.arizona.edu
/
icon
/
historic
/
v92.tgz
/
v92.tar
/
v92
/
src
/
iconc
/
typinfer.c
< prev
Wrap
C/C++ Source or Header
|
1996-03-22
|
153KB
|
5,135 lines
/*
* typinfer.c - routines to perform type inference.
*/
#include "::h:gsupport.h"
#include "::h:lexdef.h"
#include "ctrans.h"
#include "csym.h"
#include "ctree.h"
#include "ctoken.h"
#include "cglobals.h"
#include "ccode.h"
#include "cproto.h"
#ifdef TypTrc
#ifdef HighResTime
#include <sys/time.h>
#include <sys/resource.h>
#endif /* HighResTime */
#endif /* TypTrc */
/*
* Information about co-expressions is keep on a list.
*/
struct t_coexpr {
nodeptr n; /* code for co-expression */
int typ_indx; /* relative type number (index) */
struct store *in_store; /* store entry into co-expression via activation */
struct store *out_store; /* store at end of co-expression */
unsigned int *act_typ; /* types passed via co-expression activation */
unsigned int *rslt_typ; /* types resulting from "co-expression return" */
int iteration;
struct t_coexpr *next;
};
struct t_coexpr *coexp_lst;
#ifdef TypTrc
extern int typealloc; /* flag to account for allocation */
extern long typespace; /* amount of space for type inference */
#endif /* TypTrc */
/*
* A type is a bit vector representing a union of basic types. There
* are 3 sizes of types: first class types (Icon language types),
* intermediate value types (first class types plus variable references),
* run-time routine types (intermediate value types plus internal
* references to descriptors such as set elements). When the size of
* the type is known from context, a simple bit vector can be used.
* In other contexts, the size must be included.
*/
struct type {
int size;
unsigned int *bits;
struct type *next;
};
struct symtyps *cur_symtyps; /* maps run-time routine symbols to types */
/*
* argtyps is the an array of types large enough to accommodate the argument
* list of any operation.
*/
struct argtyps {
struct argtyps *next;
unsigned int *types[1]; /* actual size is max_prm */
};
/*
* prototypes for static functions.
*/
hidden novalue abstr_new Params((struct node *n, struct il_code *il));
hidden novalue abstr_typ Params((struct il_code *il, struct type *typ));
hidden struct store *alloc_stor Params((int stor_sz, int n_types));
hidden unsigned int *alloc_typ Params((int n_types));
hidden novalue bitrange Params((int typcd, int *frst_bit,
int *last_bit));
hidden int bitset Params((unsigned int *typ, int bit));
hidden novalue clr_typ Params((unsigned int *type,
unsigned int bit));
hidden novalue chk_succ Params((int ret_flag,
struct store *susp_stor));
hidden struct store *cpy_store Params((struct store *source));
hidden novalue deref_lcl Params((unsigned int *src,
unsigned int *dest));
hidden int eval_cond Params((struct il_code *il));
hidden novalue free_argtyp Params((struct argtyps *argtyps));
hidden novalue free_store Params((struct store *store));
hidden novalue free_wktyp Params((struct type *typ));
hidden int findloops Params(( struct node *n, int resume,
unsigned int *rslt_type));
hidden novalue find_new Params((struct node *n));
hidden novalue gen_inv Params((unsigned int *prc_typ, nodeptr n));
hidden struct argtyps *get_argtyp Params((noargs));
hidden struct store *get_store Params((int clear));
hidden struct type *get_wktyp Params((noargs));
hidden int has_type Params((unsigned int *typ, int typcd,
int clear));
hidden novalue infer_act Params((nodeptr n));
hidden novalue infer_con Params((struct rentry *rec, nodeptr n));
hidden int infer_il Params((struct il_code *il));
hidden novalue infer_impl Params((struct implement *impl,
nodeptr n, struct symtyps *symtyps,
unsigned int *rslt_typ));
hidden novalue infer_nd Params((nodeptr n));
hidden novalue infer_prc Params((struct pentry *proc, nodeptr n));
hidden int is_empty Params((unsigned int *typ));
hidden novalue mrg_act Params((struct t_coexpr *coexp,
struct store *e_store,
struct type *rslt_typ));
hidden novalue mrg_store Params((struct store *source,
struct store *dest));
hidden int other_type Params((unsigned int *typ, int typcd));
hidden novalue set_ret Params((unsigned int *typ));
hidden novalue set_typ Params((unsigned int *type,
unsigned int bit));
hidden novalue side_effect Params((struct il_code *il));
hidden struct symtyps *symtyps Params((int nsyms));
hidden novalue typcd_bits Params((int typcd, struct type *typ));
hidden novalue typ_deref Params((unsigned int *src,
unsigned int *dest, int chk));
#ifdef TypTrc
hidden novalue prt_d_typ Params((FILE *file, unsigned int *typ));
hidden novalue prt_typ Params((FILE *file, unsigned int *typ));
#endif /* TypTrc */
/*
* CpyTyp - copy a type of the given size from one bit vector to another.
*/
#define CpyTyp(size,src,dest) {\
int typ_indx;\
for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx)\
(dest)[typ_indx] = (src)[typ_indx];}
/*
* MrgTyp - merge a type of the given size from one bit vector into another.
*/
#define MrgTyp(size,src,dest) {\
int typ_indx;\
for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx)\
(dest)[typ_indx] |= (src)[typ_indx];}
/*
* MrgTyp - merge a type of the given size from one bit vector into another,
* updating the changed flag if the destination is changed by the merger.
*/
#define ChkMrgTyp(size,src,dest) {\
int typ_indx; unsigned int old;\
for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx) {\
old = (dest)[typ_indx];\
(dest)[typ_indx] |= (src)[typ_indx];\
if (old != (dest)[typ_indx]) ++changed;}}
/*
* ClrTyp - zero out the bit vector for a type.
*/
#define ClrTyp(size,typ) {\
int typ_indx;\
for (typ_indx = 0; typ_indx < NumInts((size)); ++typ_indx)\
(typ)[typ_indx] = 0;}
/*
* NumInts - convert from the number of bits in a bit vector to the
* number of integers implementing it.
*/
#define NumInts(n_bits) (n_bits - 1) / IntBits + 1
#define CanFail 1
/*
* cur_coexp is non-null while performing type inference on code from a
* create expression. If it is null, the possible current co-expressions
* must be found from cur_proc.
*/
struct t_coexpr *cur_coexp = NULL;
struct gentry **proc_map; /* map procedure types to symbol table entries */
struct rentry **rec_map; /* map record types to record information */
struct t_coexpr **coexp_map; /* map co-expression types to information */
/*
* Data base type codes are mapped to type inferencing information using
* an array.
*/
struct typ_info {
int frst_bit; /* first bit in bit vector allocated to this type */
int num_bits; /* number of bits in bit vector allocated to this type */
int new_indx; /* index into arrays of allocated types for operation */
unsigned int *typ; /* for variables: initial type */
};
static struct typ_info *type_array;
static int num_new; /* number of types supporting "new" abstract type comp */
/*
* Data base component codes are mapped to type inferencing information
* using an array.
*/
struct compnt_info {
int frst_bit; /* first bit in bit vector allocated to component */
int num_bits; /* number of bits allocated to this component */
struct store *store; /* maps component "reference" to the type it holds */
};
static struct compnt_info *compnt_array;
static unsigned int frst_fld; /* bit number of 1st record field */
static unsigned int n_fld; /* number of record fields */
static unsigned int frst_gbl; /* bit number of 1st global reference type */
static unsigned int n_gbl; /* number of global variables */
static unsigned int n_nmgbl; /* number of named global variables */
static unsigned int frst_loc; /* bit number of 1st local reference type */
static unsigned int n_loc; /* maximum number of locals in any procedure */
static unsigned int nxt_bit; /* next unassigned bit in bit vector */
static unsigned int n_icntyp; /* number of non-variable types */
static unsigned int n_intrtyp; /* number of types in intermediate values */
static unsigned int n_rttyp; /* number of types in runtime computations */
static unsigned int val_mask; /* mask for non-var types in last int of type */
static unsigned int null_bit; /* bit for null type */
static unsigned int str_bit; /* bit for string type */
static unsigned int cset_bit; /* bit for cset type */
static unsigned int int_bit; /* bit for integer type */
static unsigned int real_bit; /* bit for real type */
static struct store *fld_stor; /* record fields */
static int *cur_new; /* allocated types for current operation */
static struct store *succ_store = NULL; /* current success store */
static struct store *fail_store = NULL; /* current failure store */
static struct store *dummy_stor;
static struct store *store_pool = NULL; /* free list of store structs */
static struct type *type_pool = NULL; /* free list of type structs */
static struct type cur_rslt = {0, NULL, NULL}; /* result type of operation */
static struct argtyps *argtyp_pool = NULL; /* free list of arg type arrays */
static struct argtyps *arg_typs = NULL; /* current arg type array */
static int num_args; /* number of arguments for current operation */
static int n_vararg; /* size of variable part of arg list to run-time routine */
static unsigned int *any_typ; /* type bit vector with all bits on */
long changed; /* number of changes to type information in this iteration */
int iteration; /* iteration number for type inferencing */
#ifdef TypTrc
static FILE *trcfile = NULL; /* output file pointer for tracing */
static char *trcname = NULL; /* output file name for tracing */
static char *trc_indent = "";
#endif /* TypTrc */
/*
* typeinfer - infer types of operands. If "do_typinfer" is set, actually
* do abstract interpretation, otherwise assume any type for all operands.
*/
novalue typeinfer()
{
struct gentry *gptr;
struct lentry *lptr;
nodeptr call_main;
struct pentry *p;
struct rentry *rec;
struct t_coexpr *coexp;
struct store *init_store;
struct store *f_store;
unsigned int *type;
struct implement *ip;
struct lentry **lhash;
struct lentry **vartypmap;
int i, j, k;
int size;
int flag;
#ifdef TypTrc
/*
* Set up for type tracing.
*/
long start_infer, end_infer;
#ifdef HighResTime
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
start_infer = rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000;
#else /* HighResTime */
start_infer = millisec();
#endif /* HighResTime */
typealloc = 1; /* note allocation in this phase */
#ifdef EnvVars
trcname = getenv("TYPTRC");
#else /* EnvVars */
trcname = "typtrc.out";
#endif /* EnvVars */
if (trcname != NULL && strlen(trcname) != 0) {
#if UNIX
if (trcname[0] == '|') {
FILE *popen();
trcfile = popen(trcname+1, WriteText);
}
else
#endif /* UNIX */
trcfile = fopen(trcname, WriteText);
if (trcfile == NULL) {
fprintf(stderr, "TYPTRC: cannot open %s\n", trcname);
fflush(stderr);
exit(ErrorExit);
}
}
#endif /* TypTrc */
/*
* Make sure max_prm is large enough for any run-time routine.
*/
for (i = 0; i < IHSize; ++i)
for (ip = bhash[i]; ip != NULL; ip = ip->blink)
if (ip->nargs > max_prm)
max_prm = ip->nargs;
for (i = 0; i < IHSize; ++i)
for (ip = ohash[i]; ip != NULL; ip = ip->blink)
if (ip->nargs > max_prm)
max_prm = ip->nargs;
/*
* Allocate an arrays to map data base type codes and component codes
* to type inferencing information.
*/
type_array = (struct typ_info *)alloc((unsigned int)(num_typs *
sizeof(struct typ_info)));
compnt_array = (struct compnt_info *)alloc((unsigned int)(num_cmpnts *
sizeof(struct compnt_info)));
/*
* Find those types that support the "new" abstract type computation
* assign to them locations in the arrays of allocated types associated
* with operation invocations. Also initialize the number of type bits.
* Types with no subtypes have one bit. Types allocated with the the "new"
* abstract have a default sub-type that is allocated here. Procedures
* have a subtype to for string invocable operators. Co-expressions
* have a subtype for &main. Records are handled below.
*/
num_new = 0;
for (i = 0; i < num_typs; ++i) {
if (icontypes[i].support_new)
type_array[i].new_indx = num_new++;
type_array[i].num_bits = 1; /* reserve one type bit */
}
type_array[list_typ].num_bits = 2; /* default & list for arg to main() */
cur_coexp = NewStruct(t_coexpr);
cur_coexp->n = NULL;
cur_coexp->next = NULL;
coexp_lst = cur_coexp;
if (do_typinfer) {
/*
* Go through the syntax tree for each procedure locating program
* points that may create structures at run time. Allocate the
* appropriate structure type(s) to each such point.
*/
for (p = proc_lst; p != NULL; p = p->next) {
if (p->nargs < 0)
p->arg_lst = type_array[list_typ].num_bits++; /* list for varargs */
find_new(Tree1(p->tree)); /* initial clause */
find_new(Tree2(p->tree)); /* body of procedure */
}
}
/*
* Allocate a type number for each record type (use record number for
* offset) and a variable type number for each field.
*/
n_fld = 0;
if (rec_lst == NULL) {
type_array[rec_typ].num_bits = 0;
rec_map = NULL;
}
else {
type_array[rec_typ].num_bits = rec_lst->rec_num + 1;
rec_map = (struct rentry **)alloc(
(unsigned int)((rec_lst->rec_num + 1)*sizeof(struct rentry *)));
for (rec = rec_lst; rec != NULL; rec = rec->next) {
rec->frst_fld = n_fld;
n_fld += rec->nfields;
rec_map[rec->rec_num] = rec;
}
}
/*
* Allocate type numbers to global variables. Don't count those procedure
* variables that are no longer referenced in the syntax tree. Do count
* static variables. Also allocate types to procedures, built-in functions,
* record constructors.
*/
n_gbl = 0;
for (i = 0; i < GHSize; i++)
for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) {
flag = gptr->flag;
if (flag & F_SmplInv)
gptr->index = -1; /* unused: set to something not a valid type */
else {
gptr->index = n_gbl++;
if (flag & (F_Proc | F_Record | F_Builtin))
gptr->init_type = type_array[proc_typ].num_bits++;
}
if (flag & F_Proc) {
for (lptr = gptr->val.proc->statics; lptr != NULL;lptr = lptr->next)
lptr->val.index = n_gbl++;
}
}
n_nmgbl = n_gbl;
/*
* Determine relative bit numbers for predefined variable types that
* are treated as sets of global variables.
*/
for (i = 0; i < num_typs; ++i)
if (icontypes[i].deref == DrfGlbl)
type_array[i].frst_bit = n_gbl++; /* converted to absolute later */
proc_map = (struct gentry **)alloc(
(unsigned int)((type_array[proc_typ].num_bits)*sizeof(struct gentry *)));
proc_map[0] = NULL; /* proc type for string invocable operators */
for (i = 0; i < GHSize; i++)
for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) {
flag = gptr->flag;
if (!(flag & F_SmplInv) && (flag & (F_Proc | F_Record | F_Builtin)))
proc_map[gptr->init_type] = gptr;
}
/*
* Allocate type numbers to local variables. The same numbers are reused
* in different procedures.
*/
n_loc = 0;
for (p = proc_lst; p != NULL; p = p->next) {
i = Abs(p->nargs);
for (lptr = p->args; lptr != NULL; lptr = lptr->next)
lptr->val.index = --i;
i = Abs(p->nargs);
for (lptr = p->dynams; lptr != NULL; lptr = lptr->next)
lptr->val.index = i++;
n_loc = Max(n_loc, i);
/*
* produce a mapping from the variable types used in this procedure
* to the corresponding symbol table entries.
*/
if (n_gbl + n_loc == 0)
vartypmap = NULL;
else
vartypmap = (struct lentry **)alloc(
(unsigned int)((n_gbl + n_loc)*sizeof(struct lentry *)));
for (i = 0; i < n_gbl + n_loc; ++i)
vartypmap[i] = NULL; /* no entries for foreign statics */
p->vartypmap = vartypmap;
lhash = p->lhash;
for (i = 0; i < LHSize; ++i) {
for (lptr = lhash[i]; lptr != NULL; lptr = lptr->blink) {
switch (lptr->flag) {
case F_Global:
gptr = lptr->val.global;
if (!(gptr->flag & F_SmplInv))
vartypmap[gptr->index] = lptr;
break;
case F_Static:
vartypmap[lptr->val.index] = lptr;
break;
case F_Dynamic:
case F_Argument:
vartypmap[n_gbl + lptr->val.index] = lptr;
}
}
}
}
/*
* There is a component reference subtype for every subtype of the
* associated aggregate type.
*/
for (i = 0; i < num_cmpnts; ++i)
compnt_array[i].num_bits = type_array[typecompnt[i].aggregate].num_bits;
/*
* Assign bits for non-variable (first-class) types.
*/
nxt_bit = 0;
for (i = 0; i < num_typs; ++i)
if (icontypes[i].deref == DrfNone) {
type_array[i].frst_bit = nxt_bit;
nxt_bit += type_array[i].num_bits;
}
n_icntyp = nxt_bit; /* number of first-class types */
/*
* Load some commonly needed bit numbers into global variable.
*/
null_bit = type_array[null_typ].frst_bit;
str_bit = type_array[str_typ].frst_bit;
cset_bit = type_array[cset_typ].frst_bit;
int_bit = type_array[int_typ].frst_bit;
real_bit = type_array[real_typ].frst_bit;
/*
* Assign bits for predefined variable types that are not treated as
* sets of globals.
*/
for (i = 0; i < num_typs; ++i)
if (icontypes[i].deref == DrfCnst || icontypes[i].deref == DrfSpcl) {
type_array[i].frst_bit = nxt_bit;
nxt_bit += type_array[i].num_bits;
}
/*
* Assign bits to aggregate compontents that are variables.
*/
for (i = 0; i < num_cmpnts; ++i)
if (typecompnt[i].var) {
compnt_array[i].frst_bit = nxt_bit;
nxt_bit += compnt_array[i].num_bits;
}
/*
* Assign bits to record fields and named variables.
*/
frst_fld = nxt_bit;
nxt_bit += n_fld;
frst_gbl = nxt_bit;
nxt_bit += n_gbl;
frst_loc = nxt_bit;
nxt_bit += n_loc;
/*
* Convert from relative to ablsolute bit numbers for predefined variable
* types that are treated as sets of global variables.
*/
for (i = 0; i < num_typs; ++i)
if (icontypes[i].deref == DrfGlbl)
type_array[i].frst_bit += frst_gbl;
n_intrtyp = nxt_bit; /* number of types for intermediate values */
/*
* Assign bits to aggregate compontents that are not variables. These
* are the runtime system's internal descriptor reference types.
*/
for (i = 0; i < num_cmpnts; ++i)
if (!typecompnt[i].var) {
compnt_array[i].frst_bit = nxt_bit;
nxt_bit += compnt_array[i].num_bits;
}
n_rttyp = nxt_bit; /* total size of type system */
#ifdef TypTrc
if (trcfile != NULL) {
/*
* Output a summary of the type system.
*/
for (i = 0; i < num_typs; ++i) {
fprintf(trcfile, "%s", icontypes[i].id);
if (strcmp(icontypes[i].id, icontypes[i].abrv) != 0)
fprintf(trcfile, "(%s)", icontypes[i].abrv);
fprintf(trcfile, " sub-types: %d\n", type_array[i].num_bits);
}
}
#endif /* TypTrc */
/*
* The division between bits for first-class types and variables types
* generally occurs in the middle of a word. Set up a mask for extracting
* the first-class types from this word.
*/
val_mask = 0;
i = n_icntyp - (NumInts(n_icntyp) - 1) * IntBits;
while (i--)
val_mask = (val_mask << 1) | 1;
if (do_typinfer) {
/*
* Create stores large enough for the component references. These
* are global to the entire program, rather than being propagated
* from node to node in the syntax tree.
*/
for (i = 0; i < num_cmpnts; ++i) {
if (i == str_var)
size = n_intrtyp;
else
size = n_icntyp;
compnt_array[i].store = alloc_stor(compnt_array[i].num_bits, size);
}
fld_stor = alloc_stor(n_fld, n_icntyp);
dummy_stor = get_store(0);
/*
* First list is arg to main: a list of strings.
*/
set_typ(compnt_array[lst_elem].store->types[1], str_typ);
}
/*
* Set up a type bit vector with all bits on.
*/
any_typ = alloc_typ(n_rttyp);
for (i = 0; i < NumInts(n_rttyp); ++i)
any_typ[i] = ~(unsigned int)0;
/*
* Initialize stores and return values for procedures. Also initialize
* flag indicating whether the procedure can be executed.
*/
call_main = NULL;
for (p = proc_lst; p != NULL; p = p->next) {
if (do_typinfer) {
p->iteration = 0;
p->ret_typ = alloc_typ(n_intrtyp);
p->coexprs = alloc_typ(n_icntyp);
p->in_store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (p->ret_flag & DoesSusp)
p->susp_store = alloc_stor(n_gbl, n_icntyp);
else
p->susp_store = NULL;
for (i = Abs(p->nargs); i < n_loc; ++i)
set_typ(p->in_store->types[n_gbl + i], null_bit);
if (p->nargs < 0)
set_typ(p->in_store->types[n_gbl + Abs(p->nargs) - 1],
type_array[list_typ].frst_bit + p->arg_lst);
if (strcmp(p->name, "main") == 0) {
/*
* create a the initial call to main with one list argument.
*/
call_main = invk_main(p);
call_main->type = alloc_typ(n_intrtyp);
Tree2(call_main)->type = alloc_typ(n_intrtyp);
set_typ(Tree2(call_main)->type, type_array[list_typ].frst_bit + 1);
call_main->store = alloc_stor(n_gbl + n_loc, n_icntyp);
}
p->out_store = alloc_stor(n_gbl, n_icntyp);
p->reachable = 0;
}
else
p->reachable = 1;
/*
* Analyze the code of the procedure to determine where to place stores
* that survive iterations of type inferencing. Note, both the initial
* clause and the body of the procedure are bounded.
*/
findloops(Tree1(p->tree), 0, NULL);
findloops(Tree2(p->tree), 0, NULL);
}
/*
* If type inferencing is suppressed, we have set up very conservative
* type information and will do no inferencing.
*/
if (!do_typinfer)
return;
if (call_main == NULL)
return; /* no main procedure, cannot continue */
if (tfatals > 0)
return; /* don't do inference if there are fatal errors */
/*
* Construct mapping from co-expression types to information
* about the co-expressions and finish initializing the information.
*/
i = type_array[coexp_typ].num_bits;
coexp_map = (struct t_coexpr **)alloc(
(unsigned int)(i * sizeof(struct t_coexpr *)));
for (coexp = coexp_lst; coexp != NULL; coexp = coexp->next) {
coexp_map[--i] = coexp;
coexp->typ_indx = i;
coexp->in_store = alloc_stor(n_gbl + n_loc, n_icntyp);
coexp->out_store = alloc_stor(n_gbl + n_loc, n_icntyp);
coexp->act_typ = alloc_typ(n_intrtyp);
coexp->rslt_typ = alloc_typ(n_intrtyp);
coexp->iteration = 0;
}
/*
* initialize globals
*/
init_store = get_store(1);
for (i = 0; i < GHSize; i++)
for (gptr = ghash[i]; gptr != NULL; gptr = gptr->blink) {
flag = gptr->flag;
if (!(flag & F_SmplInv)) {
type = init_store->types[gptr->index];
if (flag & (F_Proc | F_Record | F_Builtin))
set_typ(type, type_array[proc_typ].frst_bit + gptr->init_type);
else
set_typ(type, null_bit);
}
}
/*
* Initialize types for predefined variable types.
*/
for (i = 0; i < num_typs; ++i) {
type = NULL;
switch (icontypes[i].deref) {
case DrfGlbl:
/*
* Treated as a global variable.
*/
type = init_store->types[type_array[i].frst_bit - frst_gbl];
break;
case DrfCnst:
/*
* Type doesn't change so keep one copy.
*/
type = alloc_typ(n_intrtyp);
type_array[i].typ = type;
break;
}
if (type != NULL) {
/*
* Determine which types are in the initial type for this variable.
*/
for (j = 0; j < num_typs; ++j) {
if (icontypes[i].typ[j] != '.') {
for (k = 0; k < type_array[j].num_bits; ++k)
set_typ(type, type_array[j].frst_bit + k);
}
}
}
}
f_store = get_store(1);
/*
* Type inferencing iterates over the program until a fixed point is
* reached.
*/
changed = 1L; /* force first iteration */
iteration = 0;
if (verbose > 1)
fprintf(stderr, "type inferencing: ");
while (changed > 0L) {
changed = 0L;
++iteration;
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, "**** iteration %d ****\n", iteration);
#endif /* TypTrc */
/*
* Start at the implicit initial call to the main procedure. Inferencing
* walks the call graph from here.
*/
succ_store = cpy_store(init_store);
fail_store = f_store;
infer_nd(call_main);
/*
* If requested, monitor the progress of inferencing.
*/
switch (verbose) {
case 0:
case 1:
break;
case 2:
fprintf(stderr, ".");
break;
default: /* > 2 */
if (iteration != 1)
fprintf(stderr, ", ");
fprintf(stderr, "%ld", changed);
}
}
/*
* Type inferencing is finished, complete any diagnostic output.
*/
if (verbose > 1)
fprintf(stderr, "\n");
#ifdef TypTrc
if (trcfile != NULL) {
#ifdef HighResTime
getrusage(RUSAGE_SELF, &rusage);
end_infer = rusage.ru_utime.tv_sec*1000 + rusage.ru_utime.tv_usec/1000;
#else /* HighResTime */
end_infer = millisec();
#endif /* HighResTime */
fprintf(trcfile, "\n**** inferencing time: %ld milliseconds\n",
end_infer - start_infer);
fprintf(trcfile, "\n**** inferencing space: %ld bytes\n",typespace);
fclose(trcfile);
}
typealloc = 0;
#endif /* TypTrc */
}
/*
* find_new - walk the syntax tree allocating structure types where
* operations create new structures.
*/
static novalue find_new(n)
struct node *n;
{
struct t_coexpr *coexp;
struct node *cases;
struct node *clause;
int nargs;
int i;
n->new_types = NULL;
switch (n->n_type) {
case N_Cset:
case N_Empty:
case N_Id:
case N_Int:
case N_Next:
case N_Real:
case N_Str:
break;
case N_Bar:
case N_Break:
case N_Field:
case N_Not:
find_new(Tree0(n));
break;
case N_Alt:
case N_Apply:
case N_Limit:
case N_Slist:
find_new(Tree0(n));
find_new(Tree1(n));
break;
case N_Activat:
find_new(Tree1(n));
find_new(Tree2(n));
break;
case N_If:
find_new(Tree0(n)); /* control clause */
find_new(Tree1(n)); /* then clause */
find_new(Tree2(n)); /* else clause, may be N_Empty */
break;
case N_Create:
/*
* Allocate a sub-type for the co-expressions created here.
*/
n->new_types = (int *)alloc((unsigned int)(sizeof(int)));
n->new_types[0] = type_array[coexp_typ].num_bits++;
coexp = NewStruct(t_coexpr);
coexp->n = Tree0(n);
coexp->next = coexp_lst;
coexp_lst = coexp;
find_new(Tree0(n));
break;
case N_Augop:
abstr_new(n, Impl0(n)->in_line); /* assignment */
abstr_new(n, Impl1(n)->in_line); /* the operation */
find_new(Tree2(n)); /* 1st operand */
find_new(Tree3(n)); /* 2nd operand */
break;
case N_Case:
find_new(Tree0(n)); /* control clause */
cases = Tree1(n);
while (cases != NULL) {
if (cases->n_type == N_Ccls) {
clause = cases;
cases = NULL;
}
else {
clause = Tree1(cases);
cases = Tree0(cases);
}
find_new(Tree0(clause)); /* value of clause */
find_new(Tree1(clause)); /* body of clause */
}
if (Tree2(n) != NULL)
find_new(Tree2(n)); /* deflt */
break;
case N_Invok:
nargs = Val0(n); /* number of arguments */
find_new(Tree1(n)); /* thing being invoked */
for (i = 1; i <= nargs; ++i)
find_new(n->n_field[i+1].n_ptr); /* arg i */
break;
case N_InvOp:
/*
* This is a call to an operation, this is what we must
* check for "new" abstract type computation.
*/
nargs = Val0(n); /* number of arguments */
abstr_new(n, Impl1(n)->in_line); /* operation */
for (i = 1; i <= nargs; ++i)
find_new(n->n_field[i+1].n_ptr); /* arg i */
break;
case N_InvProc:
case N_InvRec:
nargs = Val0(n); /* number of arguments */
for (i = 1; i <= nargs; ++i)
find_new(n->n_field[i+1].n_ptr); /* arg i */
break;
case N_Loop:
switch ((int)Val0(Tree0(n))) {
case EVERY:
case SUSPEND:
case WHILE:
case UNTIL:
find_new(Tree1(n)); /* control clause */
find_new(Tree2(n)); /* do clause - may be N_Empty*/
break;
case REPEAT:
find_new(Tree1(n)); /* clause */
break;
}
case N_Ret:
if (Val0(Tree0(n)) == RETURN)
find_new(Tree1(n)); /* value - may be N_Empty */
break;
case N_Scan:
if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK)
abstr_new(n, optab[asgn_loc].binary->in_line);
find_new(Tree1(n)); /* subject */
find_new(Tree2(n)); /* body */
break;
case N_Sect:
abstr_new(n, Impl0(n)->in_line); /* sectioning */
if (Impl1(n) != NULL)
abstr_new(n, Impl1(n)->in_line); /* plus, minus, or nothing */
find_new(Tree2(n)); /* 1st operand */
find_new(Tree3(n)); /* 2nd operand */
find_new(Tree4(n)); /* 3rd operand */
break;
case N_SmplAsgn:
case N_SmplAug:
find_new(Tree3(n));
break;
default:
fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
exit(ErrorExit);
}
}
/*
* abstr_new - find the abstract clauses in the implementation of an operation.
* If they indicate that the operations creates structures, allocate a
* type for the structures and associate it with the node in the syntax tree.
*/
static novalue abstr_new(n, il)
struct node *n;
struct il_code *il;
{
int i;
int num_cases, indx;
struct typ_info *t_info;
if (il == NULL)
return;
switch (il->il_type) {
case IL_New:
/*
* We have found a "new" construct in an abstract type computation.
* Make sure an array has been created to hold the types allocated
* to this call, then allocate the indicated type if one has not
* already been allocated.
*/
if (n->new_types == NULL) {
n->new_types = (int *)alloc((unsigned int)(num_new * sizeof(int)));
for (i = 0; i < num_new; ++i)
n->new_types[i] = -1;
}
t_info = &type_array[il->u[0].n]; /* index by type code */
if (n->new_types[t_info->new_indx] < 0) {
n->new_types[t_info->new_indx] = t_info->num_bits++;
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, "%s (%d,%d) %s\n", n->n_file, n->n_line,
n->n_col, icontypes[il->u[0].n].id);
#endif /* TypTrc */
}
i = il->u[1].n; /* num args */
indx = 2;
while (i--)
abstr_new(n, il->u[indx++].fld);
break;
case IL_If1:
abstr_new(n, il->u[1].fld);
break;
case IL_If2:
abstr_new(n, il->u[1].fld);
abstr_new(n, il->u[2].fld);
break;
case IL_Tcase1:
num_cases = il->u[1].n;
indx = 2;
for (i = 0; i < num_cases; ++i) {
indx += 2; /* skip type info */
abstr_new(n, il->u[indx++].fld); /* action */
}
break;
case IL_Tcase2:
num_cases = il->u[1].n;
indx = 2;
for (i = 0; i < num_cases; ++i) {
indx += 2; /* skip type info */
abstr_new(n, il->u[indx++].fld); /* action */
}
abstr_new(n, il->u[indx].fld); /* default */
break;
case IL_Lcase:
num_cases = il->u[0].n;
indx = 1;
for (i = 0; i < num_cases; ++i) {
++indx; /* skip selection num */
abstr_new(n, il->u[indx++].fld); /* action */
}
abstr_new(n, il->u[indx].fld); /* default */
break;
case IL_Acase:
abstr_new(n, il->u[2].fld); /* C_integer action */
if (largeints)
abstr_new(n, il->u[3].fld); /* integer action */
abstr_new(n, il->u[4].fld); /* C_double action */
break;
case IL_Abstr:
case IL_Inter:
case IL_Lst:
case IL_TpAsgn:
case IL_Union:
abstr_new(n, il->u[0].fld);
abstr_new(n, il->u[1].fld);
break;
case IL_Compnt:
case IL_Store:
case IL_VarTyp:
abstr_new(n, il->u[0].fld);
break;
case IL_Block:
case IL_Call:
case IL_Const: /* should have been replaced by literal node */
case IL_Err1:
case IL_Err2:
case IL_IcnTyp:
case IL_Subscr:
case IL_Var:
break;
default:
fprintf(stderr, "compiler error: unknown info in data base\n");
exit(ErrorExit);
}
}
/*
* alloc_stor - allocate a store with empty types.
*/
static struct store *alloc_stor(stor_sz, n_types)
int stor_sz;
int n_types;
{
struct store *stor;
int i;
/*
* If type inferencing is disabled, we don't actually make use of
* any stores, but the initialization code asks for them anyway.
*/
if (!do_typinfer)
return NULL;
stor = (struct store *)alloc((unsigned int)(sizeof(struct store) +
((stor_sz - 1) * sizeof(unsigned int *))));
stor->next = NULL;
stor->perm = 1;
for (i = 0; i < stor_sz; ++i) {
stor->types[i] = (unsigned int *)alloc_typ(n_types);
}
return stor;
}
/*
* alloc_typ - allocate a bit vector for a set of basic types.
*/
static unsigned int *alloc_typ(n_types)
int n_types;
{
int n_ints;
unsigned int *typ;
int i;
unsigned int init = 0;
n_ints = NumInts(n_types);
typ = (unsigned int *)alloc((unsigned int)((n_ints)*sizeof(unsigned int)));
/*
* Initialization: if we are doing inference, start out assuming no types.
* If we are not doing inference, assume any type.
*/
if (!do_typinfer)
init = ~init;
for (i = 0; i < n_ints; ++i)
typ[i] = init;
return typ;
}
/*
* set_typ - set a particular type bit in a type bit vector.
*/
static novalue set_typ(type, bit)
unsigned int *type;
unsigned int bit;
{
unsigned int indx;
unsigned int mask;
indx = bit / IntBits;
mask = 1;
mask <<= bit % IntBits;
type[indx] |= mask;
}
/*
* clr_type - clear a particular type bit in a type bit vector.
*/
static novalue clr_typ(type, bit)
unsigned int *type;
unsigned int bit;
{
unsigned int indx;
unsigned int mask;
indx = bit / IntBits;
mask = 1;
mask <<= bit % IntBits;
type[indx] &= ~mask;
}
/*
* findloops - find both explicit loops and implicit loops caused by
* goal-directed evaluation. Allocate stores for them. Determine which
* expressions cannot fail (used to eliminate dynamic store allocation
* for some bounded expressions). Allocate stores for 'if' and 'case'
* expressions that can be resumed. Initialize expression types.
* The syntax tree is walked in reverse execution order looking for
* failure and for generators.
*/
static int findloops(n, resume, rslt_type)
struct node *n;
int resume;
unsigned int *rslt_type;
{
struct loop {
int resume;
int can_fail;
int every_cntrl;
unsigned int *type;
struct loop *prev;
} loop_info;
struct loop *loop_sav;
static struct loop *cur_loop = NULL;
struct node *cases;
struct node *clause;
int can_fail;
int nargs, i;
n->store = NULL;
if (!do_typinfer)
rslt_type = any_typ;
switch (n->n_type) {
case N_Activat:
if (rslt_type == NULL)
rslt_type = alloc_typ(n_intrtyp);
n->type = rslt_type;
/*
* Assume activation can fail.
*/
can_fail = findloops(Tree2(n), 1, NULL);
can_fail = findloops(Tree1(n), can_fail, NULL);
n->symtyps = symtyps(2);
if (optab[Val0(Tree0(n))].tok.t_type == AUGAT)
n->symtyps->next = symtyps(2);
break;
case N_Alt:
if (rslt_type == NULL)
rslt_type = alloc_typ(n_intrtyp);
n->type = rslt_type;
#ifdef TypTrc
rslt_type = NULL; /* don't share result loc with subexpressions*/
#endif /* TypTrc */
if (resume)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
can_fail = findloops(Tree0(n), resume, rslt_type) |
findloops(Tree1(n), resume, rslt_type);
break;
case N_Apply:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
/*
* Assume operation can suspend or fail.
*/
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
can_fail = findloops(Tree1(n), 1, NULL);
can_fail = findloops(Tree0(n), can_fail, NULL);
n->symtyps = symtyps(max_sym);
break;
case N_Augop:
if (rslt_type == NULL)
rslt_type = alloc_typ(n_intrtyp);
n->type = rslt_type;
can_fail = resume;
/*
* Impl0(n) is assignment.
*/
if (resume && Impl0(n)->ret_flag & DoesSusp)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (MightFail(Impl0(n)->ret_flag))
can_fail = 1;
/*
* Impl1(n) is the augmented operation.
*/
if (can_fail && Impl1(n)->ret_flag & DoesSusp && n->store == NULL)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (MightFail(Impl1(n)->ret_flag))
can_fail = 1;
can_fail = findloops(Tree3(n), can_fail, NULL); /* operand 2 */
can_fail = findloops(Tree2(n), can_fail, NULL); /* operand 1 */
n->type = Tree2(n)->type;
Typ4(n) = alloc_typ(n_intrtyp);
n->symtyps = symtyps(n_arg_sym(Impl1(n)));
n->symtyps->next = symtyps(n_arg_sym(Impl0(n)));
break;
case N_Bar:
can_fail = findloops(Tree0(n), resume, rslt_type);
n->type = Tree0(n)->type;
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
break;
case N_Break:
if (cur_loop == NULL) {
nfatal(n, "invalid context for break", NULL);
return 0;
}
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
loop_sav = cur_loop;
cur_loop = cur_loop->prev;
loop_sav->can_fail |= findloops(Tree0(n), loop_sav->resume,
loop_sav->type);
cur_loop = loop_sav;
can_fail = 0;
break;
case N_Case:
if (rslt_type == NULL)
rslt_type = alloc_typ(n_intrtyp);
n->type = rslt_type;
#ifdef TypTrc
rslt_type = NULL; /* don't share result loc with subexpressions*/
#endif /* TypTrc */
if (resume)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
/*
* control clause is bounded
*/
can_fail = findloops(Tree0(n), 0, NULL);
cases = Tree1(n);
while (cases != NULL) {
if (cases->n_type == N_Ccls) {
clause = cases;
cases = NULL;
}
else {
clause = Tree1(cases);
cases = Tree0(cases);
}
/*
* The expression being compared can be resumed.
*/
findloops(Tree0(clause), 1, NULL);
/*
* Body.
*/
can_fail |= findloops(Tree1(clause), resume, rslt_type);
}
if (Tree2(n) == NULL)
can_fail = 1;
else
can_fail |= findloops(Tree2(n), resume, rslt_type); /* default */
break;
case N_Create:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
findloops(Tree0(n), 1, NULL); /* co-expression code */
/*
* precompute type
*/
i= type_array[coexp_typ].frst_bit;
if (do_typinfer)
i += n->new_types[0];
set_typ(n->type, i);
can_fail = resume;
break;
case N_Cset:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
set_typ(n->type, type_array[cset_typ].frst_bit); /* precompute type */
can_fail = resume;
break;
case N_Empty:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
set_typ(n->type, null_bit); /* precompute type */
can_fail = resume;
break;
case N_Id: {
struct lentry *var;
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
/*
* Precompute type
*/
var = LSym0(n);
if (var->flag & F_Global)
set_typ(n->type, frst_gbl + var->val.global->index);
else if (var->flag & F_Static)
set_typ(n->type, frst_gbl + var->val.index);
else
set_typ(n->type, frst_loc + var->val.index);
can_fail = resume;
}
break;
case N_Field:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
can_fail = findloops(Tree0(n), resume, NULL);
n->symtyps = symtyps(1);
break;
case N_If:
if (rslt_type == NULL)
rslt_type = alloc_typ(n_intrtyp);
n->type = rslt_type;
#ifdef TypTrc
rslt_type = NULL; /* don't share result loc with subexpressions*/
#endif /* TypTrc */
/*
* control clause is bounded
*/
findloops(Tree0(n), 0, NULL);
can_fail = findloops(Tree1(n), resume, rslt_type);
if (Tree2(n)->n_type == N_Empty)
can_fail = 1;
else {
if (resume)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
can_fail |= findloops(Tree2(n), resume, rslt_type);
}
break;
case N_Int:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
set_typ(n->type, int_bit); /* precompute type */
can_fail = resume;
break;
case N_Invok:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
nargs = Val0(n); /* number of arguments */
/*
* Assume operation can suspend and fail.
*/
if (resume)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
can_fail = 1;
for (i = nargs; i >= 0; --i)
can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
n->symtyps = symtyps(max_sym);
break;
case N_InvOp:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
nargs = Val0(n); /* number of arguments */
if (resume && Impl1(n)->ret_flag & DoesSusp)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (MightFail(Impl1(n)->ret_flag))
can_fail = 1;
else
can_fail = resume;
for (i = nargs; i >= 1; --i)
can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
n->symtyps = symtyps(n_arg_sym(Impl1(n)));
break;
case N_InvProc:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
nargs = Val0(n); /* number of arguments */
if (resume && Proc1(n)->ret_flag & DoesSusp)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (Proc1(n)->ret_flag & DoesFail)
can_fail = 1;
else
can_fail = resume;
for (i = nargs; i >= 1; --i)
can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
break;
case N_InvRec:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
nargs = Val0(n); /* number of args */
if (err_conv)
can_fail = 1;
else
can_fail = resume;
for (i = nargs; i >= 1; --i)
can_fail = findloops(n->n_field[i+1].n_ptr, can_fail, NULL);
break;
case N_Limit:
findloops(Tree0(n), resume, rslt_type);
can_fail = findloops(Tree1(n), 1, NULL);
n->type = Tree0(n)->type;
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
n->symtyps = symtyps(1);
break;
case N_Loop: {
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
loop_info.prev = cur_loop;
loop_info.resume = resume;
loop_info.can_fail = 0;
loop_info.every_cntrl = 0;
loop_info.type = n->type;
cur_loop = &loop_info;
switch ((int)Val0(Tree0(n))) {
case EVERY:
case SUSPEND:
/*
* The control clause can be resumed. The body is bounded.
*/
loop_info.every_cntrl = 1;
can_fail = findloops(Tree1(n), 1, NULL);
loop_info.every_cntrl = 0;
findloops(Tree2(n), 0, NULL);
break;
case REPEAT:
/*
* The loop needs a saved store. The body is bounded.
*/
findloops(Tree1(n), 0, NULL);
can_fail = 0;
break;
case WHILE:
/*
* The loop needs a saved store. The control
* clause and the body are each bounded.
*/
can_fail = findloops(Tree1(n), 0, NULL);
findloops(Tree2(n), 0, NULL);
break;
case UNTIL:
/*
* The loop needs a saved store. The control
* clause and the body are each bounded.
*/
findloops(Tree1(n), 0, NULL);
findloops(Tree2(n), 0, NULL);
can_fail = 1;
break;
}
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (do_typinfer && resume)
n->store->next = alloc_stor(n_gbl + n_loc, n_icntyp);
can_fail |= cur_loop->can_fail;
cur_loop = cur_loop->prev;
}
break;
case N_Next:
if (cur_loop == NULL) {
nfatal(n, "invalid context for next", NULL);
return 1;
}
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
can_fail = cur_loop->every_cntrl;
break;
case N_Not:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
set_typ(n->type, null_bit); /* precompute type */
/*
* The expression is bounded.
*/
findloops(Tree0(n), 0, NULL);
can_fail = 1;
break;
case N_Real:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
set_typ(n->type, real_bit); /* precompute type */
can_fail = resume;
break;
case N_Ret:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
if (Val0(Tree0(n)) == RETURN) {
/*
* The expression is bounded.
*/
findloops(Tree1(n), 0, NULL);
}
can_fail = 0;
break;
case N_Scan: {
struct implement *asgn_impl;
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
n->symtyps = symtyps(1);
can_fail = resume;
if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK) {
asgn_impl = optab[asgn_loc].binary;
if (resume && asgn_impl->ret_flag & DoesSusp)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (MightFail(asgn_impl->ret_flag))
can_fail = 1;
n->symtyps->next = symtyps(n_arg_sym(asgn_impl));
}
can_fail = findloops(Tree2(n), can_fail, NULL); /* body */
can_fail = findloops(Tree1(n), can_fail, NULL); /* subject */
}
break;
case N_Sect:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
can_fail = resume;
/*
* Impl0(n) is sectioning.
*/
if (resume && Impl0(n)->ret_flag & DoesSusp)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (MightFail(Impl0(n)->ret_flag))
can_fail = 1;
n->symtyps = symtyps(n_arg_sym(Impl0(n)));
if (Impl1(n) != NULL) {
/*
* Impl1(n) is plus or minus
*/
if (can_fail && Impl1(n)->ret_flag & DoesSusp && n->store == NULL)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (MightFail(Impl1(n)->ret_flag))
can_fail = 1;
n->symtyps->next = symtyps(n_arg_sym(Impl1(n)));
}
can_fail = findloops(Tree4(n), can_fail, NULL); /* operand 3 */
can_fail = findloops(Tree3(n), can_fail, NULL); /* operand 2 */
can_fail = findloops(Tree2(n), can_fail, NULL); /* operand 1 */
break;
case N_Slist:
/*
* 1st expression is bounded.
*/
findloops(Tree0(n), 0, NULL);
can_fail = findloops(Tree1(n), resume, rslt_type);
n->type = Tree1(n)->type;
break;
case N_SmplAsgn:
can_fail = findloops(Tree3(n), resume, NULL); /* 2nd operand */
findloops(Tree2(n), can_fail, rslt_type); /* variable */
n->type = Tree2(n)->type;
break;
case N_SmplAug:
can_fail = resume;
/*
* Impl1(n) is the augmented operation.
*/
if (resume && Impl1(n)->ret_flag & DoesSusp)
n->store = alloc_stor(n_gbl + n_loc, n_icntyp);
if (MightFail(Impl1(n)->ret_flag))
can_fail = 1;
can_fail = findloops(Tree3(n), can_fail, NULL); /* 2nd operand */
findloops(Tree2(n), can_fail, rslt_type); /* variable */
n->symtyps = symtyps(n_arg_sym(Impl1(n)));
n->type = Tree2(n)->type;
Typ4(n) = alloc_typ(n_intrtyp);
break;
case N_Str:
if (rslt_type == NULL)
n->type = alloc_typ(n_intrtyp);
else
n->type = rslt_type;
set_typ(n->type, str_bit); /* precompute type */
can_fail = resume;
break;
default:
fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
exit(ErrorExit);
}
if (can_fail)
n->flag = CanFail;
else
n->flag = 0;
return can_fail;
}
/*
* symtyps - determine the number of entries needed for a symbol table
* that maps argument indexes to types for an operation in the
* data base. Allocate the symbol table.
*/
static struct symtyps *symtyps(nsyms)
int nsyms;
{
struct symtyps *tab;
if (nsyms == 0)
return NULL;
tab = (struct symtyps *)alloc((unsigned int)(sizeof(struct symtyps) +
(nsyms - 1) * sizeof(int *)));
tab->nsyms = nsyms;
tab->next = NULL;
while (nsyms)
tab->types[--nsyms] = alloc_typ(n_intrtyp);
return tab;
}
/*
* infer_proc - perform type inference on a call to an Icon procedure.
*/
static novalue infer_prc(proc, n)
struct pentry *proc;
nodeptr n;
{
struct store *s_store;
struct store *f_store;
struct store *store;
struct pentry *sv_proc;
struct t_coexpr *sv_coexp;
struct lentry *lptr;
nodeptr n1;
int i;
int nparams;
int coexp_bit;
/*
* Determine what co-expressions the procedure might be called from.
*/
if (cur_coexp == NULL)
ChkMrgTyp(n_icntyp, cur_proc->coexprs, proc->coexprs)
else {
coexp_bit = type_array[coexp_typ].frst_bit + cur_coexp->typ_indx;
if (!bitset(proc->coexprs, coexp_bit)) {
++changed;
set_typ(proc->coexprs, coexp_bit);
}
}
proc->reachable = 1; /* this procedure can be called */
/*
* If this procedure can suspend, there may be backtracking paths
* to this invocation. If so, propagate types of globals from the
* backtracking paths to the suspends of the procedure and propagate
* types of locals to the success store of the call.
*/
if (proc->ret_flag & DoesSusp && n->store != NULL) {
for (i = 0; i < n_gbl; ++i)
ChkMrgTyp(n_icntyp, n->store->types[i], proc->susp_store->types[i])
for (i = 0; i < n_loc; ++i)
MrgTyp(n_icntyp, n->store->types[n_gbl + i], succ_store->types[n_gbl +
i])
}
/*
* Merge the types of global variables into the "in store" of the
* procedure. Because the body of the procedure may already have
* been processed for this pass, the "changed" flag must be set if
* there is a change of type in the store. This will insure that
* there will be another iteration in which to propagate the change
* into the body.
*/
store = proc->in_store;
for (i = 0; i < n_gbl; ++i)
ChkMrgTyp(n_icntyp, succ_store->types[i], store->types[i])
#ifdef TypTrc
/*
* Trace the call.
*/
if (trcfile != NULL)
fprintf(trcfile, "%s (%d,%d) %s%s(", n->n_file, n->n_line, n->n_col,
trc_indent, proc->name);
#endif /* TypTrc */
/*
* Get the types of the arguments, starting with the non-varargs part.
*/
nparams = proc->nargs; /* number of parameters */
if (nparams < 0)
nparams = -nparams - 1;
for (i = 0; i < num_args && i < nparams; ++i) {
typ_deref(arg_typs->types[i], store->types[n_gbl + i], 1);
#ifdef TypTrc
if (trcfile != NULL) {
/*
* Trace the argument type to the call.
*/
if (i > 0)
fprintf(trcfile, ", ");
prt_d_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
}
/*
* Get the type of the varargs part of the argument list.
*/
if (proc->nargs < 0)
while (i < num_args) {
typ_deref(arg_typs->types[i],
compnt_array[lst_elem].store->types[proc->arg_lst], 1);
#ifdef TypTrc
if (trcfile != NULL) {
/*
* Trace the argument type to the call.
*/
if (i > 0)
fprintf(trcfile, ", ");
prt_d_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
++i;
}
/*
* Missing arguments have the null type.
*/
while (i < nparams) {
set_typ(store->types[n_gbl + i], null_bit);
++i;
}
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, ")\n");
{
char *trc_ind_sav = trc_indent;
trc_indent = ""; /* staring a new procedure, don't indent tracing */
#endif /* TypTrc */
/*
* only perform type inference on the body of a procedure
* once per iteration
*/
if (proc->iteration < iteration) {
proc->iteration = iteration;
s_store = succ_store;
f_store = fail_store;
sv_proc = cur_proc;
succ_store = cpy_store(proc->in_store);
cur_proc = proc;
sv_coexp = cur_coexp;
cur_coexp = NULL; /* we are not in a create expression */
/*
* Perform type inference on the initial clause. Static variables
* are initialized to null on this path.
*/
for (lptr = proc->statics; lptr != NULL; lptr = lptr->next)
set_typ(succ_store->types[lptr->val.index], null_bit);
n1 = Tree1(proc->tree);
if (n1->flag & CanFail) {
/*
* The initial clause can fail. Because it is bounded, we need
* a new failure store that we can merge into the success store
* at the end of the clause.
*/
store = get_store(1);
fail_store = store;
infer_nd(n1);
mrg_store(store, succ_store);
free_store(store);
}
else
infer_nd(n1);
/*
* Perform type inference on the body of procedure. Execution may
* pass directly to it without executing initial clause.
*/
mrg_store(proc->in_store, succ_store);
n1 = Tree2(proc->tree);
if (n1->flag & CanFail) {
/*
* The body can fail. Because it is bounded, we need a new failure
* store that we can merge into the success store at the end of
* the procedure.
*/
store = get_store(1);
fail_store = store;
infer_nd(n1);
mrg_store(store, succ_store);
free_store(store);
}
else
infer_nd(n1);
set_ret(NULL); /* implicit fail */
free_store(succ_store);
succ_store = s_store;
fail_store = f_store;
cur_proc = sv_proc;
cur_coexp = sv_coexp;
}
#ifdef TypTrc
trc_indent = trc_ind_sav;
}
#endif /* TypTrc */
/*
* Get updated types for global variables at the end of the call.
*/
store = proc->out_store;
for (i = 0; i < n_gbl; ++i)
CpyTyp(n_icntyp, store->types[i], succ_store->types[i]);
/*
* If the procedure can fail, merge variable types into the failure
* store.
*/
if (proc->ret_flag & DoesFail)
mrg_store(succ_store, fail_store);
/*
* The return type of the procedure is the result type of the call.
*/
MrgTyp(n_intrtyp, proc->ret_typ, n->type);
}
/*
* cpy_store - make a copy of a store.
*/
static struct store *cpy_store(source)
struct store *source;
{
struct store *dest;
int stor_sz;
int i;
if (source == NULL)
dest = get_store(1);
else {
stor_sz = n_gbl + n_loc;
dest = get_store(0);
for (i = 0; i < stor_sz; ++i)
CpyTyp(n_icntyp, source->types[i], dest->types[i])
}
return dest;
}
/*
* mrg_store - merge the source store into the destination store.
*/
static novalue mrg_store(source, dest)
struct store *source;
struct store *dest;
{
int i;
if (source == NULL)
return;
/*
* Is this store included in the state that must be checked for a fixed
* point?
*/
if (dest->perm) {
for (i = 0; i < n_gbl + n_loc; ++i)
ChkMrgTyp(n_icntyp, source->types[i], dest->types[i])
}
else {
for (i = 0; i < n_gbl + n_loc; ++i)
MrgTyp(n_icntyp, source->types[i], dest->types[i])
}
}
/*
* set_ret - Save return type and the store for global variables.
*/
static novalue set_ret(typ)
unsigned int *typ;
{
int i;
/*
* Merge the return type into the type of the procedure, dereferencing
* locals in the process.
*/
if (typ != NULL)
deref_lcl(typ, cur_proc->ret_typ);
/*
* Update the types that variables may have upon exit of the procedure.
*/
for (i = 0; i < n_gbl; ++i)
MrgTyp(n_icntyp, succ_store->types[i], cur_proc->out_store->types[i]);
}
/*
* deref_lcl - dereference local variable sub-types.
*/
static novalue deref_lcl(src, dest)
unsigned int *src;
unsigned int *dest;
{
int i, j;
int ref_gbl;
int frst_stv;
int num_stv;
struct store *stv_stor;
struct type *wktyp;
/*
* Make a copy of the type to be dereferenced.
*/
wktyp = get_wktyp();
CpyTyp(n_intrtyp, src, wktyp->bits);
/*
* Determine which variable types must be dereferenced. Merge the
* dereferenced type into the return type and delete the variable
* type. Start with simple local variables.
*/
for (i = 0; i < n_loc; ++i)
if (bitset(wktyp->bits, frst_loc + i)) {
MrgTyp(n_icntyp, succ_store->types[n_gbl + i], wktyp->bits)
clr_typ(wktyp->bits, frst_loc + i);
}
/*
* Check for substring trapped variables. If a sub-string trapped
* variable references a local, add "string" to the return type.
* If a sub-string trapped variable references a global, leave the
* trapped variable in the return type.
* It is theoretically possible for a sub-string trapped variable type to
* reference both a local and a global. When the trapped variable type
* is returned to the calling procedure, the local is re-interpreted
* as a local of that procedure. This is a "valid" overestimate of
* of the semantics of the return. Because this is unlikely to occur
* in real programs, the overestimate is of no practical consequence.
*/
num_stv = type_array[stv_typ].num_bits;
frst_stv = type_array[stv_typ].frst_bit;
stv_stor = compnt_array[str_var].store;
for (i = 0; i < num_stv; ++i) {
if (bitset(wktyp->bits, frst_stv + i)) {
/*
* We have found substring trapped variable i, see whether it
* references locals or globals. Globals include structure
* element references.
*/
for (j = 0; j < n_loc; ++j)
if (bitset(stv_stor->types[i], frst_loc + j)) {
set_typ(wktyp->bits, str_bit);
break;
}
ref_gbl = 0;
for (j = n_icntyp; j < frst_loc; ++j)
if (bitset(stv_stor->types[i], j)) {
ref_gbl = 1;
break;
}
/*
* Keep the trapped variable only if it references globals.
*/
if (!ref_gbl)
clr_typ(wktyp->bits, frst_stv + i);
}
}
/*
* Merge the types into the destination.
*/
MrgTyp(n_intrtyp, wktyp->bits, dest);
#ifdef TypTrc
if (trcfile != NULL) {
prt_typ(trcfile, wktyp->bits);
fprintf(trcfile, "\n");
}
#endif /* TypTrc */
free_wktyp(wktyp);
}
/*
* get_store - get a store large enough to hold globals and locals.
*/
static struct store *get_store(clear)
int clear;
{
struct store *store;
int store_sz;
int i;
/*
* Warning, stores for all procedures must be the same size. In some
* situations involving sub-string trapped variables (for example
* when using the "default" trapped variable) a referenced local variable
* type may be interpreted in a procedure to which it does not belong.
* This represents an impossible execution and type inference may
* "legally" produce any results for this part of the abstract
* interpretation. As long as the store is large enough to include any
* such "impossible" variables, type inference will do something legal.
* Note that n_loc is the maximum number of locals in any procedure,
* so store_sz is large enough.
*/
store_sz = n_gbl + n_loc;
if ((store = store_pool) == NULL) {
store = alloc_stor(store_sz, n_icntyp);
store->perm = 0;
}
else {
store_pool = store_pool->next;
/*
* See if the variables in the store should be initialized to the
* empty type.
*/
if (clear)
for (i = 0; i < store_sz; ++i)
ClrTyp(n_icntyp, store->types[i]);
}
return store;
}
static novalue free_store(store)
struct store *store;
{
store->next = store_pool;
store_pool = store;
}
/*
* infer_nd - perform type inference on a subtree of the syntax tree.
*/
static novalue infer_nd(n)
nodeptr n;
{
struct node *cases;
struct node *clause;
struct store *s_store;
struct store *f_store;
struct store *store;
struct loop {
struct store *succ_store;
struct store *fail_store;
struct store *next_store;
struct store *susp_store;
struct loop *prev;
} loop_info;
struct loop *loop_sav;
static struct loop *cur_loop;
struct argtyps *sav_argtyp;
int sav_nargs;
struct type *wktyp;
int i;
switch (n->n_type) {
case N_Activat:
infer_act(n);
break;
case N_Alt:
f_store = fail_store;
store = get_store(1);
fail_store = store;
infer_nd(Tree0(n)); /* 1st alternative */
/*
* "Correct" type inferencing of alternation has a performance
* problem. Propagating stores through nested alternation
* requires as many iterations as the depth of the nesting.
* This is solved by adding two edges to the flow graph. These
* represent impossible execution paths but this does not
* affect the soundness of type inferencing and, in "real"
* programs, does not affect the preciseness of its inference.
* One edge is directly from the 1st alternative to the 2nd.
* The other is a backtracking edge immediately back into
* the alternation from the 1st alternative.
*/
mrg_store(succ_store, store); /* imaginary edge to 2nd alternative */
if (n->store != NULL) {
mrg_store(succ_store, n->store); /* imaginary backtracking edge */
mrg_store(n->store, fail_store);
}
s_store = succ_store;
succ_store = store;
fail_store = f_store;
infer_nd(Tree1(n)); /* 2nd alternative */
mrg_store(s_store, succ_store);
free_store(s_store);
if (n->store != NULL)
mrg_store(n->store, fail_store);
fail_store = n->store;
#ifdef TypTrc
MrgTyp(n_intrtyp, Tree0(n)->type, n->type);
MrgTyp(n_intrtyp, Tree1(n)->type, n->type);
#else /* TypTrc */
/*
* Type is computed by sub-expressions directly into n->type.
*/
#endif /* TypTrc */
break;
case N_Apply: {
struct type *lst_types;
int frst_lst;
int num_lst;
struct store *lstel_stor;
infer_nd(Tree0(n)); /* thing being invoked */
infer_nd(Tree1(n)); /* list */
frst_lst = type_array[list_typ].frst_bit;
num_lst = type_array[list_typ].num_bits;
lstel_stor = compnt_array[lst_elem].store;
/*
* All that is available is a "summary" of the types of the
* elements of the list. Each argument to the invocation
* could be any type in the summary. Set up a maximum length
* argument list.
*/
lst_types = get_wktyp();
typ_deref(Tree1(n)->type, lst_types->bits, 0);
wktyp = get_wktyp();
for (i = 0; i < num_lst; ++i)
if (bitset(lst_types->bits, frst_lst + i))
MrgTyp(n_icntyp, lstel_stor->types[i], wktyp->bits);
bitset(wktyp->bits, null_bit); /* arg list extension might be done */
sav_nargs = num_args;
sav_argtyp = arg_typs;
num_args = max_prm;
arg_typs = get_argtyp();
for (i = 0; i < max_prm; ++i)
arg_typs->types[i] = wktyp->bits;
gen_inv(Tree0(n)->type, n); /* inference on general invocation */
free_wktyp(wktyp);
free_wktyp(lst_types);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
}
break;
case N_Augop:
infer_nd(Tree2(n)); /* 1st operand */
infer_nd(Tree3(n)); /* 2nd operand */
/*
* Perform type inference on the operation.
*/
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = 2;
arg_typs->types[0] = Tree2(n)->type;
arg_typs->types[1] = Tree3(n)->type;
infer_impl(Impl1(n), n, n->symtyps, Typ4(n));
chk_succ(Impl1(n)->ret_flag, n->store);
/*
* Perform type inference on the assignment.
*/
arg_typs->types[1] = Typ4(n);
infer_impl(Impl0(n), n, n->symtyps->next, n->type);
chk_succ(Impl0(n)->ret_flag, n->store);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
break;
case N_Bar:
/*
* This operation intercepts failure and has an associated
* resumption store. If backtracking reaches this operation
* execution may either continue backward or proceed forward
* again.
*/
mrg_store(n->store, fail_store);
mrg_store(n->store, succ_store);
fail_store = n->store;
infer_nd(Tree0(n));
/*
* Type is computed by operand.
*/
break;
case N_Break:
/*
* The success and failure stores for the operand of break are
* those associated with the enclosing loop.
*/
fail_store = cur_loop->fail_store;
loop_sav = cur_loop;
cur_loop = cur_loop->prev;
infer_nd(Tree0(n));
cur_loop = loop_sav;
mrg_store(succ_store, cur_loop->succ_store);
if (cur_loop->susp_store != NULL)
mrg_store(cur_loop->susp_store, fail_store);
free_store(succ_store);
succ_store = get_store(1); /* empty store says: can't get past here */
fail_store = dummy_stor; /* shouldn't be used */
/*
* Result of break is empty type. Result type of expression
* is computed directly into result type of loop.
*/
break;
case N_Case:
f_store = fail_store;
s_store = get_store(1);
infer_nd(Tree0(n)); /* control clause */
cases = Tree1(n);
while (cases != NULL) {
if (cases->n_type == N_Ccls) {
clause = cases;
cases = NULL;
}
else {
clause = Tree1(cases);
cases = Tree0(cases);
}
/*
* Set up a failure store to capture the effects of failure
* of the selection clause.
*/
store = get_store(1);
fail_store = store;
infer_nd(Tree0(clause)); /* value of clause */
/*
* Create the effect of the possible failure of the comparison
* of the selection value to the control value.
*/
mrg_store(succ_store, fail_store);
/*
* The success and failure stores and the result of the body
* of the clause are those of the whole case expression.
*/
fail_store = f_store;
infer_nd(Tree1(clause)); /* body of clause */
mrg_store(succ_store, s_store);
free_store(succ_store);
succ_store = store;
if (n->store != NULL)
mrg_store(n->store, fail_store); /* 'case' can be resumed */
#ifdef TypTrc
MrgTyp(n_intrtyp, Tree1(clause)->type, n->type);
#else /* TypTrc */
/*
* Type is computed by case clause directly into n->type.
*/
#endif /* TypTrc */
}
/*
* Check for default clause.
*/
if (Tree2(n) == NULL)
mrg_store(succ_store, f_store);
else {
fail_store = f_store;
infer_nd(Tree2(n)); /* default */
mrg_store(succ_store, s_store);
if (n->store != NULL)
mrg_store(n->store, fail_store); /* 'case' can be resumed */
#ifdef TypTrc
MrgTyp(n_intrtyp, Tree2(n)->type, n->type);
#else /* TypTrc */
/*
* Type is computed by default clause directly into n->type.
*/
#endif /* TypTrc */
}
free_store(succ_store);
succ_store = s_store;
if (n->store != NULL)
fail_store = n->store;
break;
case N_Create:
/*
* Record initial values of local variables for coexpression.
*/
store = coexp_map[n->new_types[0]]->in_store;
for (i = 0; i < n_loc; ++i)
ChkMrgTyp(n_icntyp, succ_store->types[n_gbl + i],
store->types[n_gbl + i])
/*
* Type is precomputed.
*/
break;
case N_Cset:
case N_Empty:
case N_Id:
case N_Int:
case N_Real:
case N_Str:
/*
* Type is precomputed.
*/
break;
case N_Field: {
struct fentry *fp;
struct par_rec *rp;
int frst_rec;
if ((fp = flookup(Str0(Tree1(n)))) == NULL) {
break; /* error message printed elsewhere */
}
/*
* Determine the record types.
*/
infer_nd(Tree0(n));
typ_deref(Tree0(n)->type, n->symtyps->types[0], 0);
/*
* For each record containing this field, get the tupe of
* the field in that record.
*/
frst_rec = type_array[rec_typ].frst_bit;
for (rp = fp->rlist; rp != NULL; rp = rp->next) {
if (bitset(n->symtyps->types[0], frst_rec + rp->rec->rec_num))
set_typ(n->type, frst_fld + rp->rec->frst_fld + rp->offset);
}
}
break;
case N_If:
f_store = fail_store;
if (Tree2(n)->n_type != N_Empty) {
/*
* If there is an else clause, we must set up a failure store
* to capture the effects of failure of the control clause.
*/
store = get_store(1);
fail_store = store;
}
infer_nd(Tree0(n)); /* control clause */
/*
* If the control clause succeeds, execution passes into the
* then clause with the failure store for the entire if expression.
*/
fail_store = f_store;
infer_nd(Tree1(n)); /* then clause */
if (Tree2(n)->n_type != N_Empty) {
if (n->store != NULL)
mrg_store(n->store, fail_store); /* 'if' expr can be resumed */
s_store = succ_store;
/*
* The entering success store of the else clause is the failure
* store of the control clause. The failure store is that of
* the entire if expression.
*/
succ_store = store;
fail_store = f_store;
infer_nd(Tree2(n)); /* else clause */
if (n->store != NULL) {
mrg_store(n->store, fail_store); /* 'if' expr can be resumed */
fail_store = n->store;
}
/*
* Join the exiting success stores of the then and else clauses.
*/
mrg_store(s_store, succ_store);
free_store(s_store);
}
#ifdef TypTrc
MrgTyp(n_intrtyp, Tree1(n)->type, n->type);
if (Tree2(n)->n_type != N_Empty)
MrgTyp(n_intrtyp, Tree2(n)->type, n->type);
#else /* TypTrc */
/*
* Type computed by 'then' and 'else' clauses directly into n->type.
*/
#endif /* TypTrc */
break;
case N_Invok:
/*
* General invocation.
*/
infer_nd(Tree1(n)); /* thing being invoked */
/*
* Perform type inference on all the arguments and copy the
* results into the argument type array.
*/
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = Val0(n); /* number of arguments */
for (i = 0; i < num_args; ++i) {
infer_nd(n->n_field[i+2].n_ptr); /* arg i */
arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
}
/*
* If this is mutual evaluation, get the type of the last argument,
* otherwise do inference on general invocation.
*/
if (Tree1(n)->n_type == N_Empty) {
MrgTyp(n_intrtyp, arg_typs->types[num_args - 1], n->type);
}
else
gen_inv(Tree1(n)->type, n);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
break;
case N_InvOp:
/*
* Invocation of a run-time operation. Perform inference on all
* the arguments, copying the results into the argument type
* array.
*/
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = Val0(n); /* number of arguments */
for (i = 0; i < num_args; ++i) {
infer_nd(n->n_field[i+2].n_ptr); /* arg i */
arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
}
/*
* Perform inference on operation invocation.
*/
infer_impl(Impl1(n), n, n->symtyps, n->type);
chk_succ(Impl1(n)->ret_flag, n->store);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
break;
case N_InvProc:
/*
* Invocation of a procedure. Perform inference on all
* the arguments, copying the results into the argument type
* array.
*/
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = Val0(n); /* number of arguments */
for (i = 0; i < num_args; ++i) {
infer_nd(n->n_field[i+2].n_ptr); /* arg i */
arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
}
/*
* Perform inference on the procedure invocation.
*/
infer_prc(Proc1(n), n);
chk_succ(Proc1(n)->ret_flag, n->store);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
break;
case N_InvRec:
/*
* Invocation of a record constructor. Perform inference on all
* the arguments, copying the results into the argument type
* array.
*/
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = Val0(n); /* number of arguments */
for (i = 0; i < num_args; ++i) {
infer_nd(n->n_field[i+2].n_ptr); /* arg i */
arg_typs->types[i] = n->n_field[i+2].n_ptr->type;
}
infer_con(Rec1(n), n); /* inference on constructor invocation */
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
break;
case N_Limit:
infer_nd(Tree1(n)); /* limit */
typ_deref(Tree1(n)->type, n->symtyps->types[0], 0);
mrg_store(succ_store, fail_store); /* limit might be 0 */
mrg_store(n->store, fail_store); /* resumption may bypass expr */
infer_nd(Tree0(n)); /* expression */
if (fail_store != NULL)
mrg_store(n->store, fail_store); /* expression may be resumed */
fail_store = n->store;
/*
* Type is computed by expression being limited.
*/
break;
case N_Loop: {
/*
* Establish stores used by break and next.
*/
loop_info.prev = cur_loop;
loop_info.succ_store = get_store(1);
loop_info.fail_store = fail_store;
loop_info.next_store = NULL;
loop_info.susp_store = n->store->next;
cur_loop = &loop_info;
switch ((int)Val0(Tree0(n))) {
case EVERY:
infer_nd(Tree1(n)); /* control clause */
f_store = fail_store;
/*
* Next in the do clause resumes the control clause as
* does success of the do clause.
*/
loop_info.next_store = fail_store;
infer_nd(Tree2(n)); /* do clause */
mrg_store(succ_store, f_store);
break;
case REPEAT:
/*
* The body of the loop can be entered by entering the
* loop, by executing a next in the body, or by having
* the loop succeed or fail. n->store captures all but
* the first case, which is covered by the initial success
* store.
*/
fail_store = n->store;
mrg_store(n->store, succ_store);
loop_info.next_store = n->store;
infer_nd(Tree1(n));
mrg_store(succ_store, n->store);
break;
case SUSPEND:
infer_nd(Tree1(n)); /* value */
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, "%s (%d,%d) suspend ", n->n_file, n->n_line,
n->n_col);
#endif /* TypTrc */
set_ret(Tree1(n)->type); /* set return type of procedure */
/*
* Get changes to types of global variables from
* resumption.
*/
store = cur_proc->susp_store;
for (i = 0; i < n_gbl; ++i)
CpyTyp(n_icntyp, store->types[i], succ_store->types[i]);
/*
* Next in the do clause resumes the control clause as
* does success of the do clause.
*/
f_store = fail_store;
loop_info.next_store = fail_store;
infer_nd(Tree2(n)); /* do clause */
mrg_store(succ_store, f_store);
break;
case WHILE:
/*
* The control clause can be entered by entering the loop,
* executing a next expression, or by having the do clause
* succeed or fail. n->store captures all but the first case,
* which is covered by the initial success store.
*/
mrg_store(n->store, succ_store);
loop_info.next_store = n->store;
infer_nd(Tree1(n)); /* control clause */
fail_store = n->store;
infer_nd(Tree2(n)); /* do clause */
mrg_store(succ_store, n->store);
break;
case UNTIL:
/*
* The control clause can be entered by entering the loop,
* executing a next expression, or by having the do clause
* succeed or fail. n->store captures all but the first case,
* which is covered by the initial success store.
*/
mrg_store(n->store, succ_store);
loop_info.next_store = n->store;
f_store = fail_store;
/*
* Set up a failure store to capture the effects of failure
* of the control clause.
*/
store = get_store(1);
fail_store = store;
infer_nd(Tree1(n)); /* control clause */
mrg_store(succ_store, f_store);
free_store(succ_store);
succ_store = store;
fail_store = n->store;
infer_nd(Tree2(n)); /* do clause */
mrg_store(succ_store, n->store);
break;
}
free_store(succ_store);
succ_store = loop_info.succ_store;
if (n->store->next != NULL)
fail_store = n->store->next;
cur_loop = cur_loop->prev;
/*
* Type is computed by break expressions.
*/
}
break;
case N_Next:
if (cur_loop->next_store == NULL)
mrg_store(succ_store, fail_store); /* control clause of every */
else
mrg_store(succ_store, cur_loop->next_store);
free_store(succ_store);
succ_store = get_store(1); /* empty store says: can't get past here */
fail_store = dummy_stor; /* shouldn't be used */
/*
* Result is empty type.
*/
break;
case N_Not:
/*
* Set up a failure store to capture the effects of failure
* of the negated expression, it becomes the success store
* of the entire expression.
*/
f_store = fail_store;
store = get_store(1);
fail_store = store;
infer_nd(Tree0(n));
mrg_store(succ_store, f_store); /* if success, then fail */
free_store(succ_store);
succ_store = store;
fail_store = f_store;
/*
* Type is precomputed.
*/
break;
case N_Ret:
if (Val0(Tree0(n)) == RETURN) {
if (Tree1(n)->flag & CanFail) {
/*
* Set up a failure store to capture the effects of failure
* of the returned expression and the corresponding procedure
* failure.
*/
store = get_store(1);
fail_store = store;
infer_nd(Tree1(n)); /* return value */
mrg_store(store, succ_store);
free_store(store);
}
else
infer_nd(Tree1(n)); /* return value */
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, "%s (%d,%d) return ", n->n_file, n->n_line,
n->n_col);
#endif /* TypTrc */
set_ret(Tree1(n)->type);
}
else { /* fail */
set_ret(NULL);
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, "%s (%d,%d) fail\n", n->n_file, n->n_line,
n->n_col);
#endif /* TypTrc */
}
free_store(succ_store);
succ_store = get_store(1); /* empty store says: can't get past here */
fail_store = dummy_stor; /* shouldn't be used */
/*
* Empty type.
*/
break;
case N_Scan: {
struct implement *asgn_impl;
infer_nd(Tree1(n)); /* subject */
typ_deref(Tree1(n)->type, n->symtyps->types[0], 0);
infer_nd(Tree2(n)); /* body */
if (optab[Val0(Tree0(n))].tok.t_type == AUGQMARK) {
/*
* Perform type inference on the assignment.
*/
asgn_impl = optab[asgn_loc].binary;
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = 2;
arg_typs->types[0] = Tree1(n)->type;
arg_typs->types[1] = Tree2(n)->type;
infer_impl(asgn_impl, n, n->symtyps->next, n->type);
chk_succ(asgn_impl->ret_flag, n->store);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
}
else
MrgTyp(n_intrtyp, Tree2(n)->type, n->type);
}
break;
case N_Sect:
infer_nd(Tree2(n)); /* 1st operand */
infer_nd(Tree3(n)); /* 2nd operand */
infer_nd(Tree4(n)); /* 3rd operand */
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
if (Impl1(n) != NULL) {
/*
* plus or minus.
*/
num_args = 2;
arg_typs->types[0] = Tree3(n)->type;
arg_typs->types[1] = Tree4(n)->type;
wktyp = get_wktyp();
infer_impl(Impl1(n), n, n->symtyps->next, wktyp->bits);
chk_succ(Impl1(n)->ret_flag, n->store);
arg_typs->types[2] = wktyp->bits;
}
else
arg_typs->types[2] = Tree4(n)->type;
num_args = 3;
arg_typs->types[0] = Tree2(n)->type;
arg_typs->types[1] = Tree3(n)->type;
/*
* sectioning
*/
infer_impl(Impl0(n), n, n->symtyps, n->type);
chk_succ(Impl0(n)->ret_flag, n->store);
if (Impl1(n) != NULL)
free_wktyp(wktyp);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
break;
case N_Slist:
f_store = fail_store;
if (Tree0(n)->flag & CanFail) {
/*
* Set up a failure store to capture the effects of failure
* of the first operand; this is merged into the
* incoming success store of the second operand.
*/
store = get_store(1);
fail_store = store;
infer_nd(Tree0(n));
mrg_store(store, succ_store);
free_store(store);
}
else
infer_nd(Tree0(n));
fail_store = f_store;
infer_nd(Tree1(n));
/*
* Type is computed by second operand.
*/
break;
case N_SmplAsgn: {
/*
* Optimized assignment to a named variable.
*/
struct lentry *var;
int indx;
infer_nd(Tree3(n));
var = LSym0(Tree2(n));
if (var->flag & F_Global)
indx = var->val.global->index;
else if (var->flag & F_Static)
indx = var->val.index;
else
indx = n_gbl + var->val.index;
ClrTyp(n_icntyp, succ_store->types[indx]);
typ_deref(Tree3(n)->type, succ_store->types[indx], 0);
#ifdef TypTrc
/*
* Trace assignment.
*/
if (trcfile != NULL) {
fprintf(trcfile, "%s (%d,%d) %s%s := ", n->n_file, n->n_line,
n->n_col, trc_indent, var->name);
prt_d_typ(trcfile, Tree3(n)->type);
fprintf(trcfile, "\n");
}
#endif /* TypTrc */
/*
* Type is precomputed.
*/
}
break;
case N_SmplAug: {
/*
* Optimized augmented assignment to a named variable.
*/
struct lentry *var;
int indx;
/*
* Perform type inference on the operation.
*/
infer_nd(Tree3(n)); /* 2nd operand */
/*
* Set up type array for arguments of operation.
*/
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = 2;
arg_typs->types[0] = Tree2(n)->type; /* type was precomputed */
arg_typs->types[1] = Tree3(n)->type;
/*
* Perform inference on the operation.
*/
infer_impl(Impl1(n), n, n->symtyps, Typ4(n));
chk_succ(Impl1(n)->ret_flag, n->store);
/*
* Perform assignment to the variable.
*/
var = LSym0(Tree2(n));
if (var->flag & F_Global)
indx = var->val.global->index;
else if (var->flag & F_Static)
indx = var->val.index;
else
indx = n_gbl + var->val.index;
ClrTyp(n_icntyp, succ_store->types[indx]);
typ_deref(Typ4(n), succ_store->types[indx], 0);
#ifdef TypTrc
/*
* Trace assignment.
*/
if (trcfile != NULL) {
fprintf(trcfile, "%s (%d,%d) %s%s := ", n->n_file, n->n_line,
n->n_col, trc_indent, var->name);
prt_d_typ(trcfile, Typ4(n));
fprintf(trcfile, "\n");
}
#endif /* TypTrc */
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
/*
* Type is precomputed.
*/
}
break;
default:
fprintf(stderr, "compiler error: node type %d unknown\n", n->n_type);
exit(ErrorExit);
}
}
/*
* infer_con - perform type inference for the invocation of a record
* constructor.
*/
static novalue infer_con(rec, n)
struct rentry *rec;
nodeptr n;
{
int fld_indx;
int nfields;
int i;
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, "%s (%d,%d) %s%s(", n->n_file, n->n_line, n->n_col,
trc_indent, rec->name);
#endif /* TypTrc */
/*
* Dereference argument types into appropriate entries of field store.
*/
fld_indx = rec->frst_fld;
nfields = rec->nfields;
for (i = 0; i < num_args && i < nfields; ++i) {
typ_deref(arg_typs->types[i], fld_stor->types[fld_indx++], 1);
#ifdef TypTrc
if (trcfile != NULL) {
if (i > 0)
fprintf(trcfile, ", ");
prt_d_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
}
/*
* If there are too few arguments, add null type to appropriate entries
* of field store.
*/
while (i < nfields) {
if (!bitset(fld_stor->types[fld_indx], null_bit)) {
++changed;
set_typ(fld_stor->types[fld_indx], null_bit);
}
++fld_indx;
++i;
}
/*
* return record type
*/
set_typ(n->type, type_array[rec_typ].frst_bit + rec->rec_num);
#ifdef TypTrc
if (trcfile != NULL) {
fprintf(trcfile, ") =>> ");
prt_typ(trcfile, n->type);
fprintf(trcfile, "\n");
}
#endif /* TypTrc */
}
/*
* infer_act - perform type inference on coexpression activation.
*/
static novalue infer_act(n)
nodeptr n;
{
struct implement *asgn_impl;
struct store *s_store;
struct store *f_store;
struct store *e_store;
struct store *store;
struct t_coexpr *sv_coexp;
struct t_coexpr *coexp;
struct type *rslt_typ;
struct argtyps *sav_argtyp;
int frst_coexp;
int num_coexp;
int sav_nargs;
int i;
int j;
#ifdef TypTrc
FILE *trc_save;
#endif /* TypTrc */
num_coexp = type_array[coexp_typ].num_bits;
frst_coexp = type_array[coexp_typ].frst_bit;
infer_nd(Tree1(n)); /* value to transmit */
infer_nd(Tree2(n)); /* coexpression */
/*
* Dereference the two arguments. Note that only locals in the
* transmitted value are dereferenced.
*/
#ifdef TypTrc
trc_save = trcfile;
trcfile = NULL; /* don't trace value during dereferencing */
#endif /* TypTrc */
deref_lcl(Tree1(n)->type, n->symtyps->types[0]);
#ifdef TypTrc
trcfile = trc_save;
#endif /* TypTrc */
typ_deref(Tree2(n)->type, n->symtyps->types[1], 0);
rslt_typ = get_wktyp();
/*
* Set up a store for the end of the activation and propagate local
* variables across the activation; the activation may succeed or
* fail.
*/
e_store = get_store(1);
for (i = 0; i < n_loc; ++i)
CpyTyp(n_icntyp, succ_store->types[n_gbl + i], e_store->types[n_gbl + i])
if (fail_store->perm) {
for (i = 0; i < n_loc; ++i)
ChkMrgTyp(n_icntyp, succ_store->types[n_gbl + i],
fail_store->types[n_gbl + i])
}
else {
for (i = 0; i < n_loc; ++i)
MrgTyp(n_icntyp, succ_store->types[n_gbl + i],
fail_store->types[n_gbl + i])
}
/*
* Go through all the co-expressions that might be activated,
* perform type inference on them, and transmit stores along
* the execution paths induced by the activation.
*/
s_store = succ_store;
f_store = fail_store;
for (j = 0; j < num_coexp; ++j) {
if (bitset(n->symtyps->types[1], frst_coexp + j)) {
coexp = coexp_map[j];
/*
* Merge the types of global variables into the "in store" of the
* co-expression. Because the body of the co-expression may already
* have been processed for this pass, the "changed" flag must be
* set if there is a change of type in the store. This will insure
* that there will be another iteration in which to propagate the
* change into the body.
*/
store = coexp->in_store;
for (i = 0; i < n_gbl; ++i)
ChkMrgTyp(n_icntyp, s_store->types[i], store->types[i])
ChkMrgTyp(n_intrtyp, n->symtyps->types[0], coexp->act_typ)
/*
* Only perform type inference on the body of a co-expression
* once per iteration. The main co-expression has no body.
*/
if (coexp->iteration < iteration & coexp->n != NULL) {
coexp->iteration = iteration;
succ_store = cpy_store(coexp->in_store);
fail_store = coexp->out_store;
sv_coexp = cur_coexp;
cur_coexp = coexp;
infer_nd(coexp->n);
/*
* Dereference the locals in the value resulting from
* the execution of the co-expression body.
*/
#ifdef TypTrc
if (trcfile != NULL)
fprintf(trcfile, "%s (%d,%d) %sC%d =>> ", coexp->n->n_file,
coexp->n->n_line, coexp->n->n_col, trc_indent, j);
#endif /* TypTrc */
deref_lcl(coexp->n->type, coexp->rslt_typ);
mrg_store(succ_store, coexp->out_store);
free_store(succ_store);
cur_coexp = sv_coexp;
}
/*
* Get updated types for global variables, assuming the co-expression
* fails or returns by completing.
*/
store = coexp->out_store;
for (i = 0; i < n_gbl; ++i)
MrgTyp(n_icntyp, store->types[i], e_store->types[i]);
if (f_store->perm) {
for (i = 0; i < n_gbl; ++i)
ChkMrgTyp(n_icntyp, store->types[i], f_store->types[i]);
}
else {
for (i = 0; i < n_gbl; ++i)
MrgTyp(n_icntyp, store->types[i], f_store->types[i]);
}
MrgTyp(n_intrtyp, coexp->rslt_typ, rslt_typ->bits)
}
}
/*
* Control may return from the activation if another co-expression
* activates the current one. If we are in a create expression,
* cur_coexp is the current co-expression, otherwise the current
* procedure may be called within several co-expressions.
*/
if (cur_coexp == NULL) {
for (j = 0; j < num_coexp; ++j)
if (bitset(cur_proc->coexprs, frst_coexp + j))
mrg_act(coexp_map[j], e_store, rslt_typ);
}
else
mrg_act(cur_coexp, e_store, rslt_typ);
free_store(s_store);
succ_store = e_store;
fail_store = f_store;
#ifdef TypTrc
if (trcfile != NULL) {
fprintf(trcfile, "%s (%d,%d) %s", n->n_file, n->n_line, n->n_col,
trc_indent);
prt_typ(trcfile, n->symtyps->types[0]);
fprintf(trcfile, " @ ");
prt_typ(trcfile, n->symtyps->types[1]);
fprintf(trcfile, " =>> ");
prt_typ(trcfile, rslt_typ->bits);
fprintf(trcfile, "\n");
}
#endif /* TypTrc */
if (optab[Val0(Tree0(n))].tok.t_type == AUGAT) {
/*
* Perform type inference on the assignment.
*/
asgn_impl = optab[asgn_loc].binary;
sav_argtyp = arg_typs;
sav_nargs = num_args;
arg_typs = get_argtyp();
num_args = 2;
arg_typs->types[0] = Tree1(n)->type;
arg_typs->types[1] = rslt_typ->bits;
infer_impl(asgn_impl, n, n->symtyps->next, n->type);
chk_succ(asgn_impl->ret_flag, n->store);
free_argtyp(arg_typs);
arg_typs = sav_argtyp;
num_args = sav_nargs;
}
else
ChkMrgTyp(n_intrtyp, rslt_typ->bits, n->type)
free_wktyp(rslt_typ);
}
/*
* mrg_act - merge entry information for the co-expression to the
* the ending store and result type for the activation being
* analyzed.
*/
static novalue mrg_act(coexp, e_store, rslt_typ)
struct t_coexpr *coexp;
struct store *e_store;
struct type *rslt_typ;
{
struct store *store;
int i;
store = coexp->in_store;
for (i = 0; i < n_gbl; ++i)
MrgTyp(n_icntyp, store->types[i], e_store->types[i]);
MrgTyp(n_intrtyp, coexp->act_typ, rslt_typ->bits)
}
/*
* typ_deref - perform dereferencing in the abstract type realm.
*/
static novalue typ_deref(src, dest, chk)
unsigned int *src;
unsigned int *dest;
int chk;
{
struct store *tblel_stor;
struct store *tbldf_stor;
struct store *ttv_stor;
struct store *store;
unsigned int old;
int num_tbl;
int frst_tbl;
int num_bits;
int frst_bit;
int i;
int j;
/*
* copy values to destination
*/
for (i = 0; i < NumInts(n_icntyp) - 1; ++i) {
old = dest[i];
dest[i] |= src[i];
if (chk && (old != dest[i]))
++changed;
}
old = dest[i];
dest[i] |= src[i] & val_mask; /* mask out variables */
if (chk && (old != dest[i]))
++changed;
/*
* predefined variables whose types do not change.
*/
for (i = 0; i < num_typs; ++i) {
if (icontypes[i].deref == DrfCnst) {
if (bitset(src, type_array[i].frst_bit))
if (chk)
ChkMrgTyp(n_icntyp, type_array[i].typ, dest)
else
MrgTyp(n_icntyp, type_array[i].typ, dest)
}
}
/*
* substring trapped variables
*/
num_bits = type_array[stv_typ].num_bits;
frst_bit = type_array[stv_typ].frst_bit;
for (i = 0; i < num_bits; ++i)
if (bitset(src, frst_bit + i))
if (!bitset(dest, str_bit)) {
if (chk)
++changed;
set_typ(dest, str_bit);
}
/*
* table element trapped variables
*/
num_bits = type_array[ttv_typ].num_bits;
frst_bit = type_array[ttv_typ].frst_bit;
num_tbl = type_array[tbl_typ].num_bits;
frst_tbl = type_array[tbl_typ].frst_bit;
tblel_stor = compnt_array[tbl_val].store;
tbldf_stor = compnt_array[tbl_dflt].store;
ttv_stor = compnt_array[trpd_tbl].store;
for (i = 0; i < num_bits; ++i)
if (bitset(src, frst_bit + i))
for (j = 0; j < num_tbl; ++j)
if (bitset(ttv_stor->types[i], frst_tbl + j)) {
if (chk) {
ChkMrgTyp(n_icntyp, tblel_stor->types[j], dest)
ChkMrgTyp(n_icntyp, tbldf_stor->types[j], dest)
}
else {
MrgTyp(n_icntyp, tblel_stor->types[j], dest)
MrgTyp(n_icntyp, tbldf_stor->types[j], dest)
}
}
/*
* Aggregate compontents that are variables.
*/
for (i = 0; i < num_cmpnts; ++i) {
if (typecompnt[i].var) {
frst_bit = compnt_array[i].frst_bit;
num_bits = compnt_array[i].num_bits;
store = compnt_array[i].store;
for (j = 0; j < num_bits; ++j) {
if (bitset(src, frst_bit + j))
if (chk)
ChkMrgTyp(n_icntyp, store->types[j], dest)
else
MrgTyp(n_icntyp, store->types[j], dest)
}
}
}
/*
* record fields
*/
for (i = 0; i < n_fld; ++i)
if (bitset(src, frst_fld + i))
if (chk)
ChkMrgTyp(n_icntyp, fld_stor->types[i], dest)
else
MrgTyp(n_icntyp, fld_stor->types[i], dest)
/*
* global variables
*/
for (i = 0; i < n_gbl; ++i)
if (bitset(src, frst_gbl + i))
if (chk)
ChkMrgTyp(n_icntyp, succ_store->types[i], dest)
else
MrgTyp(n_icntyp, succ_store->types[i], dest)
/*
* local variables
*/
for (i = 0; i < n_loc; ++i)
if (bitset(src, frst_loc + i))
if (chk)
ChkMrgTyp(n_icntyp, succ_store->types[n_gbl + i], dest)
else
MrgTyp(n_icntyp, succ_store->types[n_gbl + i], dest)
}
/*
* infer_impl - perform type inference on a call to built-in operation
* using the implementation entry from the data base.
*/
static novalue infer_impl(impl, n, symtyps, rslt_typ)
struct implement *impl;
nodeptr n;
struct symtyps *symtyps;
unsigned int *rslt_typ;
{
unsigned int *typ;
int flag;
int nparms;
int i;
int j;
#ifdef TypTrc
if (trcfile != NULL) {
fprintf(trcfile, "%s (%d,%d) %s", n->n_file, n->n_line, n->n_col,
trc_indent);
if (impl->oper_typ == 'K')
fprintf(trcfile, "&%s", impl->name);
else
fprintf(trcfile, "%s(", impl->name);
}
#endif /* TypTrc */
/*
* Set up the "symbol table" of dereferenced and undereferenced
* argument types as needed by the operation.
*/
nparms = impl->nargs;
j = 0;
for (i = 0; i < num_args && i < nparms; ++i) {
if (impl->arg_flgs[i] & RtParm) {
CpyTyp(n_intrtyp, arg_typs->types[i], symtyps->types[j]);
#ifdef TypTrc
if (trcfile != NULL) {
if (i > 0)
fprintf(trcfile, ", ");
prt_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
++j;
}
if (impl->arg_flgs[i] & DrfPrm) {
typ_deref(arg_typs->types[i], symtyps->types[j], 0);
#ifdef TypTrc
if (trcfile != NULL) {
if (impl->arg_flgs[i] & RtParm)
fprintf(trcfile, "->");
else if (i > 0)
fprintf(trcfile, ", ");
prt_d_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
++j;
}
}
if (nparms > 0) {
/*
* Check for varargs. Merge remaining arguments into the
* type of the variable part of the parameter list.
*/
flag = impl->arg_flgs[nparms - 1];
if (flag & VarPrm) {
n_vararg = num_args - nparms + 1;
if (n_vararg < 0)
n_vararg = 0;
typ = symtyps->types[j - 1];
while (i < num_args) {
if (flag & RtParm) {
MrgTyp(n_intrtyp, arg_typs->types[i], typ)
#ifdef TypTrc
if (trcfile != NULL) {
if (i > 0)
fprintf(trcfile, ", ");
prt_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
}
else {
typ_deref(arg_typs->types[i], typ, 0);
#ifdef TypTrc
if (trcfile != NULL) {
if (i > 0)
fprintf(trcfile, ", ");
prt_d_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
}
++i;
}
nparms -= 1; /* Don't extend with nulls into variable part */
}
}
while (i < nparms) {
if (impl->arg_flgs[i] & RtParm)
set_typ(symtyps->types[j++], null_bit); /* Extend args with nulls */
if (impl->arg_flgs[i] & DrfPrm)
set_typ(symtyps->types[j++], null_bit); /* Extend args with nulls */
++i;
}
/*
* If this operation can suspend, there may be backtracking paths
* to this invocation. Merge type information from those paths
* into the current store.
*/
if (impl->ret_flag & DoesSusp)
mrg_store(n->store, succ_store);
cur_symtyps = symtyps;
cur_rslt.bits = rslt_typ;
cur_rslt.size = n_intrtyp;
cur_new = n->new_types;
infer_il(impl->in_line); /* perform inference on operation */
if (MightFail(impl->ret_flag))
mrg_store(succ_store, fail_store);
#ifdef TypTrc
if (trcfile != NULL) {
if (impl->oper_typ != 'K')
fprintf(trcfile, ")");
fprintf(trcfile, " =>> ");
prt_typ(trcfile, rslt_typ);
fprintf(trcfile, "\n");
}
#endif /* TypTrc */
}
/*
* chk_succ - check to see if the operation can succeed. In particular,
* see if it can suspend. Change the succ_store and failure store
* appropriately.
*/
static novalue chk_succ(ret_flag, susp_stor)
int ret_flag;
struct store *susp_stor;
{
if (ret_flag & DoesSusp) {
if (susp_stor != NULL && (ret_flag & DoesRet))
mrg_store(susp_stor, fail_store); /* "pass along" failure */
fail_store = susp_stor;
}
else if (!(ret_flag & DoesRet)) {
free_store(succ_store);
succ_store = get_store(1);
fail_store = dummy_stor; /* shouldn't be used */
}
}
/*
* infer_il - perform type inference on a piece of code within built-in
* operation and determine whether execution can get past it.
*/
static int infer_il(il)
struct il_code *il;
{
struct il_code *il1;
int condition;
int case_fnd;
int ncases;
int may_fallthru;
int indx;
int i;
if (il == NULL)
return 1;
switch (il->il_type) {
case IL_Const: /* should have been replaced by literal node */
return 0;
case IL_If1:
condition = eval_cond(il->u[0].fld);
may_fallthru = (condition & MaybeFalse);
if (condition & MaybeTrue)
may_fallthru |= infer_il(il->u[1].fld);
return may_fallthru;
case IL_If2:
condition = eval_cond(il->u[0].fld);
may_fallthru = 0;
if (condition & MaybeTrue)
may_fallthru |= infer_il(il->u[1].fld);
if (condition & MaybeFalse)
may_fallthru |= infer_il(il->u[2].fld);
return may_fallthru;
case IL_Tcase1:
type_case(il, infer_il, NULL);
return 1; /* no point in trying very hard here */
case IL_Tcase2:
indx = type_case(il, infer_il, NULL);
if (indx != -1)
infer_il(il->u[indx].fld); /* default */
return 1; /* no point in trying very hard here */
case IL_Lcase:
ncases = il->u[0].n;
indx = 1;
case_fnd = 0;
for (i = 0; i < ncases && !case_fnd; ++i) {
if (il->u[indx++].n == n_vararg) { /* selection number */
infer_il(il->u[indx].fld); /* action */
case_fnd = 1;
}
++indx;
}
if (!case_fnd)
infer_il(il->u[indx].fld); /* default */
return 1; /* no point in trying very hard here */
case IL_Acase: {
int maybe_int;
int maybe_dbl;
eval_arith((int)il->u[0].fld->u[0].n, (int)il->u[1].fld->u[0].n,
&maybe_int, &maybe_dbl);
if (maybe_int) {
infer_il(il->u[2].fld); /* C_integer action */
if (largeints)
infer_il(il->u[3].fld); /* integer action */
}
if (maybe_dbl)
infer_il(il->u[4].fld); /* C_double action */
return 1; /* no point in trying very hard here */
}
case IL_Err1:
case IL_Err2:
return 0;
case IL_Block:
return il->u[0].n;
case IL_Call:
return ((il->u[3].n & DoesFThru) != 0);
case IL_Lst:
if (infer_il(il->u[0].fld))
return infer_il(il->u[1].fld);
else
return 0;
case IL_Abstr:
/*
* Handle side effects.
*/
il1 = il->u[0].fld;
if (il1 != NULL) {
while (il1->il_type == IL_Lst) {
side_effect(il1->u[1].fld);
il1 = il1->u[0].fld;
}
side_effect(il1);
}
/*
* Set return type.
*/
abstr_typ(il->u[1].fld, &cur_rslt);
return 1;
default:
fprintf(stderr, "compiler error: unknown info in data base\n");
exit(ErrorExit);
/* NOTREACHED */
}
}
/*
* side_effect - perform a side effect from an abstract clause of a
* built-in operation.
*/
static novalue side_effect(il)
struct il_code *il;
{
struct type *var_typ;
struct type *val_typ;
struct store *store;
int num_bits;
int frst_bit;
int i, j;
/*
* il is IL_TpAsgn, get the variable type and value type, and perform
* the side effect.
*/
var_typ = get_wktyp();
val_typ = get_wktyp();
abstr_typ(il->u[0].fld, var_typ); /* variable type */
abstr_typ(il->u[1].fld, val_typ); /* value type */
/*
* Determine which types that can be assigned to are in the variable
* type.
*
* Aggregate compontents.
*/
for (i = 0; i < num_cmpnts; ++i) {
frst_bit = compnt_array[i].frst_bit;
num_bits = compnt_array[i].num_bits;
store = compnt_array[i].store;
for (j = 0; j < num_bits; ++j) {
if (bitset(var_typ->bits, frst_bit + j))
ChkMrgTyp(n_icntyp, val_typ->bits, store->types[j])
}
}
/*
* record fields
*/
for (i = 0; i < n_fld; ++i)
if (bitset(var_typ->bits, frst_fld + i))
ChkMrgTyp(n_icntyp, val_typ->bits, fld_stor->types[i]);
/*
* global variables
*/
for (i = 0; i < n_gbl; ++i)
if (bitset(var_typ->bits, frst_gbl + i))
MrgTyp(n_icntyp, val_typ->bits, succ_store->types[i]);
/*
* local variables
*/
for (i = 0; i < n_loc; ++i)
if (bitset(var_typ->bits, frst_loc + i))
MrgTyp(n_icntyp, val_typ->bits, succ_store->types[n_gbl + i]);
free_wktyp(var_typ);
free_wktyp(val_typ);
}
/*
* abstr_typ - compute the type bits corresponding to an abstract type
* from an abstract clause of a built-in operation.
*/
static novalue abstr_typ(il, typ)
struct il_code *il;
struct type *typ;
{
struct type *typ1;
struct type *typ2;
struct rentry *rec;
struct store *store;
struct compnt_info *compnts;
int num_bits;
int frst_bit;
int frst_cmpnt;
int num_comps;
int typcd;
int new_indx;
int i;
int j;
int indx;
int size;
int t_indx;
unsigned int *prmtyp;
if (il == NULL)
return;
switch (il->il_type) {
case IL_VarTyp:
/*
* type(<parameter>)
*/
indx = il->u[0].fld->u[0].n; /* symbol table index of variable */
if (indx >= cur_symtyps->nsyms) {
prmtyp = any_typ;
size = n_rttyp;
}
else {
prmtyp = cur_symtyps->types[indx];
size = n_intrtyp;
}
if (typ->size < size)
size = typ->size;
MrgTyp(size, prmtyp, typ->bits);
break;
case IL_Store:
/*
* store[<type>]
*/
typ1 = get_wktyp();
abstr_typ(il->u[0].fld, typ1); /* type to be "dereferenced" */
/*
* Dereference types that are Icon varaibles.
*/
typ_deref(typ1->bits, typ->bits, 0);
/*
* "Dereference" aggregate compontents that are not Icon variables.
*/
for (i = 0; i < num_cmpnts; ++i) {
if (!typecompnt[i].var) {
if (i == stv_typ) {
/*
* Substring trapped variable stores contain variable
* references, so the types are larger, but we cannot
* copy more than the destination holds.
*/
size = n_intrtyp;
if (typ->size < size)
size = typ->size;
}
else
size = n_icntyp;
frst_bit = compnt_array[i].frst_bit;
num_bits = compnt_array[i].num_bits;
store = compnt_array[i].store;
for (j = 0; j < num_bits; ++j) {
if (bitset(typ1->bits, frst_bit + j))
MrgTyp(size, store->types[j], typ->bits);
}
}
}
free_wktyp(typ1);
break;
case IL_Compnt:
/*
* <type>.<component>
*/
typ1 = get_wktyp();
abstr_typ(il->u[0].fld, typ1); /* type */
i = il->u[1].n;
if (i == CM_Fields) {
/*
* The all_fields component must be handled differently
* from the others.
*/
frst_bit = type_array[rec_typ].frst_bit;
num_bits = type_array[rec_typ].num_bits;
for (i = 0; i < num_bits; ++i)
if (bitset(typ1->bits, frst_bit + i)) {
rec = rec_map[i];
for (j = 0; j < rec->nfields; ++j)
set_typ(typ->bits, frst_fld + rec->frst_fld + j);
}
}
else {
/*
* Use component information arrays to transform type bits to
* the corresponding component bits.
*/
frst_bit = type_array[typecompnt[i].aggregate].frst_bit;
num_bits = type_array[typecompnt[i].aggregate].num_bits;
frst_cmpnt = compnt_array[i].frst_bit;
if (!typecompnt[i].var && typ->size < n_rttyp)
break; /* bad abstract type computation */
for (i = 0; i < num_bits; ++i)
if (bitset(typ1->bits, frst_bit + i))
set_typ(typ->bits, frst_cmpnt + i);
free_wktyp(typ1);
}
break;
case IL_Union:
/*
* <type 1> ++ <type 2>
*/
abstr_typ(il->u[0].fld, typ);
abstr_typ(il->u[1].fld, typ);
break;
case IL_Inter:
/*
* <type 1> ** <type 2>
*/
typ1 = get_wktyp();
typ2 = get_wktyp();
abstr_typ(il->u[0].fld, typ1);
abstr_typ(il->u[1].fld, typ2);
size = n_rttyp;
for (i = 0; i < NumInts(size); ++i)
typ1->bits[i] &= typ2->bits[i];
if (typ->size < size)
size = typ->size;
MrgTyp(size, typ1->bits, typ->bits);
free_wktyp(typ1);
free_wktyp(typ2);
break;
case IL_New:
/*
* new <type-name>(<type 1> , ...)
*
* If a type was not allocated for this node, use the default
* one.
*/
typ1 = get_wktyp();
typcd = il->u[0].n; /* type code */
new_indx = type_array[typcd].new_indx;
t_indx = 0; /* default is first index of type */
if (cur_new != NULL && cur_new[new_indx] > 0)
t_indx = cur_new[new_indx];
/*
* This RTL expression evaluates to the "new" sub-type.
*/
set_typ(typ->bits, type_array[typcd].frst_bit + t_indx);
/*
* Update stores for components based on argument types in the
* "new" expression.
*/
num_comps = icontypes[typcd].num_comps;
j = icontypes[typcd].compnts;
compnts = &compnt_array[j];
if (typcd == stv_typ) {
size = n_intrtyp;
}
else
size = n_icntyp;
for (i = 0; i < num_comps; ++i) {
ClrTyp(n_rttyp, typ1->bits);
abstr_typ(il->u[2 + i].fld, typ1);
ChkMrgTyp(size, typ1->bits, compnts[i].store->types[t_indx]);
}
free_wktyp(typ1);
break;
case IL_IcnTyp:
typcd_bits((int)il->u[0].n, typ); /* type code */
break;
}
}
/*
* eval_cond - evaluate the condition of in 'if' statement from a
* built-in operation. The result can be both true and false because
* of uncertainty and because more than one execution path may be
* involved.
*/
static int eval_cond(il)
struct il_code *il;
{
int cond1;
int cond2;
switch (il->il_type) {
case IL_Bang:
cond1 = eval_cond(il->u[0].fld);
cond2 = 0;
if (cond1 & MaybeTrue)
cond2 = MaybeFalse;
if (cond1 & MaybeFalse)
cond2 |= MaybeTrue;
return cond2;
case IL_And:
cond1 = eval_cond(il->u[0].fld);
cond2 = eval_cond(il->u[1].fld);
return (cond1 & cond2 & MaybeTrue) | ((cond1 | cond2) & MaybeFalse);
case IL_Cnv1:
case IL_Cnv2:
return eval_cnv((int)il->u[0].n, (int)il->u[1].fld->u[0].n,
0, NULL);
case IL_Def1:
case IL_Def2:
return eval_cnv((int)il->u[0].n, (int)il->u[1].fld->u[0].n,
1, NULL);
case IL_Is:
return eval_is((int)il->u[0].n, il->u[1].fld->u[0].n);
default:
fprintf(stderr, "compiler error: unknown info in data base\n");
exit(ErrorExit);
/* NOTREACHED */
}
}
/*
* eval_cnv - evaluate the conversion of a variable to a specific type
* to see if it may succeed or fail.
*/
int eval_cnv(typcd, indx, def, cnv_flags)
int typcd; /* type to convert to */
int indx; /* index into symbol table of variable */
int def; /* flag: conversion has a default value */
int *cnv_flags; /* return flag for detailed conversion information */
{
struct type *may_succeed; /* types where conversion sometimes succeed */
struct type *must_succeed; /* types where conversion always succeeds */
struct type *must_cnv; /* types where actual conversion is performed */
struct type *as_is; /* types where value already has correct type */
unsigned int *typ; /* possible types of the variable */
int cond;
int i;
/*
* Conversions may succeed for strings, integers, csets, and reals.
* Conversions may fail for any other types. In addition,
* conversions to integer or real may fail for specific values.
*/
if (indx >= cur_symtyps->nsyms)
return MaybeTrue | MaybeFalse;
typ = cur_symtyps->types[indx];
may_succeed = get_wktyp();
must_succeed = get_wktyp();
must_cnv = get_wktyp();
as_is = get_wktyp();
if (typcd == cset_typ || typcd == TypTCset) {
set_typ(as_is->bits, cset_bit);
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, int_bit);
set_typ(must_cnv->bits, real_bit);
set_typ(must_succeed->bits, str_bit);
set_typ(must_succeed->bits, cset_bit);
set_typ(must_succeed->bits, int_bit);
set_typ(must_succeed->bits, real_bit);
}
else if (typcd == str_typ || typcd == TypTStr) {
set_typ(as_is->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
set_typ(must_cnv->bits, int_bit);
set_typ(must_cnv->bits, real_bit);
set_typ(must_succeed->bits, str_bit);
set_typ(must_succeed->bits, cset_bit);
set_typ(must_succeed->bits, int_bit);
set_typ(must_succeed->bits, real_bit);
}
else if (typcd == TypCStr) {
/*
* as_is is empty.
*/
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
set_typ(must_cnv->bits, int_bit);
set_typ(must_cnv->bits, real_bit);
set_typ(must_succeed->bits, str_bit);
set_typ(must_succeed->bits, cset_bit);
set_typ(must_succeed->bits, int_bit);
set_typ(must_succeed->bits, real_bit);
}
else if (typcd == real_typ) {
set_typ(as_is->bits, real_bit);
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
set_typ(must_cnv->bits, int_bit);
set_typ(must_succeed->bits, int_bit);
set_typ(must_succeed->bits, real_bit);
}
else if (typcd == TypCDbl) {
/*
* as_is is empty.
*/
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
set_typ(must_cnv->bits, int_bit);
set_typ(must_cnv->bits, real_bit);
set_typ(must_succeed->bits, int_bit);
set_typ(must_succeed->bits, real_bit);
}
else if (typcd == int_typ) {
set_typ(as_is->bits, int_bit);
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
set_typ(must_cnv->bits, real_bit);
set_typ(must_succeed->bits, int_bit);
}
else if (typcd == TypCInt) {
/*
* Note that conversion from an integer to a C integer can be
* done by changing the way the descriptor is accessed. It
* is not considered a real conversion. Conversion may fail
* even for integers if large integers are supported.
*/
set_typ(as_is->bits, int_bit);
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
set_typ(must_cnv->bits, real_bit);
if (!largeints)
set_typ(must_succeed->bits, int_bit);
}
else if (typcd == TypEInt) {
set_typ(as_is->bits, int_bit);
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
set_typ(must_succeed->bits, int_bit);
}
else if (typcd == TypECInt) {
set_typ(as_is->bits, int_bit);
set_typ(must_cnv->bits, str_bit);
set_typ(must_cnv->bits, cset_bit);
if (!largeints)
set_typ(must_succeed->bits, int_bit);
}
MrgTyp(n_icntyp, as_is->bits, may_succeed->bits);
MrgTyp(n_icntyp, must_cnv->bits, may_succeed->bits);
if (def) {
set_typ(may_succeed->bits, null_bit);
set_typ(must_succeed->bits, null_bit);
}
/*
* Determine if the conversion expression may evaluate to true or false.
*/
cond = 0;
for (i = 0; i < NumInts(n_intrtyp); ++i) {
if (typ[i] & may_succeed->bits[i])
cond = MaybeTrue;
if (typ[i] & ~must_succeed->bits[i])
cond |= MaybeFalse;
}
/*
* See if more detailed information about the conversion is needed.
*/
if (cnv_flags != NULL) {
*cnv_flags = 0;
for (i = 0; i < NumInts(n_intrtyp); ++i) {
if (typ[i] & as_is->bits[i])
*cnv_flags |= MayKeep;
if (typ[i] & must_cnv->bits[i])
*cnv_flags |= MayConvert;
}
if (def && bitset(typ, null_bit))
*cnv_flags |= MayDefault;
}
free_wktyp(may_succeed);
free_wktyp(must_succeed);
free_wktyp(must_cnv);
free_wktyp(as_is);
return cond;
}
/*
* eval_is - evaluate the result of an 'is' expression within a built-in
* operation.
*/
int eval_is(typcd, indx)
int typcd;
int indx;
{
int cond;
unsigned int *typ;
if (indx >= cur_symtyps->nsyms)
return MaybeTrue | MaybeFalse;
typ = cur_symtyps->types[indx];
if (has_type(typ, typcd, 0))
cond = MaybeTrue;
else
cond = 0;
if (other_type(typ, typcd))
cond |= MaybeFalse;
return cond;
}
/*
* has_type - determine if a bit vector representing types has any bits
* set that correspond to a specific type code from the data base. Also,
* if requested, clear any such bits.
*/
static int has_type(typ, typcd, clear)
unsigned int *typ;
int typcd;
int clear;
{
int frst_bit, last_bit;
int i;
int found;
found = 0;
bitrange(typcd, &frst_bit, &last_bit);
for (i = frst_bit; i < last_bit; ++i) {
if (bitset(typ, i)) {
found = 1;
if (clear)
clr_typ(typ, i);
}
}
return found;
}
/*
* other_type - determine if a bit vector representing types has any bits
* set that correspond to a type *other* than specific type code from the
* data base.
*/
static int other_type(typ, typcd)
unsigned int *typ;
int typcd;
{
int frst_bit, last_bit;
int i;
bitrange(typcd, &frst_bit, &last_bit);
for (i = 0; i < frst_bit; ++i)
if (bitset(typ, i))
return 1;
for (i = last_bit; i < n_intrtyp; ++i)
if (bitset(typ, i))
return 1;
return 0;
}
/*
* eval_arith - determine which cases of an arith_case may be taken based
* on the types of its arguments.
*/
novalue eval_arith(indx1, indx2, maybe_int, maybe_dbl)
int indx1;
int indx2;
int *maybe_int;
int *maybe_dbl;
{
unsigned int *typ1; /* possible types of first variable */
unsigned int *typ2; /* possible types of second variable */
int int1 = 0;
int int2 = 0;
int dbl1 = 0;
int dbl2 = 0;
typ1 = cur_symtyps->types[indx1];
typ2 = cur_symtyps->types[indx2];
/*
* First see what might result if you do a convert to numeric on each
* variable.
*/
if (bitset(typ1, int_bit))
int1 = 1;
if (bitset(typ1, real_bit))
dbl1 = 1;
if (bitset(typ1, str_bit) || bitset(typ1, cset_bit)) {
int1 = 1;
dbl1 = 1;
}
if (bitset(typ2, int_bit))
int2 = 1;
if (bitset(typ2, real_bit))
dbl2 = 1;
if (bitset(typ2, str_bit) || bitset(typ2, cset_bit)) {
int2 = 1;
dbl2 = 1;
}
/*
* Use the conversion information to figure out what type of arithmetic
* might be done.
*/
if (int1 && int2)
*maybe_int = 1;
else
*maybe_int = 0;
*maybe_dbl = 0;
if (dbl1 && dbl2)
*maybe_dbl = 1;
else if (dbl1 && int2)
*maybe_dbl = 1;
else if (int1 && dbl2)
*maybe_dbl = 1;
}
/*
* bitrange - determine the range of bit positions in a type bit vector
* that correspond to a type code from the data base.
*/
static novalue bitrange(typcd, frst_bit, last_bit)
int typcd;
int *frst_bit;
int *last_bit;
{
if (typcd == TypVar) {
/*
* All variable types.
*/
*frst_bit = n_icntyp;
*last_bit = n_intrtyp;
}
else {
*frst_bit = type_array[typcd].frst_bit;
*last_bit = *frst_bit + type_array[typcd].num_bits;
}
}
/*
* type_case - Determine which cases are selected in a type_case
* statement. This routine is used by both type inference and
* the code generator: a different fnc is passed in each case.
* In addition, the code generator passes a case_anlz structure.
*/
int type_case(il, fnc, case_anlz)
struct il_code *il;
int (*fnc)();
struct case_anlz *case_anlz;
{
int *typ_vect;
int i, j;
int num_cases;
int num_types;
int indx;
int sym_indx;
int typcd;
int use_dflt;
unsigned int *typ;
int select;
struct type *wktyp;
/*
* Make a copy of the type of the variable the type case is
* working on.
*/
sym_indx = il->u[0].fld->u[0].n; /* symbol table index */
if (sym_indx >= cur_symtyps->nsyms)
typ = any_typ; /* variable is not a parameter, don't know type */
else
typ = cur_symtyps->types[sym_indx];
wktyp = get_wktyp();
CpyTyp(n_intrtyp, typ, wktyp->bits);
typ = wktyp->bits;
/*
* Loop through all the case clauses.
*/
num_cases = il->u[1].n;
indx = 2;
for (i = 0; i < num_cases; ++i) {
/*
* For each of the types selected by this clause, see if the variable's
* type bit vector contains that type and delete the type from the
* bit vector (so we know if we need the default when we are done).
*/
num_types = il->u[indx++].n;
typ_vect = il->u[indx++].vect;
select = 0;
for (j = 0; j < num_types; ++j)
if (has_type(typ, typ_vect[j], 1)) {
typcd = typ_vect[j];
select += 1;
}
if (select > 0) {
fnc(il->u[indx].fld); /* action */
/*
* If this routine was called by the code generator, we need to
* return extra information.
*/
if (case_anlz != NULL) {
++case_anlz->n_cases;
if (select == 1) {
if (case_anlz->il_then == NULL) {
case_anlz->typcd = typcd;
case_anlz->il_then = il->u[indx].fld;
}
else if (case_anlz->il_else == NULL)
case_anlz->il_else = il->u[indx].fld;
}
else {
/*
* There is more than one possible type that will cause
* us to select this case. It can only be used in the "else".
*/
if (case_anlz->il_else == NULL)
case_anlz->il_else = il->u[indx].fld;
else
case_anlz->n_cases = 3; /* force no inlining. */
}
}
}
++indx;
}
/*
* If there are types that have not been handled, indicate this by
* returning the index of the default clause.
*/
use_dflt = 0;
for (i = 0; i < n_intrtyp; ++i)
if (bitset(typ, i)) {
use_dflt = 1;
break;
}
free_wktyp(wktyp);
if (use_dflt)
return indx;
else
return -1;
}
/*
* typcd_bits - set the bits of a bit vector corresponding to a type
* code from the data base.
*/
static novalue typcd_bits(typcd, typ)
int typcd;
struct type *typ;
{
int frst_bit;
int last_bit;
int i;
if (typcd == TypEmpty)
return; /* Do nothing. */
if (typcd == TypAny) {
/*
* Set bits corresponding to first-class types.
*/
for (i = 0; i < NumInts(n_icntyp) - 1; ++i)
typ->bits[i] |= ~(unsigned int)0;
typ->bits[i] |= val_mask;
return;
}
bitrange(typcd, &frst_bit, &last_bit);
if (last_bit > typ->size) /* bad abstract type computation */
return;
for (i = frst_bit; i < last_bit; ++i)
set_typ(typ->bits, i);
}
/*
* gen_inv - general invocation. The argument list is set up, perform
* abstract interpretation on each possible things being invoked.
*/
static novalue gen_inv(typ, n)
unsigned int *typ;
nodeptr n;
{
int ret_flag = 0;
struct store *s_store;
struct store *store;
struct gentry *gptr;
struct implement *ip;
struct type *prc_typ;
int frst_prc;
int num_prcs;
int i;
#ifdef TypTrc
if (trcfile != NULL) {
fprintf(trcfile, "%s (%d,%d) {\n", n->n_file, n->n_line, n->n_col);
trc_indent = " ";
}
#endif /* TypTrc */
frst_prc = type_array[proc_typ].frst_bit;
num_prcs = type_array[proc_typ].num_bits;
/*
* Dereference the type of the thing being invoked.
*/
prc_typ = get_wktyp();
typ_deref(typ, prc_typ->bits, 0);
s_store = succ_store;
store = get_store(1);
if (bitset(prc_typ->bits, str_bit) ||
bitset(prc_typ->bits, cset_bit) ||
bitset(prc_typ->bits, int_bit) ||
bitset(prc_typ->bits, real_bit)) {
/*
* Assume integer invocation; any argument may be the result type.
*/
#ifdef TypTrc
if (trcfile != NULL) {
fprintf(trcfile, "%s (%d,%d) %s{i}(", n->n_file, n->n_line, n->n_col,
trc_indent);
}
#endif /* TypTrc */
for (i = 0; i < num_args; ++i) {
MrgTyp(n_intrtyp, arg_typs->types[i], n->type);
#ifdef TypTrc
if (trcfile != NULL) {
if (i > 0)
fprintf(trcfile, ", ");
prt_typ(trcfile, arg_typs->types[i]);
}
#endif /* TypTrc */
}
/*
* Integer invocation may succeed or fail.
*/
ret_flag |= DoesRet | DoesFail;
mrg_store(s_store, store);
mrg_store(s_store, fail_store);
#ifdef TypTrc
if (trcfile != NULL) {
fprintf(trcfile, ") =>> ");
prt_typ(trcfile, n->type);
fprintf(trcfile, "\n");
}
#endif /* TypTrc */
}
if (bitset(prc_typ->bits, str_bit) ||
bitset(prc_typ->bits, cset_bit)) {
/*
* Assume string invocation; add all procedure types to the thing
* being invoked.
*/
for (i = 0; i < num_prcs; ++i)
set_typ(prc_typ->bits, frst_prc + i);
}
if (bitset(prc_typ->bits, frst_prc)) {
/*
* First procedure type represents all operators that are
* available via string invocation. Scan the operator table
* looking for those that are in the string invocation table.
* Note, this is not particularly efficient or precise.
*/
for (i = 0; i < IHSize; ++i)
for (ip = ohash[i]; ip != NULL; ip = ip->blink)
if (ip->iconc_flgs & InStrTbl) {
succ_store = cpy_store(s_store);
infer_impl(ip, n, n->symtyps, n->type);
ret_flag |= ip->ret_flag;
mrg_store(succ_store, store);
free_store(succ_store);
}
}
/*
* Check for procedure, built-in, and record constructor types
* and perform type inference on invocations of them.
*/
for (i = 1; i < num_prcs; ++i)
if (bitset(prc_typ->bits, frst_prc + i)) {
succ_store = cpy_store(s_store);
gptr = proc_map[i];
switch (gptr->flag & (F_Proc | F_Builtin | F_Record)) {
case F_Proc:
infer_prc(gptr->val.proc, n);
ret_flag |= gptr->val.proc->ret_flag;
break;
case F_Builtin:
infer_impl(gptr->val.builtin, n, n->symtyps, n->type);
ret_flag |= gptr->val.builtin->ret_flag;
break;
case F_Record:
infer_con(gptr->val.rec, n);
ret_flag |= DoesRet | (err_conv ? DoesFail : 0);
break;
}
mrg_store(succ_store, store);
free_store(succ_store);
}
/*
* If error conversion is supported and a non-procedure value
* might be invoked, assume the invocation can fail.
*/
if (err_conv && other_type(prc_typ->bits, proc_typ))
mrg_store(s_store, fail_store);
free_store(s_store);
succ_store = store;
chk_succ(ret_flag, n->store);
free_wktyp(prc_typ);
#ifdef TypTrc
if (trcfile != NULL) {
fprintf(trcfile, "%s (%d,%d) }\n", n->n_file, n->n_line, n->n_col);
trc_indent = "";
}
#endif /* TypTrc */
}
/*
* get_wktyp - get a dynamically allocated bit vector to use as a
* work area for doing type computations.
*/
static struct type *get_wktyp()
{
struct type *typ;
if ((typ = type_pool) == NULL) {
typ = NewStruct(type);
typ->size = n_rttyp;
typ->bits = alloc_typ(n_rttyp);
}
else {
type_pool = type_pool->next;
ClrTyp(n_rttyp, typ->bits);
}
return typ;
}
/*
* free_wktyp - free a dynamically allocated type bit vector.
*/
static novalue free_wktyp(typ)
struct type *typ;
{
typ->next = type_pool;
type_pool = typ;
}
/*
* bitset - determine if a specific bit in a bit vector is set.
*/
static int bitset(typ, bit)
unsigned int *typ;
int bit;
{
int mask;
int indx;
indx = bit / IntBits;
mask = 1;
mask <<= bit % IntBits;
return typ[indx] & mask;
}
#ifdef TypTrc
/*
* ChkSep - supply a separating space if this is not the first item.
*/
#define ChkSep(n) (++n > 1 ? " " : "")
/*
* prt_typ - print a type that can include variable references.
*/
static novalue prt_typ(file, typ)
FILE *file;
unsigned int *typ;
{
struct gentry *gptr;
struct lentry *lptr;
char *name;
int i, j, k;
int n;
int frst_bit;
int num_bits;
char *abrv;
fprintf(trcfile, "{");
n = 0;
/*
* Go through the types and see any sub-types are present.
*/
for (k = 0; k < num_typs; ++k) {
frst_bit = type_array[k].frst_bit;
num_bits = type_array[k].num_bits;
abrv = icontypes[k].abrv;
if (k == proc_typ) {
/*
* procedures, record constructors, and built-in functions.
*/
for (i = 0; i < num_bits; ++i)
if (bitset(typ, frst_bit + i)) {
if (i == 0)
fprintf(file, "%sops", ChkSep(n));
else {
gptr = proc_map[i];
switch (gptr->flag & (F_Proc | F_Builtin | F_Record)) {
case F_Proc:
fprintf(file, "%s%s:%s", ChkSep(n), abrv, gptr->name);
break;
case F_Builtin:
fprintf(file, "%sfnc:%s", ChkSep(n), gptr->name);
break;
case F_Record:
fprintf(file, "%sconstr:%s", ChkSep(n), gptr->name);
break;
}
}
}
}
else if (k == rec_typ) {
/*
* records - include record name.
*/
for (i = 0; i < num_bits; ++i)
if (bitset(typ, frst_bit + i))
fprintf(file, "%s%s:%s", ChkSep(n), abrv, rec_map[i]->name);
}
else if (icontypes[k].support_new | k == coexp_typ) {
/*
* A type with sub-types.
*/
for (i = 0; i < num_bits; ++i)
if (bitset(typ, frst_bit + i))
fprintf(file, "%s%s%d", ChkSep(n), abrv, i);
}
else {
/*
* A type with no subtypes.
*/
if (bitset(typ, frst_bit))
fprintf(file, "%s%s", ChkSep(n), abrv);
}
}
for (k = 0; k < num_cmpnts; ++k) {
if (typecompnt[k].var) {
/*
* Structure component that is a variable.
*/
frst_bit = compnt_array[k].frst_bit;
num_bits = compnt_array[k].num_bits;
abrv = typecompnt[k].abrv;
for (i = 0; i < num_bits; ++i)
if (bitset(typ, frst_bit + i))
fprintf(file, "%s%s%d", ChkSep(n), abrv, i);
}
}
/*
* record fields
*/
for (i = 0; i < n_fld; ++i)
if (bitset(typ, frst_fld + i))
fprintf(file, "%sfld%d", ChkSep(n), i);
/*
* global variables
*/
for (i = 0; i < n_nmgbl; ++i)
if (bitset(typ, frst_gbl + i)) {
name = NULL;
for (j = 0; j < GHSize && name == NULL; j++)
for (gptr = ghash[j]; gptr != NULL && name == NULL;
gptr = gptr->blink)
if (gptr->index == i)
name = gptr->name;
for (lptr = cur_proc->statics; lptr != NULL && name == NULL;
lptr = lptr->next)
if (lptr->val.index == i)
name = lptr->name;
/*
* Static variables may be returned and dereferenced in a procedure
* they don't belong to.
*/
if (name == NULL)
name = "?static?";
fprintf(file, "%svar:%s", ChkSep(n), name);
}
/*
* local variables
*/
for (i = 0; i < n_loc; ++i)
if (bitset(typ, frst_loc + i)) {
name = NULL;
for (lptr = cur_proc->args; lptr != NULL && name == NULL;
lptr = lptr->next)
if (lptr->val.index == i)
name = lptr->name;
for (lptr = cur_proc->dynams; lptr != NULL && name == NULL;
lptr = lptr->next)
if (lptr->val.index == i)
name = lptr->name;
/*
* Local variables types may appear in the wrong procedure due to
* substring trapped variables and the inference of impossible
* execution paths. Make sure we don't end up with a NULL name.
*/
if (name == NULL)
name = "?";
fprintf(file, "%svar:%s", ChkSep(n), name);
}
fprintf(trcfile, "}");
}
/*
* prt_d_typ - dereference a type and print it.
*/
static novalue prt_d_typ(file, typ)
FILE *file;
unsigned int *typ;
{
struct type *wktyp;
wktyp = get_wktyp();
typ_deref(typ, wktyp->bits, 0);
prt_typ(file, wktyp->bits);
free_wktyp(wktyp);
}
#endif /* TypTrc */
/*
* get_argtyp - get an array of pointers to type bit vectors for use
* in constructing an argument list. The array is large enough for the
* largest argument list.
*/
static struct argtyps *get_argtyp()
{
struct argtyps *argtyps;
if ((argtyps = argtyp_pool) == NULL)
argtyps = (struct argtyps *)alloc((unsigned int)(sizeof(struct argtyps) +
((max_prm - 1) * sizeof(unsigned int *))));
else
argtyp_pool = argtyp_pool->next;
return argtyps;
}
/*
* free_argtyp - free array of pointers to type bitvectors.
*/
static novalue free_argtyp(argtyps)
struct argtyps *argtyps;
{
argtyps->next = argtyp_pool;
argtyp_pool = argtyps;
}
/*
* varsubtyp - examine a type and determine what kinds of variable
* subtypes it has and whether it has any non-variable subtypes.
* If the type consists of a single named variable, return its symbol
* table entry through the parameter "single".
*/
int varsubtyp(typ, single)
unsigned int *typ;
struct lentry **single;
{
struct store *stv_stor;
int subtypes;
int n_types;
int var_indx;
int frst_bit;
int num_bits;
int i, j;
subtypes = 0;
n_types = 0;
var_indx = -1;
/*
* check for non-variables.
*/
for (i = 0; i < n_icntyp; ++i)
if (bitset(typ, i)) {
subtypes |= HasVal;
++n_types;
}
/*
* Predefined variable types.
*/
for (i = 0; i < num_typs; ++i) {
if (icontypes[i].deref != DrfNone) {
frst_bit = type_array[i].frst_bit;
num_bits = type_array[i].num_bits;
for (j = 0; j < num_bits; ++j) {
if (bitset(typ, frst_bit + j)) {
if (i == stv_typ) {
/*
* We have found substring trapped variable j, see whether it
* references locals or globals.
*/
if (do_typinfer) {
stv_stor = compnt_array[str_var].store;
subtypes |= varsubtyp(stv_stor->types[j], NULL);
}
else
subtypes |= HasLcl | HasPrm | HasGlb;
}
else
subtypes |= HasGlb;
++n_types;
}
}
}
}
/*
* Aggregate compontents that are variables.
*/
for (i = 0; i < num_cmpnts; ++i) {
if (typecompnt[i].var) {
frst_bit = compnt_array[i].frst_bit;
num_bits = compnt_array[i].num_bits;
for (j = 0; j < num_bits; ++j) {
if (bitset(typ, frst_bit + j)) {
subtypes |= HasGlb;
++n_types;
}
}
}
}
/*
* record fields
*/
for (i = 0; i < n_fld; ++i)
if (bitset(typ, frst_fld + i)) {
subtypes |= HasGlb;
++n_types;
}
/*
* global variables, including statics
*/
for (i = 0; i < n_gbl; ++i) {
if (bitset(typ, frst_gbl + i)) {
subtypes |= HasGlb;
var_indx = i;
++n_types;
}
}
/*
* local variables
*/
for (i = 0; i < n_loc; ++i) {
if (bitset(typ, frst_loc + i)) {
if (i < Abs(cur_proc->nargs))
subtypes |= HasPrm;
else
subtypes |= HasLcl;
var_indx = n_gbl + i;
++n_types;
}
}
if (single != NULL) {
/*
* See if the type consists of a single named variable.
*/
if (n_types == 1 && var_indx != -1)
*single = cur_proc->vartypmap[var_indx];
else
*single = NULL;
}
return subtypes;
}
/*
* mark_recs - go through the list of parent records for this field
* and mark those that are in the type. Also gather information
* to help generate better code.
*/
novalue mark_recs(fp, typ, num_offsets, offset, bad_recs)
struct fentry *fp;
unsigned int *typ;
int *num_offsets;
int *offset;
int *bad_recs;
{
struct par_rec *rp;
struct type *wktyp;
int frst_rec;
*num_offsets = 0;
*offset = -1;
*bad_recs = 0;
wktyp = get_wktyp();
CpyTyp(n_icntyp, typ, wktyp->bits);
/*
* For each record containing this field, see if the record is
* in the type.
*/
frst_rec = type_array[rec_typ].frst_bit;
for (rp = fp->rlist; rp != NULL; rp = rp->next) {
if (bitset(wktyp->bits, frst_rec + rp->rec->rec_num)) {
/*
* This record is in the type.
*/
rp->mark = 1;
clr_typ(wktyp->bits, frst_rec + rp->rec->rec_num);
if (*offset != rp->offset) {
*offset = rp->offset;
*num_offsets += 1;
}
}
}
/*
* Are there any records that do not contain this field?
*/
*bad_recs = has_type(wktyp->bits, rec_typ, 0);
free_wktyp(wktyp);
}
/*
* past_prms - return true if execution might continue past the parameter
* evaluation. If a parameter has no type, this will not happen.
*/
int past_prms(n)
nodeptr n;
{
struct implement *impl;
struct symtyps *symtyps;
int nparms;
int nargs;
int flag;
int i, j;
nargs = Val0(n);
impl = Impl1(n);
symtyps = n->symtyps;
nparms = impl->nargs;
if (symtyps == NULL)
return 1;
j = 0;
for (i = 0; i < nparms; ++i) {
flag = impl->arg_flgs[i];
if (flag & VarPrm && i >= nargs)
break; /* no parameters for variable part of arg list */
if (flag & RtParm) {
if (is_empty(symtyps->types[j]))
return 0;
++j;
}
if (flag & DrfPrm) {
if (is_empty(symtyps->types[j]))
return 0;
++j;
}
}
return 1;
}
/*
* is_empty - determine if a type bit vector is empty.
*/
static int is_empty(typ)
unsigned int *typ;
{
int i;
for (i = 0; i < NumInts(n_intrtyp); ++i) {
if (typ[i] != 0)
return 0;
}
return 1;
}