#include "../../../h/em_mnem.h" #include "../share/types.h" #include "../share/debug.h" #include "../share/global.h" #include "../share/lset.h" #include "../share/cset.h" #include "../share/aux.h" #include "../share/map.h" #include "cs.h" #include "cs_aux.h" #include "cs_debug.h" #include "cs_avail.h" #include "cs_entity.h" STATIC base_valno(enp) entity_p enp; { /* Return the value number of the (base) address of an indirectly * accessed entity. */ switch (enp->en_kind) { default: assert(FALSE); break; case ENINDIR: return enp->en_ind; case ENOFFSETTED: return enp->en_base; case ENARRELEM: return enp->en_arbase; } /* NOTREACHED */ } STATIC entity_p find_base(vn) valnum vn; { /* Vn is the valuenumber of the (base) address of an indirectly * accessed entity. Return the entity that holds this address * recursively. */ register Lindex i; register avail_p ravp; for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) { register entity_p renp = en_elem(i); if (renp->en_vn == vn) { switch (renp->en_kind) { case ENAEXTERNAL: case ENALOCAL: case ENALOCBASE: case ENAARGBASE: return renp; case ENAOFFSETTED: return find_base(renp->en_base); } } } /* We couldn't find it among the entities. * Let's try the available expressions. */ for (ravp = avails; ravp != (avail_p) 0; ravp = ravp->av_before) { if (ravp->av_result == vn) { if (ravp->av_instr == (byte) op_aar) return find_base(ravp->av_ofirst); if (ravp->av_instr == (byte) op_ads) return find_base(ravp->av_oleft); } } /* Bad luck. */ return (entity_p) 0; } STATIC bool obj_overlap(op1, op2) obj_p op1, op2; { /* Op1 and op2 point to two objects in the same datablock. * Obj_overlap returns whether these objects might overlap. */ obj_p tmp; if (op1->o_off > op2->o_off) { /* Exchange them. */ tmp = op1; op1 = op2; op2 = tmp; } return op1->o_size == UNKNOWN_SIZE || op1->o_off + op1->o_size > op2->o_off; } #define same_datablock(o1, o2) ((o1)->o_dblock == (o2)->o_dblock) STATIC bool addr_local(enp) entity_p enp; { /* Is enp the address of a stack item. */ if (enp == (entity_p) 0) return FALSE; return enp->en_kind == ENALOCAL || enp->en_kind == ENALOCBASE || enp->en_kind == ENAARGBASE; } STATIC bool addr_external(enp) entity_p enp; { /* Is enp the address of an external. */ return enp != (entity_p) 0 && enp->en_kind == ENAEXTERNAL; } STATIC kill_external(obp, indir) obj_p obp; int indir; { /* A store is done via the object in obp. If this store is direct * we kill directly accessed entities in the same data block only * if they overlap with obp, otherwise we kill everything in the * data block. Indirectly accessed entities of which it can not be * proven taht they are not in the same data block, are killed in * both cases. */ register Lindex i; OUTTRACE("kill external", 0); for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) { entity_p enp = en_elem(i); entity_p base; switch (enp->en_kind) { case ENEXTERNAL: if (!same_datablock(enp->en_ext, obp)) break; if (!indir && !obj_overlap(enp->en_ext, obp)) break; OUTTRACE("kill %d", enp->en_vn); enp->en_vn = newvalnum(); break; case ENINDIR: case ENOFFSETTED: case ENARRELEM: /* We spare its value number if we are sure * that its (base) address points into the * stack or into another data block. */ base = find_base(base_valno(enp)); if (addr_local(base)) break; if (addr_external(base) && !same_datablock(base->en_ext, obp) ) break; OUTTRACE("kill %d", enp->en_vn); enp->en_vn = newvalnum(); break; } } } STATIC bool loc_overlap(enp1, enp2) entity_p enp1, enp2; { /* Enp1 and enp2 point to two locals. Loc_overlap returns whether * they overlap. */ entity_p tmp; assert(enp1->en_kind == ENLOCAL && enp2->en_kind == ENLOCAL); if (enp1->en_loc > enp2->en_loc) { /* Exchange them. */ tmp = enp1; enp1 = enp2; enp2 = tmp; } if (enp1->en_loc < 0 && enp2->en_loc >= 0) return FALSE; /* Locals and parameters do not overlap. */ else return enp1->en_size == UNKNOWN_SIZE || enp1->en_loc + enp1->en_size > enp2->en_loc; } STATIC kill_local(enp, indir) entity_p enp; bool indir; { /* This time a store is done into an ENLOCAL. */ register Lindex i; OUTTRACE("kill local", 0); for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) { entity_p rep = en_elem(i); entity_p base; switch (rep->en_kind) { case ENLOCAL: if (indir) { /* Kill locals that might be stored into * via a pointer. Note: enp not used. */ if (!is_regvar(rep->en_loc)) { OUTTRACE("kill %d", rep->en_vn); rep->en_vn = newvalnum(); } } else if (loc_overlap(rep, enp)) { /* Only kill overlapping locals. */ OUTTRACE("kill %d", rep->en_vn); rep->en_vn = newvalnum(); } break; case ENINDIR: case ENOFFSETTED: case ENARRELEM: if (!is_regvar(enp->en_loc)) { base = find_base(base_valno(rep)); if (!addr_external(base)) { OUTTRACE("kill %d", rep->en_vn); rep->en_vn = newvalnum(); } } break; } } } STATIC kill_sim() { /* A store is done into the ENIGNMASK. */ register Lindex i; OUTTRACE("kill sim", 0); for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) { register entity_p rep = en_elem(i); if (rep->en_kind == ENIGNMASK) { OUTTRACE("kill %d", rep->en_vn); rep->en_vn = newvalnum(); return; /* There is only one ignoremask. */ } } } kill_direct(enp) entity_p enp; { /* A store will be done into enp. We must forget the values of all the * entities this one may overlap with. */ switch (enp->en_kind) { default: assert(FALSE); break; case ENEXTERNAL: kill_external(enp->en_ext, FALSE); break; case ENLOCAL: kill_local(enp, FALSE); break; case ENIGNMASK: kill_sim(); break; } } kill_indir(enp) entity_p enp; { /* An indirect store is done, in an ENINDIR, * an ENOFFSETTED or an ENARRELEM. */ entity_p p; /* If we can find the (base) address of this entity, then we can spare * the entities that are provably not pointed to by the address. * We will also make use of the MES 3 pseudo's, generated by * the front-end. When a MES 3 is generated for a local, this local * will not be referenced indirectly. */ if ((p = find_base(base_valno(enp))) == (entity_p) 0) { kill_much(); /* Kill all entities without registermessage. */ } else { switch (p->en_kind) { case ENAEXTERNAL: /* An indirect store into global data. */ kill_external(p->en_ext, TRUE); break; case ENALOCAL: case ENALOCBASE: case ENAARGBASE: /* An indirect store into stack data. */ kill_local(p, TRUE); break; } } } kill_much() { /* Kills all killable entities, * except the locals for which a registermessage was generated. */ register Lindex i; OUTTRACE("kill much", 0); for (i = Lfirst(entities); i != (Lindex) 0; i = Lnext(i, entities)) { register entity_p rep = en_elem(i); if (rep->en_static) continue; if (rep->en_kind == ENLOCAL && is_regvar(rep->en_loc)) continue; OUTTRACE("kill %d", rep->en_vn); rep->en_vn = newvalnum(); } } STATIC bool bad_procflags(pp) proc_p pp; { /* Return whether the flags about the procedure in pp indicate * that we have little information about it. It might be that * we haven't seen the text of pp, or that we have seen that pp * calls a procedure which we haven't seen the text of. */ return !(pp->p_flags1 & PF_BODYSEEN) || (pp->p_flags1 & PF_CALUNKNOWN); } STATIC kill_globset(s) cset s; { /* S is a set of global variables that might be changed. * We act as if a direct store is done into each of them. */ register Cindex i; OUTTRACE("kill globset", 0); for (i = Cfirst(s); i != (Cindex) 0; i = Cnext(i,s)) { kill_external(omap[Celem(i)], FALSE); } } kill_call(pp) proc_p pp; { /* Kill everything that might be destroyed by calling * the procedure in pp. */ if (bad_procflags(pp)) { /* We don't know enough about this procedure. */ kill_much(); } else if (pp->p_change->c_flags & CF_INDIR) { /* The procedure does an indirect store. */ kill_much(); } else { /* Procedure might affect global data. */ kill_globset(pp->p_change->c_ext); } } kill_all() { /* Kills all entities. */ register Lindex i; OUTTRACE("kill all entities", 0); for (i = Lfirst(entities); i != (Lindex) i; i = Lnext(i, entities)) { entity_p enp = en_elem(i); OUTTRACE("kill %d", enp->en_vn); enp->en_vn = newvalnum(); } }