summaryrefslogtreecommitdiff
path: root/src/iconc/typinfer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iconc/typinfer.c')
-rw-r--r--src/iconc/typinfer.c5189
1 files changed, 5189 insertions, 0 deletions
diff --git a/src/iconc/typinfer.c b/src/iconc/typinfer.c
new file mode 100644
index 0000000..8a96e23
--- /dev/null
+++ b/src/iconc/typinfer.c
@@ -0,0 +1,5189 @@
+/*
+ * 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 */
+#ifdef OptimizeType
+ struct typinfo *act_typ; /* types passed via co-expression activation */
+ struct typinfo *rslt_typ; /* types resulting from "co-expression return" */
+#else /* OptimizeType */
+ unsigned int *act_typ; /* types passed via co-expression activation */
+ unsigned int *rslt_typ; /* types resulting from "co-expression return" */
+#endif /* OptimizeType */
+ 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 */
+
+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;
+#ifdef OptimizeType
+ struct typinfo *types[1]; /* actual size is max_prm */
+#else /* OptimizeType */
+ unsigned int *types[1]; /* actual size is max_prm */
+#endif /* OptimizeType */
+ };
+
+/*
+ * prototypes for static functions.
+ */
+#ifdef OptimizeType
+void and_bits_to_packed (struct typinfo *src,
+ struct typinfo *dest, int size);
+struct typinfo *alloc_typ (int n_types);
+unsigned int *alloc_mem_typ (unsigned int n_types);
+int bitset (struct typinfo *typ, int bit);
+void clr_typ (struct typinfo *type, unsigned int bit);
+void clr_packed (struct typinfo *src, int nsize);
+void cpy_packed_to_packed (struct typinfo *src,
+ struct typinfo *dest, int nsize);
+static void deref_lcl (struct typinfo *src,
+ struct typinfo *dest);
+static int findloops ( struct node *n, int resume,
+ struct typinfo *rslt_type);
+static void gen_inv (struct typinfo *prc_typ, nodeptr n);
+int has_type (struct typinfo *typ, int typcd, int clear);
+static void infer_impl (struct implement *impl,
+ nodeptr n, struct symtyps *symtyps,
+ struct typinfo *rslt_typ);
+int is_empty (struct typinfo *typ);
+int mrg_packed_to_packed (struct typinfo *src,
+ struct typinfo *dest, int nsize);
+int other_type (struct typinfo *typ, int typcd);
+static void set_ret (struct typinfo *typ);
+void set_typ (struct typinfo *type, unsigned int bit);
+void typcd_bits (int typcd, struct type *typ);
+static void typ_deref (struct typinfo *src,
+ struct typinfo *dest, int chk);
+int xfer_packed_to_bits (struct typinfo *src,
+ struct typinfo *dest, int nsize);
+#else /* OptimizeType */
+unsigned int *alloc_typ (int n_types);
+int bitset (unsigned int *typ, int bit);
+void clr_typ (unsigned int *type, unsigned int bit);
+static void deref_lcl (unsigned int *src, unsigned int *dest);
+static int findloops ( struct node *n, int resume,
+ unsigned int *rslt_type);
+static void gen_inv (unsigned int *prc_typ, nodeptr n);
+int has_type (unsigned int *typ, int typcd, int clear);
+static void infer_impl (struct implement *impl,
+ nodeptr n, struct symtyps *symtyps,
+ unsigned int *rslt_typ);
+int is_empty (unsigned int *typ);
+int other_type (unsigned int *typ, int typcd);
+static void set_ret (unsigned int *typ);
+void set_typ (unsigned int *type, unsigned int bit);
+void typcd_bits (int typcd, struct type *typ);
+static void typ_deref (unsigned int *src, unsigned int *dest, int chk);
+#endif /* OptimizeType */
+
+static void abstr_new (struct node *n, struct il_code *il);
+static void abstr_typ (struct il_code *il, struct type *typ);
+static struct store *alloc_stor (int stor_sz, int n_types);
+static void chk_succ (int ret_flag, struct store *susp_stor);
+static struct store *cpy_store (struct store *source);
+static int eval_cond (struct il_code *il);
+static void free_argtyp (struct argtyps *argtyps);
+static void free_store (struct store *store);
+static void free_wktyp (struct type *typ);
+static void find_new (struct node *n);
+static struct argtyps *get_argtyp (void);
+static struct store *get_store (int clear);
+static struct type *get_wktyp (void);
+static void infer_act (nodeptr n);
+static void infer_con (struct rentry *rec, nodeptr n);
+static int infer_il (struct il_code *il);
+static void infer_nd (nodeptr n);
+static void infer_prc (struct pentry *proc, nodeptr n);
+static void mrg_act (struct t_coexpr *coexp,
+ struct store *e_store,
+ struct type *rslt_typ);
+static void mrg_store (struct store *source, struct store *dest);
+static void side_effect (struct il_code *il);
+static struct symtyps *symtyps (int nsyms);
+
+#ifdef TypTrc
+static void prt_d_typ (FILE *file, struct typinfo *typ);
+static void prt_typ (FILE *file, struct typinfo *typ);
+#endif /* TypTrc */
+
+#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 */
+
+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 */
+unsigned int n_icntyp; /* number of non-variable types */
+unsigned int n_intrtyp; /* number of types in intermediate values */
+static unsigned int n_rttyp; /* number of types in runtime computations */
+unsigned int val_mask; /* mask for non-var types in last int of type */
+
+unsigned int null_bit; /* bit for null type */
+unsigned int str_bit; /* bit for string type */
+unsigned int cset_bit; /* bit for cset type */
+unsigned int int_bit; /* bit for integer type */
+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 */
+
+#ifdef OptimizeType
+static struct typinfo *any_typ; /* type bit vector with all bits on */
+struct typinfo *free_typinfo = NULL;
+struct typinfo *start_typinfo = NULL;
+struct typinfo *high_typinfo = NULL;
+struct typinfo *low_typinfo = NULL;
+#else /* OptimizeType */
+static unsigned int *any_typ; /* type bit vector with all bits on */
+#endif /* OptimizeType */
+
+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.
+ */
+void 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;
+#ifdef OptimizeType
+ struct typinfo *type;
+#else /* OptimizeType */
+ unsigned int *type;
+#endif /* OptimizeType */
+ 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 */
+
+ trcname = getenv("TYPTRC");
+
+ if (trcname != NULL && strlen(trcname) != 0) {
+
+ if (trcname[0] == '|') {
+ FILE *popen();
+
+ trcfile = popen(trcname+1, "w");
+ }
+ else
+
+ trcfile = fopen(trcname, "w");
+
+ if (trcfile == NULL) {
+ fprintf(stderr, "TYPTRC: cannot open %s\n", trcname);
+ fflush(stderr);
+ exit(EXIT_FAILURE);
+ }
+ }
+#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.
+ */
+#ifdef OptimizeType
+ any_typ = alloc_typ(n_rttyp);
+ any_typ->bits = alloc_mem_typ(DecodeSize(any_typ->packed));
+ for (i = 0; i < NumInts(n_rttyp); ++i)
+ any_typ->bits[i] = ~(unsigned int)0;
+#else /* OptimizeType */
+ any_typ = alloc_typ(n_rttyp);
+ for (i = 0; i < NumInts(n_rttyp); ++i)
+ any_typ[i] = ~(unsigned int)0;
+#endif /* OptimizeType */
+
+ /*
+ * 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 void 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(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * 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 void 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(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * 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;
+
+#ifdef OptimizeType
+ stor = (struct store *)alloc((unsigned int)(sizeof(struct store) +
+ ((stor_sz - 1) * sizeof(struct typinfo *))));
+ stor->next = NULL;
+ stor->perm = 1;
+ for (i = 0; i < stor_sz; ++i) {
+ stor->types[i] = (struct typinfo *)alloc_typ(n_types);
+ }
+#else /* OptimizeType */
+ 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);
+ }
+#endif /* OptimizeType */
+
+ return stor;
+ }
+
+/*
+ * 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;
+#ifdef OptimizeType
+struct typinfo *rslt_type;
+#else /* OptimizeType */
+unsigned int *rslt_type;
+#endif /* OptimizeType */
+ {
+ struct loop {
+ int resume;
+ int can_fail;
+ int every_cntrl;
+#ifdef OptimizeType
+ struct typinfo *type;
+#else /* OptimizeType */
+ unsigned int *type;
+#endif /* OptimizeType */
+ 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(EXIT_FAILURE);
+ }
+ 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;
+
+#ifdef OptimizeType
+ tab = (struct symtyps *)alloc((unsigned int)(sizeof(struct symtyps) +
+ (nsyms - 1) * sizeof(struct typinfo *)));
+#else /* OptimizeType */
+ tab = (struct symtyps *)alloc((unsigned int)(sizeof(struct symtyps) +
+ (nsyms - 1) * sizeof(int *)));
+#endif /* OptimizeType */
+ 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 void 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 void 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 void set_ret(typ)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+ {
+ 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 void deref_lcl(src, dest)
+#ifdef OptimizeType
+struct typinfo *src;
+struct typinfo *dest;
+#else /* OptimizeType */
+unsigned int *src;
+unsigned int *dest;
+#endif /* OptimizeType */
+ {
+ 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 void 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 void 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(EXIT_FAILURE);
+ }
+ }
+
+/*
+ * infer_con - perform type inference for the invocation of a record
+ * constructor.
+ */
+static void 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 void 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 void 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 void typ_deref(src, dest, chk)
+#ifdef OptimizeType
+struct typinfo *src;
+struct typinfo *dest;
+#else /* OptimizeType */
+unsigned int *src;
+unsigned int *dest;
+#endif /* OptimizeType */
+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;
+ int ret;
+/*
+ if (src->bits == NULL) {
+ src->bits = alloc_mem_typ(src->size);
+ xfer_packed_types(src);
+ }
+ if (dest->bits == NULL) {
+ dest->bits = alloc_mem_typ(dest->size);
+ xfer_packed_types(dest);
+ }
+*/
+ /*
+ * copy values to destination
+ */
+#ifdef OptimizeType
+ if ((src->bits != NULL) && (dest->bits != NULL)) {
+ for (i = 0; i < NumInts(n_icntyp) - 1; ++i) {
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i];
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i] & val_mask; /* mask out variables */
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ else if ((src->bits != NULL) && (dest->bits == NULL)) {
+ dest->bits = alloc_mem_typ(DecodeSize(dest->packed));
+ xfer_packed_types(dest);
+ for (i = 0; i < NumInts(n_icntyp) - 1; ++i) {
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i];
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ old = dest->bits[i];
+ dest->bits[i] |= src->bits[i] & val_mask; /* mask out variables */
+ if (chk && (old != dest->bits[i]))
+ ++changed;
+ }
+ else if ((src->bits == NULL) && (dest->bits != NULL)) {
+ ret = xfer_packed_to_bits(src, dest, n_icntyp);
+ if (chk)
+ changed += ret;
+ }
+ else {
+ ret = mrg_packed_to_packed(src, dest, n_icntyp);
+ if (chk)
+ changed += ret;
+ }
+#else /* OptimizeType */
+ 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;
+#endif /* OptimizeType */
+
+ /*
+ * 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 void infer_impl(impl, n, symtyps, rslt_typ)
+struct implement *impl;
+nodeptr n;
+struct symtyps *symtyps;
+#ifdef OptimizeType
+struct typinfo *rslt_typ;
+#else /* OptimizeType */
+unsigned int *rslt_typ;
+#endif /* OptimizeType */
+ {
+#ifdef OptimizeType
+ struct typinfo *typ;
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+ 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 void 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(EXIT_FAILURE);
+ /* NOTREACHED */
+ }
+ }
+
+/*
+ * side_effect - perform a side effect from an abstract clause of a
+ * built-in operation.
+ */
+static void 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 void 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;
+#ifdef OptimizeType
+ struct typinfo *prmtyp;
+#else /* OptimizeType */
+ unsigned int *prmtyp;
+#endif /* OptimizeType */
+
+ 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;
+#ifdef OptimizeType
+ and_bits_to_packed(typ2->bits, typ1->bits, size);
+#else /* OptimizeType */
+ for (i = 0; i < NumInts(size); ++i)
+ typ1->bits[i] &= typ2->bits[i];
+#endif /* OptimizeType */
+ 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(EXIT_FAILURE);
+ /* 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 */
+#ifdef OptimizeType
+ struct typinfo *typ; /* possible types of the variable */
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+ int cond;
+ int i;
+#ifdef OptimizeType
+ unsigned int val1, val2;
+#endif /* OptimizeType */
+
+ /*
+ * 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;
+
+/*
+ if (typ->bits == NULL) {
+ typ->bits = alloc_mem_typ(typ->size);
+ xfer_packed_types(typ);
+ }
+ if (may_succeed->bits->bits == NULL) {
+ may_succeed->bits->bits = alloc_mem_typ(may_succeed->bits->size);
+ xfer_packed_types(may_succeed->bits);
+ }
+ if (must_succeed->bits->bits == NULL) {
+ must_succeed->bits->bits = alloc_mem_typ(must_succeed->bits->size);
+ xfer_packed_types(must_succeed->bits);
+ }
+*/
+ for (i = 0; i < NumInts(n_intrtyp); ++i) {
+#ifdef OptimizeType
+ if ((typ->bits != NULL) && (may_succeed->bits->bits != NULL)) {
+ if (typ->bits[i] & may_succeed->bits->bits[i])
+ cond = MaybeTrue;
+ }
+ else if ((typ->bits == NULL) && (may_succeed->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & may_succeed->bits->bits[i])
+ cond = MaybeTrue;
+ }
+ else if ((typ->bits != NULL) && (may_succeed->bits->bits == NULL)) {
+ val2 = get_bit_vector(may_succeed->bits, i);
+ if (typ->bits[i] & val2)
+ cond = MaybeTrue;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(may_succeed->bits, i);
+ if (val1 & val2)
+ cond = MaybeTrue;
+ }
+ if ((typ->bits != NULL) && (must_succeed->bits->bits != NULL)) {
+ if (typ->bits[i] & ~must_succeed->bits->bits[i])
+ cond |= MaybeFalse;
+ }
+ else if ((typ->bits == NULL) && (must_succeed->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & ~must_succeed->bits->bits[i])
+ cond |= MaybeFalse;
+ }
+ else if ((typ->bits != NULL) && (must_succeed->bits->bits == NULL)) {
+ val2 = get_bit_vector(must_succeed->bits, i);
+ if (typ->bits[i] & ~val2)
+ cond |= MaybeFalse;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(must_succeed->bits, i);
+ if (val1 & ~val2)
+ cond |= MaybeFalse;
+ }
+#else /* OptimizeType */
+ if (typ[i] & may_succeed->bits[i])
+ cond = MaybeTrue;
+ if (typ[i] & ~must_succeed->bits[i])
+ cond |= MaybeFalse;
+#endif /* OptimizeType */
+ }
+
+ /*
+ * See if more detailed information about the conversion is needed.
+ */
+ if (cnv_flags != NULL) {
+ *cnv_flags = 0;
+/*
+ if (as_is->bits == NULL) {
+ as_is->bits->bits = alloc_mem_typ(as_is->bits->size);
+ xfer_packed_types(as_is->bits);
+ }
+ if (must_cnv->bits->bits == NULL) {
+ must_cnv->bits->bits = alloc_mem_typ(must_cnv->bits->size);
+ xfer_packed_types(must_cnv->bits);
+ }
+*/
+ for (i = 0; i < NumInts(n_intrtyp); ++i) {
+#ifdef OptimizeType
+ if ((typ->bits != NULL) && (as_is->bits->bits != NULL)) {
+ if (typ->bits[i] & as_is->bits->bits[i])
+ *cnv_flags |= MayKeep;
+ }
+ else if ((typ->bits == NULL) && (as_is->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & as_is->bits->bits[i])
+ *cnv_flags |= MayKeep;
+ }
+ else if ((typ->bits != NULL) && (as_is->bits->bits == NULL)) {
+ val2 = get_bit_vector(as_is->bits, i);
+ if (typ->bits[i] & val2)
+ *cnv_flags |= MayKeep;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(as_is->bits, i);
+ if (val1 & val2)
+ *cnv_flags |= MayKeep;
+ }
+ if ((typ->bits != NULL) && (must_cnv->bits->bits != NULL)) {
+ if (typ->bits[i] & must_cnv->bits->bits[i])
+ *cnv_flags |= MayConvert;
+ }
+ else if ((typ->bits == NULL) && (must_cnv->bits->bits != NULL)) {
+ val1 = get_bit_vector(typ, i);
+ if (val1 & must_cnv->bits->bits[i])
+ *cnv_flags |= MayConvert;
+ }
+ else if ((typ->bits != NULL) && (must_cnv->bits->bits == NULL)) {
+ val2 = get_bit_vector(must_cnv->bits, i);
+ if (typ->bits[i] & val2)
+ *cnv_flags |= MayConvert;
+ }
+ else {
+ val1 = get_bit_vector(typ, i);
+ val2 = get_bit_vector(must_cnv->bits, i);
+ if (val1 & val2)
+ *cnv_flags |= MayConvert;
+ }
+#else /* OptimizeType */
+ if (typ[i] & as_is->bits[i])
+ *cnv_flags |= MayKeep;
+ if (typ[i] & must_cnv->bits[i])
+ *cnv_flags |= MayConvert;
+#endif /* OptimizeType */
+ }
+ 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;
+#ifdef OptimizeType
+ struct typinfo *typ;
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+
+ 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;
+ }
+
+/*
+ * eval_arith - determine which cases of an arith_case may be taken based
+ * on the types of its arguments.
+ */
+void eval_arith(indx1, indx2, maybe_int, maybe_dbl)
+int indx1;
+int indx2;
+int *maybe_int;
+int *maybe_dbl;
+ {
+#ifdef OptimizeType
+ struct typinfo *typ1; /* possible types of first variable */
+ struct typinfo *typ2; /* possible types of second variable */
+#else /* OptimizeType */
+ unsigned int *typ1; /* possible types of first variable */
+ unsigned int *typ2; /* possible types of second variable */
+#endif /* OptimizeType */
+ 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;
+ }
+
+/*
+ * 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;
+#ifdef OptimizeType
+ struct typinfo *typ;
+#else /* OptimizeType */
+ unsigned int *typ;
+#endif /* OptimizeType */
+ 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;
+ }
+
+/*
+ * gen_inv - general invocation. The argument list is set up, perform
+ * abstract interpretation on each possible things being invoked.
+ */
+static void gen_inv(typ, n)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+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 void free_wktyp(typ)
+struct type *typ;
+ {
+ typ->next = type_pool;
+ type_pool = typ;
+ }
+
+#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 void prt_typ(file, typ)
+FILE *file;
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+ {
+ 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 void prt_d_typ(file, typ)
+FILE *file;
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+{
+ 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)
+#ifdef OptimizeType
+ argtyps = (struct argtyps *)alloc((unsigned int)(sizeof(struct argtyps) +
+ ((max_prm - 1) * sizeof(struct typinfo *))));
+#else /* OptimizeType */
+ argtyps = (struct argtyps *)alloc((unsigned int)(sizeof(struct argtyps) +
+ ((max_prm - 1) * sizeof(unsigned int *))));
+#endif /* OptimizeType */
+ else
+ argtyp_pool = argtyp_pool->next;
+ return argtyps;
+ }
+
+/*
+ * free_argtyp - free array of pointers to type bitvectors.
+ */
+static void 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 "singl".
+ */
+int varsubtyp(typ, singl)
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+struct lentry **singl;
+ {
+ 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 (singl != NULL) {
+ /*
+ * See if the type consists of a single named variable.
+ */
+ if (n_types == 1 && var_indx != -1)
+ *singl = cur_proc->vartypmap[var_indx];
+ else
+ *singl = 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.
+ */
+void mark_recs(fp, typ, num_offsets, offset, bad_recs)
+struct fentry *fp;
+#ifdef OptimizeType
+struct typinfo *typ;
+#else /* OptimizeType */
+unsigned int *typ;
+#endif /* OptimizeType */
+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;
+ }