/*
 * Copyright (c) 2002, The Tendra Project <http://www.ten15.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 unmodified, 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
 *
 *
 *    		 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.
 *
 * $TenDRA: tendra/src/installers/alpha/common/eval.c,v 1.11 2005/09/16 08:38:16 stefanf Exp $
*/


/*
  eval.c
  This file contains functions which output data to the assembler
  file.  The parameters are an exp and an index into the table of
  externals.
*/

#include "config.h"
#include "fmm.h"

#include "addresstypes.h"
#include "common_types.h"
#include "tags.h"
#include "expmacs.h"
#include "exp.h"
#include "exptypes.h"
#include "maxminmacs.h"
#include "shapemacs.h"
#include "flpttypes.h"
#include "flpt.h"
#include "main.h"
#include "frames.h"
#include "reg_defs.h"
#include "output.h"
#include "fbase.h"
#include "f64.h"
#include "cross.h"
#include "pseudo.h"
#include "ibinasm.h"
#include "out_ba.h"
#include "syms.h"
#include "shape_range.h"  /* provides definitions of 
			     scmm_max,scmm_min, etc. */
#include "inst_fmt.h"
#include "eval.h"
#include "fail.h"

#if DO_SCHEDULE
#include "scheduler.h"
#endif
#include "procrecs.h"

/*
  storage types
*/
char *s_byte="byte";
char *s_word="word";
char *s_long="long";
char *s_quad="quad";


/*
   The current alignment of the program
*/
int current_alignment=-1;


long  G_number = 64;		/* to give choice of .sdata or data */

int   data_lab = 33;

/* anonymous label in data space - $$n in assembler o/p */
int
next_data_lab(void)
{
  return data_lab++;
}


/* as above-but also gives it a symno for .G output */
int
next_dlab_sym(void)
{	
  symnofordata (data_lab);
  return data_lab++;
}


/* various pieces of info for outputting data depending on shape */
mm scmm = {
  scmm_max, scmm_min, "\t.byte %ld :%ld\n"
};
mm uscmm = {
  uscmm_max,uscmm_min, "\t.byte %ld :%ld\n"
};
mm shmm = {
  shmm_max,shmm_min, "\t.word %ld :%ld\n"
};
mm ushmm = {
  ushmm_max,ushmm_min, "\t.word %ld :%ld\n"
};
mm swmm = {
  swmm_max,swmm_min, "\t.long %ld :%ld\n"
};
mm uswmm = {
  uswmm_max,uswmm_min,"\t.long %ld :%ld\n"
};

mm u64mm = {
  u64mm_max,u64mm_min,"\t.quad %ld :%ld\n"
};

mm s64mm = {
  s64mm_max,s64mm_min, "\t.quad %ld :%ld\n"
};



/*
   maxmin

   finds the data size from the range of an integer shape
*/
mm
maxmin(shape s)
{
  switch (name (s)) {
  case scharhd: 
    return scmm;
  case ucharhd: 
    return uscmm;
  case swordhd: 
    return shmm;
  case uwordhd: 
    return ushmm;
  case slonghd: 
    return swmm;
  case ulonghd: 
    return uswmm;
  case s64hd:
    return s64mm;
  case u64hd:
    return u64mm;
  default: 	
    return uswmm;
  }
}


/*
  outlab
  outputs the label parameter if non negative else interprets it
  to be an index into the externals and outputs the identifier.
*/

char *
outlab(int l)
{
#if DO_SCHEDULE
  char * res = (char*)xcalloc(20,sizeof(char));
#else
  char * res = (char*)NULL;
#endif
  if (l >= 0) {
#if !DO_SCHEDULE
    (void)fprintf (as_file, "$$%d", l);
#else
    (void)sprintf(res,"$$%d",l);
#endif
  }
  else {
    char *extname = main_globals[-l - 1] -> dec_u.dec_val.dec_id;
#if !DO_SCHEDULE
    (void)fprintf (as_file, "%s", extname);
#else
    (void)sprintf (res, "%s", extname);
#endif
  }
  return res;
}

char  fltrepr[120];

void
output_data_records(char *strng, char *str, int size)
{
  int pos = 0;
  Assert(size>0);
  Assert(!strng);
  while(size>0){
    output_data((char*)NULL,
		out_data(str,min(size,binasm_record_length)));
    pos += binasm_record_length;
    size -= binasm_record_length;
  }
  return;
}

      


/*
   This function outputs an IEEE format floating point number
*/
void
outfloat(exp e, int rep, ash a)
{
  INT64 val;
#if DO_SCHEDULE
  char * outline = (char*)xcalloc(80,sizeof(char));
#endif
  int fv = name(sh(e)) - shrealhd;
  r2l ieeeflt;
  ieeeflt = real2longs_IEEE(&flptnos[no(e)],fv);
  switch(fv){
    case 0:
    if(as_file){
#if !DO_SCHEDULE
      outstring("\t.long ");
      outhex(ieeeflt.i1);	
      outstring(" : ");
      outint(rep);
      outstring("\t# .s floating");
      outstring("\n");
#else
      outass("\t.long ");
      sprintf(outline,"0x%08x",ieeeflt.i1);
      outass(outline);
      outass(" : ");
      sprintf(outline,"%d",rep);
      outass(outline);
      outass("\t# .s floating\n");
#endif
    }
#if DO_SCHEDULE
    output_data(outass((char*)NULL),out_value(0,ilong,ieeeflt.i1,rep));
#else
    out_value(0,ilong,make_INT64(0,ieeeflt.i1),rep);
/*    out_value(0,ilong,ieeeflt.i1,rep);*/
#endif
    break;
    case 1:
    if(as_file){
#if !DO_SCHEDULE
      outstring("\t.quad ");
      outhex(ieeeflt.i2);
      outhexlow(ieeeflt.i1);
      outstring(" : ");
      outint(rep);
      outstring("\t# .t floating");
      outstring("\n");
#else
      outass("\t.quad ");
      sprintf(outline,"0x%08x%08x",ieeeflt.i2,ieeeflt.i1);
      outass(outline);
      outass(" : ");
      sprintf(outline,"%d",rep);
      outass(outline);
      outass("\t# .t floating\n");
#endif
    }
/*    val = ((long)ieeeflt.i2<<32) + (unsigned)ieeeflt.i1;*/
    val = make_INT64(ieeeflt.i2,(unsigned)ieeeflt.i1);
#if !DO_SCHEDULE     
    out_value(0,iquad,val,rep);
#else
    output_data(outass((char*)NULL),out_value(0,iquad,val,rep));
#endif     
    break;
    default:
    failer("invalid floating variety\n");
  }
#if DO_SCHEDULE
  free(outline);
#endif
  return;
}

/*
  evaluate the exp 'e' and return the resulting value
*/
INT64
evalexp(exp e)
{
  
  switch (name(e)) {
    case  val_tag : {
      if(al2(sh(e))>=8 && name(sh(e)) == offsethd) {
	return INT64_shift_right(flt64_to_INT64(exp_to_f64(e)),3,1);
      }
      return flt64_to_INT64(exp_to_f64(e));
    }
    case bitf_to_int_tag : {
      return evalexp (son (e));
    }
    case int_to_bitf_tag : {
      ash a;
      INT64  w = evalexp (son (e));
      a = ashof (sh (e));
      if (a.ashalign != 1) {
	failer ("should be align 1");
      }	
      if(a.ashsize!=64){
	w = INT64_and(w,INT64_subtract(INT64_shift_left(make_INT64(0,1),
							a.ashsize,1),
				       make_INT64(0,1),1));
      }	
      return w;
    }
    case not_tag: {
      return (INT64_not(evalexp (son (e))));
    }	
    case and_tag: {
      return (INT64_and(evalexp(son(e)),evalexp(bro(son(e)))));
    }
    case or_tag: {
      return (INT64_or(evalexp(son(e)),evalexp(bro(son(e)))));
    }
    case xor_tag: {
      return (INT64_xor(evalexp(son(e)),evalexp(bro(son(e)))));
    }
    case shr_tag: {
      return (INT64_shift_right(evalexp(son(e)),
				low_INT64(evalexp(bro(son(e)))),1));
    }
    case shl_tag: {
      return (INT64_shift_left(evalexp(son(e)),
			       low_INT64(evalexp(bro(son(e)))),1));
    }
    case concatnof_tag: {
      ash a;
      INT64 wd = evalexp (son (e));
      a = ashof (sh (son (e)));
      return (INT64_or(wd,
		       INT64_shift_left(evalexp(bro(son(e))),a.ashsize,1)));
    }
    case clear_tag: {
      ash a;
      a = ashof (sh (e));
      if (a.ashsize > REG_SIZE)
	failer ("clearshape");
      return zero_int64;
    }	
    case general_env_offset_tag :
    case env_offset_tag : {
      return make_INT64(0,frame_offset(son(e)));
    }
    case env_size_tag : {
      exp tg = son(son(e));
      procrec *pr = &procrecs[no(son(tg))];
      return (pr->frame_size+pr->callee_size)>>3;
    }
    case offset_add_tag : {
      return (evalexp(son(e)) + evalexp(bro(son(e))));
    }
    case offset_max_tag : {
      return max(evalexp(son(e)),evalexp(bro(son(e))));
    }
    case offset_pad_tag : {
      return rounder(evalexp(son(e)),shape_align(sh(e))>>3);
    }
    case offset_mult_tag : {
      return evalexp(son(e))*evalexp(bro(son(e)));
    }
    case offset_div_tag : 
    case offset_div_by_int_tag : {
      return evalexp(son(e))/evalexp(bro(son(e)));
    }
    case offset_subtract_tag : {
      return evalexp(son(e)) - evalexp(bro(son(e)));
    }
    case offset_negate_tag : {
      return -evalexp(son(e));
    }
    
    default: 
    failer ("tag not in evalexp");
  }
  return zero_int64;
}


/*
  This function outputs values to the assembler file.  The 
  alignment of the last value to be output is retained and, 
  if it differs from the current one, a new alignment is set.
*/
void
oneval(INT64 val, int al, int rep)
{
  char *store_type;
  char * outline = (char*)NULL;
  static int lastal = -1;
  unsigned int bval;
  if(al!=lastal){
    set_align(al);
    lastal=al;
  }
  switch(al){
  case 8:
    store_type=s_byte;
    bval = ibyte;
    break;
  case 16:
    store_type=s_word;
    bval = iword;
    break;
  case 32:
    store_type=s_long;
    bval = ilong;
    break;
  case 64:
    store_type=s_quad;
    bval = iquad;
    break;
  default:
    store_type=s_long;
    bval = ilong;
    break;
  }
  if(as_file){
#if !DO_SCHEDULE
    (void)fprintf(as_file,"\t.%s ",store_type);
    out_INT64(val);
    (void)fprintf(as_file," :%d\n",rep);
#else
    outline = (char*)xcalloc(30,sizeof(char));
    sprintf(outline,"\t.%s %ld :%d\n",store_type,val,rep);
#endif
  }
#if DO_SCHEDULE
  output_data(outline,out_value(0,bval,val,rep));
#else  
  out_value(0,bval,val,rep);
#endif
  return;
}


INT64
bits_list(int val)
{
  int loop;
  INT64 result=make_INT64(0,0);
/*  Assert (val <=31);*/
  Assert (val <=64);
  for(loop=0;loop<val;++loop){
    result = INT64_shift_left(result,1,1);
    result = INT64_or(result,make_INT64(0,1));
#if 0
    result <<=1;
    result |= 1;
#endif
  }
  return result;
}



/*
  Outputs the expression 'e', rep times.
*/
void
evalone(exp e, int rep)
{
  ash a;
  int overflow;
  if (e == nilexp) return;
  a = ashof (sh (e));
  switch (name (e)) {
  case string_tag: {
    long char_size = props(e);
    long  strsize = shape_size(sh(e))/char_size;
    char *st = nostr(e);
    long  strs = shape_size(sh(e))>>3;
    int   i,j;
    int hex_output=0;
#if DO_SCHEDULE
    char * outline = (char*)xcalloc(80,sizeof(char));
#endif
    if (rep != 1 && as_file){
#if !DO_SCHEDULE
      (void)fprintf (as_file, "\t.repeat %d\n", rep);
#else
      (void)sprintf(outline,"\t.repeat %d\n",rep);
      outass(outline);
#endif
    }
    set_align(a.ashalign);
    if(as_file){
      if(strsize<256 && (char_size ==8)){
#if !DO_SCHEDULE
	(void)fprintf(as_file,"\t.ascii\t\"");
#else
	outass("\t.ascii\t\"");
#endif
	for(j=0;j<strsize;++j){
	  if(st[j]>=32 && st[j]<0x7f && (!hex_output)){
	    if(st[j]=='\"'){
#if !DO_SCHEDULE
	      (void)fprintf(as_file,"\\\"");
#else
	      outass("\\\"");
#endif
	    }
	    else if(st[j]=='\\'){
#if !DO_SCHEDULE
	      (void)fprintf(as_file,"\\\\");
#else
	      outass("\\\\");
#endif
	    }
	    else{
#if !DO_SCHEDULE
	      (void)fprintf(as_file,"%c",st[j]);
#else
	      (void)sprintf(outline,"%c",st[j]);
	      outass(outline);
#endif
	    }
	  }	
	  else{
#if !DO_SCHEDULE
	    (void)fprintf(as_file,"\\X%x",st[j]&0xff);
#else
	    (void)sprintf(outline,"\\X%x",st[j]&0xff);
	    outass(outline);
#endif
	    hex_output=1;
	  }
	 }
#if !DO_SCHEDULE
	(void)fprintf(as_file,"\"\n");
#else
	outass("\"\n");
#endif
      }
      else{
	for (j=0; j< strsize; ) {
	  switch(char_size) {
	  case 8:{
#if !DO_SCHEDULE
	    (void)fprintf (as_file, "\t.byte ");
#else	
	    outass("\t.byte ");
#endif	
	    break;
	  }
	  case 16:{
#if !DO_SCHEDULE
	    (void)fprintf (as_file, "\t.word ");
#else	
	    outass("\t.word ");
#endif
	    break;
	  }
	  case 32:{
#if !DO_SCHEDULE
	    (void)fprintf (as_file, "\t.long "); 
#else
	    outass("\t.long ");
#endif
	    break;
	  }
	  case 64:{
#if !DO_SCHEDULE
	    (void)fprintf (as_file, "\t.quad "); 
#else	
	    outass("\t.quad ");
#endif
	    break;
	  }
	  }
	  for (i = j; i < strsize && i-j < 8; i++) {
	    if (i != j) 
	      outstring(", ");
	    switch (char_size) { 
	    case 8:
#if !DO_SCHEDULE
	      (void)fprintf (as_file, "0x%x", st[i]&0xff); 
#else
	      sprintf(outline,"0x%x", st[i]&0xff); 
	      outass(outline);
#endif
	      break;
	    case 16:
#if !DO_SCHEDULE
	      (void)fprintf (as_file, "0x%x", ((unsigned short *)st)[i]); 
#else
	      (void)sprintf (outline, "0x%x", ((unsigned short *)st)[i]); 
	      outass(outline);
#endif
	      break;
	    case 32:
#if !DO_SCHEDULE
	      (void)fprintf (as_file, "0x%x", ((int *)st)[i]); 
#else
	      (void)sprintf (outline, "0x%x", ((int *)st)[i]); 
	      outass(outline);
#endif
	      break;
	    case 64:{
	      flt64 bigint;
	      bigint = flt_to_f64(((flpt*)st)[i],is_signed(sh(e)),&overflow);
#if !DO_SCHEDULE
	      out_INT64(flt64_to_INT64(bigint));
#else
	      sprintf(outline,"%ld", flt64_to_INT64(bigint));
	      outass(outline);
#endif	
	      break;
	    }		        	        
	    }
	  }
	  j =i;
#if DO_SCHEDULE
	  outass("\n");
#else
	  (void)fprintf (as_file, "\n");
#endif
	}
      }
    }
#if !DO_SCHEDULE
    out_chars(0,iascii,strs,rep);
#else
    output_data(outass((char*)NULL),out_chars(0,iascii,strs,rep));
#endif     
    if(char_size == 64){
      /* replace the float indexes used to represent the array */
      char * newst = (char*)xcalloc(strs,sizeof(char));
      int i;
      for(i=0;i<strsize;++i){
	((INT64*)newst)[i] = flt64_to_INT64(flt_to_f64(((flpt*)st)[i],
						       is_signed(sh(e)),
						       &overflow));
      }
#if DO_SCHEDULE
      output_data_records((char*)NULL,newst,strs);
#else
      out_data(newst,strs);
#endif
    }
    else{
#if DO_SCHEDULE
      output_data_records((char*)NULL,st,strs);
      output_data((char*)NULL,out_data(st,strs));
#else       
      out_data(st,strs);
#endif
    }
    return;
  }
  case real_tag: {
    outfloat(e,rep,a);
    return;
  }	
  case null_tag: 
    no (e) = 0;
    FALL_THROUGH
  case val_tag: {
    if(isbigval(e)){
      oneval(flt64_to_INT64(exp_to_f64(e)),a.ashalign,rep);
    }	
    else{
      if((al2(sh(e)) >= 8) && (name(sh(e)) == offsethd)){
	no(e) = no(e)>>3;
      }
      if(is_signed(sh(e))){
	oneval(make_INT64(0,no(e)),a.ashalign,rep);
      }
      else{
	oneval(make_INT64(0L,(unsigned)uno(e)),a.ashalign,rep);
      }	
    }
    return;
    }	
  case name_tag: {
    dec * globdec= brog(son (e));/* must be global name */
    char *nm = globdec -> dec_u.dec_val.dec_id;
    long symdef = globdec ->dec_u.dec_val.sym_number;
    char *storage_type;
    int storage_id;
    char * outline = (char*)NULL;
    switch(a.ashalign){
      case 8:
      storage_type = s_byte;
      storage_id = ibyte;
      break;
      case 16:
      storage_type = s_word;
      storage_id = iword;
      break;
      case 32:
      storage_type = s_long;
      storage_id = ilong;
      break;
      case 64:
      storage_type = s_quad;
      storage_id = iquad;
      break;
    }	
    set_align(a.ashalign);	
    if (as_file) {
#if DO_SCHEDULE
      outline = (char*)xcalloc(40,sizeof(char));
#endif
      if (no (e) == 0) {
#if !DO_SCHEDULE
	(void)fprintf (as_file, "\t.%s %s : %d\n", storage_type,nm, rep);
#else
	(void)sprintf (outline, "\t.%s %s : %d\n", storage_type,nm, rep);
#endif
      }		
      else {
#if !DO_SCHEDULE
	(void)fprintf (as_file, "\t.%s %s + %d :%d\n", storage_type,
			nm, no (e) / 8, rep);
#else
	(void)sprintf (outline, "\t.%s %s + %d :%d\n", storage_type,
			nm, no (e) / 8, rep);
#endif
      }
    }
#if DO_SCHEDULE
    output_data(outline,out_value(symnos[symdef],storage_id,no(e)/8,rep));
#else     
    out_value(symnos[symdef],storage_id,make_INT64(0,no(e)/8),rep);
#endif
    return;
   }
  case compound_tag:  {
    exp tup = son (e);
    INT64 val;
    bool first_bits=1;
    long bits_start =0;
    long offs =0;
    if (rep != 1)
      failer ("CAN'T REP TUPLES");
    set_align(a.ashalign);
    for(;;) {
      ash ae;
      ae = ashof(sh(bro(tup)));
      offs = no(tup);
      if (ae.ashalign == 1) {
	INT64 vb = evalexp(bro(tup));			
	if (first_bits) {
	  val = INT64_and(vb,bits_list(ae.ashsize));
	  /*val = vb & bits_list(ae.ashsize);*/
	  bits_start =offs;
	  first_bits=0;
	}	
	else 
	  if (offs - bits_start +ae.ashsize <= REG_SIZE) {
	    val = INT64_or(val,
		      INT64_shift_left(
				       INT64_and(vb,bits_list(ae.ashsize)),
				       offs-bits_start,1)
			   );
	    /*val |= ((vb&bits_list(ae.ashsize)) <<(offs-bits_start));*/
	  }
	  else {
	    if (BIGEND) {
	      for(;;) {
		oneval(INT64_shift_right(val,24,1),8,1);
		/*oneval(val>>24, 8, 1);*/
		val = INT64_shift_left(val,8,1);
		/*val <<=8;*/
		bits_start+=8;
		if (offs-bits_start <= 0) break;
	      }	
	    }
	    else {                          
	      for(;;) {  
		oneval(INT64_and(val,make_INT64(0,255)),8,1);
		/*oneval(val &255, 8,1);*/
		/*val >>= 8;*/
		val = INT64_shift_right(val,8,1);
		bits_start += 8;
		if (offs - bits_start  <=0)
		  break;
	      }
	    }
	    val = vb;
	  }
      }
      else {
	if (!first_bits) {
	  first_bits=1;
	  if (BIGEND) {
	    for(;;) {
	      oneval(INT64_shift_right(val,24,1),8,1);
	      /*oneval(val>>24, 8, 1);*/
	      val = INT64_shift_left(val,8,1);
	      /*val <<=8;*/
	      bits_start+=8;
	      if (offs-bits_start <= 0) break;
	    }
	  }
	  else {		    
	    for(;;) {  
	      oneval(INT64_and(val,make_INT64(0,255)),8,1);
	      /*oneval(val &255, 8,1);*/
	      val = INT64_shift_right(val,8,1);
	      /*val >>=8;*/
	      bits_start += 8;
	      if ( offs - bits_start  <=0)
		break;
	    }
	  }
	}
	evalone(bro(tup),1);
      }
      if (last(bro(tup))) {
	offs += ae.ashsize;
	for(;!first_bits;) {
	  if (BIGEND) {
	    oneval(INT64_shift_right(val,24,1),8,1);
	    /*oneval(val>>24, 8, 1);*/
	    val = INT64_shift_left(val,8,1);
	    /*val <<=8;*/
	    bits_start+=8;
	    if (offs-bits_start<= 0) break;
	  }
	  else {         
	    oneval(INT64_and(val,make_INT64(0,255)),8,1);
	    /*oneval(val &255, 8,1);*/
	    val = INT64_shift_right(val,8,1);
	    /*val >>= 8;*/
	    bits_start +=8;
	    if ( offs - bits_start <=0)
	      break;
	  }
	}	
	while (a.ashsize > offs) { /* pad out unions etc */
	  oneval(make_INT64(0,0),8,1);
/*	  oneval(0,8,1);*/
	  offs+=8;
	}
	return;
      }
      tup = bro(bro(tup));
    }
  }	
  case nof_tag: {
    exp s = son(e);
    if (rep != 1)
      failer ("CAN'T REP TUPLES");   	
    set_align(a.ashalign);
    if (s == nilexp) return;
    for(;;) {
      evalone(s,1);
      if (last(s)) return;
      s = bro(s);
    }
  }		
  case ncopies_tag: {
    if (name(son(e)) == compound_tag || name(son(e)) == concatnof_tag ||
	name(son(e)) == nof_tag) {
      int n;
      for (n = rep*no(e); n > 0; n--) {
	evalone(son(e), 1);
      }
    }
    else evalone (son (e), rep * no (e));
    return;
  }
  case concatnof_tag: {
    if (a.ashalign == 1) {
      INT64 ee = evalexp(e);
      /*long  ee = evalexp (e);*/
      exp dad = father(e);
      ash abits;
      abits = ashof(sh(dad));
      oneval(ee, abits.ashalign, rep);
    }
    else {
      if (rep != 1)
	failer ("CAN'T REP concat");
      evalone (son (e), 1);
      evalone (bro (son (e)), 1);
    }
    return;
  }
  case clear_tag: {
    char * outline;
    if (as_file){
#if !DO_SCHEDULE
      (void)fprintf (as_file, "\t.space %d\n",((a.ashsize+7)>>3) * rep);
#else
      outline = (char*)xcalloc(20,sizeof(char));
      sprintf(outline,"\t.space %d\n",((a.ashsize+7)>>3) * rep);
#endif
    }
#if DO_SCHEDULE
    output_data(outline,out_value(0,ispace,((a.ashsize+7)>>3)+rep,1));
#else
    out_value (0, ispace, make_INT64(0,((a.ashsize + 7) >> 3) * rep), 1);
#endif
    return;
  }
    case not_tag : 
    case and_tag : 
    case or_tag : 
    case shl_tag : 
    case shr_tag : 
    case bitf_to_int_tag : 
    case int_to_bitf_tag :
    case general_env_offset_tag :
    case env_offset_tag :
    case env_size_tag :
    case offset_add_tag :
    case offset_max_tag :
    case offset_pad_tag :
    case offset_mult_tag :
    case offset_div_tag :
    case offset_div_by_int_tag :
    case offset_subtract_tag :
    case offset_negate_tag : {
#if 1
      INT64 ee = evalexp (e);
      oneval(ee, a.ashalign, rep);
#endif
      return;
    }
#if 1
  case chvar_tag: {
    sh(son(e)) = sh(e);
    evalone(son(e),1);
    alphawarn("Dubious change variety\n");
    return;
  }
#endif
  default: 
    failer ("tag not in evaluated");
  }				/* end switch */
}	


/*
  evaluated
  
  This outputs data from the evaluated exp into either .sdata 
  or .data depending on size and labels this data either with 
  either id in main_globals or an anonymous label derived from l. 
  The result is the instore "address" of the constant. A negative 
  l implies that this is the initialisation of a global variable.
*/
instore
evaluated(exp e, int l)
{
  
  int   lab = (l == 0) ? next_dlab_sym () 
    : (l< 0)? l: -l;
  int   lab0 = lab;
#if DO_SCHEDULE
  char * outline = (char*)xcalloc(80,sizeof(char));
#endif
  ash a;
  instore isa;
  exp z = e;

  isa.adval = 0;
  isa.b.offset = 0;
  isa.b.base = lab0;
  if (name (e) == clear_tag) {/* uninitialised global */
    int   size = (ashof (sh (e)).ashsize + 7) >> 3;
    bool temp = (l == 0 ||
		 (main_globals[-lab - 1] -> dec_u.dec_val.dec_id)[0] == '$');
    if (as_file) {
#if !DO_SCHEDULE
      (void)fprintf (as_file, (temp) ? "\t.lcomm\t" : "\t.comm\t");
      outlab(lab);
#else
      outass((temp)?"\t.lcomm\t":"\t.comm\t");
      outass(outlab(lab));
#endif	
#if !DO_SCHEDULE
      (void)fprintf (as_file, ", %d\n", size);
#else
      sprintf(outline,", %d\n",size);
      outass(outline);
#endif
    }
#if DO_SCHEDULE
    output_data(outass((char*)NULL),out_value((lab>=0)?tempsnos[lab-32]:
				  symnos[-lab-1],(temp)?ilcomm:icomm,size,1));
    
#else
    out_value((lab>=0)?tempsnos[lab-32]:symnos[-lab-1],(temp)?ilcomm:icomm,
	      make_INT64(0,size),1);
#endif      
    return isa;
  }
  a = ashof (sh (z));
  if (a.ashsize <= G_number) {
    if (as_file){
#if DO_SCHEDULE
      outline = (char*)xcalloc(20,sizeof(char));
      (void)sprintf(outline, "\t" SDATA_INSTR "\n");
#else
      (void)fprintf (as_file, "\t" SDATA_INSTR "\n");
#endif
    }
#if DO_SCHEDULE
    output_data(outline,out_common(0,isdata));
#else
    out_common(0,isdata);
#endif
  }
  else {
    if (as_file){
#if DO_SCHEDULE
      outline = (char*)xcalloc(20,sizeof(char));
      (void)sprintf(outline, "\t.data\n");
#else	
      (void)fprintf (as_file, "\t.data\n");
#endif
    }
#if DO_SCHEDULE
    output_data(outline,out_common(0,idata));
#else      
    out_common(0,idata);
#endif
  }
  if (as_file) {
#if DO_SCHEDULE
    outline = outlab(lab);
    strcat(outline,":\n");
#else    
    (void)outlab (lab);
    (void)fprintf (as_file, ":\n");
#endif
  }
#if DO_SCHEDULE
  output_data(outline,out_common((lab>0)?tempsnos[lab-32]:symnos[-lab-1],
				 ilabel));
#else
  out_common((lab>0)?tempsnos[lab-32]:symnos[-lab-1],ilabel);
#endif
  if(as_file){
#if !DO_SCHEDULE
    fprintf(as_file,"\t.align 3\n");
    fprintf(as_file,"\t.align 0\n");
#endif
  }
#if DO_SCHEDULE
  output_instruction(class_null,"\t.align 3\n",out_value(0,ialign,3,0));
  output_instruction(class_null,"\t.align 0\n",out_value(0,ialign,0,0));
#else
  out_value(0,ialign,make_INT64(0,3),0);
  out_value(0,ialign,make_INT64(0,0),0);
#endif
  current_alignment=8;
  evalone (z, 1);
  return isa;
}










