Subversion Repositories tendra.SVN

Rev

Rev 2 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific, prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 */
/*
                 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$     */

#ifndef lint
static char vcid[] = "$Id$";
#endif /* lint */

/*
$Log: scan.c,v $
 * Revision 1.1.1.1  1998/01/17  15:56:01  release
 * First version to be checked into rolling release.
 *
 * Revision 1.31  1997/09/05  12:23:20  john
 * bugfix
 *
 * Revision 1.29  1996/03/15  10:29:12  john
 * Fixed bug in apply_general_tag
 *
 * Revision 1.28  1996/02/29  17:36:36  john
 * Fix to shift op
 *
 * Revision 1.27  1996/02/19  09:25:23  john
 * Fixed postlude with call
 *
 * Revision 1.26  1996/02/15  09:57:48  john
 * Fixed bug in allocation of space for integer to floating point
 * conversion.
 *
 * Revision 1.25  1996/01/23  16:58:30  john
 * Fix to general procs
 *
 * Revision 1.24  1995/12/04  09:13:42  john
 * Removed code
 *
 * Revision 1.23  1995/11/14  15:37:21  john
 * Fixes to general procs
 *
 * Revision 1.22  1995/11/13  12:43:50  john
 * Added prof_tag case
 *
 * Revision 1.21  1995/09/29  15:53:17  john
 * Some changes for vcallers
 *
 * Revision 1.20  1995/09/20  10:46:58  john
 * Added trap_tag
 *
 * Revision 1.19  1995/09/13  16:33:49  john
 * Added special_tag
 *
 * Revision 1.18  1995/09/04  16:24:18  john
 * Fix to general procs
 *
 * Revision 1.17  1995/08/31  15:47:39  john
 * Added fmax_tag
 *
 * Revision 1.16  1995/08/30  16:15:12  john
 * Fix to diagnostics
 *
 * Revision 1.15  1995/08/23  16:06:26  john
 * Fix to compound_tag
 *
 * Revision 1.14  1995/08/04  15:50:44  john
 * Minor change
 *
 * Revision 1.13  1995/07/27  10:09:55  john
 * Changes to needs
 *
 * Revision 1.12  1995/07/04  09:08:09  john
 * Temporary change to ident_tag
 *
 * Revision 1.11  1995/06/30  08:00:12  john
 * Removed next_frame_tag made change to ident_tag
 *
 * Revision 1.10  1995/06/28  10:26:42  john
 * Fixed needs for cont_tag
 *
 * Revision 1.9  1995/06/21  14:25:39  john
 * Reformatting
 *
 * Revision 1.8  1995/06/15  09:43:57  john
 * Fixed code for stack error handling
 *
 * Revision 1.7  1995/06/13  14:01:45  john
 * A few cosmetic changes
 *
 * Revision 1.6  1995/05/23  13:26:09  john
 * Reformatting
 *
 * Revision 1.5  1995/05/16  10:55:24  john
 * Changes for spec 3.1
 *
 * Revision 1.4  1995/04/10  14:14:05  john
 * Fix to likeplus
 *
 * Revision 1.3  1995/04/07  11:05:49  john
 * Fix to scan_cond, and removed subvar_use
 *
 * Revision 1.2  1995/03/29  14:05:28  john
 * Changes to keep tcheck happy
 *
 * Revision 1.1.1.1  1995/03/23  10:39:17  john
 * Entered into CVS
 *
 * Revision 1.22  1995/03/23  10:13:55  john
 * Several changes for AVS test suite
 *
 * Revision 1.21  1995/02/13  09:50:32  john
 * Changed handling of cond_tag
 *
 * Revision 1.20  1995/01/26  13:49:17  john
 * Removed unused code
 *
 * Revision 1.19  1995/01/10  09:44:53  john
 * Modified register requirements.
 *
*/

/*
  scan.c
  Defines the scan through a program which reorganises it so
  that all arguments of operations are suitable for later
  code-production. The procedure scan evaluates the register
  requirements of an exp. The exps are produced from the decoding
  process and the various exp -> exp transformations in the proc
  independent (common to other  translators)
*/

#include "config.h"
#include "common_types.h"
#include "exptypes.h"
#include "exp.h"
#include "expmacs.h"
#include "tags.h"
#include "procrectypes.h"
#include "bitsmacs.h"
#include "maxminmacs.h"
#include "regable.h"
#include "tempdecs.h"
#include "shapemacs.h"
#include "special.h"
#include "const.h"
#include "new_tags.h"
#include "flpt.h"
#include "install_fns.h"
#include "externs.h"
#include "extratags.h"
#include "frames.h"
#include "regexps.h"
#include "reg_defs.h"
#include "bool.h"
#include "oddtest.h"
#include "check.h"
#include "coder.h"
#include "szs_als.h"
#include "scan.h"

int maxfix, maxfloat;           /* the maximum number of t-regs */
static int stparam, fixparam, floatparam;
       /* used by scan to set initial parameter positions */
static int numparams=0;

extern alignment long_to_al(int);

extern long notbranch[6];
extern bool do_tlrecursion;

static bool rscope_level = 0;
static bool nonevis = 1;
static int callerfortr;

needs scan(exp *,exp **);

/*
  identifies integer varieties which require more work to manipulate
  (because of a lack of appropriate instructions)
*/
#define is_awkward_variety(vname)((vname == scharhd || vname == ucharhd \
                                  || vname == swordhd || vname == uwordhd))



/*
   declaration of scan.
   needs is defined in procrectypes.h.
   This is a structure which has two integers giving
   the number of fixed and floating point registers required
   to contain live values in the expression parameters. A
   further field prop is used for various flags about certain
   forms of exp (mainly idents and procs). The maxargs field
   gives the maximum size in bits for the parameters of all the
   procs called in the exp. The needs of a proc body are preserved
   in the needs field of the procrec (see procrectypes.h).
*/


#if DO_NEW_DIVISION
#define is_machine_divide(e)(name(bro(son(e)))!= val_tag)
#else
#define is_machine_divide(e)1
#endif


/*
  cca

  This procedure effectively inserts a new declaration into an
  exp. This is used to stop a procedure requiring more than the
  available number of registers.
*/
void cca
(exp **to, exp *x)
{

  if (name((**to)) ==diagnose_tag) {
    *to = & (son((**to)));
  }
  if (x == (*to)) {
    exp def = *(x);
    /* replace by  Let tg = def In tg Ni */
    exp id = getexp(sh(def), bro(def), last(def), def, nilexp,
                     0, 1, ident_tag);
    exp tg = getexp(sh(def), id, 1, id, nilexp,
                     0, 0, name_tag);
    pt (id) = tg;               /* use of tag */
    bro (def) = tg;             /* bro(def) is body of Let = tg */
    clearlast(def);
    * (x) = id;         /* replace pointer to x by Let */
    return;
  }
  else {                /* replace by Let tg = def In ato/def = tg
                           Ni */
    exp def = *(x);
    exp ato = *(*to);
    exp id = getexp(sh(ato), bro(ato), last(ato), def, nilexp,
                     0, 1, ident_tag);
    exp tg = getexp(sh(def), bro(def), last(def), id, nilexp,
                     0, 0, name_tag);
    pt (id) = tg;               /* use of tg */
    bro (def) = ato;            /* ato is body of Let */
    clearlast(def);
    bro (ato) = id;             /* its father is Let */
    setlast(ato);
    * (*to) = id;               /* replace pointer to 'to' by Let */
    * (x) = tg;         /* replace use of x by tg */
    *to = & bro(def);           /* later replacement to same 'to' will be
                                   at body of Let */
    return;
  }
}

needs onefix = {
  1, 0, 0, 0
};                              /* needs one fix pt reg */
needs twofix = {
  2, 0, 0, 0
};                              /* needs 2 fix pt regs */

needs threefix = {
  3,0,0,0
};


needs fourfix = {
  4,0,0,0
};

needs fivefix = {
  5,0,0,0
};


needs onefloat = {
  0, 1, 0, 0
};                              /* needs 1 flt pt regs */
needs zeroneeds = {
  0, 0, 0, 0
};                              /* has no needs */



/*
  Calculate the number of registers required to move a data item of
  shape s to/from memory.  Worst case values.
*/
needs shapeneeds
(shape s)
{
  if (is_floating(name(s))) {
    return onefloat;
  }
  else{
    ash as;
    as = ashof(s);
    if((as.ashalign==8) /*&& (name(s)==ptrhd)*/){
      return fourfix;
    }
    if ((as.ashalign==16)) {
      return fivefix;           /* If not aligned on 4 byte boundary */
    }
    if (valregable(s)) {
      return onefix;
    }
    else{
      return twofix;
    }
  }
}

static void make_bitfield_offset
(exp e, exp pe, int spe, shape sha)
{
  exp omul;
  exp val8;
  if (name(e) == val_tag) {
    no(e)*= 8;
    return;
  }
  omul = getexp(sha,bro(e), (int)(last(e)),e,nilexp,0,0,offset_mult_tag);
  val8 = getexp(slongsh,omul,1,nilexp,nilexp,0,8,val_tag);
  clearlast(e);
  setbro(e, val8);
  if (spe) {
    son(pe) = omul;
  }
  else{
    bro(pe) = omul;
  }
  return;
}

bool complex
(exp e)
{
  /* these are basically the expressions
     which cannot be accessed by a simple
     load or store instruction */
  if (name(e) == name_tag ||
    (name(e) == cont_tag && name(son(e)) == name_tag &&
      isvar(son(son(e))))
     || name(e) == val_tag || name(e) == real_tag || name(e) ==null_tag) {
    return 0;
  }
  else {
    return 1;
  }
}

int scan_cond
(exp *e, exp outer_id)
{
  exp ste = *e;
  exp first = son(ste);
  exp labst = bro(first);
  exp second = bro(son(labst));

  Assert(name(ste) ==cond_tag);

  if (name(second) ==top_tag && name(sh(first)) ==bothd && no(son(labst)) ==1
      && name(first) ==seq_tag && name(bro(son(first))) == goto_tag) {
    /* cond is { ... test(L); ? ; goto X | L:make_top}
       if ? empty can replace by seq { ... not-test(X); make_top }
       */
    exp l = son(son(first));
    while (!last(l)) { l = bro(l); }
    while (name(l) ==seq_tag) { l = bro(son(l)); }
    if (name(l) ==test_tag && pt(l) ==labst) {
      settest_number(l, notbranch[test_number(l) -1]);
      pt(l) = pt(bro(son(first)));
      bro(son(first)) = second;
      bro(second) = first; setlast(second);
      bro(first) = bro(ste);
      if (last(ste)) { setlast(first);} else { clearlast(first); }
      *e = first;
      return 1;
    }
    else return 0;
  }


  if (name(first) == seq_tag && name(second) == cond_tag
      && no(son(labst)) == 1
      && name(son(son(first))) == test_tag
      && pt(son(son(first))) == labst
      && name(son(second)) == seq_tag
      && name(son(son(son(second)))) == test_tag) {
    /* cond is ( seq (test to L;....| L:cond(seq(test;...),...) )
       ..... */
    exp test1 = son(son(first));
    exp test2 = son(son(son(second)));
    exp op11 = son(test1);
    exp op21 = bro(op11);
    exp op12 = son(test2);
    exp op22 = bro(op12);
    bool c1 = complex(op11);
    bool c2 = complex(op21);

    if (c1 && eq_exp(op11, op12)) {
                                /* ....if first operands of tests are
                                   same, identify them */
      exp newid = getexp(sh(ste), bro(ste), last(ste), op11, nilexp,
                          0, 2, ident_tag);
      exp tg1 = getexp(sh(op11), op21, 0, newid, nilexp, 0, 0, name_tag);
      exp tg2 = getexp(sh(op12), op22, 0, newid, nilexp, 0, 0, name_tag);

      pt(newid) = tg1;
      pt (tg1) = tg2;   /* uses of newid */
      bro (op11) = ste; clearlast (op11);/* body of newid */
      /* forget son test2 = son test1 */
      bro(ste) = newid;
      setlast (ste);    /* father body = newid */
      son(test1) = tg1;
      son (test2) = tg2;        /* relace 1st operands of test */
      if (!complex(op21)) {
        /* if the second operand of 1st test is
           simple, then identification could go
           in a t-teg (!!!NB overloading of inlined flag!!!).... */
        setinlined(newid);
      }
      kill_exp(op12, op12);
      *(e) = newid;
      if (scan_cond(&bro(son(labst)), newid) == 2 && complex(op22)) {
        /* ... however a further use of identification means that
           the second operand of the second test must also be simple */
        clearinlined(newid);
      }
      return 1;
    }
    else if (c2 && eq_exp(op21, op22)) {
                                /* ....if second operands of tests are
                                   same, identify them */

      exp newid = getexp(sh(ste), bro(ste), last(ste), op21,
                          nilexp, 0, 2, ident_tag);
      exp tg1 = getexp(sh(op21), test1, 1,
                        newid, nilexp, 0, 0, name_tag);
      exp tg2 = getexp(sh(op22), test2, 1, newid, nilexp,
                        0, 0, name_tag);

      pt(newid) = tg1;
      pt (tg1) = tg2;   /* uses of newid */
      bro(op21) = ste; clearlast(op21);
      /* body of newid */
      /* forget bro son test2 = bro son test1 */
      bro(ste) = newid;
      setlast (ste);    /* father body = newid */
      bro(op11) = tg1;
      bro(op12) = tg2;
      if (!complex(op11)) { setinlined(newid); }
      kill_exp(op22, op22);
      /* relace 2nd operands of test */
      *(e) = newid;
      if (scan_cond(&bro(son(labst)), newid) == 2 && complex(op12)) {
        clearinlined(newid);
      }
      return 1;
    }
    else if (name(op12)!= name_tag
             && name(op11) == name_tag
             && son(op11) == outer_id
             && eq_exp(son(outer_id), op12)
            ) {
      /* 1st param of test1 is already identified with
         1st param of  test2 */
      exp tg = getexp(sh(op12), op22, 0, outer_id,
                       pt(outer_id), 0, 0, name_tag);
      pt(outer_id) = tg;
      no(outer_id) += 1;
      if (complex(op21)) { clearinlined(outer_id); }
      /* update usage of ident */
      son(test2) = tg;
      kill_exp(op12, op12);
      if (scan_cond(&bro(son(labst)), outer_id) == 2 && complex(op22)) {
        clearinlined(outer_id);
      }
      return 2;
    }
  }
  return 0;
}

/*
   does the scan on commutative and associative operations and
   may perform various transformations allowed by these properties
*/
needs likeplus
(exp *e, exp **at)
{
  needs a1;
  needs a2;
  prop pc;
  exp * br  = &son(*e);
  exp dad = *(e);
  exp prev;
  bool commuted = 0;

#if 0
  if (optop(*e)) {
    Assert(name(*br)!= val_tag);
  }
#endif
  a1 = scan(br, at);
  /* scan the first operand - won't be a val_tag */
  do {
    exp * prevbr;
    prevbr = br;
    prev = *(br);
    br = &bro(prev);
    a2 = scan(br, at);
    /* scan the next operand ... */
    if (name(*(br))!= val_tag) {
      a1.floatneeds = max(a1.floatneeds, a2.floatneeds);
      pc = a2.propsneeds & hasproccall;
      if (a2.fixneeds < maxfix && pc == 0) {
        /* ..its evaluation  will not disturb the accumulated result */
        a1.fixneeds = max(a1.fixneeds, a2.fixneeds + 1);
        a1.propsneeds = a1.propsneeds | a2.propsneeds;
      }
      else if (a1.fixneeds < maxfix &&
              (a1.propsneeds & hasproccall) == 0 && !commuted) {
        /* ..its evaluation will call a proc, so put it first */
        exp op1 = son(dad);
        exp cop = *(br);
        bool lcop = last(cop);
        bro(prev) = bro(cop);
        if (lcop)
          setlast(prev);
        bro(cop) = op1;
        clearlast(cop);
        son(dad) = cop;
        br = (prev==op1)? &bro(cop):prevbr;
        commuted = 1;
        a1.fixneeds = max(a2.fixneeds, a1.fixneeds + 1);
        a1.propsneeds |= a2.propsneeds;
        a1.maxargs = max(a1.maxargs, a2.maxargs);
      }
      else {    /* ... its evaluation would disturb
                   accumulated result, so replace it by a
                   newly declared tag */
        cca(at, br);
        a1.fixneeds = max(a1.fixneeds, 2);
        a1.propsneeds = a1.propsneeds | morefix | (pc << 1);
        a1.maxargs = max(a1.maxargs, a2.maxargs);
      }
    }
  } while (!last(*(br)));
  return a1;
}


needs likediv
(exp *e, exp **at)
{
  /* scan non-commutative fix pt operation
   */
  needs l;
  needs r;
  prop pc;
  exp * arg = &son(*e);
  l = scan(arg, at);
  /* scan 1st operand */
  arg = &bro(*arg);
  r = scan(arg, at);
  /* scan second operand ... */
  l.floatneeds = max(l.floatneeds, r.floatneeds);
  pc = r.propsneeds & hasproccall;
  if (r.fixneeds < maxfix && pc == 0) {/* ...it fits into registers */
    l.fixneeds = max(l.fixneeds, r.fixneeds + 1);
    l.propsneeds = l.propsneeds | r.propsneeds;
  }
  else {                        /* ...it requires new declaration of
                                   second operand */
    cca(at, arg);
    l.fixneeds = max(l.fixneeds, 1);
    l.propsneeds = l.propsneeds | morefix | (pc << 1);
    l.maxargs = max(l.maxargs, r.maxargs);
  }
  return l;
}

needs fpop
(exp *e, exp **at)
{
  /* scans diadic floating point operation  */
  needs l;
  needs r;
  exp op = *(e);
  prop pcr, pcl;
  exp * arg = &son(op);
  bool withert = !(optop(*e));

  l = scan(arg, at);
  arg = &bro(*arg);
  r = scan(arg, at);
  l.fixneeds = max(l.fixneeds, r.fixneeds);
  pcr = r.propsneeds & hasproccall;
  pcl = l.propsneeds & hasproccall;

  if (r.floatneeds <= l.floatneeds && r.floatneeds < maxfloat && pcr==0) {
    l.floatneeds = max(2, max(l.floatneeds, r.floatneeds + 1));
    l.propsneeds = l.propsneeds | r.propsneeds;
    ClearRev(op);
  }
  else if (pcl == 0 && l.floatneeds<=r.floatneeds && l.floatneeds<maxfloat) {
    l.floatneeds = max(2, max(r.floatneeds, l.floatneeds + 1));
    l.propsneeds = l.propsneeds | r.propsneeds;
    SetRev(op);
  }
  else if (r.floatneeds < maxfloat && pcr == 0) {
    l.floatneeds = max(2, max(l.floatneeds, r.floatneeds + 1));
    l.propsneeds = l.propsneeds | r.propsneeds;
    ClearRev(op);
  }
  else {
    cca(at, arg);
    ClearRev(op);
    l.floatneeds = max(l.floatneeds, 2);
    l.propsneeds = l.propsneeds | morefloat | (pcr << 1);
    l.maxargs = max(l.maxargs, r.maxargs);
  }
  if (withert && l.fixneeds < 2)l.fixneeds = 2;
  return l;
}

/*
  maxneeds
  Calculates a needs value. Each element of which is the
  maximum of the corresponding elements in the two parameter needs
*/
needs maxneeds
(needs a, needs b)
{
  needs an;
  an.fixneeds = max(a.fixneeds, b.fixneeds);
  an.floatneeds = max(a.floatneeds, b.floatneeds);
  an.maxargs = max(a.maxargs, b.maxargs);
  an.numparams=max(a.numparams,b.numparams);
  an.propsneeds = a.propsneeds | b.propsneeds;
  return an;
}

/*
   calculates the needs of a tuple of expressions; any new
   declarations required by a component expression will
   replace the component expression
*/
needs maxtup
(exp e, exp **at)
{
  exp * stat = &son(e);
  needs an;

  an = zeroneeds;
  if (son(e) == nilexp) return zeroneeds;
  while (an = maxneeds(an, scan(stat, at)), !last(*stat)) {
    stat = &bro(*stat);
  }
  return an;
}

/*
   finds if usedname is only used in cont operation or as result
   of ident i.e. value of name is unchanged over its scope
*/
bool unchanged
(exp usedname, exp ident)
{
  exp uses = pt(usedname);
  while (uses != nilexp) {
    if (intnl_to(ident, uses)) {
      if (!last(uses) || name(bro(uses))!= cont_tag) {
        exp z = uses;
        while (z != ident) {
          if (!last(z) ||
             (name(bro(z))!= seq_tag && name(bro(z))!= ident_tag)) {
            return 0;
          }
          z = bro(z);
        }
      }
    }
    uses = pt(uses);
  }
  return 1;
}


/* check if e  is (let a = 0 in cond(inttest(L)=result; a=1 | L:top);
   a ni ) This will be compiled later using set instructions instead
   of branches
*/
exp absbool
(exp id)
{
  if (isvar(id) && name(son(id)) == val_tag && no(son(id)) == 0
      && no (id) == 2 /* name initially 0 only used twice */ ) {
    exp bdy = bro(son(id));
    if (name(bdy) == seq_tag && name(bro(son(bdy))) == cont_tag &&
        name(son(bro(son(bdy)))) == name_tag &&
        son(son(bro(son(bdy)))) == id
        /* one use is result  of sequence body */ ) {
      exp c = son(son(bdy));
      if (last (c) && name (c) == cond_tag /* seq is cond=c; id */ ) {
        exp first = son(c);
        exp second = bro(son(c));
        if (no (son (second)) == 1 /* only one jump to else */ &&
            name(bro(son(second))) == top_tag
            && name (first) == seq_tag /* cond is (seq= first | L: top) */ ) {
          exp s = son(son(first));
          exp r = bro(son(first));
          if (name(r) == ass_tag && name(son(r)) == name_tag &&
              son(son(r)) == id && name(bro(son(r))) == val_tag &&
              no (bro (son (r))) == 1 /* last of seq is id = 1 */ &&
              last(s) && name(s) == test_tag && pt(s) == second
              && !is_floating(name(sh(son(s))))
              /* *t of seq is int test jumping to
                 second */
             ) {
            return s;
          }
        }
      }
    }
  }
  return 0;
}


exp * ptr_position
(exp e)
{
  exp * a;
  exp dad = father(e);
  if (son(dad) ==e) {
    a = &son(dad);
  }
  else {
    exp sib = son(dad);
    while (bro(sib)!=e) { sib = bro(sib); }
    a = &bro(sib);
  }
  return a;
}

bool chase
(exp sel, exp *e)
{
  /* distribute selection throughout compound expressions */
  bool b = 0;
  exp * one;
  switch (name(*e)) {
    case ident_tag:
    case seq_tag:
    case rep_tag:
    case labst_tag: {
      b = chase(sel, &bro(son(*e)));
      break;
    }
    case solve_tag:
    case cond_tag: {
      one = &son(*e);
      for (;;) {
        b |= chase(sel, one);
        if (last(*one))break;
        one = &bro(*one);
      }
      break;
    }
    case field_tag: {
      if (chase(*e, &son(*e))) {
        /* inner field has been distributed */
        exp stare = *e;
        exp ss = son(stare);
        if (!last(stare))clearlast(ss);
        bro(ss) = bro(stare);
        sh(ss) = sh(stare);
        *e = ss;
        return chase(sel, e);
      } /* ... continue to default */
    }
      FALL_THROUGH;
    default: {
      if ((son(sel)!= *e) && (name(sh(*e))!=bothd)) {
        /* only change if not outer */
        exp stare = *e;
        exp newsel = getexp(sh(sel), bro(stare), last(stare), stare,
                             nilexp,props(sel), no(sel), name(sel));
        *e =  newsel;
        bro(stare) =newsel;setlast(stare);
        b = 1;
      }
    }
  }
  if (b)sh(*e) = sh(sel);
  return b;
}


/* check for C style varargs */
bool vascan
(exp *e)
{
  bool result = FALSE;
  exp tr;
  int s2;
  for (tr=son(*e);(name(tr) ==ident_tag) && (isparam(tr)) && (!result);
                  tr = bro(son(tr))) {
    s2 = shape_size(sh(son(tr)));
    result = (name(sh(son(tr))) ==cpdhd) &&last_param(tr) && (s2==0);
  }
  return result;
}


bool gen_call;
bool in_vcallers_proc;


/*
  scan

  This procedure works out register requirements of an exp. At each
  call the fix field of the needs is the number of fixpnt registers
  required to contain live values to evaluate this expression.
  This never exceeds maxfix because if it would have, a new
  declaration is introduced in the exp tree (similarly for
  floating regs and maxfloat). In these cases the prop field will
  contain the bits morefix (or morefloat).

  As well as working out the register requirements scan performs
  some transformations on the procedure.  It also determines whether
  or not the procedure uses varargs, if it contains a division by a
  non-constant, and if it may need to move values between float and
  fixed point registers.

  If the procedure does contain a division by a non constant then
  those registers which are corrupted by the division instruction
  are not made available to the register allocator for the duration
  of that procedure (see settempregs()).  A better, though more
  complicated, solution would be to disallow the use of these
  registers in evaluating the LHS of operations in which the RHS
  contains a division.
*/
needs scan
(exp *e, exp **at)
{
  /*  e is the expression to be scanned, at
      is the place to put any new decs . NB order of recursive
      calls with same at is critical */
  static int has_old_varargs;
  static int has_div;
  static int has_float;
  exp   ste = *(e);
  int   nstare = name(ste);

  switch (nstare) {
    case 0: {
      return zeroneeds;
    }

    case compound_tag:
    case nof_tag:
    case concatnof_tag:
    case ncopies_tag:{
      needs nl;
      bool cantdo;
      exp dad;
      if (name(ste) ==ncopies_tag && name(son(ste))!=name_tag
          && name(son(ste))!= val_tag) {
        nl = scan(&son(*e), at);
        cca(at, &son(*e));
      }
      else nl = maxtup(*(e), at);
      dad = father(ste);
      if (name(dad) ==compound_tag || name(dad) == nof_tag
          || name(dad) == concatnof_tag) {
        cantdo=0;
      }
      else if (last(ste)) {
        if (name(bro(ste)) == ass_tag) {
          exp a = son(bro(ste));
          cantdo = (name(a)!= name_tag || !isvar(son(a)));
        }
        else cantdo = 1;
      }
      else if (last(bro(ste))) { cantdo = (name(bro(bro(ste)))!= ident_tag);}
      else cantdo = 1;

      if (cantdo) {
        /*can only deal with tuples in simple assignment or identity*/
        int prps = (nl.propsneeds & hasproccall) << 1;
        cca(at, ptr_position(ste));
        nl = shapeneeds(sh(*(e)));
        nl.propsneeds |= morefix;
        nl.propsneeds |= prps;
      }

      if (nl.fixneeds <2)nl.fixneeds = 2;
      return nl;
    }

    case cond_tag: {
      exp t, f, v;
      if (oddtest(ste, & t, &f, &v)) {
        /* transform to f((absbool(t) <<1)-1)  */
        exp bc = bro(ste);
        bool lc = last(ste);
        exp ab = getexp(sh(v),nilexp,0,t, nilexp, 0, 0, absbool_tag);
        exp shl = getexp(sh(v), nilexp, 0, ab, nilexp, 0, 0, shl_tag);
        exp v1 = getexp(sh(v), shl, 1, nilexp,nilexp, 0, 1, val_tag);
        exp p = getexp(sh(v), nilexp, 1, shl, nilexp, 0, 0, plus_tag);
        exp vm1 = getexp(sh(v), p, 1, nilexp,nilexp, 0, -1, val_tag);
        bro(ab) = v1;
        bro(shl) = vm1;
        bro(t) = ab; setlast(t);
        if (no(v) ==-1) {settest_number(t, notbranch[test_number(t) -1]);}
        if (f==v) {
          *e = p;
        }
        else {
          son(bro(v)) = p;
          bro(p) = bro(v);
          *e = f;
        }
        bro(*e) = bc; if (lc) { setlast(*e); } else {clearlast(*e); }
        return scan(e, at);
      }
/*
        if (is_maxlike(ste, &t) ) {
        son(ste) = t;
        bro(t) = ste; setlast(t);
        setname(ste, maxlike_tag);
        return scan(&son(ste), at);
        }
        if (is_minlike(ste, &t) ) {
        son(ste) = t;
        bro(t) = ste; setlast(t);
        setname(ste, minlike_tag);
        return scan(&son(ste), at);
        }
        */
      if (is_abslike(ste, &t)) {
        son(ste) = t;
        bro(t) = ste; setlast(t);
        setname(ste, abslike_tag);
        return scan(&son(ste), at);
      }
      if (is_fabs(ste, &t)) {
        son(ste) = son(t);
        bro(son(t)) = ste; setlast(son(t));
        setname(ste, fabs_tag);
        return scan(&son(ste), at);
      }

      if (scan_cond(e, nilexp)!=0) {
        return scan(e, at);
      }                 /* else goto next case */
    }
    FALL_THROUGH;
    case labst_tag:
    case rep_tag:
    case solve_tag: {
      exp * stat;
      exp * statat;
      needs an;
      stat = &son(*e);
      statat = stat;
      an = zeroneeds;
      while (an = maxneeds(an, scan(stat, &statat)),

             !last(*(stat))) {
        stat = &bro(*stat);
        statat = stat;
      }
      if ((an.propsneeds & usesproccall)!= 0) {
        an.propsneeds |= hasproccall;
      }
      return an;
    }

      /*
        ident

        shape of exp is body,
        son is def, brother of son is body,
        ptr of ident exp is chain of uses
        */
    case ident_tag:   {
      needs bdy;
      needs def;
      exp stare = *(e);
      exp * arg = &bro(son(stare));  /* ptr to body */
      exp t = pt(stare);
      exp s;
      bool fxregble;
      bool flregble;
      bool old_nonevis = nonevis;
      exp ab;
      /*          bdy.numparams=0;*/
#if 1
      if (!iscaonly(stare))setvis(stare);
      if (name(son(stare)) == formal_callee_tag) {
        setvis(stare);
      }
#endif

      if (isparam(stare) && name(son(stare))!= formal_callee_tag) {
        exp def = son(stare);
        shape shdef = sh(def);
        long n = rounder(stparam, shape_align(shdef));
        long sizep = shape_size(shdef);
        numparams = min(numparams+rounder(sizep,REG_SIZE),6*REG_SIZE);
        /*numparams=min(numparams+max(REG_SIZE,sizep),6*REG_SIZE);*/
        /*Assert(name(def)==clear_tag); */
        if (is_floating(name(shdef))) {
          if (sizep<=64 && stparam <= 320) {
            props(def) = floatparam;
            maxfloat--;
          }
        }
        else if (sizep<=64  && stparam<=320  ) { /*change for 64 bit regs*/
            props(def) = fixparam;
            maxfix--;
          }
          else if (stparam<=320) {
            props(def) = fixparam;
          }
          else props(def) =0;
        stparam = rounder(n+sizep, 64 );        /* calculate the offset */
        fixparam = 16+(stparam>>6);     /* >> 6, was >>5 */
        floatparam=16+ (stparam>>6);
        if (((isvis(stare) && props(son(stare))!=0 && (name(sh(son(stare))) ==cpdhd)) || in_vcallers_proc) && last_param(stare)) {
          numparams=12*REG_SIZE;        /* must allow space for all
                                           parameter registers for
                                           varargs function */
        }
        no(def) =n;
        /* if varargs then save all param regs to stack */

        if (!is_floating(name(shdef)) && !valregable(shdef))
          setvis(stare);
        /* now props(def) = pos parreg and no(def) = par stack address
         */
      }
      else if (isparam(stare) && name(son(stare)) == formal_callee_tag) {
        exp def = son(stare);
        shape shdef = sh(def);
        long sizep = shape_size(shdef);
        long alp = shape_align(shdef);
        long n = rounder(callee_size, alp);
        no(def) = n;
        callee_size = rounder(n+sizep, REG_SIZE);
      }
      if (gen_call) {
        numparams = max(6*REG_SIZE,numparams);
      }

      nonevis &= !isvis(stare);
      bdy = scan(arg, &arg);
      /* scan the body-scope */
      arg = &son(stare);
      def = scan(arg, &arg);
      bdy.numparams = numparams;
      /* scan the initialisation of tag */

      nonevis = old_nonevis;
      t = son(stare);
      s = bro(t);
      fxregble = fixregable(stare);
      flregble = floatregable(stare);

      if (isparam(stare)) {
        if (name(son(stare))!=formal_callee_tag && !isvis(stare) &&
            !isoutpar(stare) && (bdy.propsneeds & anyproccall) ==0  ) {
          /* leave pars in par regs or put in t-regs
             !! WHAT ABOUT TEMP DECS !!
             */
          int x = props(son(stare));
          if (x != 0) {
            no(stare) = x;
            if (flregble) {
              props(stare) |= infreg_bits;
            }
            else { props(stare) |= inreg_bits; }
          }
          else if (fxregble && bdy.fixneeds < maxfix &&
                  (bdy.propsneeds & morefix) == 0) {
            no(stare) = NO_REG;
            props(stare) |= inreg_bits;
            bdy.fixneeds+=1;
          }
          else if (flregble &&
                   bdy.floatneeds < maxfloat &&
                  (bdy.propsneeds & morefloat) == 0) {
            no(stare) = NO_REG;
            props(stare) |= infreg_bits;
            bdy.floatneeds +=1;
          }
          else no(stare) = 100;
        }
        else no(stare) = 100;

      }
      else {
        if ((ab = absbool(stare))!= nilexp) {
          /* form is (let a = 0 in cond(test(L)=ab;
             a=1 | L:top) ni replace declaration by
             ABS */
          bro(ab) = stare;
          setlast (ab);       /* father => *e */
          son(stare) = ab;
          pt(stare) = nilexp;
          pt(ab) = nilexp;
          setname(stare, absbool_tag);
          return maxneeds(bdy, def);
        }

        if (!isvis(*e) && !isparam(*e) &&
           (bdy.propsneeds & (anyproccall | uses2_bit)) == 0
            && (fxregble || flregble) &&
           (name(t) == apply_tag || name(t) == apply_general_tag ||
            (name(s) == seq_tag && name(bro(son(s))) == res_tag &&
              name(son(bro(son(s)))) == cont_tag && isvar(stare) &&
              name(son(son(bro(son(s))))) == name_tag &&
              son(son(son(bro(son(s))))) == stare
              )               /* Let a := ..; return cont a */
            )
            ) {         /* put tag in result reg if definition is
                           call of proc, or body ends with return
                           tag, provided result is not used other
                           wise */
          props(stare) |= (fxregble)? inreg_bits : infreg_bits;
          bdy.propsneeds |= uses2_bit;
          no (stare) = 101;   /* identification  uses result reg in body
                               */
        }
        else if (!isvar(*e) && !isparam(*e) &&
                ((name(t) == reff_tag && name(son(t)) == cont_tag &&
                   name(son(son(t))) == name_tag && isvar(son(son(son(t))))
                   && !isvis(son(son(son(t)))) &&
                   !isglob(son(son(son(t))))
                   && unchanged(son(son(son(t))), stare)
                   /* reff cont variable-not assigned to in
                      scope */
                  ) ||
                 (name(t) == cont_tag && name(son(t)) == name_tag &&
                   isvar(son(son(t))) && !isvis(son(son(t))) &&
                   !isglob(son(son(t))) && unchanged(son(son(t)), stare)
                   /* cont variable - not assigned to in
                      scope */
                  )
                 )
                ) {
          props(stare) |= defer_bit;
          /* dont take space for this dec */
        }
        else if (!isvar(stare) && !isvis(stare) &&
                 ((props (stare) & 0x10 /* forced in const */ ) == 0)
                 && (name(t) == name_tag || name(t) == val_tag)) {
          props(stare) |= defer_bit;
          /* dont take space for this dec */
        }
        else if (fxregble && (/*isinlined(stare)||*/
                             (bdy.fixneeds < maxfix &&
                              (bdy.propsneeds & morefix) == 0 &&
                              ((bdy.propsneeds & anyproccall) == 0 ||
                                tempdec(stare,((bdy.propsneeds&morefix) ==0 &&
                                              bdy.fixneeds < maxfix-2)))))) {
          /* put this tag in some  fixpt t-reg -
             which will be decided  in make_code */
          props(stare) |= inreg_bits;
          no (stare) = NO_REG;  /* aha! */
          bdy.fixneeds += 1;
        }
        else if (bdy.floatneeds < maxfloat &&
                (bdy.propsneeds & morefloat) == 0 && flregble &&
                ((bdy.propsneeds & anyproccall) == 0
                  || tempdec(stare,((bdy.propsneeds & morefloat) == 0 &&
                                      bdy.floatneeds < maxfloat-2/*6*/)))) {
          /* put this tag in some  float t-reg -
             which will be decided  in make_code */
          props(stare) |= infreg_bits;
          no(stare) = NO_REG;
          bdy.floatneeds += 1;
        }
        else {
#if 1
          if (fxregble && ((bdy.propsneeds & anyproccall) == 0) &&
             (bdy.fixneeds < maxfix)) {
            SetPossParReg(stare);       /* +1 to fixneeds ? */
            bdy.fixneeds += 1;
          }
#endif
          no(stare) = 100;
          /* allocate either on stack or saved reg */
        }
      }
      bdy = maxneeds(bdy, def);
      if ((bdy.propsneeds & usesproccall)!= 0) {
        bdy.propsneeds |= hasproccall;
      }
      return bdy;
    }

      /*
        sequence

        shape of exp is shape of end of sequence, son is sequence
        holder, son of this is list of voided statements.
        */

    case seq_tag: {
      exp * arg = &bro(son(*e));
      needs an;
      exp * stat;

      an = scan(arg, &arg);
      stat = &son(son(*e));

      arg = stat;
      for (;;) {
        needs stneeds;
        stneeds = scan(stat, &arg);
        /* initial statements voided */
        an = maxneeds(an, stneeds);
        if (last(*(stat))) {
          if ((an.propsneeds & usesproccall)!= 0) {
            an.propsneeds |= hasproccall;
          }
          return an;
        }
        stat = &bro(*stat);
        arg = stat;
      }

    }

    /*
      goto

      shape is bottom
      son is exp for value jumped with
      ptr is labelled exp
      */
    case goto_tag: {
      return zeroneeds;
    }

    case ass_tag:
    case assvol_tag: {
      exp * lhs = &son(*e);
      exp * rhs = &bro(*lhs);
      needs nr;
      ash a;

      nr = scan(rhs, at);
      /* scan source */

      a = ashof(sh(*(rhs)));
      if (nstare != ass_tag || a.ashsize != a.ashalign || a.ashalign == 1) {
        /* complicated move */
        nr.propsneeds |= uses2_bit;
      }
      if (name(*(lhs)) == name_tag &&
         (isvar(son(*(lhs))) ||
          ((nr.propsneeds & (hasproccall | morefix)) == 0
            && nr.fixneeds < maxfix
           )
          )
          ) {                   /* simple destination */
        return nr;
      }
      else {
        needs nl;
        prop prps = (nr.propsneeds & hasproccall) << 1;
        nl = scan(lhs, at);
        /* scan destination */
        nr.fixneeds += 1;
        if (name(*(rhs)) == apply_tag && name(*(rhs)) ==apply_general_tag &&
            nstare == ass_tag && (nl.propsneeds &
                                 (uses2_bit | anyproccall)) == 0) {
          /* source is proc call, so assign result
             reg directly */
         ;
        }
        else if (nr.fixneeds >= maxfix || prps != 0) {
          /* source and destination regs overlap, so identify source */
          cca(at, rhs);
          nl = shapeneeds(sh(*(rhs)));
          nl.propsneeds |= morefix;
          nl.propsneeds &= ~(prps >> 1);
          nl.propsneeds |= prps;
        }
        return maxneeds(nl, nr);
      }
    }
    case untidy_return_tag:
    case res_tag: {
      ash a;
      needs x;
      shape s;
      exp * arg = &son(*e);
      exp r, ss, t;
      s = sh(*(arg));
      a = ashof(s);
      props(*e) = 0; /* clear possibility of tlrecirsion; may be set later */
      x = scan(arg, at);
      /* scan result exp ... */
      if (is_floating (name (s))) {/* ... floating pt result */
        x.propsneeds |= realresult_bit;
        if (name(s)!= shrealhd) {
          x.propsneeds |= longrealresult_bit;
        }
      }
      else {
        if (!valregable (s)) {/* .... result does not fit into reg */
          x.propsneeds |= long_result_bit;
        }
      }
      if (a.ashsize != 0) {     /* ...not a void result */
        x.propsneeds |= has_result_bit;
      }

      if ((name(*e) == res_tag) &&
         (x.propsneeds & (long_result_bit | anyproccall | uses2_bit)) == 0) {
        r = son(*(e));
        if (name(r) == ident_tag && isvar(r) &&
            name(ss = bro(son(r))) == seq_tag &&
            name(t = bro(son(ss))) == cont_tag &&
            name(son(t)) == name_tag && son(son(t)) == r) {
          /* result is tag allocated into result reg
             - see ident_tag: */
          if ((props(r) & inreg_bits)!= 0) {
            x.fixneeds--;
          }
          else if ((props(r) & infreg_bits)!= 0) {
            x.floatneeds--;
          }
          else {
            props(r) |= (is_floating(name(s)))? infreg_bits : inreg_bits;
          }
          x.propsneeds |= uses2_bit;
          no (r) = 101; /* identification  uses result reg in body
                         */
        }
      }
      return x;
    }
    case apply_general_tag: {
      exp application = *(e);
      exp *fn = &son(application);
      exp callers = bro(*fn);
      exp *cerl = &son(callers);
      int stpar = 0;
      needs nds,pstldnds;
      int i;
      gen_call = 1;
      nds = scan(fn,at);
      if(nds.propsneeds & hasproccall){ /* Identify it */
        cca(at,fn);
        nds.propsneeds &= ~hasproccall;
        nds.propsneeds |= usesproccall;
        fn = &son(application);
      }
      for (i=0;i<no(callers);++i) {
        needs onepar;
        shape shonepar = sh(*cerl);
        exp * par = (name(*cerl) ==caller_tag)?&son(*cerl):cerl;
        int n = rounder(stpar,shape_align(shonepar));
        onepar = scan(par,at);
        if (((i != 0) && (onepar.propsneeds & hasproccall)) ||
          (onepar.fixneeds+ (stpar>>6) > maxfix)) {
          /* not the first parameter, and calls a proc */
          cca(at,par);
          nds.propsneeds |= usesproccall;
          nds = maxneeds(shapeneeds(sh(*(par))),nds);
          nds.maxargs = max(nds.maxargs,onepar.maxargs);
        }
        else{
          nds = maxneeds(onepar,nds);
        }
        if (name(*cerl) == caller_tag) {
          no(*cerl) = n;
        }
        n += shape_size(shonepar);
        stpar = rounder(n,REG_SIZE);
        cerl = &bro(*cerl);
      }
      nds.maxargs = max(nds.maxargs,stpar);
      nds = maxneeds(scan(&bro(bro(son(application))),at),nds);
      pstldnds = scan(&bro(bro(bro(son(application)))),at);
      if (pstldnds.propsneeds & (anyproccall | uses2_bit)) {
        props(*e) = 1;
        if (valregable(sh(application)) || floatregable(sh(application))) {
          cca(at,ptr_position(application));
          pstldnds.propsneeds |= usesproccall;
        }
      }
      else{
        props(*e) = 0;
      }
      nds = maxneeds(nds,pstldnds);
      nds.propsneeds |= hasproccall;
      return nds;
    }
    case make_callee_list_tag: {
      exp cllees = *e;
      exp *par = &son(cllees);
      needs nds;
      int stpar = 0,i;
      nds = zeroneeds;
      for (i=0;i<no(cllees);++i) {
        needs onepar;
        shape shonepar = sh(*par);
        int n = rounder(stpar,shape_align(shonepar));
        onepar = scan(par,at);
        if ((onepar.propsneeds & hasproccall) || (onepar.fixneeds+1>maxfix)) {
          /* identify it */
          cca(at,par);
          nds.propsneeds |= usesproccall;
          nds = maxneeds(shapeneeds(sh(*par)),nds);
          nds.maxargs = max(nds.maxargs,onepar.maxargs);
        }
        else{
          nds = maxneeds(onepar,nds);
        }
        n += shape_size(shonepar);
        stpar = rounder(n,REG_SIZE);
        par = &bro(*par);
      }
      no(cllees) = stpar;
      return nds;
    }

    case make_dynamic_callee_tag: {
      exp callees = *e;
      exp *ptr = &son(callees);
      needs ndsp,nds;
      nds = zeroneeds;
      ndsp = scan(ptr,at);
      if ((ndsp.propsneeds & hasproccall) || (ndsp.fixneeds+1 > maxfix)) {
        cca(at,ptr);
        nds.propsneeds |= usesproccall;
        nds = maxneeds(shapeneeds(sh(*ptr)),nds);
        nds.maxargs = max(nds.maxargs,ndsp.maxargs);
      }
      else{
        nds = ndsp;
      }
      ndsp = scan(&bro(son(*e)),at);
      if ((ndsp.propsneeds & hasproccall) || (ndsp.fixneeds+2 > maxfix)) {
        cca(at,&bro(son(callees)));
        nds.propsneeds |= usesproccall;
        nds = maxneeds(shapeneeds(sh(bro(son(*e)))),nds);
        nds.maxargs = max(nds.maxargs,ndsp.maxargs);
      }
      else{
        nds = maxneeds(ndsp,nds);
      }
      if(nds.fixneeds<5) nds.fixneeds = 5;      /* ?? */
      return nds;
    }

    case same_callees_tag: {
      needs nds;
      nds = zeroneeds;
      nds.fixneeds = 4;         /* ?? */
      return nds;
    }

    case tail_call_tag: {
      needs ndsp,nds;
      exp *fn = &son(*e);
      ndsp = scan(fn,at);
      if ((ndsp.propsneeds & hasproccall) || (ndsp.fixneeds+1 > maxfix)) {
        cca(at,fn);
        nds.propsneeds |= usesproccall;
        nds = maxneeds(shapeneeds(sh(*fn)),nds);
        nds.maxargs = max(nds.maxargs,ndsp.maxargs);
      }
      else{
        nds = ndsp;
      }
      gen_call = 1;
      ndsp = scan(&bro(son(*e)),at);
      nds = maxneeds(nds,ndsp);
      return nds;
    }

    case apply_tag: {
      exp application = *(e);
      exp fn = son(application);
      exp * par = &bro(fn);
      exp * fnexp = &son(*e);
      int   parsize =0;
      needs nds;
      bool tlrecpos = nonevis && callerfortr && (rscope_level == 0);
      int   i;

      nds = scan(fnexp, at);
      /* scan the function exp ... */
      if ((nds.propsneeds & hasproccall)!= 0) {
        /* .... it must be identified */
        cca(at, fnexp);
        nds.propsneeds &= ~hasproccall;
        nds.propsneeds |= usesproccall;
        fn = son(application);
        par = &bro(fn);
      }

      if (name(fn)!= name_tag ||
         (son(son(fn))!= nilexp && name(son(son(fn)))!= proc_tag)) {
        tlrecpos = 0;
      }

      for (i = 1;!last(fn); ++i) {      /* scan parameters in turn ... */
        needs onepar;
        shape shpar = sh(*par);
        onepar = scan(par, at);

        if ((i != 1 && (onepar.propsneeds & hasproccall)!= 0) ||
            onepar.fixneeds+ (parsize>>6) > maxfix) {
          /* if it isn't the first parameter, and it
             calls a proc, identify it */
          cca(at, par);
          nds.propsneeds |= usesproccall;
          nds = maxneeds(shapeneeds(sh(*(par))), nds);
          nds.maxargs = max(nds.maxargs, onepar.maxargs);
        }
        else {
          nds = maxneeds(onepar, nds);
        }
        parsize = rounder(parsize, shape_align(shpar));
        parsize = rounder(parsize+shape_size(shpar), REG_SIZE);
        /* ? */
        if ((!valregable(shpar) && !is_floating(name(shpar))) || parsize > 384) {
          tlrecpos = 0;
        }
        if (last(*(par))) {
          break;
        }
        par = &bro(*par);
      }
#if DO_SPECIAL
      if ((i = specialfn (fn)) > 0) {/* eg strlen */
        nds = maxneeds(specialneeds(i), nds);
        return nds;
      }
      else
        if (i == -1) {  /* call of strcpy .... */
          exp par2 = *(par);
          /* TEST for constant string?????????????????
             if (name (par2) == eval_tag && name (son (par2)) == pack_tag
             && name (son (son (par2))) == string_tag) {
             setname (* (e), ass_tag);
             son (* (e)) = * (parlist);
             son (par2) = son (son (par2));
             sh (par2) = sh (son (par2));
             bro (par2) = * (e) ;
             bro(son(par2)) = par2;
             return maxneeds (nds, twofix);
             }
             */
        }
#endif
      if (tlrecpos) {
        exp dad = father(application);
        if (name(dad) ==res_tag) {
          props(dad) = 1; /* do a tl recursion*/
        }
      }
      nds.propsneeds |= hasproccall;
      nds.maxargs = max(nds.maxargs, parsize);
      return nds;

    }

    case name_tag: {
      if (is_vararg(*e)) {
        /* if the tag represents va_list (set in spec_toks.c) */
        has_old_varargs = 1;
      }
      return shapeneeds(sh(*(e)));
    }

    case val_tag: {
      exp s = sh(*e);
      if (name(s) ==offsethd && al2(s) >= 8) {
        /* express disps in bytes */
        no(*e) = no(*e) >>3;
      }
      /*... and continue */
    }
    FALL_THROUGH;
    case env_size_tag:
    case give_stack_limit_tag:
    case null_tag:
    case real_tag:
    case string_tag:
    case env_offset_tag:
    case general_env_offset_tag:
    case caller_name_tag:
    /*    case next_frame_tag :*/
    case current_env_tag:
    case make_lv_tag:
    case last_local_tag:{
      return shapeneeds(sh(*(e)));
    }

    case clear_tag:
    case formal_callee_tag:
    case top_tag:
    case prof_tag:
    case local_free_all_tag:{
      return zeroneeds;
    }
    case set_stack_limit_tag:
#ifdef return_to_label_tag
    case return_to_label_tag:
#endif
    case diagnose_tag:
    case neg_tag:
    case case_tag:
    case not_tag:
    case offset_negate_tag:
    case absbool_tag:
    case goto_lv_tag:
    case abs_tag:
    case local_free_tag:{
      exp * arg = &son(*e);
      return scan(arg, at);
    }
    case fneg_tag:
    case fabs_tag:
    case chfl_tag: {
      needs nds;
      nds = scan(&son(*e), at);
      if (!optop(*e) && nds.fixneeds <2)nds.fixneeds = 2;
      return nds;
    }

    case alloca_tag: {
      needs nds;
      nds = scan(&son(*e), at);
      if (nds.fixneeds <2)nds.fixneeds = 2;
      return nds;
    }
    case bitf_to_int_tag: {
      /* is bitfield signed or unsigned ?? */
      exp * arg = &son(*e);
      needs nds;
      exp stararg;
      exp stare;
      int sizeb;

      nds = scan(arg, at);
      stararg = *(arg);
      stare = *(e);
      sizeb = ashof(sh(stararg)).ashsize;
      if ((name(stararg) ==name_tag &&
          ((sizeb == 8 && (no(stararg) & 7) == 0)
            || (sizeb == 16 && (no(stararg) & 15) == 0)
            || (sizeb == 32 && (no(stararg) & 31) == 0)
            || (sizeb == 64 && (no(stararg) & 63) ==0)
           )
          ) || (name(stararg) ==cont_tag &&
                ((name(son(stararg))!= name_tag &&
                   name(son(stararg))!=reff_tag)
                  || (sizeb == 8 && (no(son(stararg)) & 7) == 0)
                  || (sizeb == 16 && (no(son(stararg)) & 15) == 0)
                  || (sizeb == 32 && (no(son(stararg)) & 31) == 0)
                  || (sizeb == 64 && (no(son(stararg)) & 63) == 0)
                 )
                )
         ) {
        bool sgned = name(sh(stare)) & 1;
        shape ns = (sizeb==8)?((sgned)?scharsh:ucharsh)
          :(sizeb==16)?((sgned)?swordsh:uwordsh)
          : sh(stare);
        /*  can use short loads instead of bits extractions*/
        if (name(stararg) ==cont_tag) {
          /* make the ptr shape consistent */
          sh(son(stararg)) = f_pointer(long_to_al(shape_align(ns)));
        }
        sh(stararg) = ns;
        setname(stare, chvar_tag);
      }
      return nds;
    }

    case int_to_bitf_tag: {
      exp * arg = &son(*e);
      return scan(arg, at);
    }

    case round_tag: {
      needs s;
      exp * arg = &son(*e);
      s = scan(arg, at);
      s.fixneeds = max(s.fixneeds, 2);
      s.floatneeds = max(s.floatneeds, 2);
      has_float = 1;
      return s;
    }

    case shl_tag:
    case shr_tag:
    case long_jump_tag: {
      exp * lhs = &son(*e);
      exp * rhs  = & bro(*lhs);
      needs nr;
      needs nl;
      prop prps;
      nr = scan(rhs, at);
      nl = scan(lhs, at);
      rhs = &bro(*lhs);
      prps = (nr.propsneeds & hasproccall) << 1;
      if (nr.fixneeds >= maxfix || prps != 0) {
        /* if reg requirements overlap, identify
           second operand */
        cca(at, rhs);
        nl = shapeneeds(sh(*(rhs)));
        nl.propsneeds |= morefix;
        nl.propsneeds &= ~(prps >> 1);
        nl.propsneeds |= prps;
      }
      nr.fixneeds += 1;
      return maxneeds(nl, nr);

    }

    case test_tag: {
      exp stare = *(e);
      exp l = son(stare);
      exp r = bro(l);
      exp dad = father(stare);
      bool xlike = (name(dad) ==maxlike_tag || name(dad) ==minlike_tag || name(dad) ==abslike_tag);
      /* don't do various optimisations if xlike */

      if (!last(stare) && name(bro(stare)) == test_tag &&
          no(stare) == no(bro(stare)) &&
          props(stare) ==props(bro(stare)) &&
          eq_exp(l, son(bro(stare))) && eq_exp(r, bro(son(bro(stare))))
          ) {                   /* same test following in seq list -
                                   remove second test */
        if (last(bro(stare)))
          setlast(stare);
        bro(stare) = bro(bro(stare));
      }

      if (last (stare) && name (bro (stare)) == 0/* seq holder */
          && name(bro(bro(stare))) == test_tag &&
          name(bro(bro(bro(stare)))) == seq_tag &&
          no(stare) == no(bro(bro(stare))) &&
          props(stare) ==props(bro(bro(stare))) &&
          eq_exp(l, son(bro(bro(stare))))
          && eq_exp(r, bro(son(bro(bro(stare)))))
          ) {                   /* same test following in seq res - void
                                   second test */
        setname(bro(bro(stare)), top_tag);
        son(bro(bro(stare))) = nilexp;
        pt(bro(bro(stare))) = nilexp;
      }

      if (!xlike && name(l) == val_tag && (props(stare) == 5 || props(stare) == 6)) {
        /* commute  const = x */
        bro(l) = stare;
        setlast(l);
        bro(r) = l;
        clearlast(r);
        son(stare) = r;
        r = l;
        l = son(stare);
      }

      if (!xlike && name(r) == val_tag && (props(stare) == 5
                                            || props(stare) == 6) && no(r) == 0 &&
          name(l) == and_tag && name(bro(son(l))) == val_tag &&
         (no(bro(son(l))) & (no(bro(son(l))) - 1)) == 0
         ) {
        /* zero test  x & 2^n   -> neg test (x shl
           (31-n)) */
        exp copy;
        INT64  n = isbigval(bro(son(l)))?exp_to_INT64((bro(son(l)))):
          make_INT64(0,no(bro(son(l))));
        int   x;
        for (x = 0; INT64_lt(zero_int64,n);++x) {
/*      for (x = 0; n > 0; x++) {*/
          n = INT64_shift_left(n,1,1);
          /*n = n << 1;*/
        }
        if (x == 0) {           /* no shift required */
          bro (son (l)) = r;    /* zero there */
          son (stare) = son (l);/* x */
        }
        else {
          setname(l, shl_tag);
          no(bro(son(l))) = x;
        }
        props (stare) -= 3;     /* test for neg */
        if (!is64(sh(son(stare))) && name(l)!=shl_tag) {
          sh(son(stare)) = slongsh;
          copy = getexp(s64sh,bro(son(stare)),0,son(stare),nilexp,0,0,
                        chvar_tag);
          son(stare) = copy;
        }
        else{
          sh(son(stare)) = s64sh;
        }

      }
      if (name(l) == bitf_to_int_tag && name(r) == val_tag &&
         (props(stare) == 5 || props(stare) == 6) &&
         (name(son(l)) == cont_tag || name(son(l)) == name_tag)) {
        /* equality of bits against +ve consts
           doesnt need sign adjustment */
        long  n = no(r);
        switch (name(sh(l))) {
          case scharhd: {
            if (n >= 0 && n <= 127) {
              sh(l) = ucharsh;
            } break;
          }
          case swordhd: {
            if (n >= 0 && n <= 0xffff) {
              sh(l) = uwordsh;
            } break;
          }
          default:;
        }
      }
      else if (is_floating(name(sh(l)))) {
        return fpop(e, at);
      }
      else if (!xlike && name(r) == val_tag && no(r) == 1 && !isbigval(r)
               && (props(stare) == 3 || props(stare) == 2)) {
        no(r) = 0;
        if (props(stare) == 3) {
          props (stare) = 4;/* branch >=1 -> branch > 0 */
        }
        else     {
          props (stare) = 1;/* branch <1 -> branch <= 0 */
        }
      }
      return likediv(e, at);
    }
    case plus_tag:{
      /* replace any operands which are neg(..)
         by - ,if poss */
      exp sum = *(e);
      exp list = son(sum);
      bool someneg = 0;
      bool allneg = 1;
      for (;optop(sum);) {
        if (name(list) == neg_tag)
          someneg = 1;
        else
          allneg = 0;
        if (last(list))
          break;
        list = bro(list);
      }

      if (someneg) {            /* there are some neg() operands */
        if (allneg) {
          /* transform -..-... to -(..+.. +...) */
          exp x = son(sum);
          list = son(x);
          /* ALTERATION #1 here to fix minor structural bug */
          for (;;) {
            if (!last(x)) {
              bro(list) = son(bro(x));
              clearlast(list);
              list = bro(list);
              x = bro(x);
            }
            else {
              bro(list) = sum;
              setlast(list);
              son(sum) = son(son(sum));
              /* use existing exp */
              break;
            }
          }
          x = getexp(sh(sum), bro(sum), last(sum), sum, nilexp,
                      0, 0, neg_tag);
          setlast(sum); bro(sum)=x; /* set father of sum to be negate */
          *(e) = x;

        }                       /* end allneg */
        else {
          /* transform to  ((..(..+..) - ..) -..) */
          int   n = 0;
          exp brosum = bro(sum);
          bool lastsum = last(sum);
          exp x = son(sum);
          exp newsum = sum;
          list = nilexp;
          for (;;) {
            exp nxt = bro(x);
            bool final = last(x);
            if (name(x) == neg_tag) {
              bro(son(x)) = list;
              list = son(x);
            }
            else {
              bro(x) = newsum;
              newsum = x;
              if ((n++) == 0)
                setlast(newsum);
              else
                clearlast(newsum);
            }
            if (final)
              break;
            x = nxt;
          }

          if (n > 1) {
            son(sum) = newsum;
            newsum = sum;       /* use existing exp for add operations */
          }
          for (;;) {            /* introduce - operations */
            exp nxt = bro(list);
            bro(newsum) = list;
            clearlast(newsum);
            x = getexp(sh(sum), nilexp, 0, newsum, nilexp, 0, 0, minus_tag);

            bro(list) = x;
            setlast(list);
            newsum = x;
            if ((list = nxt) == nilexp)
              break;
          }
          bro(newsum) = brosum;
          if (lastsum) {
            setlast(newsum);
          }
          else {
            clearlast(newsum);
          }
          *(e) = newsum;

        }                       /* end else allneg */

        return scan(e, at);

      }                 /* end someneg - else continue to next
                           case */
    }
      FALL_THROUGH
    case and_tag:
    case mult_tag:
    case or_tag:
    case xor_tag: {
        return likeplus(e, at);
      }
    case addptr_tag: {
      exp ptr_arg = son(*e);
      exp offset_arg = bro(ptr_arg);
      int fralign = frame_al_of_ptr(sh(ptr_arg));
      if (fralign) {
        int offalign = frame_al1_of_offset(sh(offset_arg));
#if 0
        if (((offalign-1) &offalign)!= 0) {
          failer("Mixed frame offsets not supported");
        }
#endif
        if (includes_vcallees(fralign) && l_or_cees(offalign)) {
          exp newexp = getexp(sh(ptr_arg),offset_arg,0,ptr_arg,nilexp,0,0,
                              locptr_tag);
          bro(ptr_arg) = newexp;
          setlast(ptr_arg);
          son(*e) = newexp;
        }
      }
      return likediv(e,at);
    }
    case locptr_tag:
    case reff_tag:
    case offset_pad_tag:
    case chvar_tag: {
      exp * arg = &son(*e);
      needs nds;
      nds = maxneeds(scan(arg, at),shapeneeds(sh(*(e))));
      /*      nds.fixneeds += 1;*/
      return nds;
    }

    case float_tag:  {
      needs nds;
      exp * arg = &son(*e);
      nds = maxneeds(scan(arg, at), shapeneeds(sh(*(e))));
      if ((name(sh(son(*(e)))) == ulonghd) || (name(sh(son(*(e)))) ==u64hd)) {
        if (nds.floatneeds <2) nds.floatneeds =2;       /* remove */
      }
      has_float = 1;
      return nds;
    }
    case cont_tag:
    case contvol_tag: {
      exp * arg = &son(*e);
      needs nds;

      nds = maxneeds(scan(arg, at), shapeneeds(sh(*(e))));
      if (is_awkward_variety(name(sh(*e)))) {
        nds.fixneeds = max(nds.fixneeds,4);
      }
      else{
        nds.fixneeds = max(nds.fixneeds, 2);
      }
      if (nstare != cont_tag) {
        nds.propsneeds |= uses2_bit;
      }
      return nds;
    }

    case offset_mult_tag:
    case offset_div_tag: {
      exp op2 = bro(son(*e));
      shape s = sh(op2);
      if (name(op2) ==val_tag && no(op2) == 8 && name(s) ==offsethd && al2(s) >= 8) {
        /* offset is one  byte */
        exp op1 = son(*e);
        bro(op1) = bro(*e);
        if (last(*e)) { setlast(op1); } else {clearlast(op1); }
        *e = op1;
        return(scan(e, at));
      }
      /*... else continue */
    }
      FALL_THROUGH;
    case div2_tag:
    case rem2_tag:
    case rem0_tag:
    case div0_tag:
    case offset_div_by_int_tag:{
        if (is_machine_divide(*e)) {
          has_div = 1;
        }
        return likediv(e,at);
      }
    case offset_add_tag:
    case offset_subtract_tag: {
      if ((al2(sh(son(*e))) == 1) && (al2(sh(bro(son(*e))))!= 1)) {
        make_bitfield_offset(bro(son(*e)),son(*e),0,sh(*e));
      }
      if ((al2(sh(son(*e)))!= 1) && (al2(sh(bro(son(*e)))) == 1)) {
        make_bitfield_offset(son(*e),*e,1,sh(*e));
      }
    }
    FALL_THROUGH;
#ifdef make_stack_limit_tag
    case make_stack_limit_tag:
#endif
    case min_tag:
    case max_tag:
    case minus_tag:
    case subptr_tag:
    case minptr_tag:
    case offset_max_tag:
    case component_tag:{
      return likediv(e, at);
    }
    case div1_tag: {
      if (is_machine_divide(*e)) {
        has_div = 1;
      }
      if ((name(sh(*e)) & 1) ==0) { setname(*e, div2_tag); }
      return likediv(e,at);
    }
    case mod_tag: {
      if (is_machine_divide(*e)) {
        has_div = 1;
      }
      if ((name(sh(*e)) & 1) ==0) { setname(*e, rem2_tag); }
      return likediv(e,at);
    }
    case fdiv_tag:
#if (FBASE==10)         /* (FBASE==10) is now defunct */
    {
      /* replace X/const by X*const^-1 */
      exp z = *(e);
      exp a2 = bro(son(z));
      if (name(a2) == real_tag) {
        flt inverse;
        flt unitflt;
        str2flt("1.0", &unitflt,(char **)0);
        if (flt_div(unitflt, flptnos[no(a2)], &inverse) == OKAY) {

          int   f = new_flpt();
          flptnos[f] = inverse;
          no(a2) = f;
          setname(z, fmult_tag);
        }
      }
    }
#endif
    case fplus_tag:
    case fminus_tag:
    case fmult_tag: {
      exp op = *(e);
      exp a2 = bro(son(op));
      has_float = 1;
      if (!last(a2)) {
        /* + and * can have >2 parameters
           - make them diadic - can do better
           a+exp => let x = exp in a+x */
        exp opn = getexp(sh(op), op, 0, a2, nilexp, 0, 0, name(op));
        /* dont need to transfer error treatment - nans */
        exp nd = getexp(sh(op), bro(op), last(op), opn, nilexp, 0, 1,
                        ident_tag);
        exp id = getexp(sh(op), op, 1, nd, nilexp, 0, 0, name_tag);
        pt(nd) = id;
        bro(son(op)) = id;
        setlast(op); bro(op) = nd;
        while (!last(a2))a2 = bro(a2);
        bro(a2) = opn;
        *(e) = nd;
        return scan(e, at);
      }

      return fpop(e, at);
    }

    case fmax_tag: {
      has_float = 1;
      return fpop(e,at);
    }

    case field_tag: {
      needs str;
      exp * arg = &son(*e);
      if (chase(*e, arg)) { /* field has been distributed */
        exp stare = *e;
        exp ss = son(stare);
        if (!last(stare))
          clearlast(ss);
        bro(ss) = bro(stare);
        sh(ss) = sh(stare);
        *e = ss;
        return(scan(e, at));
      }
      str = scan(arg, at);
      return maxneeds(str, shapeneeds(sh(*(e))));
    }
    case general_proc_tag:
    case proc_tag:{
      exp * bexp;
      exp * bat;
      needs body;
      exp stare = *(e);
      callerfortr = do_tlrecursion && !proc_has_setjmp(stare)
        && !proc_has_alloca(stare) && !proc_has_lv(stare) &&
        !proc_uses_crt_env(stare);
      callerfortr=0;
      maxfix = 12;  /* excluding regs corrupted by div */
      maxfloat = 12; /* jm - 21? */
      stparam = 0;
      fixparam = 16;
      floatparam = 16;
      nonevis = 1;
      rscope_level = 0;
      numparams=0;
      callee_size = 0;
      gen_call = (name(stare) == general_proc_tag);
      in_vcallers_proc = (gen_call && proc_has_vcallers(stare));
      bexp = & son(*e);
      bat = bexp;
      body = scan(bexp, &bat);
      /* scan the body of the proc */
      if (gen_call || Has_fp) {
        /* reserve space for the link area */
        callee_size += 4*PTR_SZ;
      }
#if 0
      if (name(stare) == proc_tag && gen_call) {
        set_proc_has_gen_call(*e);
      }

#endif
      if (has_old_varargs) {
        set_has_c_vararg(*e);
        has_old_varargs = 0;
      }
      if (has_div) {
        set_has_machine_division(*e);
        has_div = 0;
      }
      if (has_float) {
        set_has_float(*e);      /* need to allocate space on stack for
                                   a float <-> int register move */
      }
      return body;       /*  should never require this in reg in C */
    }
    case movecont_tag: {
      exp * d = &son(*e);
      exp * s = & bro(*d);
      exp * sz = &bro(*s);
      needs nd;
      needs ns;
      needs nsz;
      prop prps;
      nd = scan(d, at);
      ns = scan(s, at);
      nsz = scan(sz, at);
      prps = (ns.propsneeds & hasproccall) << 1;
      if (ns.fixneeds >= maxfix || prps != 0) {
        /* if reg requirements overlap, identify
           second operand */
        cca(at, s);
        ns = shapeneeds(sh(*(s)));
        ns.propsneeds |= morefix;
        ns.propsneeds &= ~(prps >> 1);
        ns.propsneeds |= prps;
      }
      nd.fixneeds += 1;
      nd = maxneeds (nd, ns); /* ns? */
      prps= (nsz.propsneeds & hasproccall) << 1;
      if (nd.fixneeds+nsz.fixneeds >= maxfix || prps != 0) {
        /* if reg requirements overlap, identify last operand */
        cca(at, sz);
        nsz = shapeneeds(sh(*(sz)));
        nsz.propsneeds |= morefix;
        nsz.propsneeds &= ~(prps >> 1);
        nsz.propsneeds |= prps;
      }
      nd.fixneeds+=1;
      nd = maxneeds(nd,nsz);
      if (nd.fixneeds < 4)nd.fixneeds = 3;
      return nd;
    }
    case trap_tag:
    case special_tag:{
      return zeroneeds;
    }

    default: {
      printf("case %d not covered in needs scan\n", name(* e));
      /* NB should call failer */
      return zeroneeds;
    }
  }
}