Subversion Repositories tendra.SVN

Rev

Rev 5 | 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$
 */
/*
    Copyright (c) 1993 Open Software Foundation, Inc.


    All Rights Reserved


    Permission to use, copy, modify, and distribute this software
    and its documentation for any purpose and without fee is hereby
    granted, provided that the above copyright notice appears in all
    copies and that both the copyright notice and this permission
    notice appear in supporting documentation.


    OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING
    ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    PARTICULAR PURPOSE.


    IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
    CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
    NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
    WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

/*
                 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/02/04 15:49:01 $
$Revision: 1.2 $
$Log: needscan.c,v $
 * Revision 1.2  1998/02/04  15:49:01  release
 * Added OSF copyright message.
 *
 * Revision 1.1.1.1  1998/01/17  15:55:57  release
 * First version to be checked into rolling release.
 *
 * Revision 1.4  1996/10/14  17:31:56  pwe
 * include called callees in env_size
 *
 * Revision 1.3  1996/10/14  15:53:31  pwe
 * preserve regresult during postlude
 *
 * Revision 1.2  1996/10/04  16:03:03  pwe
 * add banners and mod for PWE ownership
 *
**********************************************************************/


/******************************************************************

                needs_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 "memtdf.h"
#include "codegen.h"

#include "myassert.h"
#include "comment.h"


#include "common_types.h"
#include "exptypes.h"
#include "exp.h"
#include "expmacs.h"
#include "tags.h"
#include "localtypes.h"
#include "procrectypes.h"
#include "bitsmacs.h"
#include "maxminmacs.h"
#include "regable.h"
#include "tempdecs.h"
#include "shapemacs.h"
#include "const.h"
#include "flpt.h"
#include "install_fns.h"
#include "externs.h"

#include "flags.h"

#include "machine.h"
#include "translat.h"
#include "check.h"
#include "makecode.h"
#include "needscan.h"
#include "me_fns.h"
#include "stack.h"
#include "error.h"
#include "dynamic_init.h"
/*
 * Will an ident exp be in memory?
 * We have to guess at this stage for non globals.
 */
#define INMEMIDENT(ident_exp)   (isvis(ident_exp) || isglob(ident_exp))

/*
 * Will evaluating exp 'e' cause last instruction to be a load from store?
 * Always false if generating diagnostics, we dont want to rearrange in
 * this case as it makes debugging less obvious.
 * This is not exact, register contents tracking may find a copy in reg.
 */
#define LOADFROMSTORE(e)\
        (\
        !diagnose \
        && \
        (\
         (name(e) == cont_tag && (name(son(e))!= name_tag || INMEMIDENT(son(son(e)))))\
          || \
          (name(e) == name_tag && isglob(son(e))) /* load of TOC entry */ \
        )\
        )
int maxfix, maxfloat;           /* the maximum number of t-regs */
bool tail_call;
bool gen_call;
long callee_size;
long max_callees;
long no_of_returns;
int end_param;

/* The following are used for allocating param regs to t-regs */
static int freefixed;
static int freefloat;


static int stparam, fixparam, floatparam;


extern bool do_tlrecursion;

static bool nonevis = 1;
static bool rep_tag_scanned;

int scan_cond(exp *,exp);
needs scan(exp *, exp **);
static void number_caller_parameter(exp);
static void number_callee_parameter(exp);

/* 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).
   */


/***************************************************************
                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.
****************************************************************/

static 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;
  }
}

/* General useful needs */
static needs onefix = { 1, 0, 0, 0 };                   /* needs one fix pt reg */
static needs twofix = { 2, 0, 0, 0 };                   /* needs 2 fix pt regs */
static needs onefloat = { 0, 1, 0, 0 };                 /* needs 1 flt pt regs */
static needs zeroneeds = { 0, 0, 0, 0 };                /* has no needs */


static needs shapeneeds(shape s)
{                               /* this gives the needs for manipulating a
                                 * value of shape s */
  if (is_floating(name(s)))
  {
    return onefloat;
  }
  else
  {
    if (valregable(s))
    {
      return onefix;
    }
    else
    {                           /* if the shape does not fit into a reg, needs
                                 * two fixed regs for moving ... */
      return twofix;
    }
  }
}


static 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
     )
  {
    return 0;
  }
  else
  {
    return 1;
  }
}


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

  ASSERT(father(son(*e)) == *e);

  /* scan the first operand - won't be a val_tag */
  a1 = scan(br, at);

  /*
   * if first operand is a proc, or ends with a load instruction,
   * it is not worth doing a commute to a later position
   */
  dont_commute = (a1.fixneeds >= maxfix || (a1.propsneeds & hasproccall))
                 || LOADFROMSTORE(*br);

  do
  {
    exp *prevbr;

    prevbr = br;
    prev = *(br);
    br = &bro(prev);
    a2 = scan(br, at);
    /* scan the next operand ... */
    if (name(*(br))!= val_tag)
    {
      prop pc;
      bool all_treg_needs;

      a1.floatneeds = max(a1.floatneeds, a2.floatneeds);
      pc = a2.propsneeds & hasproccall;
      all_treg_needs = (a2.fixneeds >= maxfix || pc != 0);

      if (!dont_commute
           &&
          (all_treg_needs || LOADFROMSTORE(*br))
           &&
          (a1.fixneeds < maxfix && (a1.propsneeds & hasproccall) == 0)
        )
      {
        /*
         * ...its evaluation will call a proc, or ends with a load instruction,
         * 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;
        dont_commute = 1;
        a1.fixneeds = max(a2.fixneeds, a1.fixneeds + 1);
        a1.propsneeds |= a2.propsneeds;
        a1.maxargs = max(a1.maxargs, a2.maxargs);
      }
      else if (all_treg_needs)
      {                         /* ... 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);
      }
      else
      {
        /*
         * ... its evaluation  will not disturb the accumulated result
         */
        a1.fixneeds = max(a1.fixneeds, a2.fixneeds + 1);
        a1.propsneeds = a1.propsneeds | a2.propsneeds;
      }
    }
  } while (!last(*(br)));

  return a1;
}


needs non_commutative_scan(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;
}

static 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);

  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);
  }
  return l;
}
/**********************************************************************
        maxneeds

Calculates a needs value. Each element of which is the maximum of the
corresponding elements in the two parameter needs
**********************************************************************/

static 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.propsneeds = a.propsneeds | b.propsneeds;
  return an;
}


/**********************************************************************
        maxsequence

**********************************************************************/

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

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


static bool unchanged(exp usedname, exp ident)
{
  /*
   * finds if usedname is only used in cont operation or as result of ident
   * i.e. value of name is unchanged over its scope
   */
  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;
}


static 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;
}



/*
 * The POWER convention for delivering a struct from a procedure is is have an
 * extra pointer parameter in the proc; this means that there always must be
 * space in the calling work-space for the result struct whether or not the
 * value is used e.g. as in f(x); or f(x).a etc. This proc is part of the
 * mechanism to determine whether it is necessary to insert a dummy
 * declaration to ensure that this space exists.
 */
static 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 */
    }
  default:
    {
      if (son(sel)!= *e)
      {                         /* 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;
}



/********************************************************************
                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).
        Scan also works out various things concerned with proc calls.
The maxargs field contains the max size in bits of the space required for the
parameters of all the procedures called in the exp. An exp proc call
produces a hasproccall bit in the prop field, if this is transformed as part of
the definition of a new declaration the bit is replaced by a usesproccall. The
distinction is only used in unfolding nested proc calls; POWER requires this to
be done statically. The condition that a proc exp is a leaf (i.e no proc calls)
is that its prop contains neither bit.
        If an ident exp is suitable, scan marks the props of ident with
either inreg or infreg bits to indicate that a t reg may be used for this tag.

        A thorough understanding of needs along with other procedures
that do switch(name(exp)) requires a knowledge of the meaning of the fields
of the exp in each case.

********************************************************************/


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
   */
  exp ste = *(e);
  int nstare = name(ste);
  static long exp_num = 0;              /* count of exps we evaluate */

  exp_num++;
  ASSERT(*e != nilexp);


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

   case compound_tag:
   case nof_tag:
   case concatnof_tag:
   case ncopies_tag:
    {
      needs nl;
      bool cantdo;
      exp dad;

      if (nstare==nof_tag && son(ste) ==nilexp)
        return zeroneeds;

      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);
      }
      ste = *e;
      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;
      }

      nl.fixneeds = max(nl.fixneeds,2);

      return nl;
    };

  case cond_tag:
    {
      if (scan_cond(e, nilexp)!=0)
      {
        return scan(e, at);
      }                   /* Else goto next case */
    }
    /*FALLTHROUGH*/
   case rep_tag:
   case solve_tag:
    {
      exp *stat;
      exp *statat;
      needs an;

      stat = &son(*e);
      statat = stat;
      an = zeroneeds;
      rep_tag_scanned=0;
      /*
       * Simply scan each argument
       * The arguments are effectively independent pieces
       * of code for these constructions
       */
      /***********************************************************/
      /*    _        _________                                   */
      /*   |_|----->|        _|                                  */
      /*  /         |    _  |_|                                  */
      /* e          |___|_|___|                                  */
      /*               / |                                       */
      /*              /  |                                       */
      /*          stat(1)|       stat(2)       stat(3)           */
      /*             ____v____  /  _________  /  _________       */
      /*            |        _|/  |        _|/  |        _|      */
      /*            |    _  |_|-->|    _  |_|-->|    _  |_|-->   */
      /*            |___|_|___|   |___|_|___|   |___|_|___|      */
      /*                                                         */
      /***********************************************************/
      while (an = maxneeds(an, scan(stat, &statat)), !last(*(stat)))
      {
        stat = &bro(*stat);
        statat = stat;
      }
      if (name(*e) ==rep_tag)
      {
        if (rep_tag_scanned==0)
        {
          setinnermost(*e);
        }
        else
        {
          clearinnermost(*e);
        }
      }
      rep_tag_scanned=1;
      if ((an.propsneeds & usesproccall)!= 0)
      {
        an.propsneeds |= hasproccall;
      }
      return an;
    }

  case labst_tag:
    {
      exp *stat;
      exp *statat;
      needs an;
      int expn = exp_num;

      ASSERT(!last(son(*e)));
      ASSERT(last(bro(son(*e))));

      /****************************************/
      /*    _     _________                   */
      /*   |_|-->| labst   |                  */
      /*  /      |    _    |                  */
      /* e       |___|_|___|   stat           */
      /*              |       /               */
      /*          ____v____  /  ________      */
      /*         | clear  _|/  |       _|     */
      /*         |       |_|-->|      |_|     */
      /*         |_________|   |________|     */
      /*                                      */
      /****************************************/
      stat = &bro(son(*e));
      statat = stat;
      an = scan(stat, &statat);

      if ((an.propsneeds & usesproccall)!= 0)
      {
        an.propsneeds |= hasproccall;
      }

      /*
       * ptno(son()) is set to exp number so that make_code can estimate
       * distances of conditional branches, which is limited on POWER.
       */
      ptno(son(*e)) = expn;

      return an;
    }


/*********************************************************************
  ident_tag

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 defneeds;
      exp stare = *(e);
      exp *arg;
      exp t = pt(stare), s;
      bool fxregble;
      bool flregble;
      bool old_nonevis = nonevis;
      bool uses_R_RESULT;
      bool uses_FR_RESULT;
#if 0
      /* We can't do this because of env_offset not appearing in the list of uses */
      if (pt(stare) == nilexp)
      {
        /* no uses, should have caonly flag set (not already set for params) */
        setcaonly(stare);
      }
#endif
      if (isvar(stare) && (!iscaonly(stare) || all_variables_visible))
      {
        setvis(stare);
      }

      if (isparam(stare))
      {
        if (name(son(stare))!=formal_callee_tag)
        {
          number_caller_parameter(stare);
        }
        else
        {
          number_callee_parameter(stare);
        }
      }

      nonevis &= !isvis(stare);

      /* Scan the body of the ident */
      arg = &bro(son(stare));
      bdy = scan(arg, &arg);
      /* Scan the def of the ident */
      arg = &son(stare);
      defneeds = scan(arg, &arg);
      ASSERT(stare == *e);

      nonevis = old_nonevis;
      t = son(stare);
      s = bro(t);
      fxregble = fixregable(stare);
      flregble = floatregable(stare);
      uses_R_RESULT = (bdy.propsneeds & uses_R_RESULT_bit)!=0;
      uses_FR_RESULT = (bdy.propsneeds & uses_FR_RESULT_bit)!=0;
/*****************************************************************************/
      if (name(son(stare)) ==caller_name_tag)
      {
        /*
         * IDENT is a caller in postlude
         */
        no(stare) = R_NO_REG;
        /* At present all callers in postludes are only allowed on the stack*/
        /* This is because of the problems created by nested postludes */
      }
/*****************************************************************************/
      else if (isparam(stare) && name(son(stare)) ==formal_callee_tag)
      {
        /*
         * IDENT is a callee parameter
         */
        no(stare) = R_NO_REG;
      }
/*****************************************************************************/
      else if (isparam(stare) && name(son(stare))!=formal_callee_tag)
      {
        /*
         * IDENT is a caller parameter
         */
        if (do_profile)
        {
          /* mcount is called after the last param is dealt with */
          /* So we must put all params on the stack or in s-regs */
          bdy.propsneeds |= hasproccall;
        }
        no(stare) =R_NO_REG;
      }
/*****************************************************************************/
      else
      {
        /*
         * IDENT is a normal ident
         */
        ASSERT(!isparam(*e));


        if (!isvis(*e) &&
           (bdy.propsneeds & anyproccall) ==0 &&
           (
            (uses_R_RESULT==0 && fxregble) ||
            (uses_FR_RESULT==0 && flregble)
            ) &&
           (
             name(t) == apply_tag || /* Let a := f()*/
            (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 */
            )
           )
        {
          /* Ident suitable for res reg */
          if (fxregble)
          {
            props(stare) |= inreg_bits;
            no(stare) = R_RESULT;
            bdy.propsneeds |= uses_R_RESULT_bit;
          }
          else
          {
            props(stare) |= infreg_bits;
            no(stare) = FR_RESULT;
            bdy.propsneeds |= uses_FR_RESULT_bit;
          }
        }

#if 1
        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 */
        }
#endif
#if 0   /* dont undo large const in loop optimisation */
        else if (!isvar(stare) &&
                (isusereg(stare) == 0)
                 && (name(t) == name_tag || name(t) == val_tag))
        {
          props(stare) |= defer_bit;
          /* dont take space for this dec */
        }
#endif
#if 1
        else if (!isvar(stare)
                 && name(t) == name_tag
                 && !isvar(son(t))
                 && !isvis(son(t))
                 && (props(son(t)) & inanyreg)
                )
        {
          /*
           * dont take space for this constant dec,
           * initialiser is another simple constant ident
           * (eg from double nested loop optimisation)
           */
          props(stare) |= defer_bit;
        }
#endif
        /* All the parameters have been scanned at this point so
           maxfix gives the total no of free t-regs */
        else if (fxregble &&
                 bdy.fixneeds < maxfix &&
                (bdy.propsneeds & morefix) == 0 &&
                ((bdy.propsneeds & anyproccall) ==0
#if 0
                  ||
                  tempdec(stare,((bdy.propsneeds & morefix) ==0) && bdy.fixneeds<2)
#endif
                 )
                )
        {
          if ((props(stare) & notparreg) ==0)
          {
            no(stare) = R_NO_REG;
            props(stare) |= inreg_bits;
            if (uses_R_RESULT==1)
            {
              props(stare) |= notresreg;
            }
            bdy.fixneeds += 1;
          }
        }
        else if (flregble &&
                 bdy.floatneeds < maxfloat &&
                (bdy.propsneeds & morefloat) == 0 &&
                ((bdy.propsneeds & anyproccall) ==0
#if 0
                  ||
                  tempdec(stare,((bdy.propsneeds & morefloat) == 0 &&
                                     bdy.floatneeds < 1))
#endif
                 )
                )
        {
          if ((props(stare) & notparreg) == 0)
          {
            /* Ident suitable for float t-reg */
            no(stare) = FR_NO_REG;
            props(stare) |= infreg_bits;
            if (uses_FR_RESULT==1)
            {
              props(stare) |= notresreg;
            }
            bdy.floatneeds += 1;
          }
        }
        else
        {
          /*
           * allocate either on stack or saved reg, decided later by
           * regalloc()
           */
          no(stare) = R_NO_REG;
        }
      }
      bdy = maxneeds(bdy, defneeds);
      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;
      exp * atsc = &son(son(*e));
      for (;;)
      {
        exp sc = *atsc;
        if (name(sc) == cond_tag && name(sh(son(sc))) ==bothd
            && name(bro(son(bro(son(sc))))) == top_tag)
        {
          /* sc is cond(... goto | make_top); can replace
             make_top by next exp in sequence */
          exp lbst = bro(son(sc));
          exp mkt = bro(son(lbst));
          exp ne = (last(sc))? bro(son(*e)): bro(sc);
          exp bne = bro(ne);
          bool lne = last(ne);
          if (name(ne)!= cond_tag)
          {
            /* only worthwhile eliding if ne is a cond */
            if (last(sc))break;
            atsc = &bro(sc);
            continue;
          }
          sh(sc) = sh(ne);
          bro(ne) = lbst; setlast(ne);
          bro(son(lbst)) = ne;
          /* sc is now cond( ... goto | next cond exp) */
          if (!last(sc))
          { /* not last in seq - swallow next*/
            bro(sc) = bne;
            if (lne) { setlast(sc); } else { clearlast(sc);}
            no(son(*e))--; /* one less statement */
          }
          else if (no(son(*e))!= 1)
          { /* last but not only - replace by
               make_top and put cond in res posn */
            bro(mkt) = bro(sc); setlast(mkt);
            *atsc = mkt;
            bro(sc) = bne;
            if (lne) { setlast(sc); } else { clearlast(sc);}
            *arg = sc;
            sc = mkt;
          }
          else
          { /* whole sequence can be replace by cond */
            bro(sc) = bro(*e);
            if (last(*e)) { setlast(sc); } else {clearlast(sc); }
            *e = sc;
            return scan(e, at);
          }

        }
        if (last(sc))break;
        atsc = &bro(sc);
      }
      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:
    /* By popular request the  infamous trap_tag */
   case trap_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 (!valregable(sh(*rhs)))
      {
        /* complicated memory move */
        if (!(a.ashsize <= 32 && a.ashsize == a.ashalign))
          nr.fixneeds += 2;     /* memory block copy */
      }

      if (name(*(lhs)) == name_tag &&
         ((isvar(son(*(lhs))) && !isglob(son(*(lhs)))) ||
          ((nr.propsneeds & (hasproccall | morefix)) == 0
            && nr.fixneeds+1 < maxfix
           )
          )
        )
      {
        /* simple destination */
        if (isvar(son(*(lhs))) && isglob(son(*(lhs))))
          nr.fixneeds += 1;             /* for TOC access */
        return nr;
      }
      else
      {
        needs nl;
        prop prps = (nr.propsneeds & hasproccall) << 1;

        nl = scan(lhs, at);
        /* scan destination */
        if (APPLYLIKE(*(rhs)) &&
            nstare == ass_tag &&
           (nl.propsneeds & (anyproccall|uses_R_RESULT_bit|uses_FR_RESULT_bit)) ==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;
        }
        nr.fixneeds += 1;
        return maxneeds(nl, nr);
      }
    };
   case untidy_return_tag:
   case res_tag:
    {
      needs x;
      shape s;
      exp *arg = &son(*e);
      s = sh(*(arg));
      props(*e) = 0;            /* clear possibility of tlrecirsion; may be
                                 * set later */
      no_of_returns++;
      x = scan(arg, at);        /* scan result exp ... */

      if (shape_size(s)!= 0)
      {
        /* ...not a void result */
        x.propsneeds |= has_result_bit;

        if (is_floating(name(s)))
        {
          /* ... floating pt result */
          x.propsneeds |= realresult_bit;
          if (name(s)!= shrealhd)
          {
            x.propsneeds |= longrealresult_bit;
          }
        }
        else
        {
          if (!valregable(s))
          {
            ASSERT(redo_structfns==0);
            x.propsneeds |= long_result_bit;
          }
        }
      }

#if 0                           /* +++ if we can avoid leaf proc conflict */
      if ((x.propsneeds & (long_result_bit | anyproccall | uses_res_reg_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 |= uses_res_reg_bit;
          no(r) = R_USE_RES_REG;/* identification  uses result reg in body */
        }
      }
#endif
      return x;
    };

  case apply_tag:
    {
      exp application = *(e);
      exp fn = son(application);
      exp *par = &bro(fn);
      exp *fnexp = &son(*e);
      int parsize = 0;
      needs nds;
      bool regresult = reg_result(sh(application));
      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);
      }


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

        par_regs_used = (parsize >> 5);

        if (par_regs_used >= (end_param-R_FIRST_PARAM+1))
        {
          par_regs_used = (end_param-R_FIRST_PARAM+1);
          move_to_stack_regs = 1;       /* can no longer move to param reg, need spare */
        }
        else
        {
          move_to_stack_regs = 0;
        }

        onepar = scan(par, at);

        FULLCOMMENT4("scan: apply_tag: i=%d parn=%d pars=%d mover=%d",
                i, onepar.fixneeds, par_regs_used, move_to_stack_regs);

        if (((i != 1 || regresult) && (onepar.propsneeds & hasproccall)!= 0))
        {
          /* if it isn't the first parameter, and it calls a proc, identify it */
          FULLCOMMENT("scan apply_tag: cca bring forward apply");
          cca(at, par);
          nds.propsneeds |= usesproccall;
          nds = maxneeds(shapeneeds(sh(*(par))), nds);
          nds.maxargs = max(nds.maxargs, onepar.maxargs);
        }
        else if ((i != 1 && (onepar.propsneeds & hasproccall)!= 0) ||
                 onepar.fixneeds >= 6 /* +++ remove safety net */ ||
                 onepar.fixneeds + move_to_stack_regs + par_regs_used > maxfix)
        {
          /* requires to many regs to evaluate, identify it */
          FULLCOMMENT("scan apply_tag: cca, param has too large fixneeds");
          cca(at, par);
          nds.propsneeds |= morefix;
          nds = maxneeds(shapeneeds(sh(*(par))), nds);
          nds.maxargs = max(nds.maxargs, onepar.maxargs);
        }
        else
        {
          nds = maxneeds(onepar, nds);
        }
        parsize = ALIGNNEXT(parsize, shape_align(shpar));
        parsize = ALIGNNEXT(parsize + shape_size(shpar), 32);

        if (last(*(par)))
        {
          break;
        };
        par = &bro(*par);
      }

      if (!regresult && name(father(application))!= ass_tag)
      {
        /* find space for non reg result */
        FULLCOMMENT("scan apply_tag: cca space for non reg result");
        cca(at, ptr_position(application));
        nds.propsneeds |= usesproccall;
      }
      else
      {
        nds.propsneeds |= hasproccall;
      }
      nds.maxargs = max(nds.maxargs, parsize);
      return nds;
    };

  case null_tag:
    {
      /* many int optimisations keyed off val_tag so represent null as val_tag */
      name(*e) = val_tag;
      no(*e) = 0;               /* null represented as 0 */
      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 */
    }

   case name_tag:
   case real_tag:
   case string_tag:
   case env_offset_tag:
   case current_env_tag:
   case make_lv_tag:
   case last_local_tag:
    {
      return shapeneeds(sh(*(e)));
    };

    case clear_tag:
    case top_tag:
    case prof_tag:
    case local_free_all_tag:
    {
      return zeroneeds;
    };

   case neg_tag:
   case case_tag:
   case not_tag:
   case offset_negate_tag:
   case diagnose_tag:
   case goto_lv_tag:
   case alloca_tag:
    {
      return scan(&son(*e), at);
    }
   case abs_tag:
    if (architecture!=RS6000_CODE)
    {
      /* We cant use abs instruction so we convert */
      shape int_shpe = sh(*e);
      exp arg = son(*e);
      exp id = me_startid(int_shpe,arg,0);
      exp LABST__TAG;
      exp CLEAR__TAG;
      exp SEQ__TAG;
      exp TEST__TAG;
      exp VAL__TAG;
      exp NEG__TAG;
      exp COND__TAG;
      exp ZERO__TAG;
      exp ABS__TAG;
      ABS__TAG = *e;

      CLEAR__TAG = getexp(f_top, nilexp, 0, nilexp, nilexp,0, 0, clear_tag);
      LABST__TAG = me_b3(int_shpe,CLEAR__TAG,me_obtain(id),labst_tag);

      VAL__TAG = me_shint(int_shpe,0);
      TEST__TAG = me_q1(no_nat_option,f_less_than,&LABST__TAG,
                        me_obtain(id),VAL__TAG,test_tag);
      NEG__TAG = me_u3(int_shpe,me_obtain(id),neg_tag);
      pt(NEG__TAG) = pt(ABS__TAG);
      props(NEG__TAG) =props(ABS__TAG);

      ZERO__TAG = me_u3(f_top,TEST__TAG,0);
      SEQ__TAG = me_b3(int_shpe,ZERO__TAG,NEG__TAG,seq_tag);
      COND__TAG = me_b3(int_shpe,SEQ__TAG,LABST__TAG,cond_tag);
      id = me_complete_id(id,COND__TAG);
      if (last(*e))
      {
        setlast(id);
      }
      else
      {
        clearlast(id);
      }
      bro(id) = bro(*e);
      *e = id;
      return scan(e,at);
    }



   case fneg_tag:
   case fabs_tag:
   case chfl_tag:
    {
      needs nds;

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

      return scan(arg, at);
    }

  case round_tag:
    {
      needs s;
      exp *arg = &son(*e);
      shape sres = sh(*e);
      if (shape_size(sres)!=32)
      {
        exp ch = getexp(sres,bro(*e),last(*e),*e,pt(*e),props(*e),0,chvar_tag);
        bro(*e) =ch;setlast(*e);
        sh(*e) =slongsh;
        *e=ch;
        return scan(e,at);
      }
      s = scan(arg,at);
      s.fixneeds = max(s.fixneeds,1);
      s.floatneeds = max(s.floatneeds,2);
      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);

      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;
      }

      /*
       * commute tests if
       * a) lhs a const (to support convention of const on rhs); or
       * b) rhs is a load from mem, move to lhs in hope of reducing
       *    load-use delays
       */
      if (
          (
            test_number(stare) ==TEST_NE||test_number(stare) ==TEST_EQ||
            !is_floating(name(sh(l)))
           )
           &&
          (
            (name(l) == val_tag)
             ||
            (LOADFROMSTORE(r) && !LOADFROMSTORE(l))
          )
        )
      {
        /* commute */
        bro(l) = stare;
        setlast(l);
        bro(r) = l;
        clearlast(r);
        son(stare) = r;
        r = l;
        l = son(stare);
        settest_number(stare,cbranch(test_number(stare)));
      }

      if (is_floating(name(sh(l))))
      {
        return fpop(e, at);
      }
      else if (name(r) == val_tag && no(r) == 1
               && (test_number(stare) == TEST_GE ||
                   test_number(stare) == TEST_LT)
              )
      {
        /* The only reason for this optimisation is that it increases
           the chance of using the Record bit */
        no(r) = 0;
        if (test_number(stare) == TEST_GE)
        {
          /* Branch >=1 is same as >0 */
          settest_number(stare,TEST_GT);
        }
        else
        {
          /* Branch <1 is same as <= 0 */
          settest_number(stare,TEST_LE);
        }
      }
      return non_commutative_scan(e, at);
    }
   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);
     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 plus_tag:
    {                           /* replace any operands which are neg(..) by -
                                 * if poss */
      exp sum = *(e);
      exp list = son(sum);
      bool someneg = 0;
      bool allneg = 1;

      /* check BUGP13 [corruption by extract_consts()] is fixed */
      /* check father set correctly */
      ASSERT(father(son(sum)) ==sum);

      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;

          /*
           * Build a new list form operand of neg_tags, which will
           * become plus_tag operands.
           */
          x = son(sum);
          list = son(x);
          for (;;)
          {
            /*
             * 'x' moves along neg_tag's lists
             * 'list' moves along sons of neg_tag's lists, building a new list
             * eventually new list is made son of plus_tag
             */

            ASSERT(list == son(x));

            bro(list) = son(bro(x));
            if (!last(x))
            {
              clearlast(list);
              list = bro(list);
              x = bro(x);
            }
            else
            {

              setlast(list);
              bro(list) = sum;          /* set father to be */
              son(sum) = son(son(sum)); /* set new sons of plus_tag */
              break;
            }
          }

          /*
           * create new neg_tag to replace plus_tag,
           * old plus_tag being the operand of the new neg_tag.
           */
          x = getexp(sh(sum), bro(sum), last(sum), sum, nilexp,
                     0, 0, neg_tag);

          setlast(sum);

          /* set father of sum, new neg_tag exp */
          bro(sum) = x;

          /* check father of sum is correct */
          ASSERT(father(son(sum)) ==sum);

          *(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 */

        /* check father set correctly */
        ASSERT(father(son(*e)) ==*e);

        return scan(e, at);

      }                         /* end someneg - else continue to next case */
    }
   case addptr_tag:
    {
      exp p = son(*e);
      exp d = bro(p);
      int fal = frame_al_of_ptr(sh(p));
      if (fal!=0 && i_reckon_its_a_general_proc(fal))
      {
        int oal = frame_al1_of_offset(sh(d));
/*      if( ((oal-1)&oal) != 0)
        {
          fail("can't cope with mixed frame offsets yet");
        }*/
        if (!l_or_cees(oal))
        {
          /* callers are referenced through R_TP */
          /* to get this we use locptr to access through R_FP(current_env)*/
          exp ne = getexp(sh(p), d, 0, p, nilexp, 0, 0,locptr_tag);
          bro(p) = ne; setlast(p);
          son(*e) = ne;
        }
      }
      /* ... and continue */
    }


   case local_free_tag:
   case mult_tag:
   case and_tag:
   case or_tag:
   case xor_tag:
    {
      return commutative_scan(e, at);
    };
   case reff_tag:
   case offset_pad_tag:
   case chvar_tag:
   case locptr_tag:
    {
      exp *arg = &son(*e);

      return maxneeds(scan(arg, at),
                      shapeneeds(sh(*(e))));
    };

  case float_tag:
    {
      needs nds;
      exp *arg = &son(*e);

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

      nds = maxneeds(scan(arg, at), shapeneeds(sh(*(e))));
      nds.fixneeds = max(nds.fixneeds, 2);
      return nds;
    };
   case offset_mult_tag: case offset_div_tag: {
     exp op1 = son(*e);
     exp op2 = bro(op1);
     shape s = sh(op2);
     if (name(op2) ==val_tag  && name(s) ==offsethd
         && al2(s) >= 8) {
       int n = no(op2) /8;
       if (n == 1) {
         /* offset is one  byte */
         bro(op1) = bro(*e);
         if (last(*e)) { setlast(op1); } else {clearlast(op1); }
         *e = op1;
         return(scan(e, at));
       }
       else
         if (name(*e) == offset_mult_tag && n > 1 && (n& (n-1)) == 0)
           if (name(op1) == and_tag
              && name(son(op1)) == shr_tag &&
              name(bro(son(op1))) ==val_tag) {
             exp shexp = son(op1);
             exp ac = bro(shexp);
             exp shop1 = son(shexp);
             exp shop2 = bro(shop1);
             int na = no(ac);
             if ((na& (na+1)) ==0 && name(shop2) ==val_tag) {
               int pn = 0;
               int ns = no(shop2);
               int i = n;
               while (i>1) { i >>= 1; pn++; }

               if (ns > pn)
               {
                 /* can do transform:
                    (((shop1>>ns) & na) * n) =>
                    shop1>>(ns-pn) & (na*n)
                      */
                 no(shop2) = ns-pn;
                 no(ac) = na*n;
                 bro(op1) = bro(*e);
                 if (last(*e))
                 {
                   setlast(op1);
                 }
                 else
                 {
                   clearlast(op1);
                 }
                 *e = op1;
                 return(scan(e, at));
               }
             }
           }
           else
           {
             /* will do this by literal shift */
             no(op2) = n;
             return scan(&son(*e), at);
           }
     }
     return non_commutative_scan(e, at);

   }


   case div0_tag:
   case div1_tag:
   case div2_tag:
   case rem0_tag:
   case mod_tag:
   case rem2_tag:
   case minus_tag:
   case subptr_tag:
   case minptr_tag:
   case offset_div_by_int_tag:
   case max_tag:
   case min_tag:
   case offset_max_tag:
   case component_tag:
   case make_stack_limit_tag:
    {
      return non_commutative_scan(e, at);
    };
   case offset_add_tag:
    {
      exp l = son(*e);
      exp r = bro(l);
      if (name(l) == val_tag)
      {
        sh(l) = sh(r);   /* both offsets will be treated the same */
        son(*e) = r; clearlast(r);
        bro(r) = l; setlast(l); bro(l) = *e;
        /* ... and put val last */
      }
      else
      {
        if (al2(sh(l)) >=8 && al2(sh(r)) <8)
        {
          return non_commutative_scan(e, at);
        }
      }

      setname(*e, plus_tag);

      return commutative_scan(e,at);
    }
   case offset_subtract_tag: {
        exp l = son(*e);
        exp r = bro(l);
        if (name(r) ==val_tag) {
                sh(r) = sh(l);   /* both offsets will be treated the same */
        }
        else
        if (al2(sh(r)) >=8 && al2(sh(l)) <8) {
                return non_commutative_scan(e, at);
        }

        setname(*e, minus_tag);
        return non_commutative_scan(e, at);
    }

  case fdiv_tag:
  case fplus_tag:
  case fminus_tag:
  case fmult_tag:
    {
      exp op = *(e);
      exp a2 = bro(son(op));

      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 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))));
    };

/*********************************************************************
        load_proc


number is number of proc (useful for indexing)
*********************************************************************/
   case proc_tag:
   case general_proc_tag:
    {
      exp *bexp;
      exp *bat;
      needs body;

      exp_num = 0;
      callee_size = 0;
      max_callees = -1;
      no_of_returns = 0;
      maxfix = maxfix_tregs;
      maxfloat = MAXFLT_TREGS;
      stparam = 0;
      fixparam = R_FIRST_PARAM;
      floatparam = FR_FIRST_PARAM;

      /* Parameter allocation t-regs */
      freefixed = PROC_TREGS;
      freefloat = PROC_FLT_TREGS;

      if (name(*e) ==general_proc_tag)
      {
        end_param = GENERAL_PROC_PARAM_REGS + R_FIRST_PARAM - 1;
      }
      else
      {
        end_param = PROC_PARAM_REGS + R_FIRST_PARAM - 1;
      }

      nonevis = 1;
      gen_call = 0;
      tail_call = 0;
      bexp = &son(*e);
      bat = bexp;
      body = scan(bexp, &bat);
#ifdef DO_DYNAMIC_INITIALISATION
      if (proc_is_main(*e))
      {
        /* we need a call to __main */
        body.propsneeds |= usesproccall;
      }
#endif
      return body;
    }
/********************************************************************
 |  TDF SPECIFICATION 4.0 ADDITIONS       |
 ******************************************
 The new tags introduced for the move from spec 3.0 to spec 4.0 are
 general_proc
 apply_general
 make_callee_list
 make_dynamic_callee
 tail_call
 same_callees
 untidy_return
 set_stack_limit
 env_size
 general_env_offset
 caller_name
 formal_callee
 caller
********************************************************************/
   case apply_general_tag:
    {
      exp application = *(e);
      exp *fn = &son(application);
      exp cers = bro(*fn);
      exp *cerl = &son(cers);
      long stpar = 0;
      needs nds;
      needs plnds;
      int i;

      gen_call = 1;

      /* scan the function */
      nds = scan(fn, at);

      if ((nds.propsneeds & hasproccall)!= 0)
      {
        /* .... it must be identified */
        cca(at, fn);
        nds.propsneeds &= ~hasproccall;
        nds.propsneeds |= usesproccall;
        fn = &son(application);
      }
      /* scan the callers */
      for (i=0; i<no(cers); i++)
      {
        needs onepar;
        shape shonepar = sh(*cerl);
        exp * par = (name(*cerl) ==caller_tag)?&son(*cerl):cerl;
        int n = ALIGNNEXT(stpar, shape_align(shonepar));
        onepar = scan(par,at);
        if ((i != 0 && (onepar.propsneeds & hasproccall)!= 0) ||
            onepar.fixneeds+ (stpar>>5) > maxfix)
        {
          /* +++ if we go over a certain number of param regs
             they are forced to be on the stack so stpar>>5
             is not the best estimate ,but sufficient*/
          /* stpar>>5 is the no of param regs used so far */
          /* if it isn't the first parameter, and it
             calls a proc, identify it */
          /* it is ok for first param to have a proccall since we have
             no loaded parameters to corrupt */
          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)
        {
          /* for caller_tag's we record where it will live */
          no(*cerl) = n;
          clear_coded_caller(*cerl);
        }
        n = n + shape_size(shonepar);
        stpar = ALIGNNEXT(n,32);
        cerl = &bro(*cerl);
      }
      nds.maxargs = max(nds.maxargs, stpar);
      /* scan the callees */
      nds = maxneeds(scan(&bro(bro(son(application))), at), nds);
      /* scan the postlude */
      plnds = scan(&bro(bro(bro(son(application)))), at);
      if (plnds.propsneeds & anyproccall)
      {
        props(application) =1;
        if (is_floating(name(sh(application))) || valregable(sh(application)))
        {
          cca(at, ptr_position(application));
          plnds.propsneeds |= usesproccall;
        }
      }
      else
      {
        props(application) =0;
        if (is_floating(name(sh(application))) || valregable(sh(application)))
        {
          cca(at, ptr_position(application));
        }
      }
      nds = maxneeds(nds, plnds);
      nds.propsneeds |= hasproccall;
      return nds;
    }
/********************************************************************/
   case make_callee_list_tag:
    {
      exp cees = *e;
      exp *par = &son(cees);
      needs nds;
      long stpar = 0;
      int i;
      nds = zeroneeds;
      for (i=0;i<no(cees);i++)
      {
        /* scan each callee and identify if necessary */
        needs onepar;
        shape shonepar = sh(*par);
        int n = ALIGNNEXT(stpar,shape_align(shonepar));
        onepar = scan(par,at);
        if ((onepar.propsneeds & hasproccall)!=0 || onepar.fixneeds+1>maxfix)
        {
          /* if 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);
        }
        n += shape_size(shonepar);
        stpar = ALIGNNEXT(n,32);
        par = &bro(*par);
      }
      no(cees)=stpar; /* The total no of bits needed for callees */
      max_callees = max(max_callees, stpar);
      return nds;
    }

/********************************************************************/
   case make_dynamic_callee_tag:
    {
      exp cees = *e;
      exp *ptr = &son(cees);
      needs ndsp;
      needs nds;
      nds = zeroneeds;
      ndsp = scan(ptr, at);
      if (((ndsp.propsneeds & hasproccall)!= 0) ||
          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)!= 0) ||
          ndsp.fixneeds+2 > maxfix)
      {
        cca(at, &bro(son(cees)));
        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 tail_call_tag:
    {
      needs ndsp;
      needs nds;
      exp *fn = &son(*e);
      ndsp = scan(fn,at);
      tail_call = 1;
      if (((ndsp.propsneeds & hasproccall)!=0) || 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 same_callees_tag:
    {
      needs nds;
      nds = zeroneeds;
      nds.fixneeds = 4;
      max_callees = max(max_callees, callee_size);
      return nds;
    }
/********************************************************************/
   case env_size_tag:
   case set_stack_limit_tag:
   case return_to_label_tag:
    {
      exp *arg = &son(*e);
      return scan(arg,at);
    }
/********************************************************************/
   case general_env_offset_tag:
   case caller_name_tag:
    {
      return shapeneeds(sh(*e));
    }
/********************************************************************/
   case formal_callee_tag:
    {
      return zeroneeds;
    }
/********************************************************************/
   case caller_tag:
    {
      fail("Shouldn't be scanning a caller_tag");
      return zeroneeds;
    }
/********************************************************************/
   default:
    {
      FULLCOMMENT1("scan: bad nstare=%d", nstare);
      fail("case not covered in needs scan");
      return zeroneeds;
    }
  }
}
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)]);
      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;
}
static void number_caller_parameter(exp param_id)
{
  exp init_exp = son(param_id);
  shape param_shape = sh(init_exp);
  long par_size = shape_size(param_shape);
  long par_stack_location = ALIGNNEXT(stparam,32);

  ASSERT(name(init_exp) ==clear_tag);

  if (is_floating(name(param_shape)))
  {
    if (floatparam <= FR_LAST_PARAM)
    {
      props(init_exp) = floatparam;
      floatparam++;
    }
    else
    {
      props(init_exp) = 0;/*passed by stack */
    }
  }
  else
  {
    if (fixparam <= end_param)
    {
      props(init_exp) = fixparam;
    }
    else
    {
      props(init_exp) = 0;/*passed by stack*/
    }
  }
  no(init_exp) = par_stack_location;
  stparam = ALIGNNEXT(par_stack_location + par_size, 32);
  fixparam = R_FIRST_PARAM + (stparam / 32);
  return;
}


static void number_callee_parameter(exp callee_id)
{
  exp def = son(callee_id);
  shape callee_shape = sh(def);
  long size_of_callee = shape_size(callee_shape);
  long alignment_of_callee = shape_align(callee_shape);
  long n = ALIGNNEXT(callee_size , alignment_of_callee);

  no(def) = n;
  callee_size = ALIGNNEXT(n + size_of_callee , 32);
  return;
}