Subversion Repositories tendra.SVN

Rev

Rev 2 | Blame | Compare with Previous | 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.
*/


/*      $Id: dump_distr.c,v 1.1.1.1 1998/01/17 15:55:59 release Exp $    */

#ifndef lint
static char vcid[] = "$Id: dump_distr.c,v 1.1.1.1 1998/01/17 15:55:59 release Exp $";
#endif /* lint */
/* 
   dump_distrib.c
*/
#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 "shapemacs.h"
#include "frames.h"
#include "regable.h"
#include "reg_defs.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;
}


/* 
   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 suses
    PROTO_N ( ( e, pars, incpars ) )
    PROTO_T ( exp e X space *pars X int incpars )
{

  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) != NO_REG  && no(id)!=0) {/* uses floating s-reg */
          if(isparam(id) && props(son(id))!=0 && props(son(id))>=incpars){
            return ans;
          }
          else{
            ans.flt = (1<<(no(id)));
          }
        }
      }
      else
        if (no (id) != 0 && no (id) != 32) {
          /* 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 env_offset_tag :
  case 0 : 
  case goto_tag : 
  case val_tag :
  case special_tag :
  case null_tag : 
  case real_tag : 
  case string_tag : 
  case clear_tag : 
  case current_env_tag :
  case top_tag : {
    break;
  }
  case apply_general_tag:
  case tail_call_tag:
  {
    maxsp(&ans,*pars);
    goto def1;
  }
  
  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>6)?incpars:6; ; i++) {
        if (!valregable(sh(p))) i=22;
        maxsp(&ans, suses(p, pars, i));
        if(last(p)) return ans;
        p = bro(p);
      }
    } else      maxsp (&ans, *pars);
  }                             /* else cont to default */
  FALL_THROUGH
  default: def1:{
    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 )
{
  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;
}




/* 
   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 
*/
bool placedump
    PROTO_N ( ( pe, dmpd, tobd, nds ) )
    PROTO_T ( exp *pe X space *dmpd X space *tobd X space *nds )
{
  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);
}



/* 
   delivers last exp in seq first after all tests (to second) ; 
   beforeb is space up to end of tests; second only use beforeb;
   otherwise nilexp 
*/
exp goodcond
    PROTO_N ( ( first, second, beforeb, pars ) )
    PROTO_T ( exp first X exp second X space *beforeb X space *pars )
{
  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 */
  }
  FALL_THROUGH
  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, 22);
      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 ... */           
  }
    FALL_THROUGH
  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)) {
    (void)placedump ( arg, &dmpd, tobd, tobd);
  }
  else {
    (void)pushdumps ( arg, &dmpd, tobd, pars);
  }
  return;
}