Subversion Repositories tendra.SVN

Rev

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

/*
                 Crown Copyright (c) 1997

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

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

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

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

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


/*
                            VERSION INFORMATION
                            ===================

--------------------------------------------------------------------------
$Header: /u/g/release/CVSROOT/Source/src/installers/sparc/common/dw2_extra.c,v 1.5 1998/03/15 16:00:41 pwe Exp $
--------------------------------------------------------------------------
$Log: dw2_extra.c,v $
 * Revision 1.5  1998/03/15  16:00:41  pwe
 * regtrack dwarf dagnostics added
 *
 * Revision 1.4  1998/03/11  11:03:53  pwe
 * DWARF optimisation info
 *
 * Revision 1.3  1998/02/18  11:22:25  pwe
 * test corrections
 *
 * Revision 1.2  1998/01/21  10:30:11  pwe
 * labdiff change
 *
 * Revision 1.1.1.1  1998/01/17  15:55:53  release
 * First version to be checked into rolling release.
 *
 * Revision 1.1  1998/01/09  14:59:26  pwe
 * prep restructure
 *
 * Revision 1.9  1997/12/08  19:25:26  pwe
 * chfl param
 *
 * Revision 1.8  1997/12/04  19:54:52  pwe
 * ANDF-DE V1.9
 *
 * Revision 1.7  1997/11/06  09:29:29  pwe
 * ANDF-DE V1.8
 *
 * Revision 1.6  1997/10/28  10:19:28  pwe
 * extra diags
 *
 * Revision 1.5  1997/10/23  09:33:43  pwe
 * prep extra_diags
 *
 * Revision 1.4  1997/10/10  18:33:35  pwe
 * prep ANDF-DE revision
 *
 * Revision 1.3  1997/08/23  13:55:18  pwe
 * initial ANDF-DE
 *
 * Revision 1.2  1997/05/02  11:09:32  pwe
 * dwarf2 re return address offset
 *
 * Revision 1.1  1997/04/17  12:00:30  pwe
 * dwarf2 support
 *
--------------------------------------------------------------------------
*/

#include "config.h"
#include "common_types.h"

#ifdef NEWDWARF

#include "myassert.h"
#include "dg_aux.h"
#include "dw2_config.h"
#include "dw2_codes.h"
#include "dw2_basic.h"
#include "szs_als.h"
#include "addrtypes.h"
#include "expmacs.h"
#include "shapemacs.h"
#include "bitsmacs.h"
#include "tags.h"
#include "regmacs.h"
#include "locate.h"
#include "translat.h"
#include "basicread.h"
#include "codehere.h"
#include "eval.h"
#include "proc.h"
#include "procrec.h"
#include "dw2_entries.h"
#include "regable.h"
#include "const.h"
#include "flpttypes.h"
#include "f64.h"
#include "regexps.h"
#include "dw2_extra.h"
#include "dw2_locdata.h"

extern int call_base_reg;       /* declared in locate.c */



#define retaddr_column 64
#define DIAG_FREG 32

long instr_count = -1;
long fde_count = -1;


static long cie_pointer;
static long fde_end;
static long proc_end;

#ifdef NEEDS_DEBUG_ALIGN
static int calc_length;
#endif

static int extra_deref;
static int locate_param;
static int last_param_reg;
static int no_location;

static exp this_proc;

enum loctype { L_INREG = 1, L_REGOFF, L_GLOB, L_INDIRECT, L_SPLIT };

typedef struct {
  int key;
  int reg;
  long off;
} loc_s;



static void outsep
    PROTO_Z ()
{
  outs (", ");
}


int dw_is_const
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
  switch (name(e)) {
    case val_tag:
    case null_tag:
    case real_tag:
      return 1;
    case name_tag:
      if (isdiscarded(e))
        return 0;
      if (isvar(son(e)))
        return 1;
      if ( props (son(e)) & defer_bit )
        return dw_is_const (son(son(e)));
      return 0;
#if 0
    case cont_tag:
      return (name(son(e)) == name_tag && !isdiscarded(son(e)) &&
                !isvar(son(son(e))) && !isparam(son(son(e))) );
#endif
    case reff_tag:
      return 1;
    default:
      return 0;
  }
}

exp dw_has_location
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{                       /* return ident or nilexp */
  switch (name(e)) {
    case name_tag: {
      if (isdiscarded(e) || isvar(son(e)))
        return nilexp;
      if ( props (son(e)) & defer_bit )
        return dw_has_location (son(son(e)));
      return (son(e));
    }
    case cont_tag: {
      do {
        e = son(e);
        if (name(e) == name_tag && isdiscarded(e))
          return nilexp;
      }
      while (name(e) != ident_tag || (props(e) & defer_bit));
      return e;
    }
    default:
      return nilexp;
  }
}


static loc_s find_in_store
    PROTO_N ( (dc, off) )
    PROTO_T ( exp dc X long off )
{
  loc_s l;
  baseoff b;
  assert (! ( props ( dc ) & defer_bit ));
  b = boff (dc);
  l.reg = b.base;
  l.off = off + b.offset;
  l.key = (isglob(dc) ? L_GLOB : L_REGOFF);
  return l;
}


static loc_s find_loc
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
  loc_s l;
  switch ( name ( e ) ) {

    case name_tag : {
      if (isdiscarded(e) || (isglob(son(e)) && no(son(e)) == 0 &&
                                !(brog(son(e))->dec_u.dec_val.extnamed) )) {
        l.key = L_INREG;
        l.reg = 0;
        no_location = 1;
        return l;
      }
      if ( isvar(son(e)) )
        extra_deref--;
      if ( props (son(e)) & defer_bit ) {
        l = find_loc (son(son(e)));
        l.off += (no(e)/8);
      }
      else
      if (locate_param) {
        int r = no(son(son(e)))/32;
        if (!isparam(son(e))) {
          if (name(son(son(e))) == chvar_tag ||
                name(son(son(e))) == chfl_tag)
            return find_loc (son(son(son(e))));
          failer ("param inconsistency");
        }
        if (r > last_param_reg) {
          l.key = L_REGOFF;
          l.reg = R_SP;
          l.off = (no(son(son(e))) + no(e))/8 + 68;
        }
        else
        if (shape_size(sh(son(son(e)))) > 32) {
          l.key = L_SPLIT;
          l.reg = r;
        }
        else {
          l.key = L_INREG;
          l.reg = r + R_O0;
        }
      }
      else
      if ( l.reg = regofval(e), l.reg >= 0 && l.reg < R_NO_REG ) {
        l.key = L_INREG;
      }
      else
      if ( l.reg = fregofval(e), l.reg >= 0 && l.reg < R_NO_REG ) {
        l.reg = ((l.reg << 1) + DIAG_FREG);
        l.key = L_INREG;
      }
      else
        l = find_in_store (son(e), (long)no(e)/8);
      break;
    }

    case cont_tag :
    case contvol_tag : {
      if (name(son(e)) == name_tag && (isdiscarded(son(e)) ||
                        (isglob(son(son(e))) && no(son(son(e))) == 0 &&
                         !(brog(son(son(e)))->dec_u.dec_val.extnamed) ))) {
        l.key = L_INREG;
        l.reg = 0;
        no_location = 1;
        return l;
      }
      if ( name(son(e)) != name_tag || !isvar(son(son(e))) ) {
        l = find_loc (son(e));
        if (l.key == L_INREG) {
          l.key = L_REGOFF;
          l.off = 0;
        }
        else
          l.key = L_INDIRECT;
      }
      else
      if ( props (son(son(e))) & defer_bit ) {
        l = find_loc (son(son(son(e))));
        l.off += (no(son(e))/8);
      }
      else
      if (locate_param) {
        int r = no(son(son(son(e))))/32;
        if (!isparam(son(son(e)))) {
          if (name(son(son(son(e)))) == chvar_tag ||
                name(son(son(son(e)))) == chfl_tag)
            return find_loc (son(son(son(son(e)))));
          failer ("param inconsistency");
        }
        if (r > last_param_reg) {
          l.key = L_REGOFF;
          l.reg = R_SP;
          l.off = (no(son(son(son(e)))) + no(son(e)))/8 + 68;
        }
        else
        if (shape_size(sh(son(son(son(e))))) > 32) {
          l.key = L_SPLIT;
          l.reg = r;
        }
        else {
          l.key = L_INREG;
          l.reg = r + R_O0;
        }
      }
      else
      if ( l.reg = - regofval(son(e)), l.reg >= 0 ) {
        l.key = L_INREG;
      }
      else
      if ( l.reg = fregofval(son(e)), l.reg < R_NO_REG ) {
        l.reg = ((l.reg << 1) + DIAG_FREG);
        l.key = L_INREG;
      }
      else
        l = find_in_store (son(son(e)), (long)no(son(e))/8);
      break;
    }

    case reff_tag : {
      l = find_loc (son(e));
      if (l.key == L_GLOB || l.key == L_REGOFF)
        l.off += (no(e)/8);
      else
      if (l.key == L_INREG) {
        l.key = L_REGOFF;
        l.off = (no(e)/8);
        extra_deref--;
      }
      else
        l.key = L_INDIRECT;
      break;
    }

    default:
      failer ("unimplemented location condition");
  }
  return l;
}

static int inreg_length
    PROTO_N ( (r, more) )
    PROTO_T ( int r X int more )
{
  int ans = 1 + more;
  if (r >= 32)
    ans += uleb128_length((unsigned long)r);
  return ans;
}

static void out_inreg
    PROTO_N ( (r, more) )
    PROTO_T ( int r X int more )
{
  if (!more) {
    if (r < 32)
      outn ((long)(DW_OP_reg0 + r));
    else {
      outn ((long)DW_OP_regx); outsep(); uleb128((unsigned long)r);
    }
  }
  else {
    if (r < 32)
      outn ((long)(DW_OP_breg0 + r));
    else {
      outn ((long)DW_OP_bregx); outsep(); uleb128((unsigned long)r);
    }
    outsep(); outn ((long)0);
  }
  return;
}

static int regoff_length
    PROTO_N ( (l) )
    PROTO_T ( loc_s l )
{
  assert (l.reg >= 0 && l.reg < 32);
  return (1 + sleb128_length (l.off));
}

static void out_regoff
    PROTO_N ( (l) )
    PROTO_T ( loc_s l )
{
  outn ((long)(l.reg == R_FP ? DW_OP_fbreg : DW_OP_breg0 + l.reg)); outsep();
  sleb128 (l.off);
  return;
}

static int split_length
    PROTO_N ( (l) )
    PROTO_T ( loc_s l )
{
  int ans = inreg_length (l.reg + R_O0, 0) +4;
  if (l.reg == last_param_reg) {
    l.key = L_REGOFF;
    l.off = (l.reg * 4) + 72;
    l.reg = R_SP;
    ans += regoff_length (l);
  }
  else
    ans += inreg_length (l.reg + R_O1, 0);
  return ans;
}

static void out_split
    PROTO_N ( (l) )
    PROTO_T ( loc_s l )
{
  out_inreg (l.reg + R_O0, 0);
  outsep(); outn ((long)DW_OP_piece);
  outsep(); outn ((long)4); outsep();
  if (l.reg == last_param_reg) {
    l.key = L_REGOFF;
    l.off = (l.reg * 4) + 72;
    l.reg = R_SP;
    out_regoff (l);
  }
  else
    out_inreg (l.reg + R_O1, 0);
  outsep(); outn ((long)DW_OP_piece);
  outsep(); outn ((long)4);
  return;
}

static int glob_length
    PROTO_N ( (l) )
    PROTO_T ( loc_s l )
{
#ifdef NEEDS_DEBUG_ALIGN
  calc_length = 0;
#endif
  return 5;
}

static void out_glob
    PROTO_N ( (l) )
    PROTO_T ( loc_s l )
{
  outn ((long)DW_OP_addr); d_outnl ();
  out32 (); outlab (l.reg);
  if (l.off) {
    outs (" + ");
    outn ((long)l.off);
  }
  return;
}

static int indirect_length
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
  int length;
  loc_s l;
#ifdef NEEDS_DEBUG_ALIGN
  if (!calc_length)
    return 0;
#endif
  switch (name(e)) {
    case cont_tag: {
      length = 1;
      break;
    }
    case reff_tag: {
      if (no(e) >= 0)
        length = 1 + uleb128_length ((unsigned long)(no(e)/8));
      else
        length = 2 + uleb128_length ((unsigned long)(-no(e)/8));
      break;
    }
    case name_tag: {
      if (props(son(e)) & defer_bit) {
        return indirect_length (son(son(e)));
      } /* else drop through to failure */
    }
    default: {
      failer ("unimplemented dwarf locate");
      return 0;
    }
  }
  l = find_loc (son(e));
  switch (l.key) {
    case L_INREG: {
      length += inreg_length (l.reg, 1);
      break;
    }
    case L_REGOFF: {
      length += regoff_length(l);
      break;
    }
    case L_SPLIT: {
      length += split_length(l);
      break;
    }
    case L_GLOB: {
      length += glob_length(l);
      break;
    }
    case L_INDIRECT: {
      length += indirect_length(son(e));
      break;
    }
  }
  return length;
}

static void out_indirect
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
  loc_s l;
  if (name(e) == name_tag) {
    assert (props(son(e)) & defer_bit);
    out_indirect (son(son(e)));
    return;
  }
  l = find_loc (son(e));
  switch (l.key) {
    case L_INREG: {
      out_inreg (l.reg, 1);
      outsep();
      break;
    }
    case L_REGOFF: {
      out_regoff (l);
      outsep();
      break;
    }
    case L_SPLIT: {
      out_split (l);
      outsep();
      break;
    }
    case L_GLOB: {
      out_glob (l);
      d_outnl(); out8();
      break;
    }
    case L_INDIRECT: {
      out_indirect(son(e));
      outsep();
      break;
    }
  }
  switch (name(e)) {
    case cont_tag: {
      outn ((long)DW_OP_deref);
      break;
    }
    case reff_tag: {
      if (no(e) >= 0) {
        outn ((long)DW_OP_plus_uconst); outsep();
        uleb128 ((unsigned long)(no(e)/8));
      }
      else {
        outn ((long)DW_OP_constu); outsep();
        uleb128 ((unsigned long)(-no(e)/8)); outsep();
        outn ((long)DW_OP_minus);
      }
      break;
    }
  }
  return;
}


void dw2_locate_exp
    PROTO_N ( (e, locate_const, cx) )
    PROTO_T ( exp e X int locate_const X int cx )
{
  loc_s l;
  int length;
  int within_loclist = (cx & 1);
#ifdef NEEDS_DEBUG_ALIGN
  long over_lab;
  calc_length = 1;
#endif
  locate_param = (cx & 2);
  extra_deref = locate_const;
  no_location = 0;
  l = find_loc (e);     /* may reduce extra_deref */
  length = extra_deref;
  switch (l.key) {
    case L_INREG: {
      length += inreg_length (l.reg, extra_deref);
      break;
    }
    case L_REGOFF: {
      length += regoff_length(l);
      break;
    }
    case L_SPLIT: {
      length += split_length(l);
      break;
    }
    case L_GLOB: {
      length += glob_length(l);
      break;
    }
    case L_INDIRECT: {
      length += indirect_length(e);
      break;
    }
  }
  if (no_location)
    length = 0;

  if (within_loclist)
    out16 ();
  else
    out8 ();
#ifdef NEEDS_DEBUG_ALIGN
  if (!calc_length) {
    over_lab = next_dwarf_label();
    out_dwf_label (over_lab, 0);
    if (within_loclist)
      outs (" - . - 2");
    else
      outs (" - . - 1");
  }
  else
#endif
  outn ((long)length);
  d_outnl();
  if (no_location)
    return;
  out8 ();
  switch (l.key) {
    case L_INREG: {
      out_inreg (l.reg, extra_deref);
      break;
    }
    case L_REGOFF: {
      out_regoff (l);
      break;
    }
    case L_SPLIT: {
      out_split (l);
      break;
    }
    case L_GLOB: {
      out_glob (l);
      break;
    }
    case L_INDIRECT: {
      out_indirect (e);
      break;
    }
  }
  while (extra_deref) {
    if (extra_deref < 0) {
      failer ("miscalculated location");
      break;
    }
#if 0
    if (locate_const)
      failer ("constant location???");
#endif
    outsep();
    outn ((long)DW_OP_deref);
    extra_deref--;
  }
  d_outnl ();
#ifdef NEEDS_DEBUG_ALIGN
  if (!calc_length)
    out_dwf_label (over_lab, 1);
#endif
  return;
}

static long current_pprops;

void dw2_prepare_locate
    PROTO_N ( (id) )
    PROTO_T ( exp id )
{
                        /* set local proc conditions for local locations */
  exp e = son(id);      /* proc or general proc */
  procrec *pr = &procrecs [ no ( e ) ] ;
  needs *ndpr = &pr->needsproc ;
  spacereq *sppr = &pr->spacereqproc ;
  long pprops = ( long ) ( ndpr->prps ) ;
  /* bool leaf = ( bool ) ( ( pprops & anyproccall ) == 0 ) ;   */
  long maxargs = ndpr->maxargs ;/* maxargs of proc body in bits */
  long st = sppr->stack ;               /* space for locals in bits */

  Has_vcallees = (name(e) == general_proc_tag) && (proc_has_vcallees(e));
        /* callee_start_reg as initialisation */
  call_base_reg = R_NO_REG;     /* needs reset at apply_general */
  proc_state.params_offset = PARAMS_OFFSET;
  st = ( st + 63 ) & ~63 ;
  proc_state.callee_size = ndpr->callee_size;
  proc_state.locals_space = st ;
  proc_state.locals_offset = 0 ;
  proc_state.frame_size = maxargs + st ;
  proc_state.maxargs = maxargs ;
  last_param_reg = 5;
  if (proc_may_have_callees(e))
    last_param_reg = (Has_vcallees ? 3 : 4);
  this_proc = e;
  current_pprops = pprops;
  return;
}


void dw2_locate_result
    PROTO_N ( (sha) )
    PROTO_T ( shape sha )
{
  out8 ();
  if ( !valregable (sha) && name (sha) != tophd &&
        ( !is_floating ( name (sha) ) || shape_size(sha) > 64 )) {
      /* structure or union result, address of space to [ %fp+64 ] */
    loc_s l;
    l.key = L_REGOFF;
    l.reg = R_FP;
    l.off = 64;
    outn ((long)regoff_length (l)); outsep();
    out_regoff (l);
  }
  else {
    int r;
    if ( is_floating ( name (sha) ) ) {
        /* proc has real result */
      r = R_F0 + DIAG_FREG;
    }
    else if ( name (sha) > tophd  ) {
      r = R_I0;
    }
    else {
        /* no result */
      failer ("inconsistent result");
      r = R_G0;
    }
    outn ((long)inreg_length (r, 0)); outsep();
    out_inreg (r, 0);
  }
  d_outnl ();
  return;
}

void dw_at_procdetails
    PROTO_Z ()
{                       /* return address and frame base */
  out8(); outn((long)2); outsep();
  outn((long)DW_OP_breg0 + R_I7); outsep();
  outn ((long)(has_struct_res (this_proc) ? 12 : 8)); d_outnl();
  out8(); outn((long)1); outsep();
  outn((long)DW_OP_reg0 + R_SP); d_outnl();
  return;
}


void dw2_locate_val
    PROTO_N ( (v) )
    PROTO_T ( dg_where v )
{
#ifdef NEEDS_DEBUG_ALIGN
  long over_lab;
  calc_length = 1;
#endif
  out8 ();
  switch (v.k) {
    case WH_CODELAB: {
      int length;
      loc_s l;
      l.key = L_GLOB;
      l.reg = v.u.l;
      l.off = v.o;
      length = glob_length (l);
#ifdef NEEDS_DEBUG_ALIGN
      if (!calc_length) {
        over_lab = next_dwarf_label();
        out_dwf_label (over_lab, 0);
        outs (" - . - 1");
      }
      else
#endif
      outn ((long)length);
      d_outnl();
      out8 ();
      out_glob (l);
      break;
    }
    case WH_REG: {
      int r = v.u.l;
      outn ((long)inreg_length (r, 0)); outsep();
      out_inreg (r, 0);
      break;
    }
    case WH_REGOFF: {
      loc_s l;
      l.key = L_REGOFF;
      l.reg = v.u.l;
      l.off = v.o;
      outn ((long)regoff_length (l)); outsep();
      out_regoff (l);
      break;
    }
    default:
      failer ("unexpected locate val");
  }
  d_outnl ();
#ifdef NEEDS_DEBUG_ALIGN
  if (!calc_length)
    out_dwf_label (over_lab, 1);
#endif
  return;
}


static int dw_eval_exp
    PROTO_N ( (e, line_started) )
    PROTO_T ( exp e X int line_started )
{
  if (line_started)
    outsep();
  else {
    out8 ();
    line_started = 1;
  }
  switch (name(e)) {
    case name_tag:
    case cont_tag:
    case contvol_tag:
    case reff_tag: {
      loc_s l;
      locate_param = extra_deref = no_location = 0;
      l = find_loc (e);
      if (no_location || extra_deref)
        failer ("value unobtainable by DWARF expression");
      switch (l.key) {
        case L_INREG: {
          out_inreg (l.reg, extra_deref);
          break;
        }
        case L_REGOFF: {
          out_regoff (l);
          break;
        }
        case L_GLOB: {
          out_glob (l);
          d_outnl ();
          line_started = 0;
          break;
        }
        case L_INDIRECT: {
          out_indirect (e);
          break;
        }
      }
      break;
    }
    case val_tag:
    case null_tag : {
      if (isbigval(e)) {
        flt64 x;
        int ov;
        x = flt_to_f64(no(e), is_signed(sh(e)), &ov);
        outn((long)(is_signed(sh(e)) ? DW_OP_const8s : DW_OP_const8u)); d_outnl();
        out32(); outn((long)(x.small)); outsep(); outn((long)(x.big)); d_outnl();
        line_started = 0;
      }
      else
      if (no(e) >= 0 && no(e) < 32)
        outn((long)(DW_OP_lit0 + no(e)));
      else
      if (is_signed(sh(e))) {
        outn((long)DW_OP_consts); outsep();
        sleb128 ((long)no(e));
      }
      else {
        outn((long)DW_OP_constu); outsep();
        uleb128 ((unsigned long)no(e));
      }
      break;
    }
    case plus_tag:
    case offset_add_tag : {
      line_started = dw_eval_exp (son(e), line_started);
      if (name(bro(son(e))) == val_tag && !is_signed(sh(e)) && !isbigval(bro(son(e)))) {
        if (line_started)
          outsep();
        else {
          out8 ();
          line_started = 1;
        }
        outn((long)DW_OP_plus_uconst); outsep();
        uleb128 ((unsigned long)no(e));
      }
      else {
        line_started = dw_eval_exp (bro(son(e)), line_started);
        if (line_started)
          outsep();
        else {
          out8 ();
          line_started = 1;
        }
        outn((long)DW_OP_plus);
      }
      break;
    }
    case minus_tag:
    case offset_subtract_tag : {
      line_started = dw_eval_exp (son(e), line_started);
      line_started = dw_eval_exp (bro(son(e)), line_started);
      if (line_started)
        outsep();
      else {
        out8 ();
        line_started = 1;
      }
      outn((long)DW_OP_minus);
      break;
    }
    case neg_tag:
    case offset_negate_tag : {
      line_started = dw_eval_exp (son(e), line_started);
      if (line_started)
        outsep();
      else {
        out8 ();
        line_started = 1;
      }
      outn((long)DW_OP_neg);
      break;
    }
    case mult_tag:
    case offset_mult_tag : {
      line_started = dw_eval_exp (son(e), line_started);
      line_started = dw_eval_exp (bro(son(e)), line_started);
      if (line_started)
        outsep();
      else {
        out8 ();
        line_started = 1;
      }
      outn((long)DW_OP_mul);
      break;
    }
    case div0_tag :
    case div1_tag :
    case div2_tag :
    case offset_div_by_int_tag :
    case offset_div_tag : {
      line_started = dw_eval_exp (son(e), line_started);
      line_started = dw_eval_exp (bro(son(e)), line_started);
      if (line_started)
        outsep();
      else {
        out8 ();
        line_started = 1;
      }
      outn((long)DW_OP_div);
      break;
    }
    default:
      failer ("unsupported operation for DWARF expression");
  }
  return line_started;
}


void dw2_offset_exp
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
  long block_end = next_dwarf_label ();
  if (name(sh(e)) != offsethd)
    failer ("wrong shape for offset expression");
  dw_at_form (DW_FORM_block2); d_outnl();
  out16 (); out_dwf_dist_to_label (block_end); d_outnl();
  if (dw_eval_exp (e, 0))
    d_outnl();
  if (name(sh(e)) == offsethd && al2(sh(e)) < 8 ) {
    out8 (); outn((long)(DW_OP_lit0 + 8)); outsep();
    outn((long)DW_OP_mul); d_outnl();
  }
  out_dwf_label (block_end, 1);
  return;
}


void dw2_cie
    PROTO_Z ()
{
  long cie_end;
  int i;
  cie_pointer = next_dwarf_label();
  cie_end = next_dwarf_label();
  enter_section ("debug_frame");
  outnl_comment ("Common Information Entry");
  out_dwf_label (cie_pointer, 1);
  out32 (); out_dwf_dist_to_label (cie_end); d_outnl ();
  out32 (); outn ((long)DW_CIE_id); d_outnl ();
  out8 (); outn ((long)DW_CIE_MOD_VERSION); d_outnl ();
  out_string ("DERA/DDC-I");
  out8 (); uleb128 ((unsigned long)framecode_factor); d_outnl ();
  out8 (); sleb128 ((long)framedata_factor); d_outnl ();
  out8 (); outn ((long)retaddr_column); d_outnl ();     /* return address column */

  out8 (); outn ((long)DW_CFA_DD_sparc_restore_regwindow); outsep();
        sleb128 ((long) 8); d_outnl ();         /* sparc entry rules, ret offset 8 */

  for (i = R_FIRST; i <= R_LAST; i++) {
    if ((i > R_G0 && i <= (R_G0 + g_reg_max)) ||
                (i >= R_O0 && i <= R_O7 && i != R_SP)) {
        out8 (); outn ((long)DW_CFA_undefined); outsep();
        uleb128 ((unsigned long)i); d_outnl ();
    }
  }
  dot_align (PTR_SZ/8);
  out_dwf_label (cie_end, 1);
  exit_section ();
  return;
}


void dw2_start_fde
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
  long proc_start = next_dwarf_label();
  fde_end = next_dwarf_label();
  proc_end = next_dwarf_label();
  out_dwf_label (proc_start, 1);
  enter_section ("debug_frame");
  outnl_comment ("Frame Descriptor Entry");
  out32 (); out_dwf_dist_to_label (fde_end); d_outnl ();
  out32 (); out_dwf_label (cie_pointer, 0); d_outnl ();
  out32 (); out_dwf_label (proc_start, 0); d_outnl ();
  out32 (); out_dwf_labdiff (proc_start, proc_end); d_outnl ();
  this_proc = e;
  if (has_struct_res (this_proc)) {
    out8 (); outn ((long)DW_CFA_DD_location); outsep();
        uleb128 ((unsigned long)retaddr_column);  outsep();
        outn ((long)(2 + sleb128_length((long)12))); outsep();
        outn ((long)DW_OP_drop); outsep();
        outn ((long)(DW_OP_breg0 + R_O7)); outsep();
        sleb128 ((long) 12); d_outnl ();        /* return R_O7 offset 12 */
  }
  exit_section ();
  instr_count = -1;
  fde_count = 0;
  return;
}

static void fde_advance
    PROTO_N ( (here) )
    PROTO_T ( long here )
{
  if (fde_count < 0) {
    out8 (); outn ((long)DW_CFA_set_loc); d_outnl ();
    out32 (); out_dwf_label (here, 0);
  }
  else
  if (fde_count < 0x40) {
    out8 (); outn ((long)DW_CFA_advance_loc + fde_count);
  }
  else
  if (fde_count < 0x100) {
    out8 (); outn ((long)DW_CFA_advance_loc1); outsep();
    outn (fde_count);
  }
  else
  if (fde_count < 0x10000) {
    out8 (); outn ((long)DW_CFA_advance_loc2); d_outnl ();
    out16 (); outn (fde_count);
  }
  else {
    out8 (); outn ((long)DW_CFA_advance_loc4); d_outnl ();
    out32 (); outn (fde_count);
  }
  d_outnl ();
  fde_count = 0;
  return;
}

void dw2_fde_save
    PROTO_Z ()
{
  long here = 0;
  if (fde_count < 0)
    here = set_dw_text_label();
  enter_section ("debug_frame");
  fde_advance (here);
  out8 (); outn ((long)DW_CFA_DD_sparc_save_regwindow); outsep();
        sleb128 ((long) (has_struct_res (this_proc) ? 12 : 8));
        d_outnl ();
  exit_section ();
  return;
}

void dw2_fde_restore
    PROTO_Z ()
{
  long here = 0;
  if (fde_count < 0)
    here = set_dw_text_label();
  enter_section ("debug_frame");
  fde_advance (here);
  out8 (); outn ((long)DW_CFA_DD_sparc_restore_regwindow); outsep();
        sleb128 ((long) (has_struct_res (this_proc) ? 12 : 8));
        d_outnl ();
  exit_section ();
  return;
}

void dw2_complete_fde
    PROTO_Z ()
{
  out_dwf_label (proc_end, 1);
  enter_section ("debug_frame");
  dot_align (PTR_SZ/8);
  out_dwf_label (fde_end, 1);
  exit_section ();
  return;
}


static exp lab_mark_list;

static void mark_lab
    PROTO_N ( (labst) )
    PROTO_T ( exp labst )
{
  if (!dg_labmark (labst)) {
    set_dg_labmark (labst);
    if (son(son(labst)) != nilexp)
      failer ("strange labst");
    son(son(labst)) = lab_mark_list;
    lab_mark_list = labst;
  }
  return;
}

static void trace_branch_aux
    PROTO_N ( (whole, e) )
    PROTO_T ( exp whole X exp e )
{
  exp t;
  switch (name(e)) {
    case test_tag:
    case goto_tag: {
      if (!intnl_to (whole, pt(e)))
        mark_lab (pt(e));
      break;
    }
    case case_tag: {
      t = bro(son(e));
      for (;;) {
        if (!intnl_to (whole, pt(t)))
          mark_lab (pt(t));
        if (last(t)) break;
        t = bro(t);
      }
      break;
    }
    case name_tag:
    case env_offset_tag:
    case general_env_offset_tag:
      return;
  }
  t = son(e);
  if (t) {
    for (;;) {
      trace_branch_aux (whole, t);
      if (last(t) || name(e) == case_tag) break;
      t = bro(t);
    }
  }
  return;
}

void trace_dw_branch_exits
    PROTO_N ( (e) )
    PROTO_T ( exp e )
{
  lab_mark_list = nilexp;
  trace_branch_aux (e, e);
  while (lab_mark_list) {
    exp holder = son(lab_mark_list);
    clear_dg_labmark (lab_mark_list);
    lab_mark_list = son(holder);
    son(holder) = nilexp;
    dw_entry (dwe_break, (long)0);
    out32 (); out_code_label ((long)no(holder)); d_outnl ();
  }
  return;
}


int dw_loc_equivalence
    PROTO_N ( (a, b) )
    PROTO_T ( exp a X exp b )
{
  return (int)sim_exp (a, b);
}

typedef struct
{
  dg_name       alloc;
  void *        share_set;
  dg_name       nm;
  long          start;
  long          end;
} dw_regdata;

#define TRACKREGS 32

static dw_regdata regassns [TRACKREGS];


void dw_allocated
    PROTO_N ( (nm, id) )
    PROTO_T ( dg_name nm X exp id )
{
  int reg = no(id), i;
  exp x = son(nm->data.n_obj.obtain_val);
  if (!isglob(id) && (props(id) & inreg_bits) && reg < TRACKREGS) {
    dw_close_regassn (reg);
    regassns[reg].alloc = nm;
    regassns[reg].share_set = (void *)0;
  }
  for (i=0; i<TRACKREGS; i++) {
    if (regexps[i].keptexp && 
        (regexps[i].iscont ? (name(x) == cont_tag &&
                        sim_exp (son(x), regexps[i].keptexp))
                      : sim_exp (x, regexps[i].keptexp) )) {
      regassns[i].nm = nm;
      regassns[i].start = set_dw_text_label ();
      regassns[i].end = (long)0;
      break;
    }
  }
  return;
}

void dw_deallocated
    PROTO_N ( (nm) )
    PROTO_T ( dg_name nm )
{
  int i;
  for (i=0; i<TRACKREGS; i++) {
    if (regassns[i].alloc == nm) {
      dw_close_regassn (i);
      regassns[i].alloc = (dg_name)0;
      regassns[i].share_set = (void *)0;
    }
  }
  return;
}

void dw_all_deallocated         /* initialisation */
    PROTO_Z ()
{
  int i;
  for (i=0; i<TRACKREGS; i++) {
    regassns[i].alloc = (dg_name)0;
    regassns[i].share_set = (void *)0;
    regassns[i].start = regassns[i].end = (long)0;
  }
  return;
}


void dw_init_regassn
    PROTO_N ( (reg) )
    PROTO_T ( int reg )
{
  if (reg < TRACKREGS) {
    dg_name nm = find_equiv_object (regexps[reg].keptexp,
                                        regexps[reg].iscont);
    if (nm) {
      regassns[reg].nm = nm;
      regassns[reg].start = set_dw_text_label ();
      regassns[reg].end = (long)0;
    }
  }
  return;
}

void dw_used_regassn
    PROTO_N ( (reg) )
    PROTO_T ( int reg )
{
  if (reg < TRACKREGS && regassns[reg].start)
    regassns[reg].end = set_dw_text_label ();
  return;
}

void dw_close_regassn
    PROTO_N ( (reg) )
    PROTO_T ( int reg )
{
  if (reg >= TRACKREGS)
    return;
  if (regassns[reg].end) {
    if (!regassns[reg].share_set) {
      regassns[reg].share_set = (void *)
                dw_new_regshare (regassns[reg].alloc, reg);
    }
    dw_add_regshare (regassns[reg].share_set, regassns[reg].nm,
                        regassns[reg].start, regassns[reg].end);
    regassns[reg].end = (long)0;
    if (!regassns[reg].alloc)
      regassns[reg].share_set = (void *)0;
  }
  regassns[reg].start = (long)0;
  return;
}


#endif