/* * This file contains the main part of the stackheight computation phase. * * Author: Hans van Eck. */ #include #include #include #include #include "param.h" #include "assert.h" #include "types.h" #include "shc.h" #include "alloc.h" #include "proinf.h" #include "line.h" #include "ext.h" #include "pop_push.h" extern char *pop_push[]; extern char flow_tab[]; #define NON_CONTINUABLE(i) (flow_tab[i]&JUMP) #define ISABRANCH(i) (flow_tab[i]&HASLABEL) #define ISCONDBRANCH(i) (flow_tab[i]&CONDBRA) lblst_p est_list = NULL; #define INSTR(lnp) (lnp->l_instr & BMASK) #define TYPE(lnp) lnp->l_optyp #define PREV(lnp) lnp->l_prev #define SHORT(lnp) lnp->l_a.la_short #define MINI(lnp) ((lnp->l_optyp & BMASK) - Z_OPMINI) #define IS_MINI(lnp) (lnp->l_optyp >= OPMINI) #define IS_LOC(l) (l!=(line_p) 0 && INSTR(l)==op_loc && IS_MINI(l)) int state; static int stack_height = 0; init_state() { stack_height = 0; change_state(KNOWN); est_list = NULL; } shc_pseudos() { register line_p lp; for (lp = pseudos; lp != (line_p)0; lp = lp->l_next) { switch(INSTR(lp)) { case ps_con: case ps_rom: if (lp->l_optyp == OPLIST) { register arg_p ap = lp->l_a.la_arg; while (ap != (arg_p) 0) { if (ap->a_typ == ARGNUM) { assign_label(ap->a_a.a_np->n_repl); } ap = ap->a_next; } } else if (lp->l_optyp == OPNUMLAB) assign_label(lp->l_a.la_np->n_repl); } } } shc_instr(lnp) line_p lnp; { char *s; register instr = INSTR(lnp); register int mult, arg, argdef; line_p x = PREV(lnp); line_p y = (x == (line_p) 0 ? (line_p) 0 : PREV(x)); if (state == NO_STACK_MES) return; if ( instr == op_lab) { do_inst_label(lnp); return; } if (instr < sp_fmnem || instr > sp_lmnem) { return; } if(state == NOTREACHED) return; /* What else ? */ s = pop_push[instr]; if (*s != '0') while (*s != '\0') { if (*s++ == '-') mult = -1; else mult = 1; if (TYPE(lnp) == OPSHORT) { arg = SHORT(lnp); if (arg < wordsize) arg = wordsize; argdef = TRUE; } else if (IS_MINI(lnp)) { arg = MINI(lnp); if (arg > 0 && arg < wordsize) arg = wordsize; if (arg < 0 && -arg < wordsize) arg = -wordsize; argdef = TRUE; } else argdef = FALSE; switch (*s++) { case 'w': stack_height += mult * wordsize; break; case 'd': stack_height += mult * wordsize * 2; break; case 'p': stack_height += mult * pointersize; break; case 'a': if (argdef == FALSE || instr == op_ass) { change_state(NO_STACK_MES); return; } stack_height += mult * arg; break; case 'x': if (IS_LOC(x)) { arg = MINI(x); if (arg < wordsize) arg = wordsize; stack_height += mult * arg; break; } change_state(NO_STACK_MES); return; case 'y': if (IS_LOC(y)) { arg = MINI(y); if (arg < wordsize) arg = wordsize; stack_height += mult * arg; break; } change_state(NO_STACK_MES); return; case '?': /* Actually, the effect of a ret on the stack is * known, but it has a '?' anyway. I think this * should be changed in ~etc/em_table */ if (instr == op_ret) break; change_state(NO_STACK_MES); return; default: assert(FALSE); } } if (ISABRANCH(instr)) do_inst_label(lnp); if (NON_CONTINUABLE(instr)) change_state(NOTREACHED); } change_state(mode) int mode; { state = mode; if (mode != KNOWN) stack_height = 0; } delete_labels() { register lblst_p tmp; while ((tmp = est_list) != NULL) { est_list = est_list->ll_next; oldlblst(tmp); } } inst_old_label(lst_elt) register lblst_p lst_elt; { if (state != NOTREACHED) { if (stack_height < 0 || lst_elt->ll_height != stack_height) { change_state(NO_STACK_MES); } } else { /* after a label */ stack_height = lst_elt->ll_height; } } inst_new_label(label) register num_p label; { register lblst_p lst_elt; lst_elt = newlblst(); lst_elt->ll_next = est_list; lst_elt->ll_num = label; lst_elt->ll_height = stack_height; est_list = lst_elt; label->n_lst_elt = lst_elt; label->n_flags |= NUMSET; } assign_label(label) num_p label; { if (label->n_flags & NUMSET) inst_old_label(label->n_lst_elt); else inst_new_label(label); } do_inst_label(lnp) /* (re-)install a label */ line_p lnp; { num_p label = lnp->l_a.la_np->n_repl; int instr = INSTR(lnp); assign_label(label); if (instr == op_lab) { if (state == NOTREACHED) { label->n_lst_elt->ll_fallthrough = FALSE; } else { label->n_lst_elt->ll_fallthrough = TRUE; } } else if (ISCONDBRANCH(instr)) { /* conditional branch */ label->n_flags |= NUMCOND; } if (state != NO_STACK_MES) change_state(KNOWN); }