Subversion Repositories tendra.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
                 Crown Copyright (c) 1997

    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-

        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;

        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;

        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;

        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


/**********************************************************************
$Author: release $
$Date: 1998/01/17 15:56:05 $
$Revision: 1.1.1.1 $
$Log: dump_distr.c,v $
 * Revision 1.1.1.1  1998/01/17  15:56:05  release
 * First version to be checked into rolling release.
 *
 * Revision 1.2  1995/09/12  10:59:17  currie
 * gcc pedanttry
 *
 * Revision 1.1  1995/04/13  09:08:06  currie
 * Initial revision
 *
***********************************************************************/
/* dump_distr.c
 Idea is to avoid dumping of  s-registers and register parameters
    if there is a simple route through a procedure which only uses the values
     of its parameters, constants,  globals or t-registers.
    Applied to rscopes  after registers have been allocated .
    Mechanism is to insert a new exp with name dump_tag in the
    appropriate place where son is exp after dump, pt is next dump starting
    at pt of original rscope with no and prop fields telling which regs to dump.
    Main proc is dump_opt; if dump_opt_flag is off then dump is placed in at highest
    level, dumping all the required registers.

*/
#include "config.h"
#include "common_types.h"
#include "exptypes.h"
#include "exp.h"
#include "expmacs.h"
#include "tags.h"
#include "bitsmacs.h"
#include "new_tags.h"
#include "procrectypes.h"
#include "common_types.h"
#include "shapemacs.h"
#include "frames.h"
#include "regable.h"
#include "dump_distr.h"

bool do_dump_opt = 1;           /*  may be unset by -d flag */

static  space zsp = {
  0, 0
};                              /* long fixed, long flt */

void maxsp
    PROTO_N ( (a, b) )
    PROTO_T ( space * a X space b )
{
  a -> fixed |= b.fixed;
  a -> flt |= b.flt;
}

space suses
    PROTO_N ( (e, pars, incpars) )
    PROTO_T ( exp e X space * pars X int incpars )
{
  /* accumulate s regs used in e; pars gives bits indicating which s-regs
     are used for the parameters of current proc; incpars says dont ignore
        pars in registers */
  space ans;
  ans = zsp;
  if (e == nilexp)
    return ans;
  switch (name(e)) {
    case name_tag: {
        exp id = son (e);
        if (name (id) == ident_tag) {
          if (isglob (id) || (props (id) & inanyreg) == 0)
            return ans /* global or not in register */ ;
          if ((props (id) & defer_bit) != 0)
            return suses (son (id), pars, incpars) /* dec does not take space */ ;

          if (isparam(id) && no(id) !=0 &&
              ((!incpars && props(son(id)) != 0) || no(id)==props(son(id)) ) )
           /* par in original reg (perhaps destined for sreg) */
                 return ans;

          if ((props(id) & infreg_bits)!=0 ) {
            if (no (id) != 16 && no (id) != 0) {/* uses floating s-reg */
                ans.flt = 3 << ((no (id)) << 1);
            }
          }
          else
            if (no (id) != 0 && no (id) != 2) {
              /* in s seg */
              if (isparam(id) && props(son(id)) !=0 &&
                             props(son(id)) >= incpars) return ans;
              ans.fixed = 1 << (no (id));
            }
        }

        break;
      }
    case case_tag:
      {
        return suses (son (e), pars, incpars);
      }

    case seq_tag: {
        exp t = son (son (e));
        ans = suses (bro (son (e)), pars, incpars);
        for (;;) {
          maxsp (&ans, suses (t, pars,incpars));
          if (last (t)) {
            return ans;
          }
          t = bro (t);
        }
      }
    case 0:
    case goto_tag:
    case val_tag:
    case null_tag:
    case real_tag:
    case string_tag:
    case clear_tag:
    case top_tag:
    case env_offset_tag:
      {
        break;
      }

    case apply_general_tag: case tail_call_tag:{
        maxsp(&ans, *pars);
        goto default1;
    }
    case caller_tag: return suses(son(e), pars, incpars);


    case apply_tag: {
        /* proc call preserves s-regs; however must make sure that any
           pars destined for s-regs get there */
        exp dad = father(e);
        if (name(dad)==res_tag && props(dad)) {
                /* tl recursion  - don't have to dump link or later regs */
                int i;
                exp p = bro(son(e));

                if (last(son(e)) || name(p)==top_tag) return ans;
                for(i=(incpars>4)?incpars:4; ; i++) {
                        if (!valregable(sh(p))) i=8;
                        maxsp(&ans, suses(p, pars, i));
                        if(last(p)) return ans;
                        p = bro(p);
                }
        } else  maxsp (&ans, *pars);
      }                         /* else cont to default */

    default: default1:{
        exp t = son (e);
        maxsp (&ans, suses (t, pars,incpars));
        while (t!=nilexp && !last (t)) {
          t = bro (t);
          maxsp (&ans, suses (t, pars,incpars));
        }
      }
      }
  return ans;
}

bool sameregs
    PROTO_N ( (a, b) )
    PROTO_T ( space * a X space * b )
{
  /*  regs a <= regs b */
  return ((a -> fixed | b -> fixed) == b -> fixed && (a -> flt | b -> flt) == b -> flt);

}

space remd
    PROTO_N ( (tobd, dmpd) )
    PROTO_T ( space * tobd X space * dmpd )
{
  /* any regs left out of tobd after dmpd has been done */
  space ans;
  ans.fixed = tobd -> fixed & ~dmpd -> fixed;
  ans.flt = tobd -> flt & ~dmpd -> flt;
  return ans;
}

bool placedump
    PROTO_N ( (pe, dmpd, tobd, nds) )
    PROTO_T ( exp * pe X space * dmpd X space * tobd X space * nds )
{
  /* replace exp in pe by new dump with props = fixeds and no = flts to be
     dumped ; thread different dumps to same rsc via pt; delivers bool to
     say whether all sregs have been dumped */
  exp e = *pe;
  exp dflt = getexp(nilexp, nilexp, 1, nilexp,nilexp, 0, nds->flt & ~dmpd->flt, dump_tag);
  exp dump = getexp (sh (e), bro (e), last (e), e, dflt, 0, (nds -> fixed & ~dmpd -> fixed),
       dump_tag);
  bro (e) = dump;
  setlast (e);
  *(pe) = dump;
  (dmpd -> fixed) |= nds -> fixed;
  (dmpd -> flt) |= nds -> flt;
  return sameregs (tobd, dmpd);
}




exp goodcond
    PROTO_N ( (first, second, beforeb, pars) )
    PROTO_T ( exp first X exp second X space * beforeb X space * pars )
{
  /* delivers last exp in seq first after all tests (to second) ;
     beforeb is space upto end of tests; second only use beforeb;
     otherwise nilexp */
  exp t;
  space nds;
  int   n = no (son (second));  /* no of uses of labst second */
  if (name (first) != seq_tag)
    return nilexp;
  t = son (son (first));
  *beforeb = zsp;
  for (;;) {
    maxsp(beforeb, suses(t, pars, 0));

    if (name (t) == test_tag) {
      if (pt (t) != second)
        return nilexp;
      if (--n == 0) break;
    }
    if (last (t)) {
        return nilexp;
    }
    t = bro (t);
  }

  nds = suses (second, pars, 0);
  if (sameregs (&nds, beforeb))
    return t;
  return nilexp;
}

bool alljumps
    PROTO_N ( (e, slv, nol) )
    PROTO_T ( exp e X exp slv X int * nol )
{
        /* all all branches to labsts of slove_tag slv in e ? */
     recurse:
        switch (name(e)) {
           case case_tag: {
                exp z = bro(son(e));
                for(;;) {
                        if (father(pt(z))==slv) {
                                if (--(*nol)==0) return 1;
                        }
                        if (last(z)) { e = son(e); goto recurse; }
                        z = bro(z);
                }
           }
           case goto_tag: case test_tag: {
                 if (father(pt(e))==slv) {
                        if (--(*nol)==0) return 1;
                 }
                 if (name(e)== goto_tag) return 0;
                 /* and continue */
           }
           case name_tag: case val_tag: case float_tag: case string_tag:
                return 0;
           default: {
                exp se = son(e);
                if (se==nilexp) return 0;
                for(;;) {
                        if (last(se)) { e = se; goto recurse; }
                        if (alljumps(se, slv, nol)) return 1;
                        se = bro(se);
                }
           }
        }
}

bool goodsolve
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
        exp m = bro(son(e));
        int nol;
        for(nol=0;;nol++) {
                if (no(son(m))!=1) return 0; /* more than one branch to labst */
                if (last(m)) break;
                m = bro(m);
        }
        return alljumps(son(e), e, &nol);
}

static int  notregs;
static int  notfregs;
 /* use to make sure of enough t-regs which are not par regs; I reuse any
    par registers whose pars are put in s-regs as t-regs  */

void pushdumps
    PROTO_N ( (pe, dmpd, tobd, pars) )
    PROTO_T ( exp * pe X space * dmpd X space * tobd X space * pars )
{

  /* tries to delay the dumps of the s-regs as late as possible
     ; pe is the place in the tree to insert any dump found
     necessary in this recursion; dmpd gives the sregs already dumped and
     tobd is all which may have to be dumped; pars give the registers
     containing the initial position of any parameters */

  space nds;
  exp e = *(pe);
  exp *arg;

  switch (name (e)) {
    case ident_tag: {
        nds = suses (son (e), pars,0);
        if ((props (e) & inanyreg) != 0 && no (e) == 0) {
          /*  This definition will be allocated into a t-reg so make sure
             of enough t-regs which are not par regs; I reuse any par
             registers whose pars are put in s-regs as t-regs  */
          if (is_floating (name (sh (son (e))))) {
            if (notfregs-- < 0) {
              nds = remd (tobd, dmpd);
              placedump ( pe, dmpd, tobd, &nds);
              return;
            }
          }
          else {
            if (notregs-- < 0) {
              nds = remd (tobd, dmpd);
              placedump ( pe, dmpd, tobd, &nds);
              return;
            }
          }
        }

        if (name (son (e)) != clear_tag ||
              (isparam(e) && props(son(e))==0 /* ie initially on stack */)  ) {
          /* id could be in s-reg; find from use */
          maxsp (&nds, suses (pt (e), pars, 0));
        }
        if (sameregs (&nds, dmpd) ||
            !placedump ( pe, dmpd, tobd, &nds)) {
          /* not all regs have been dumped - continue with body */
          arg = &bro(son (e));
          pushdumps ( arg, dmpd, tobd, pars);
        }
        return;
      }

    case seq_tag: {
        exp prev;
        exp list = son (son (e));
        if (last(list) ) {
           nds = suses(bro(son(e)), pars, 8);
           if (nds.fixed==0 && nds.flt==0) {
                /* seq consists of two exps with last not using regs */
                pushdumps(&son(son(e)), dmpd, tobd, pars);
                return;
           }
        }
        nds = suses (list, pars, 0);
        if (!sameregs (&nds, dmpd)) {
                                /* first statement uses undumped s-regs */
          if (placedump ( pe, dmpd, tobd, &nds)) {
            return;
          }
        }
        prev = list;
        while (!last (list)) {
          prev = list;
          list = bro (list);
          nds = suses (list, pars, 0);
          if (!sameregs (&nds, dmpd)) {
            /* uses undumped s-regs; construct new seq as result of this
               one .... */
            exp s_hold = getexp (sh (e), bro (son (e)), 0, list, nilexp, 0, 0,
                name (son (e)));
            exp seq = getexp (sh (e), e, 1, s_hold, nilexp, 0, 0, seq_tag);

            bro (prev) = son (e);
            setlast (prev);
            bro (son (e)) = seq;
            bro (bro (s_hold)) = seq;
            while (!last (list)) {
              list = bro (list);
            }
            bro (list) = s_hold;
            /* .... and continue with new result */
            arg = &bro(son (e));
            if (!placedump ( arg, dmpd, tobd, &nds)) {
              pushdumps ( arg, dmpd, tobd, pars);
            }
            return;
          }
        }
        /* no new s-regs used - carry on with result */
        arg = &bro(son (e));
        pushdumps ( arg, dmpd, tobd, pars);
        return;
      }

    case cond_tag: {
        exp first = son (e);
        exp second = bro (first);
        exp t;
        bool same;
        space beforeb;
        nds = suses (first, pars, 0);

        same = sameregs (&nds, dmpd);

        if (!same && (t = goodcond (first, second, &beforeb, pars)) != nilexp) {
          /* worth looking further  into first part */
          if (!sameregs(&beforeb, dmpd) ) {
                if (placedump ( pe, dmpd, tobd, &beforeb)) {
                 return;
                }
          }
          if (!last (t)) {
            exp seq_hold =
              getexp (sh (first), bro (son (first)), 0, bro (t), nilexp, 0, 0,
                name (son (first)));
            exp new =
              getexp (sh (first), first, 1, seq_hold, nilexp, 0, 0, seq_tag);
            exp x = son (seq_hold);
            while (!last (x)) {
              x = bro (x);
            }
            bro (x) = seq_hold; /* set dad son seq_hold */

            bro (bro (seq_hold)) = new;
            setlast (bro (seq_hold));/* set dad of seq_hold */
            bro (son (first)) = new;
            setlast (t);
            bro (t) = son (first);
            /* first is now (t; (rest of first)) */
          }
          arg = &bro(son (first));
          pushdumps ( arg, dmpd, tobd, pars);
          return;

        }
        if (!same) {            /* new s-regs used in first part */
          if (placedump ( pe, dmpd, tobd, &nds)) {
            return;
          }
        }
        arg = &bro(son (e));
        pushdumps ( arg, dmpd, tobd, pars);
        return;
      }

/*    case diag_tag:
    case fscope_tag:
    case cscope_tag: {
        arg= &son(e);
        pushdumps ( arg, dmpd, tobd, pars);
        return;
      }
*/
    case labst_tag: {           /* can only arrive here from cond */
        arg = &bro(son (e));
        pushdumps ( arg, dmpd, tobd, pars);
        return;
      }

    case solve_tag: {
        if (goodsolve(e)) {
                exp m = bro(son(e));
                space old_dmpd;
                nds = suses(son(e), pars, 0);
                if (!sameregs(&nds, dmpd)) {
                        if (placedump(pe, dmpd,tobd, &nds) ) return;
                }
                old_dmpd = *dmpd;
                for(;;) {
                        pushdumps(&bro(son(m)), dmpd, tobd, pars);
                        if (last(m)) return;
                        m = bro(m);
                        *dmpd = old_dmpd;
                }
        } /* else continue ... */

    }

    default: {
        nds = suses(e, pars, 0);
        if (!sameregs(&nds, dmpd)) {
                placedump ( pe, dmpd, tobd, &nds);
        }
      }
  }

}


void dump_opt
    PROTO_N ( (rscope, tobd, pars) )
    PROTO_T ( exp rscope X space * tobd X space * pars )
{
  /* rscope is proc-tag exp;  tobd is set of s-regs to be dumped; pars is
     subset of tobd which will be used as  parameters of proc */
  exp  * arg;
  space dmpd;
  dmpd = zsp;                   /* those regs already dumped */
  arg = &son(rscope);

  notregs = 10;
  notfregs = 8;                 /* no of t-regs != par regs */
  if (!do_dump_opt || No_S || sameregs (tobd, &dmpd) ||
        name(rscope)!=proc_tag) {
    placedump ( arg, &dmpd, tobd, tobd);
  }
  else {
    pushdumps ( arg, &dmpd, tobd, pars);
  }
  return;
}