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$
 */
/*
                 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: pwe $
$Date: 1998/03/11 11:03:20 $
$Revision: 1.4 $
$Log: check_id.c,v $
 * Revision 1.4  1998/03/11  11:03:20  pwe
 * DWARF optimisation info
 *
 * Revision 1.3  1998/02/18  11:22:09  pwe
 * test corrections
 *
 * Revision 1.2  1998/02/11  16:56:38  pwe
 * corrections
 *
 * Revision 1.1.1.1  1998/01/17  15:55:46  release
 * First version to be checked into rolling release.
 *
 * Revision 1.14  1998/01/09  09:28:35  pwe
 * prep restructure
 *
 * Revision 1.13  1997/06/02  08:44:17  currie
 * diags visible
 *
 * Revision 1.12  1997/03/20  17:05:10  currie
 * Dwarf2 diags
 *
Revision 1.11  1997/02/18 12:56:21  currie
NEW DIAG STRUCTURE

 * Revision 1.10  1995/10/19  12:11:23  currie
 * compound_tag
 *
 * Revision 1.9  1995/10/17  16:33:53  currie
 * Misplace {
 *
 * Revision 1.8  1995/10/17  12:59:28  currie
 * Power tests + case + diags
 *
 * Revision 1.7  1995/10/13  15:15:03  currie
 * case + long ints on alpha
 *
 * Revision 1.6  1995/10/06  14:41:55  currie
 * Env-offset alignments + new div with ET
 *
 * Revision 1.5  1995/10/04  09:17:27  currie
 * CR95_371 + optimise compounds
 *
 * Revision 1.4  1995/08/31  14:18:58  currie
 * mjg mods
 *
 * Revision 1.3  1995/08/29  10:45:45  currie
 * Various
 *
 * Revision 1.2  1995/06/15  08:42:07  currie
 * make_label + check repbtseq
 *
 * Revision 1.1  1995/04/06  10:44:05  currie
 * Initial revision
 *
***********************************************************************/




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

                        check_id.c

   check_id tries to apply transformations to improve identity and
   variable declarations.

   check_id delivers 1 if it makes any change, 0 otherwise.

   used_in delivers 0 if the identifier declared by vardec is unused in
   the exp piece, 1 if it is used for contents operation only, 3 if it is
   used otherwise.

   simple_const tests whether e is used as a simple constant in whole.
   This is true in the following circumstances only.
   1) e is a constant.
   2) e is an identity declaration(not a variable) and the declaration is
      external to whole.
   3) e is the contents of a variable, and the variable is not used
      in whole as the destination of an assignment, and the variable
      is only used (anywhere) as the destination of assignment or
      argument of contents (ie there is no alias for it).

   no_ass is true iff there are no assignments to things that might
   be aliased during the evaluation of whole. (beware procedure calls!)

 ********************************************************************/
#include "config.h"
#include "common_types.h"
#include "exp.h"
#include "expmacs.h"
#include "shapemacs.h"
#include "check.h"
#include "tags.h"
#include "externs.h"
#include "installglob.h"
#include "flags.h"
#include "install_fns.h"
#include "me_fns.h"
#ifdef NEWDIAGS
#include "dg_aux.h"
#endif

#include "check_id.h"

#if is68000
extern int check_anyway(exp);
#endif

/* PROCEDURES */

/*********************************************************************
   make_onearg makes up an exp with the given tag (n), shape (sha)
   and single argument (a).
 *********************************************************************/

exp
hc(exp e, exp t)
{
        setlast(t);
        bro(t) = e;
        return hold_check(e);
}


static exp
make_onearg(unsigned char n, shape sha, exp a)
{
        exp r = getexp(sha, nilexp, 0, a, nilexp, 0, 0, n);
        return(hc(r, a));
}


/*********************************************************************
   make_twoarg makes up an exp with the given tag (n), shape (sha)
   and two arguments (a,b) in that order.
 *********************************************************************/

static exp
make_twoarg(unsigned char n, shape sha, exp a, exp b)
{
        exp r = getexp(sha, nilexp, 0, a, nilexp, 0, 0, n);
        bro(a) = b;
        clearlast(a);
        return(hc(r, b));
}


/************************************************************************
   used_in delivers 0 if the identifier declared by vardec is unused in
   the exp piece, 1 if it is used for contents operation only, 3 if it is
   used otherwise.
 ************************************************************************/

int
used_in(exp vardec, exp piece)
{
        int  res = 0;
        exp t = pt(vardec);
        exp q;
        exp upwards = t;
        /* test each use of the identifier */
        do {
                q = t;
                while (q != nilexp && q != piece && q != vardec &&
                       !parked(q) && (name(q) != ident_tag || !isglob(q))) {
                        upwards = q;
                        q = bro(q);
                }
                /* ascend from the use until we reach either vardec or piece */
                if (last (upwards) && q == piece) {
                        /* the use was in piece */
                        res = 1;
                        if ((last(t) || !last(bro(t)) ||
                             name(bro(bro(t))) != 0)) {
                                /* the use was not contents or in diagnostics*/
                                if (!last(t) || name(bro(t)) != cont_tag) {
                                        res = 3;
                                }
                        }
                }
                t = pt(t);
        } while (t != nilexp && res != 3);
        return(res);
}


/***********************************************************************
  simple_const tests whether e is used as a simple constant in whole.
  This is true in the following circumstances only.
  1) e is a constant.
  2) e is an identity declaration(not a variable) and the declaration is
     external to whole.
  3) e is the contents of a variable, and the variable is not used
     in whole as the destination of an assignment, and the variable
     is only used (anywhere) as the destination of assignment or
     argument of contents (ie there is no alias for it).

  no_ass is true iff there are no assignements to things that might
  be aliased during the evaluation of whole. (ware procedure calls!)
 ***********************************************************************/

int
simple_const(exp whole, exp e, int decl, int no_ass)
{
        if (name(e) == val_tag || name(e) == real_tag || name(e) == null_tag) {
                return(1);
        }
        if (name(e) == name_tag && !isvar(son(e)) &&
            (decl || !internal_to(whole, son(e)))) {
                return(1);
        }
        if (name(e) == reff_tag) {
                e = son(e);
        }
        if (name(e) == cont_tag && name(son(e)) == name_tag &&
            !isparam(son(son(e))) && isvar(son(son(e)))) {
                exp var = son(son(e));
                int  u = used_in(var, whole);
                if (u != 3 && (iscaonly(var) || no_ass)) {
                        return(1);
                }
                return(0);
        }
        return(0);
}


/* replace declaration by sequence of definition and body. Done if the
 * identifier is not used. */
static void
repbyseq(exp e)
{
        exp def = son(e);
        exp body = hold_check(bro(def));
        exp seq, s;
#ifdef NEWDIAGS
        exp t = pt(e);
        while (t != nilexp) {
                if (isdiaginfo(t))
                        setdiscarded(t);
                t = pt(t);
        }
#endif
        if (son(def) == nilexp) {
#ifdef NEWDIAGS
                if (diagnose) {
                        dg_whole_comp(e, body);
                }
#endif
                replace(e, body, e);
                retcell(def);
                return;
        }
        seq = getexp(f_bottom, nilexp, 0, def, nilexp, 0, 0, 0);
        bro(def) = seq;
        setlast(def);
        s = hold_check(make_twoarg(seq_tag, sh(body), seq, body));
#ifdef NEWDIAGS
        if (diagnose) {
                dg_whole_comp(e, s);
        }
#endif
        replace(e, s, e);
        return;
}


/************************************************************************
   propagate looks right and upwards from plc through the tree, looking
   for contents operations applied to the variable defined by vardec.
   The assumption is that plc made an assignment to the variable defined
   by vardec, and this scan looks forward from this point, marking any
   contents operations on that variable for later modification to use the
   value assigned. The variable is previously checked to make
   sure there is no alias for it.
   The scan terminates if ende is reached or when it is no longer safe
   to propagate the value forward. 1 is delivered if ende was reached
   while propagation was still safe, 0 otherwise.
 ************************************************************************/

static int
propagate(exp vardec, exp ende, exp plc, int bfirst)
{
        exp p = plc;            /* starting place */
        int good = 1;           /* good is set to 0 when we find a place
                                   where we must stop */
        int bb = bfirst;        /* if bb is 1, avoid the first up */


        /* up ascends the tree */
up:     if (bb) {
                bb = 0;
        } else {
                if (p == ende) {                /* finished */
                        goto ex;
                } else {
                        if (!last(p)) {
                                p = bro(p);
                                if (name(p) == labst_tag) {
                                        /* can't go further */
                                        good = 0;
                                        goto ex;
                                }
                        } else {
                                if (name(bro(p)) == proc_tag ||
                                    name(bro(p)) == labst_tag ||
                                    name(bro(p)) == condassign_tag) {
                                        /* can't go further */
                                        good = 0;
                                        goto ex;
                                } else {
                                        p = bro(p);
                                        if ((name(p) == ass_tag ||
                                             name(p) == assvol_tag) &&
                                            name(son(p)) == name_tag &&
                                            son(son(p)) == vardec) {
                                                good = 0;
                                                goto ex;
                                        }
                                        goto up;
                                }
                        }
                }
        }

        /* rep processes an exp */
rep:    if (name(p) == ass_tag || name(p) == assvol_tag) {
                if (name(son(p)) == name_tag && son(son(p)) == vardec) {
                        /* just process the value */
                        p = bro(son(p));
                        goto rep;
                } else {
                        /* assignment to something else */
                        p = son(p);
                        goto rep;
                }
        }

        if (name(p) == cont_tag) {
                if (name(son(p)) == name_tag && son(son(p)) == vardec) {
                        set_propagate(p);               /* mark it */
                        goto up;
                } else {
                        p = son(p);
                        goto rep;
                }
        }

        if (name(p) == name_tag || name(p) == env_offset_tag) {
                goto up;
        }

        if (name(p) == apply_tag || name(p) == apply_general_tag) {
                if (isglob(vardec)) {
                        /* vardec is global */
                        good = 0;
                        goto ex;
                } else {
                        /* not aliased so OK */
                        p = son(p);
                        goto rep;
                }
        }

        if (name(p) == rep_tag) {
                good = 0;
                goto ex;
        }

        if (name(p) == cond_tag) {
                if (propagate(vardec, son(p), son(p), 1)) {
                        good = propagate(vardec, bro(son(bro(son(p)))),
                                         bro(son(bro(son(p)))), 1);
                        /* if we can propagate right through the first of the
                         * cond we can go into the alt. This condition is
                         * stronger than needed. */
                        if (good) {
                                goto up;
                        } else {
                                goto ex;
                        }
                } else {
                        good = 0;
                        goto ex;
                }
        }

        if (name(p) == solve_tag) {
                IGNORE propagate(vardec, son(p), son(p), 1);
                /* give up after trying the first element */
                good = 0;
                goto ex;
        }

        if (name(p) == case_tag) {
                if (propagate(vardec, son(p), son(p), 1)) {
                        goto up;
                }
                good = 0;
                goto ex;
        }

        if (son(p) == nilexp) {
                goto up;
        }

        p = son(p);
        goto rep;


ex:     return(good);
}


/*******************************************************************
   change_cont looks at all the cont uses of the variable defined by
   vardec. If they have been marked by propagate or if force is 1,
   the cont(var) is replaced by val.
 *******************************************************************/

static exp
change_shape(exp e, shape sha)
{
        if (name(e) == val_tag) {
                no(e) = dochvar(no(e), sha);
        }
        sh(e) = sha;
        return(e);
}


static int
change_cont(exp vardec, exp val, int force)
{
        exp t;
        exp bh = hold(bro(son(vardec)));
        int ch = 0;
        int go = 1;
        int defsize = shape_size(sh(son(vardec)));
        while (go) {
                t = pt(vardec);
                go = 0;
                while (!go && t != nilexp) {
                        if (last(t) && name(bro(t)) == cont_tag &&
#ifdef NEWDIAGS
                            !isdiaginfo(t) &&
#endif
                            (to_propagate(bro(t)) || force)) {
                                if (defsize == shape_size(sh(bro(t)))) {
                                        exp p = bro(t);
                                        exp c = change_shape(copy(val), sh(p));
                                        kill_exp(t, son(bh));
                                        replace(p, c, son(bh));
                                        retcell(p);
                                        t = pt(vardec);
                                        ch = 1;
                                        go = 1;
                                } else {
                                        clear_propagate(bro(t));
                                }
                        } else {
                                t = pt(t);
                        }
                }
        }
        bro(son(vardec)) = son(bh);
        setlast(bro(son(vardec)));
        bro(bro(son(vardec))) = vardec;
        retcell(bh);
        return(ch);
}


/*********************************************************************
   checks identity and variable declarations.
 *********************************************************************/

int
check_id(exp e, exp scope)
{
  int is_var = isvar(e);
  int is_vis = (all_variables_visible || isvis(e));
  exp def = son(e);
  exp body = bro(def);
  int looping;
  exp t1;

  if (no(e) == 0) {
    if (!isvis(e) && !isenvoff(e) && !isglob(e) && !isparam(e)) {
      /* the variable is not used */
      repbyseq(e);
      return(1);
    } else {
      if (isparam(e)) {
        setcaonly(e);
      }
      return 0;
    }
  }


#if load_ptr_pars
  if (!is_vis && is_var && isparam(e) && no(e) > 1 && name(sh(def)) == ptrhd
#if is68000
      && check_anyway(e)
#endif
     ) {
    int ch_load = 1;
    int sz = shape_size(sh(def));
    t1 = pt(e);
    looping = 1;
    do {
#ifdef NEWDIAGS
      if (!isdiaginfo(t1)) {
#endif

        if (!last(t1) && last(bro(t1)) && name(bro(bro(t1))) == ass_tag &&
            shape_size(sh(bro(t1))) == sz) {
          ;
        } else if (!last(t1) || name(bro(t1)) != cont_tag ||
                   shape_size(sh(bro(t1))) != sz) {
          ch_load = 0;
        }

#ifdef NEWDIAGS
      }
#endif
      if (pt(t1) == nilexp) {
        looping = 0;
      } else {
        t1 = pt(t1);
      }
    } while (looping && ch_load);

    if (ch_load) {
      exp old_pt_list = pt(e);
      int old_uses = no(e);
      exp new_var;
      exp new_n;
      exp real_body;

      t1 = e;
      while (name(bro(son(t1))) == ident_tag && isparam(bro(son(t1)))) {
        t1 = bro(son(t1));
      }
      real_body = bro(son(t1));

      new_n = getexp(sh(def), real_body, 0, e, nilexp, 0, 0, name_tag);
      new_var = getexp(sh(e), nilexp, 0, new_n, old_pt_list, 1, old_uses,
                       ident_tag);
      setloadparam(new_n);
      setfather(new_var, real_body);
      pt(e) = new_n;
      no(e) = 1;
      clearvar(e);
      while (old_pt_list != nilexp) {
        son(old_pt_list) = new_var;
        old_pt_list = pt(old_pt_list);
      }
      new_var = hold_check(new_var);

      bro(son(t1)) = new_var;
      setfather(t1, new_var);
      return 1;
    }
  }
#endif

  if (!is_vis && !is_var &&
#if load_ptr_pars
      (name(def) != name_tag || !isloadparam(def)) &&
#endif
      (name(def) == val_tag ||
#if load_ptr_pars
       (name(def) == name_tag &&
        (!isparam(son(def)) || name(sh(def)) == ptrhd))
#else
       name(def) == name_tag
#endif
       ||
#if is80x86
       (name(def) == name_tag && isparam(son(def)) && !isvar(son(def)) &&
        shape_size(sh(def)) < shape_size(sh(son(son(def)))) &&
        name(sh(def)) <= ulonghd) ||
#endif

       /* substitute the definitions of identity declarations into body
        * if it seems cheaper to do so */
       (name(def) == reff_tag && name(son(def)) == cont_tag &&
        name(son(son(def))) == name_tag && isvar(son(son(son(def)))) &&
        !isglob(son(son(son(def)))) &&
        used_in(son(son(son(def))), body) != 3) ||
       (name(def) == reff_tag && name(son(def)) == name_tag &&
        isvar(son(son(def))) && !isglob(son(son(def))) &&
        used_in(son(son(def)), body) != 3) || name(def) == null_tag ||
       name(def) == real_tag)) {
         /* identifying a constant or named value */
#if !substitute_params
    int do_anyway = 0;
#else
    int do_anyway = 1;
#endif
    if (do_anyway || name(def) != name_tag || !isparam(son(def)) ||
        isvar(son(def))) {
      exp bh = hold(body);
#ifdef NEWDIAGS
      dg_info dgh = dgf(def);
      /* don't copy line info to all uses */
      dgf(def) = nildiag;
#endif
      while (pt(e) != nilexp) {
        exp mem = pt(e);
        exp cp;
        pt(e) = pt(mem);
        cp = copy(def);
#ifdef NEWDIAGS
        if (isdiaginfo(mem)) {
          IGNORE diaginfo_exp(cp);
        } else {
          --no(e);
        }
#else
        --no(e);
#endif
        if (name(cp) == name_tag) {
          no(cp) += no(mem);
        }
        if (sh(cp) != sh(mem)) {
          if (name(sh(cp)) <= u64hd) {
            cp = hold_check(me_u3(sh(mem), cp, chvar_tag));
          } else {
            sh(cp) = sh(mem);
          }
        }
#ifdef NEWDIAGS
        if (diagnose) {
          dg_whole_comp(mem, cp);
        }
#endif
        replace(mem, cp, body);
      }
#ifdef NEWDIAGS
      dgf(def) = dgh;
#endif
      bro(def) = son(bh);
      bro(bro(def)) = e;
      setlast(bro(def));
      retcell(bh);
      IGNORE check(e, scope);
      return(1);
    }
  }

  if (!is_vis && !is_var && name(def) == reff_tag && al1(sh(def)) == 1) {
    /* also substitute identity definitions which are references
       to bitfields. */
    exp t = pt(e);
    int n = no(def);
    shape sha = sh(def);
    shape shb = sh(son(def));
    exp q, k;

#ifdef NEWDIAGS
    if (diagnose) {
      dg_whole_comp(def, son(def));
    }
#endif
    replace(def, son(def), son(def));

    while (1) {
      k = pt(t);
      q = getexp(sha, nilexp, 0, copy(t), nilexp, 0, n, reff_tag);
      sh(son(q)) = shb;
      q = hc(q, son(q));
      replace(t, q, q);
      kill_exp(t, t);
      if (k == nilexp) {
        return 1;
      }
      t = k;
    }
  }

  if (!is_vis && !is_var && name(def) == string_tag) {
    /* and substitute strings */
    exp t = pt(e);
    int all_chars = 1;
    while (1) {
      if (name(sh(t)) > ucharhd) {
        all_chars = 0;
        break;
      }
      if (last (t)) {
        /* Surely this is wrong ??? */
        break;
      }
      t = pt(t);
    }
    if (all_chars) {
      char *str = nostr(def);

      t = pt(e);
      while (1) {
        /* Surely this is wrong ??? */
        int l = (int)last (t);

        exp n = bro(t);
        int  v = str[no(t) / 8];
        exp c;
        if (name(sh(t)) == ucharhd) {
          v = v & 0xff;
        }
        c = getexp(sh(t), nilexp, 0, nilexp, nilexp, 0,
                   v, val_tag);
        replace(t, c, c);
        kill_exp(t, t);
        if (l) {
          break;
        }
        t = n;
      }
      if (no(e) == 0) {
        replace(e, bro(son(e)), scope);
        return(1);
      }
      return(0);
    }
  }

  if (!is_vis && !is_var && name(body) == seq_tag &&
      name(son(son(body))) == ass_tag && name(bro(son(body))) == name_tag) {
    exp tb = bro(son(son(son(body))));
    if (name(tb) == name_tag && son(tb) == e &&
        son(bro(son(body))) == e && last(son(son(body))) &&
        sh(tb) == sh(def) && sh(tb) == sh(bro(son(body)))) {
      /*  e=id(def, seq(ass(tz, n(e)), n(e)) -> seq(ass(tz,
       *  def), cont(tz)) */
      exp ass = son(son(body));
      exp tz = son(ass);
      exp r, s, c;
      exp cz = copy(tz);
      bro(tz) = def;
      ass = hc(ass, def);
      r = getexp(f_top, nilexp, 0, ass, nilexp, 0, 0, 0);
      setlast(ass);
      bro(ass) = r;
      s = getexp(sh(body), nilexp, 0, r, nilexp, 0, 0, seq_tag);
      c = getexp(sh(body), s, 1, cz, nilexp, 0, 0, cont_tag);
      setbro(r, hc(c, cz));
      replace(e, hc(s, bro(son(s))), e);
      return(1);
    }
  }

  /* look to see if we can replace variable definitions by identities.
     This can be done if there are only contents operations and no
     aliasing */
  if (!is_vis && is_var) {
    /* variable declaration */
    int all_c = 1;      /* every use is a contents operation */
    int all_a = 1;      /* every use is an assignment operation */
    int not_aliased = 1;
    int ca = 0;         /* there is an assignment of a constant */
    int vardecass = 0;  /* there is an assignment of a variable
                           (not its contents) (lhvalue in C
                           terms). */
    exp assd_val;       /* the assigned value */
    int conversion = 0;
    int biggest_assigned_const = 0;
    exp tc = pt(e);
    int defsize = shape_size(sh(def));
    do {
      /* scan the uses of the variable */
      if (last(tc) && (name(bro(tc)) == hold_tag ||
                       name(bro(tc)) == hold2_tag)) {
#ifdef NEWDIAGS
        if (diag_visible) {
#else
        if (diagnose) {
#endif
          setvis(e);
          return 0;
        }
      } else {
        if (last(tc) && name(bro(tc)) == cont_tag && no(tc) == 0 &&
#ifdef NEWDIAGS
            !isdiaginfo(tc) &&
#endif
            (name(sh(bro(tc))) <shrealhd || name(sh(bro(tc))) >doublehd ||
             (name(sh(def)) >= shrealhd && name(sh(def)) <= doublehd))) {
          int qq = shape_size(sh(bro(tc)));
          /* contents op so not all
           * assignments */
          all_a = 0;

          if (name(father(bro(tc))) != test_tag) {
            conversion = -1;
          }
          if ((defsize != qq) && (name(sh(def)) < shrealhd)) {
#if is80x86
            if (!isparam(e) || no(e) != 1) {
              if (no(tc) == 0 && defsize <= 32) {
                if (qq == 8) {
                  setbyteuse(e);
                }
              } else {
                all_c = 0;
                not_aliased = 0;
              }
            }
#else
            all_c = 0;
            not_aliased = 0;
#endif
          }
        } else {
          if (!last(tc) && last(bro(tc)) && no(tc) == 0 &&
#ifdef NEWDIAGS
              !isdiaginfo(tc) &&
#endif
              name(bro(bro(tc))) == ass_tag) {
            /* assignment op */
            all_c = 0;          /* not all contents */
            assd_val = bro(tc);

            if (name(assd_val) == val_tag) {
              if (no(assd_val) < 0) {
                conversion = -1;
              }
              if (no(assd_val) > biggest_assigned_const) {
                biggest_assigned_const = no(assd_val);
              }
            } else if (name(assd_val) == chvar_tag &&
                       name(sh(son(assd_val))) <= uwordhd &&
                       is_signed(sh(son(assd_val)))) {
              int sz1 = shape_size(sh(son(assd_val)));
              if (conversion == 0) {
                conversion = sz1;
              } else if (conversion != sz1) {
                conversion = -1;
              }
            } else {
              conversion = -1;
            }

            if (defsize != shape_size(sh(assd_val))) {
#if is80x86
              if (no(tc) == 0 && defsize <= 32) {
                if (shape_size(sh(bro(tc))) == 8) {
                  setbyteuse(e);
                }
              } else {
                all_a = 0;
                not_aliased = 0;
              }
#else
              all_a = 0;
              not_aliased = 0;
#endif
            }
            if (name(assd_val) == val_tag || name(assd_val) == real_tag ||
                name(assd_val) == null_tag ||
                (name(assd_val) == name_tag && isglob(son(assd_val)))) {
              ca = 1;           /* assigning a constant */
            } else {
              if (name(assd_val) == ident_tag && isvar(assd_val)) {
                vardecass = 1;
              }
            }
          } else
#ifdef NEWDIAGS
                  if (!isdiaginfo(tc))
#endif
                  {
                    if (isreallyass(tc)) {
                      all_c = 0;
                      all_a = 0; /* so that we dont remove the proc call */
                    } else {
                      /* something else */
                      exp dad = father(tc);
                      all_c = 0;
                      all_a = 0;
                      if (!((name(dad) == addptr_tag ||
                             name(dad) == subptr_tag) &&
                            ((!last(dad) && last(bro(dad)) &&
                              name(bro(bro(dad))) == ass_tag) ||
                             (last(dad) && name(bro(dad)) == cont_tag))) ||
                          (name(sh(def)) == realhd &&
                           name(sh(bro(dad))) != realhd) ||
                          (name(sh(def)) == doublehd &&
                           name(sh(bro(dad))) != doublehd)) {
                        /* not an assignment to element of array */
                        not_aliased = 0;
                      } else {
                        setvis(e);
                        uses_loc_address = 1;
                      }
                    }
                  }
        }
        }
        tc = pt(tc);
      } while (tc != nilexp);

      if (not_aliased || iscaonly(e)) {
        /* set no alias flag if nothing but cont and ass */
        setcaonly (e);
      } else {
        /* set visible flag if there is an alias */
        setvis (e);
        uses_loc_address = 1;
      }

      if (all_c) {
        /* if only cont operations replace by an identity declaration and
         * change the uses accordingly */
        exp bh = hold(body);
        int i, j;
        setid(e);
        tc = e;
        do {
          tc = pt(tc);
          if (name(bro(tc)) == cont_tag) {
            sh(tc) = sh(bro(tc));
#ifdef NEWDIAGS
            if (diagnose) {
              dg_whole_comp(bro(tc), tc);
            }
#endif
            replace(bro(tc), tc, tc);
          }
        } while (pt(tc) != nilexp);

        if (no(e) < 100) {
          for (i = 0; i < no(e); ++i) {
            tc = e;
            for (j = 0; tc != nilexp && j <= i; ++j) {
              tc = pt(tc);
#ifdef NEWDIAGS
              while (tc != nilexp && isdiaginfo(tc))
                tc = pt(tc);
#endif
            }
            altered(tc, son(bh));
          }
        }

        bro(def) = son(bh);
        bro(bro(def)) = e;
        setlast(bro(def));
        retcell(bh);
        IGNORE check(e, scope);
        return(1);
      }

#if is80x86 || ishppa
      /* look for places where we can avoid sign extending */
      if (not_aliased && name(sh(def)) == slonghd &&
          conversion == 16 && /* not 8 because of 80x86 regs */
          (biggest_assigned_const & ((conversion == 8) ? (int)0xffffff80 :
                                     (int)0xffff8000)) == 0 &&
          name(def) == clear_tag) {
        exp temp = pt(e);
        shape ish = (conversion == 8) ? scharsh : swordsh;
        setse_opt(e);
        while (temp != nilexp) {
          exp next = pt(temp);
          if (last(temp)) {
            if ((last(bro(temp)) || name(bro(bro(temp))) != val_tag) &&
                name(bro(temp)) != hold_tag) {
              exp x = me_u3(slongsh, copy(bro(temp)), chvar_tag);
              sh(son(x)) = ish;
              replace(bro(temp), x, x);
              IGNORE check(father(x), father(x));
              kill_exp(bro(temp), bro(temp));
            }
          } else {
            if (name(bro(temp)) == val_tag) {
              sh(bro(temp)) = ish;
            } else {
              bro(son(bro(temp))) = bro(bro(temp));
              bro(temp) = son(bro(temp));
#if ishppa
              sh(bro(temp)) = (conversion == 8) ? ucharsh : uwordsh;
#endif
            }
          }
          temp = next;
        }
        replace(def, me_shint(slongsh, 0), def);
      }
#endif

      if (not_aliased && no(e) < 1000 &&
          (name(sh(def)) < shrealhd || name(sh(def)) > doublehd) &&
          (ca || vardecass || name(def) == val_tag ||
           name(son(e)) == real_tag || name(def) == null_tag)) {
        /* propagate constant assignment forward from the place where they
           occur */
        int  no_ass;
        int chv;
        if (name(def) == val_tag || name(son(e)) == real_tag ||
            name(def) == null_tag
            /*
               ||
               (name(def) == name_tag &&
               isglob (son(def)))
             */
           ) {
          do {
            body = bro(def);
            IGNORE propagate(e, e, body, 1);
          } while (change_cont(e, def, 0));
        }
        body = bro(def);

        do {
          chv = 0;
          no_ass = 0;
          tc = pt(e);
          while (!chv && tc != nilexp) {
            if (!last(tc) &&
#ifdef NEWDIAGS
                !isdiaginfo(tc) &&
#endif
                sh(bro(tc)) == sh(son(son(tc))) && last(bro(tc)) &&
                name(bro(bro(tc))) == ass_tag) {
              exp var = bro(tc);
              exp va, df, bd;
              if (eq_shape(sh(bro(tc)), sh(son(e))) &&
                  (name(bro(tc)) == val_tag || name(bro(tc)) == real_tag ||
                   name(bro(tc)) == null_tag
                   /*
                      ||
                      (name(bro(tc)) == name_tag &&
                      isglob (son(bro(tc))))
                    */
                  )) {
                IGNORE propagate(e, e, bro(bro(tc)), 0);
                chv = change_cont(e, bro(tc), 0);
                body = bro(def);
                ++no_ass;
              } else {
                va = son(tc);
                df = son(var);

                if (df != nilexp && (bd = bro(df)) != nilexp &&
                    !isinlined(e) && !isglob(va) && isvar(va) &&
                    name(bd) == seq_tag && name(bro(son(bd))) == cont_tag &&
                    name(son(bro(son(bd)))) == name_tag &&
                    son(son(bro(son(bd)))) == var &&
                    isvar(var) && used_in(va, bd) == 0) {
                  exp a = son(bro(var));
                  exp prev_uses, ass, seq_hold, s;
                  kill_exp(bro(son(bd)), body);
                  prev_uses = pt(va);
                  tc = var;
                  pt(va) = pt(var);
                  do {
                    son(pt(tc)) = va;
                    ++no(va);
                    tc = pt(tc);
                  } while (pt(tc) != nilexp);
                  pt(tc) = prev_uses;

                  if (name(df) == clear_tag) {
                    ass = getexp(f_top, nilexp, 0, nilexp, nilexp, 0, 0,
                                 top_tag);
                  } else {
                    ass = getexp(f_top, nilexp, 0, a, nilexp, 0, 0, ass_tag);
                    bro(a) = df;
                    bro(df) = ass;
                    setlast(df);
                  }
                  seq_hold = make_onearg(0, f_bottom, ass);
                  s = make_twoarg(seq_tag, f_top, seq_hold, son(son(bd)));
                  replace(bro(var), s, body);
                  chv = 1;
                }
              }
            }
            tc = pt(tc);
          }
        } while (chv);

#ifdef NEWDIAGS
        if (no(e) == no_ass && !isparam(e)) {
          int diagonly = 1;
          tc = pt(e);
          while (tc != nilexp) {
            if (!isdiaginfo(tc)) {
              if (diagnose) {
                dg_rem_ass(bro(bro(tc)));
              }
              replace(bro(bro(tc)), bro(tc), bro(def));
              diagonly = 0;
            }
            tc = pt(tc);
          }
          if (!diagonly) {
            repbyseq(e);
          }
        }
#else
        if (no(e) == no_ass && pt(e) != nilexp && !isparam(e)) {
          tc = pt(e);
          while (replace(bro(bro(tc)), bro(tc), bro(def)), pt(tc) != nilexp) {
            tc = pt(tc);
          }
          repbyseq(e);
        }
#endif
        return(1);
      }

      if (!isparam(e) && name(def) == clear_tag && name(body) == seq_tag &&
          name(son(son(body))) == ass_tag &&
          name(son(son(son(body)))) == name_tag &&
          son(son(son(son(body)))) == e &&
          eq_shape(sh(def), sh(bro(son(son(son(body))))))) {
        /* definition is clear and first assignment is to this variable */
        exp val = bro(son(son(son(body))));/* assigned value */
        if (!used_in(e, val)) {
          son(e) = val;         /* put it in as initialisation */
          clearlast(val);
          bro(val) = body;
          /* kill the use of var */
          kill_exp(son(son(son(body))), son(son(son(body))));
          /* replace assignment by void */
          replace(son(son(body)), getexp(f_top, nilexp, 0, nilexp, nilexp, 0,
                                         0, top_tag), body);
          return(1);
        }
      }

#ifdef NEWDIAGS
      if (all_a && !isparam(e) && !diag_visible) {
#else
      if (all_a && !isparam(e) && !diagnose) {
#endif
        /* if only assignments replace them by evaluating the value assigned
         * and discarding it. replace the declaration by a sequence of
         * definition and body */
        tc = pt(e);

        while (1) {
          if (!last(tc) && name(bro(bro(tc))) == ass_tag) {
#ifdef NEWDIAGS
            if (diagnose) {
              dg_rem_ass(bro(bro(tc)));
            }
#endif
            replace(bro(bro(tc)), bro(tc), body);
          }
          tc = pt(tc);
          if (tc == nilexp) {
            break;
          }
        }

        repbyseq(e);
        return(1);
      }

      }

      if (!is_var && !is_vis && no(e) == 1 && !isparam(e) &&
          name(body) == ident_tag && name(son(body)) == name_tag &&
          son(son(body)) == e && shape_size(def) == shape_size(son(body))) {
#ifdef NEWDIAGS
        if (diagnose) {
          exp t = pt(e);
          while (t) {
            if (isdiaginfo(t)) {
              setdiscarded(t);
            }
            t = pt(t);
          }
        }
#endif
        replace(son(body), def, def);
#ifdef NEWDIAGS
        if (diagnose) {
          dg_whole_comp(e, body);
        }
#endif
        replace(e, body, scope);
        return 1;
      }

      if (!is_var && !is_vis && name(def) == compound_tag) {
        exp c = son(def);
        int nuses = no(e);
        int changed = 0;
        for (;;) {
          int n = name(bro(c));
          if (n == val_tag || n == real_tag || n == name_tag || n == null_tag) {
            exp u = pt(e);
            for (; nuses !=0 && u !=nilexp;) {
              exp nextu = pt(u);
#ifdef NEWDIAGS
              if (!isdiaginfo(u) && no(u) ==no(c) &&
                  eq_shape(sh(u), sh(bro(c)))) {
#else
              if (no(u) ==no(c) && eq_shape(sh(u), sh(bro(c)))) {
#endif
                replace(u, copy(bro(c)), bro(def));
                nextu = pt(u); /* it could have changed */
                kill_exp(u, bro(def));
                nuses--;
                changed = 1;
              }
              u = nextu;
            }
          }
          if (nuses ==0 || last(bro(c))) {
            break;
          }
          c = bro(bro(c));
        }
        if ((no(e) ==0 || pt(e) == nilexp) && !isenvoff(e)) {
          repbyseq(e);
          return 1;
        }
        return changed;
      }
      if (!is_var && !is_vis && name(def) == nof_tag) {
        exp c = son(def);
        int changed = 0;
        int nuses = no(e);
        int sz = rounder(shape_size(sh(c)), shape_align(sh(c)));
        int nd = 0;
        for (;;) {
          int n = name(c);
          if (n == val_tag || n == real_tag || n == name_tag || n == null_tag) {
            exp u = pt(e);
            for (; nuses !=0 && u !=nilexp;) {
              exp nextu = pt(u);
#ifdef NEWDIAGS
              if (!isdiaginfo(u) && no(u) ==nd && eq_shape(sh(u), sh(c))) {
#else
              if (no(u) ==nd && eq_shape(sh(u), sh(c))) {
#endif
                replace(u, copy(c), bro(def));
                nextu = pt(u); /* it could have changed */
                kill_exp(u, bro(def));
                nuses--;
                changed = 1;
              }
              u = nextu;
            }
          }
          if (nuses==0 || last(c)) {
            break;
          }
          c = bro(c);
          nd+=sz;
        }
        if ((no(e) ==0 || pt(e) == nilexp) && !isenvoff(e)) {
          repbyseq(e);
          return 1;
        }
      return changed;
      }

  return(0);
}