/*  $VER: vbcc (supp.c) $Revision: 1.49 $     */

#include "supp.h"
#include "opt.h"

static char FILE_[]=__FILE__;

#ifndef HAVE_EXT_TYPES
char *typname[]={"strange","char","short","int","long","long long",
                 "float","double","long double","void",
                 "pointer","array","struct","union","enum","function",
                 "bool","vector"};
#endif

char *storage_class_name[]={"strange","auto","register","static","extern","typedef"};

char *ename[]={"strange","sequence","move","set+","set-","set*","set/","set%",
               "set&","set^","set|","set<<","set>>","?:","lor","land","or",
               "eor","and","eq","neq","lt","le","gt","ge","lsl",
               "lsr","add","sub","mul","div","mod","negate",
               "not","preinc","postinc","predec","postdec","neg",
               "dref-pointer","address-of","cast","call","index",
               "dref-struct-pointer","dref-struct","identifier","constant",
               "string","member",
                "convert","convert-short","convert-int","convert-long",
                "convert-float","convert-double","convert-void","convert-pointer",
                "convert-uchar","convert-ushort","convert-uint","convert-ulong",
                "address-of-array","first-element-of-array","pmult",
                "allocreg","freereg","pconstant","test","label","beq","bne",
                "blt","bge","ble","bgt","bra","compare","push","pop",
                "address-of-struct","add-int-to-pointer","sub-int-from-pointer",
                "sub-pointer-from-pointer","push-reg","pop-reg","pop-args",
                "save-regs","restore-regs","identifier-label","dc","align",
                "colon","get-return","set-return","move-from-reg","move-to-reg",
                "nop","bitfield"};

char *empty="";
zchar vchar; zuchar vuchar;
zshort vshort; zushort vushort;
zint vint; zuint vuint;
zlong vlong; zulong vulong;
zllong vllong; zullong vullong;
zmax vmax; zumax vumax;
zfloat vfloat; zdouble vdouble;
zldouble vldouble;

union atyps gval;

#ifndef DEBUG
int DEBUG;
#endif

int label;

int regs[MAXR+1],regused[MAXR+1],simple_scratch[MAXR+1];
Var *regsv[MAXR+1];
int goto_used;
int ic_count;
zmax max_offset;
int function_calls,vlas;
int coloring;
int dmalloc;
int disable;
int multiple_ccs;
int lastlabel,return_label;
int only_inline;
IC *err_ic;
long maxoptpasses=30;
long optflags;
int optsize,optspeed,unroll_all,stack_check;
int cross_module,final,no_emit;
int debug_info;
long inline_size=100;
long inline_depth=1;
long unroll_size=200;
long clist_copy_stack=6;
long clist_copy_static=6;
long clist_copy_pointer=20;
long inline_memcpy_sz=INLINEMEMCPY;
int fp_assoc,noaliasopt,noitra;
char *filename;
IC *first_ic,*last_ic;
int float_used;
bvtype regs_modified[RSIZE/sizeof(bvtype)];
/*  Das haette ich gern woanders    */
Var *vl0,*vl1,*vl2,*vl3;
int align_arguments=1;
zmax stackalign;
int misracheck,misraversion,misracomma,misratok;
int pack_align;
int short_push;
int default_unsigned;
Var *add_attr_haddecl;

char *emit_buffer[EMIT_BUF_DEPTH];
char *emit_p;
int emit_f,emit_l;
int no_inline_peephole;

static int get_scalar_byte(int f,union atyps *v,zmax n, zuchar *out)
/* Yields byte n of a constant */
{
  if(!zmleq(l2zm(0L),n)) ierror(0);
  f&=NQ;
  if(f>=CHAR&&f<=LLONG){
    int j;
    eval_const(v,f);
    if(LITTLEENDIAN)
      j=zm2l(n);
    else
      j=(int)sizetab[f]-(int)zm2l(n)-1;
    while(j){
      vumax=zumrshift(vumax,char_bit);
      j--;
    }
    *out=zum2zuc(vumax);
    return 1;
  }else
    return 0;
}

zumax get_clist_int(type *t, const_list *cl, zmax n, int sz,int *state)
/* yields an integer of size sz from offset n */
{
  zuchar zuc;
  zumax val = ZU0;

  if(LITTLEENDIAN)
    n=zmadd(n,l2zm((long)(sz-1)));
  
  while(sz){
    val=zumlshift(val,char_bit);
    if(!get_clist_byte(t,cl,n,&zuc)) {*state=0;return ZU0;}
    val=zumadd(val,zuc2zum(zuc));
    sz--;
    n=LITTLEENDIAN?zmsub(n,Z1):zmadd(n,Z1);
  }
  *state=1;
  return val;
}

int get_clist_byte(type *t,const_list *cl, zmax n, zuchar *out)
/* Yields byte n from a const list */
{
  if(!cl){
    *out=zum2zuc(ul2zum(0UL));
    return 1;
  }

  if(ISARRAY(t->flags)){
    zmax i,j,x;
    x=szof(t->next);
    i=zmdiv(n,x);
    while(1){
      if(!cl) break;
      if(zmleq(i,cl->idx)) break;
      cl=cl->next;
    }
    if(!cl||!zmeqto(cl->idx,i)){
      *out=zum2zuc(ul2zum(0UL));
      return 1;
    }
    return get_clist_byte(t->next,cl->other,zmmod(n,x),out);
  }
  if(ISUNION(t->flags)){
    int i=zm2l(cl->idx);
    if(cl->tree) return 0;
    return get_clist_byte((*t->exact->sl)[i].styp,cl->other,n,out);
  }
  if(ISSTRUCT(t->flags)){
    zmax al;int fl;type *st;
    int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL);

    sz=l2zm(0L);
    if(cl&&cl->tree){
      /* initialized by another */
      return 0;
    }else{
      for(i=0;i<t->exact->count&&cl;i++){
	if(!cl->other){ierror(0);}
	st=(*t->exact->sl)[i].styp;
	al=(*t->exact->sl)[i].align;
	if(!(*t->exact->sl)[i].identifier) ierror(0);
	bfo=(*t->exact->sl)[i].bfoffset;
	if(!zmeqto(zmmod(sz,al),l2zm(0L))){
	  sz=zmadd(sz,zmsub(al,zmmod(sz,al)));
	  if(!zmleq(sz,n)){
	    *out=zum2zuc(ul2zum(0L));
	    return 1;
	  }
	}
	if(bfo>=0){
	  /* bitfield */

	  if((*t->exact->sl)[i].identifier[0]){
	    bfs=(*t->exact->sl)[i].bfsize;
	    if(zmeqto(l2zm((long)i),cl->idx)){
	      eval_const(&cl->other->val,st->flags);
	      cl=cl->next;
	    }else{
	      vumax=ul2zum(0UL);
	    }
	    vumax=zumand(vumax,zumsub(zumlshift(ul2zum(1UL),ul2zum((unsigned long)bfs)),ul2zum(1UL)));
	    bfval=zumor(bfval,zumlshift(vumax,ul2zum((unsigned long)bflayout(bfo,bfs,st->flags))));
	  }          
	  if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){
	    /* last bitfield in integer */
	    gval.vumax=bfval;
	    eval_const(&gval,UNSIGNED|MAXINT);
	    insert_const(&gval,st->flags&NU);
	    bfval=ul2zum(0L);
	    sz=zmadd(sz,szof(st));
	    if(!zmleq(sz,n))
	      return get_scalar_byte(st->flags,&gval,zmsub(n,zmsub(sz,szof(st))),out);
	  }
	}else{
	  sz=zmadd(sz,szof(st));
	  if(!zmleq(sz,n)){
	    if(zmeqto(l2zm((long)i),cl->idx)){
	      return get_clist_byte(st,cl->other,zmsub(n,zmsub(sz,szof(st))),out);
	    }else{
	      *out=zum2zuc(ul2zum(0UL));
	      return 1;
	    }
	  }
	  if(zmeqto(l2zm((long)i),cl->idx))
	    cl=cl->next;
	}
      }
    }
    *out=zum2zuc(ul2zum(0UL));
    return 1;
  }

  if(zmeqto(cl->idx,l2zm(-1L)))
    return 0;
  else{
    if(cl->tree)
      return 0;
    else
      return get_scalar_byte(t->flags,&cl->val,n,out);

  }
  ierror(0);
}

type *new_typ(void)
/*  Erzeigt neuen (leeren) Typ.  */
{
  type *new=mymalloc(TYPS);
  new->flags=0;
  new->next=0;
  new->exact=0;
  new->attr=0;
  new->dsize=0;
  new->reg=0;
#ifdef HAVE_ECPP
/* removed */
#endif
  return new;
}

type *clone_typ(type *old)
/*  Erzeugt Kopie eines Typs und liefert Zeiger auf Kopie.  */
{
  type *new;
  if(!old) return 0;
  new=new_typ();
  *new=*old;
  if(old->attr){
    new->attr=mymalloc(strlen(old->attr)+1);
    strcpy(new->attr,old->attr);
  }
  if(new->next) new->next=clone_typ(new->next);
  return new;
}
Var *new_var(void)
{
  Var *new=mymalloc(sizeof(*new));
  new->clist=0;
  new->vtyp=0;
  new->storage_class=0;
  new->reg=0;
  new->vattr=0;
  new->next=0;
  new->flags=0;
  new->fi=0;
  new->nesting=0;
  new->filename=0;
  new->line=0;
  new->dfilename=0;
  new->dline=0;
  new->description=0;
  new->tunit=0;
  new->offset=l2zm(0L);
  new->identifier=0;
#ifdef HAVE_TARGET_ATTRIBUTES
  new->tattr=0;
#endif 
#ifdef ALEX_REG
  new->iRegCopyNr = -1;
  new->iRegCopyNrHc12V = -1;
#endif
  return new;
}  

IC *new_IC(void)
{
  IC *p=mymalloc(ICS);
  p->change_cnt=0;
  p->use_cnt=0;
  p->call_cnt=0;
  p->arg_cnt=0;
  p->use_list=0;
  p->change_list=0;
  p->call_list=0;
  p->arg_list=0;
  p->line=0;
  p->file=0;
  p->flags=0;
  p->q1.flags=p->q2.flags=p->z.flags=0;
  p->q1.am=p->q2.am=p->z.am=0;
  p->q1.val.vmax=p->q2.val.vmax=p->z.val.vmax=l2zm(0L);
  p->savedsp=0;
  p->typf=p->typf2=0;
#ifdef ALEX_REG
  p->iZWebIndex = -1;
  p->iQ1WebIndex = -1;
  p->iQ2WebIndex = -1;
  p->pFlow = NULL;
#endif /* GC_RALLOC */

  return p;
}
/* (partially) clones an IC list */
IC *clone_ic(IC *p)
{
  IC *new,*first,*last;
  first=last=new=0;
  while(p){
    new=mymalloc(sizeof(*new));
    *new=*p;
    p->copy=new;

    if(p->q1.am||p->q2.am||p->z.am) ierror(0);
    
    if(new->code==CALL){
      int i;
      new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt);
      for(i=0;i<new->arg_cnt;i++){
	if(!p->arg_list[i])
	  ierror(0);
	if(!p->arg_list[i]->copy)
	  ierror(0);
        new->arg_list[i]=p->arg_list[i]->copy;
      }
    }
    new->prev=last;
    new->next=0;
    if(!first) first=new;
    if(last) last->next=new;
    last=new;
    p=p->next;
  }
  return first;
}    
void free_IC(IC *p)
/*  Gibt IC-Liste inkl. Typen frei.                 */
{
  IC *merk;
  if(DEBUG&1) printf("free_IC()\n");
  while(p){
    /*if(p->q1.am&&!p->q1.flags) ierror(0);
    if(p->q2.am&&!p->q2.flags) ierror(0);
    if(p->z.am&&!p->z.flags) ierror(0);*/

    if(p->q1.am&&p->q1.am==p->q2.am)
      ierror(0);

    if(p->q1.am) free(p->q1.am);
    if(p->q2.am) free(p->q2.am);
    if(p->z.am) free(p->z.am);
    if(p->code==CALL) free(p->arg_list);
    merk=p->next;
    free(p);
    p=merk;
  }
}
void move_IC(IC *after,IC *p)
{
  if(p->prev)
    p->prev->next=p->next;
  else
    first_ic=p->next;
  if(p->next)
    p->next->prev=p->prev;
  else
    last_ic=p->prev;
  insert_IC(after,p);
}
void remove_IC(IC *p)
/*  Entfernt IC p aus Liste. */
{
  if(p->prev) p->prev->next=p->next; else first_ic=p->next;
  if(p->next) p->next->prev=p->prev; else last_ic=p->prev;
  if(p->q1.am) free(p->q1.am);
  if(p->q2.am) free(p->q2.am);
  if(p->z.am) free(p->z.am);
  free(p);
}
void freetyp(type *p)
/* Gibt eine Typ-Liste frei, aber keine struct_declaration oder so. */
{
  int f;type *merk;
  if(DEBUG&8){printf("freetyp: ");prd(stdout,p);printf("\n");}
  while(p){
    merk=p->next;
    f=p->flags&NQ;
    if(merk&&!ISARRAY(f)&&!ISPOINTER(f)&&!ISFUNC(f)&&!ISVECTOR(f)) 
      ierror(0);
    free(p->attr);
    free(p);
    p=merk;
  }
}

#ifndef HAVE_TGT_FALIGN
zmax falign(type *t)
/*  Liefert Alignment eines Typs. Funktioniert im Gegensatz zum  */
/*  align[]-Array auch mit zusammengesetzten Typen.              */
{
  int i,f; zmax al,alt;
  f=t->flags&NQ;
  if(ISVECTOR(f)) return szof(t);
  al=align[f];
  if(ISSCALAR(f)) return al;
  if(ISARRAY(f)){
    do{ 
      t=t->next; 
      f=t->flags&NQ;
    }while(ISARRAY(f)||ISVECTOR(f));
    alt=falign(t);
    if(zmleq(al,alt)) return alt; else return al;
  }
  if(ISUNION(f)||ISSTRUCT(f)){
    if(!t->exact) ierror(0);
    for(i=0;i<t->exact->count;i++){
      alt=(*t->exact->sl)[i].align;
      if(!zmleq(alt,al)) al=alt;
    }
  }
  return al;
}
#endif

/* check, whether t is a variable length array */
int is_vlength(type *t)
{
  if(!ISARRAY(t->flags))
    return 0;
  if(t->dsize)
    return 1;
  else 
    return is_vlength(t->next);
}

/* calculate size of a variable length array */
Var *vlength_szof(type *t)
{
  IC *new;type *nt;
  if(!ISARRAY(t->flags))
    ierror(0);
  new=new_IC();
  new->code=MULT;
  new->typf=HAVE_INT_SIZET?(UNSIGNED|INT):(UNSIGNED|LONG);
  if(t->dsize){
    new->q1.flags=VAR;
    new->q1.v=t->dsize;
    new->q1.val.vmax=l2zm(0L);
  }else{
    new->q1.flags=KONST;
#if HAVE_INT_SIZET
    new->q1.val.vuint=zum2zui(zm2zum(t->size));
#else
    new->q1.val.vulong=zum2zul(zm2zum(t->size));
#endif
  }
  new->z.flags=VAR;
  nt=new_typ();
  nt->flags=new->typf;
  new->z.v=add_tmp_var(nt);
  new->z.val.vmax=l2zm(0L);
  if(is_vlength(t->next)){
    new->q2.flags=VAR;
    new->q2.v=vlength_szof(t->next);
    new->q2.val.vmax=l2zm(0L);
  }else{
    new->q2.flags=KONST;
#if HAVE_INT_SIZET
    new->q2.val.vuint=zum2zui(zm2zum(szof(t->next)));
#else
    new->q2.val.vulong=zum2zul(zm2zum(szof(t->next)));
#endif
  }
  add_IC(new);
  return new->z.v;
}

/* return the type of a d-dim vector of base type x */
int mkvec(int x,int d)
{
  int t=x&NQ,r;
  if(d!=2&&d!=3&&d!=4&&d!=8&&d!=16) ierror(0);
  switch(t){
  case BOOL:
    r=VECBOOL;break;
  case CHAR:
    r=VECCHAR;break;
  case SHORT:
    r=VECSHORT;break;
  case INT:
    r=VECINT;break;
  case LONG:
    r=VECLONG;break;
  case FLOAT:
    r=VECFLOAT;break;
  default:
    ierror(0);
  }
  return (r+d-1)|(x&~NQ);
}

/* return the base type of a vector */
int VECTYPE(int x)
{
  int t=x&NQ,r=0;
  if(t>=VECBOOL&&t<=VECBOOL+MAXVECDIM)
    r=BOOL;
  if(t>=VECCHAR&&t<=VECCHAR+MAXVECDIM)
    r=CHAR;
  if(t>=VECSHORT&&t<=VECSHORT+MAXVECDIM)
    r=SHORT;
  if(t>=VECINT&&t<=VECINT+MAXVECDIM)
    r=INT;
  if(t>=VECLONG&&t<=VECLONG+MAXVECDIM)
    r=LONG;
  if(t>=VECFLOAT&&t<=VECFLOAT+MAXVECDIM)
    r=FLOAT;
  if(!r) ierror(0);
  return r|(x&~NQ);
}


#ifndef HAVE_TGT_SZOF
zmax szof(type *t)
/*  Liefert die benoetigte Groesse eines Typs in Bytes.     */
{
  int i=t->flags&NQ,j;zmax size,m;
#ifdef HAVE_ECPP
/* removed */
#endif

  if(ISSCALAR(i)) return sizetab[i];
  if(ISARRAY(i)){
    if(is_vlength(t))
      return sizetab[POINTER_TYPE(t->next)];
    size=zmmult((t->size),szof(t->next));
    m=align[ARRAY];
    return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
  }
  if(ISVECTOR(i)){
    zmax dim=VECDIM(i);
    if(zmeqto(dim,l2zm(3L))) dim=l2zm(4L);
    return zmmult(dim,sizetab[VECTYPE(i)&NQ]);
  }
  if(ISUNION(i)){
    for(j=0,size=l2zm(0L);j<t->exact->count;j++){
      m=szof((*t->exact->sl)[j].styp);
      if(zmeqto(m,l2zm(0L))) return l2zm(0L);
      if(!zmleq(m,size)) size=m;
    }
    m=falign(t);
    return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
  }
  if(ISSTRUCT(i)){
    size=l2zm(0L);
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
    for(j=0;j<t->exact->count;j++){
      type *h=(*t->exact->sl)[j].styp;
      if((*t->exact->sl)[j].bfoffset<=0){
	int n;size_t al;
        al=(*t->exact->sl)[j].align;
#ifdef HAVE_ECPP
/* removed */
#endif
        if(zmeqto(al,l2zm(0L))) {prd(stdout,h);ierror(0);}
        m=szof(h);
	/* find the largest type in a bitfield */
	for(n=j+1;n<t->exact->count&&(*t->exact->sl)[n].bfoffset>0;n++){
	  size_t tmp=szof((*t->exact->sl)[n].styp);
	  if(zmleq(m,tmp))
	    m=tmp;
	}
        size=zmmult(zmdiv(zmadd(size,zmsub(al,l2zm(1L))),al),al);
        /*if(zmeqto(m,l2zm(0L))) return l2zm(0L);*/
        size=zmadd(size,m);
      }
    }
    m=falign(t);
    return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */
  }
  return sizetab[i];
}
zmax struct_offset(struct_declaration *sd,const char *identifier)
{
  int i=0,intbitfield=-1;zmax offset=l2zm(0),al;
  while(i<sd->count&&strcmp((*sd->sl)[i].identifier,identifier)){
    if((*sd->sl)[i].bfoffset>=0){
      if(i+1<sd->count&&(*sd->sl)[i+1].bfoffset>0){
        i++;
        continue;
      }
    }
    al=(*sd->sl)[i].align;
    offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
    offset=zmadd(offset,szof((*sd->sl)[i].styp));
    i++;
  }
  if(i>=sd->count) {error(23,identifier);return l2zm(0L);}
  al=(*sd->sl)[i].align;
  offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al);
  return offset;
}
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
#endif

#ifndef HAVE_TGT_PRINTVAL
void printval(FILE *f,union atyps *p,int t)
/*  Gibt atyps aus.                                     */
{
  t&=NU;
  if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);}
  if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);}
  if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);}
  if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);}
  if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);}
  if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);}
  if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);}
  if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);}
  if(t==(UNSIGNED|INT)){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);}
  if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);}
  if(t==(UNSIGNED|LONG)){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);}
  if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);}
  if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);}
  if(t==MAXINT){fprintf(f,"M");printzm(f,p->vmax);}
  if(t==(UNSIGNED|MAXINT)){fprintf(f,"UM");printzum(f,p->vumax);}
  /*FIXME*/
  if(t==POINTER){fprintf(f,"P");vumax=zul2zum(p->vulong);printzum(f,vumax);}
}
void emitval(FILE *f,union atyps *p,int t)
/*  Gibt atyps aus.                                     */
{
  t&=NU;
  if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);}
  if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);}
  if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);}
  if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);}
  if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);}
  if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);}
  if(t==LDOUBLE){emitzld(f,p->vldouble);}
  if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);}
  if(t==(UNSIGNED|INT)){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
  if(t==(UNSIGNED|LONG)){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
  if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);}
  if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);}
  if(t==MAXINT){emitzm(f,p->vmax);}
  if(t==(UNSIGNED|MAXINT)){emitzum(f,p->vumax);}
  /*FIXME*/
  if(t==POINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);}
}
#endif

void pric2(FILE *f,IC *p)
/*  Gibt ein IC aus.  */
{
  if(p->code>NOP) ierror(0);
  if(p->next&&p->next->prev!=p) ierror(0);
  if(p->code>=LABEL&&p->code<=BRA){
    if(p->code==LABEL)
      fprintf(f,"L%d",p->typf);
    else{
      fprintf(f,"\t%s L%d",ename[p->code],p->typf);
      if(p->q1.flags){ fprintf(f,",");probj(f,&p->q1,0);}
    }
    if(p->code==LABEL&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (while-loop)");
    if(p->code==BRA&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (to-loop-test)");
  }else{
    fprintf(f,"\t%s ",ename[p->code]);
    if(p->typf&VOLATILE) fprintf(f,"volatile ");
    if(p->typf&CONST) fprintf(f,"const ");
    if(p->typf&UNSIGNED) fprintf(f,"unsigned ");
    if(p->typf){
      if(ISVECTOR(p->typf))
	fprintf(f,"%s%d ",typname[VECTYPE(p->typf)&NQ],VECDIM(p->typf));
      else
	fprintf(f,"%s ",typname[p->typf&NQ]);
    }
    probj(f,&p->q1,q1typ(p));
    if(p->q2.flags){fprintf(f,",");probj(f,&p->q2,q2typ(p));}
    if(p->z.flags){fprintf(f,"->");probj(f,&p->z,ztyp(p));}
    if(p->code==ASSIGN||p->code==PUSH||p->code==POP||p->code==CALL)
      fprintf(f," size=%ld",zm2l(p->q2.val.vmax));
    if((p->code==SAVEREGS||p->code==RESTOREREGS)&&p->q1.reg)
      fprintf(f," except %s",regnames[p->q1.reg]);
    if(p->code==CONVERT)
      fprintf(f," from %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
    if(p->code==LSHIFT||p->code==RSHIFT)
      fprintf(f," shift-type %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
    if(p->code==ADDI2P||p->code==SUBIFP||p->code==SUBPFP||p->code==ADDRESS)
      fprintf(f," ptype=%s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]);
    if(p->code==ASSIGN||p->code==PUSH)
      if(p->typf2) fprintf(f," align=%d\n",p->typf2);
  }
  if(p->code==CALL){
    fprintf(f," =>");
    if(p->call_cnt==0)
      fprintf(f,"(unknown)");
    else{
      int i;
      for(i=0;i<p->call_cnt;i++)
        fprintf(f," %s",p->call_list[i].v->identifier);
    }
    
  }
  if(p->flags&EFF_IC) fprintf(f," (eff_ic)");
  fprintf(f,"\n");
#if 0
  if(p->code==CALL){
    int i;
    //fprintf(f,"c=%p\n",p);
    for(i=0;i<p->arg_cnt;i++){
      //fprintf(f,"%p!\n",p->arg_list[i]);
      fprintf(f,"%02d:",i);
      pric2(f,p->arg_list[i]);
    }
  }
#endif
}
void pric(FILE *f,IC *p)
/*  Gibt IC-Liste auf dem Bildschirm aus.             */
{
  while(p){
    pric2(f,p);
/*        if(p->q1.am||p->q2.am||p->z.am) ierror(0);*/
    p=p->next;
  }
}
void printzm(FILE *f,zmax x)
/*  Konvertiert zmax nach ASCII.                       */
/*  Basiert noch einigermassen auf                      */
/*  Zweierkomplementdarstellung (d.h. -MIN>MAX).        */
/*  Ausserdem muss max(abs(max))<=max(unsigned max).  */
{
  zmax zm;zumax zum;
  zm=l2zm(0L);
  if(zmleq(x,zm)&&!zmeqto(x,zm)){
    fprintf(f,"-");zm=zum2zm(t_max(MAXINT));
    if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){
      /*  aufpassen, da -x evtl. >LONG_MAX    */
      zum=t_max(MAXINT);
      x=zmadd(x,zm);
    }else 
      zum=ul2zum(0UL);
    x=zmsub(l2zm(0L),x);
    vumax=zm2zum(x);
    zum=zumadd(zum,vumax);
  }else
    zum=zm2zum(x);
  printzum(f,zum);
}
void printzum(FILE *f,zumax x)
/*  Konvertiert zumax nach ASCII.                      */
{
  zumax zum;unsigned long l;
  zum=ul2zum(10UL);
  if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) printzum(f,zumdiv(x,zum));
  zum=zummod(x,zum);l=zum2ul(zum);
  fprintf(f,"%c",(int)(l+'0'));
}

void printzld(FILE *f,zldouble x)
/*  Konvertiert zdouble nach ASCII, noch nicht fertig.  */
{
  fprintf(f,"fp-constant");
}
void emitzm(FILE *f,zmax x)
/*  Konvertiert zmax nach ASCII.                       */
/*  Basiert noch einigermassen auf                      */
/*  Zweierkomplementdarstellung (d.h. -MIN>MAX).        */
/*  Ausserdem muss max(abs(max))<=max(unsigned max).  */
{
  zmax zm;zumax zum;
  zm=l2zm(0L);
  if(zmleq(x,zm)&&!zmeqto(x,zm)){
    emit(f,"-");zm=zum2zm(t_max(MAXINT));
    if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){
      /*  aufpassen, da -x evtl. >LONG_MAX    */
      zum=t_max(MAXINT);
      x=zmadd(x,zm);
    }else 
      zum=ul2zum(0UL);
    x=zmsub(l2zm(0L),x);
    vumax=zm2zum(x);
    zum=zumadd(zum,vumax);
  }else
    zum=zm2zum(x);
  emitzum(f,zum);
}
void emitzum(FILE *f,zumax x)
/*  Konvertiert zumax nach ASCII.                      */
{
  zumax zum;unsigned long l;
  zum=ul2zum(10UL);
  if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) emitzum(f,zumdiv(x,zum));
  zum=zummod(x,zum);l=zum2ul(zum);
  emit(f,"%c",(int)(l+'0'));
}

void emitzld(FILE *f,zldouble x)
/*  Konvertiert zdouble nach ASCII, noch nicht fertig.  */
{
  emit(f,"fp-constant");
}

typedef struct memblock {struct memblock *next;void *p;} memblock;
static memblock *first_mb;

static void add_mb(void *p)
{
  memblock *mb_second=first_mb;
  memblock *mb=malloc(sizeof(*mb));
  if(!mb){
    error(12);
    raus();
  }
  first_mb=mb;
  mb->next=mb_second;
  mb->p=p;
}  

static void remove_mb(void *p)
{
  memblock *mb_prev=0;
  memblock *mb=first_mb;
  while(mb){
    if(mb->p==p){
      if(mb_prev==0) first_mb=mb->next;
      else mb_prev->next=mb->next;
      (free)(mb);
      return;
    }
    mb_prev=mb;
    mb=mb->next;
  }
  ierror(0);
}

void *mymalloc(size_t size)
/*  Allocate memory and quit on failure.  */
{
  void *p;
  if(dmalloc)
    size+=sizeof(size);
  else if(size==0)
    /* Not very nice, but simplest way to avoid a failure when size==0. */
    size=1;
  if(!(p=malloc(size))){
    error(12);
    raus();
  }
  if(DEBUG&32768){
    printf("malloc %p (s=%lu)\n",p,(unsigned long)size);
    fflush(stdout);
  }
  if(DEBUG&65536) add_mb(p);
  if(dmalloc){
    *(size_t *)p=size;
    p=((char *)p)+sizeof(size);
    memset(p,0xaa,size-sizeof(size));
  } 
  return p;
}

void *myrealloc(void *p,size_t size)
/*  Reallocate memory and quit on failure.  */
{
  void *new;
  if(!p) return mymalloc(size);
  if(dmalloc){
    size+=sizeof(size);
    new=realloc(((char *)p)-sizeof(size),size);
    if(!new){
      error(12);
      raus();
    }
    if(DEBUG&32768){
      printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size);
      fflush(stdout);
    }
    if(DEBUG&65536){
      remove_mb(p);
      add_mb(new);
    }
    *(size_t *)new=size;
    new=((char *)new)+sizeof(size);
    return new;
  }else{
    new=realloc(p,size);
    if(!new){
      error(12);
      raus();
    }
    if(DEBUG&32768){
      printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size);
      fflush(stdout);
    }
    if(DEBUG&65536){
      remove_mb(p);
      add_mb(new);
    }
    return new;
  }
}

void myfree(void *p)
{
  if(p&&dmalloc){
    p=((char*)p)-sizeof(size_t);
    memset(p,0xbb,*(size_t *)(p));
  }
  if(DEBUG&32768){
    printf("free %p\n",p);
    fflush(stdout);
  }
  if((DEBUG&65536)&&p) remove_mb(p);
  (free)(p);  /* supp.h has #define free(x) myfree(x) */
}

char *mystrdup(char *p)
{
  char *new=mymalloc(strlen(p)+1);
  strcpy(new,p);
  return new;
}

/* Testet, ob zwei objs dieselben Register belegen. */
int collides(obj *x,obj *y)
{
    int x1,x2,y1,y2;
    if(!(x->flags&REG)||!(y->flags&REG)) return 0;
    if(reg_pair(x->reg,&rp)){
        x1=rp.r1;x2=rp.r2;
    }else{
        x1=x->reg;x2=-1;
    }
    if(reg_pair(y->reg,&rp)){
        y1=rp.r1;y2=rp.r2;
    }else{
        y1=y->reg;y2=-2;
    }
    if(x1==y1||x1==y2||x2==y1||x2==y2)
        return 1;
    else
        return 0;
}

/* Versucht, ein IC so zu drehen, dass q2 und z kein gemeinsames */
/* Register belegen. Liefert Null, wenn das nicht moeglich ist.  */
int switch_IC(IC *p)
{
    int c;
    obj o;
    if(!collides(&p->q2,&p->z)) return 1;
    c=p->code;
    if((c<OR||c>AND)&&c!=ADD&&c!=MULT&&c!=ADDI2P) return 0;
    if(c==ADDI2P&&must_convert(q1typ(p),q2typ(p),0)) return 0;
    if(collides(&p->q1,&p->z)) return 0;
    o=p->q2;p->q2=p->q1;p->q1=o;
    return 1;
}

void probj(FILE *f,obj *p,int t)
/*  Gibt Objekt auf Bildschirm aus.                    */
{
  if(p->am){ fprintf(f,"[tgt-addressing-mode]");return;}
  if(p->flags&DREFOBJ){
    fprintf(f,"([");
    if(p->dtyp&CONST) fprintf(f,"const ");
    if(p->dtyp&VOLATILE) fprintf(f,"volatile ");
    if(p->dtyp&PVOLATILE) fprintf(f,"pvolatile ");
    fprintf(f,"%s]",typname[p->dtyp&NQ]);
  }
  if(p->flags&VARADR) fprintf(f,"#");
  if(p->flags&VAR) {
    if(!(p->flags&REG))
      printval(f,&p->val,MAXINT);
    if(p->flags&REG){
        fprintf(f,"%s",regnames[p->reg]);
    }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
        fprintf(f,"+%ld(FP)", zm2l(p->v->offset));
    }else{
      if(p->v->storage_class==STATIC){
        fprintf(f,"+L%ld",zm2l(p->v->offset));
      }else{
        fprintf(f,"+_%s",p->v->identifier);
      }
    }
    if(*p->v->identifier)
      fprintf(f,"(%s)",p->v->identifier);
    else if(p->v->description)
      fprintf(f,"(%s)",p->v->description);
    else
      fprintf(f,"(%p)",(void *)p->v);
    if(p->v->reg) fprintf(f,":%s",regnames[abs(p->v->reg)]);
  }
  if((p->flags&REG)&&!(p->flags&VAR)) fprintf(f,"%s",regnames[p->reg]);
  if(p->flags&KONST){
    fprintf(f,"#");
    if(p->flags&DREFOBJ)
      printval(f,&p->val,p->dtyp&NU);
    else
      printval(f,&p->val,t&NU);
  }
  if(p->flags&SCRATCH) fprintf(f,"[S]");
  if(p->flags&DREFOBJ) fprintf(f,")");
}
void prl(FILE *o,struct_declaration *p)
/* Gibt eine struct_declaration auf dem Bildschirm aus. */
{
  int i;
  static int recurse=2;
  int merk_recurse=recurse;
  --recurse;
#ifdef HAVE_ECPP
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
  for(i=0;i<p->count;i++){
    fprintf(o," %d.:",i);
    if(recurse>=0){
      if((*p->sl)[i].identifier)fprintf(o," ident: %s; ",(*p->sl)[i].identifier);
      prd(o,(*p->sl)[i].styp);
    }
  }
  recurse=merk_recurse;
}
void prd(FILE *o,type *p)
/* Gibt einen Typ auf dem Bildschirm aus.    */
{
  int f;
  if(!p) {fprintf(o,"empty type ");return;}
    f=p->flags;
/*    fprintf(o,"(Sizeof=%ld,flags=%d)",zl2l(szof(p)),f);*/
/*    if(type_uncomplete(p)) {fprintf(o,"incomplete ");}*/
  if(f&CONST) {fprintf(o,"const ");f&=~CONST;}
  if(f&STRINGCONST) {fprintf(o,"string-const ");f&=~STRINGCONST;}
  if(f&VOLATILE) {fprintf(o,"volatile ");f&=~VOLATILE;}
  if(f&UNSIGNED) {fprintf(o,"unsigned ");f&=~UNSIGNED;}
  if(p->attr) fprintf(o,"attr(%s) ",p->attr);
  if(p->reg) fprintf(o,"reg(%s) ",regnames[p->reg]);
  if(ISFUNC(f)){
    fprintf(o,"%s with parameters (",typname[f&NQ]);
    prl(o,p->exact);
    fprintf(o,") returning ");prd(o,p->next);return;
  }
  if(ISSTRUCT(f)||ISUNION(f)){
    fprintf(o,"%s with components {",typname[f&NQ]);
    prl(o,p->exact); fprintf(o,"} ");
    return;
  }
  if(ISPOINTER(f)) {fprintf(o,"%s to ",typname[f&NQ]);prd(o,p->next);return;}
  if(ISARRAY(f)) {fprintf(o,"%s [size %ld] of ",typname[f&NQ],zm2l(p->size));prd(o,p->next);return;}
  if(ISVECTOR(f)) {fprintf(o,"vector [size %ld] of %s",zm2l(p->size),typname[VECTYPE(f)&NQ]);return;}

  fprintf(o,"%s",typname[f&NQ]);
}
void print_var(FILE *o,Var *p)
/* Gibt eine Variable aus. */
{
  if(p->identifier&&*p->identifier){
    fprintf(o, "ident: %s: ", p->identifier);
  }
  prd(o, p->vtyp);
}

/* returns the first base Type in an compound type */
int get_first_base_type(type *t) 
{
  if (!t) return 0;
  if (ISARRAY(t->flags)) {
        return get_first_base_type(t->next);
  } else if ((ISSTRUCT(t->flags)) || (ISUNION(t->flags))) {
    return get_first_base_type((*t->exact->sl)[0].styp);
  } else return t->flags;
}


#ifndef HAVE_EXT_TYPES

void insert_const(union atyps *p,int t)
/*  Traegt Konstante in entprechendes Feld ein.       */
{
  if(!p) ierror(0);
  t&=NU;
  if(t==CHAR) {p->vchar=vchar;return;}
  if(t==SHORT) {p->vshort=vshort;return;}
  if(t==INT) {p->vint=vint;return;}
  if(t==LONG) {p->vlong=vlong;return;}
  if(t==LLONG) {p->vllong=vllong;return;}
  if(t==MAXINT) {p->vmax=vmax;return;}
  if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;}
  if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;}
  if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;}
  if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;}
  if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;}
  if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;}
  if(t==FLOAT) {p->vfloat=vfloat;return;}
  if(t==DOUBLE) {p->vdouble=vdouble;return;}
  if(t==LDOUBLE) {p->vldouble=vldouble;return;}
  if(t==POINTER) {p->vulong=vulong;return;}
}
void eval_const(union atyps *p,int t)
/*  Weist bestimmten globalen Variablen Wert einer CEXPR zu.       */
{
  int f=t&NQ;
  if(!p) ierror(0);
  if(f==MAXINT||(f>=CHAR&&f<=LLONG)){
    if(!(t&UNSIGNED)){
      if(f==CHAR) vmax=zc2zm(p->vchar);
      else if(f==SHORT)vmax=zs2zm(p->vshort);
      else if(f==INT)  vmax=zi2zm(p->vint);
      else if(f==LONG) vmax=zl2zm(p->vlong);
      else if(f==LLONG) vmax=zll2zm(p->vllong);
      else if(f==MAXINT) vmax=p->vmax;
      else ierror(0);
      vumax=zm2zum(vmax);
      vldouble=zm2zld(vmax);
    }else{
      if(f==CHAR) vumax=zuc2zum(p->vuchar);
      else if(f==SHORT)vumax=zus2zum(p->vushort);
      else if(f==INT)  vumax=zui2zum(p->vuint);
      else if(f==LONG) vumax=zul2zum(p->vulong);
      else if(f==LLONG) vumax=zull2zum(p->vullong);
      else if(f==MAXINT) vumax=p->vumax;
      else ierror(0);
      vmax=zum2zm(vumax);
      vldouble=zum2zld(vumax);
    }
  }else{
    if(ISPOINTER(f)){
      vumax=zul2zum(p->vulong);
      vmax=zum2zm(vumax);vldouble=zum2zld(vumax);
    }else{
      if(f==FLOAT) vldouble=zf2zld(p->vfloat);
      else if(f==DOUBLE) vldouble=zd2zld(p->vdouble);
      else vldouble=p->vldouble;
      vmax=zld2zm(vldouble);
      vumax=zld2zum(vldouble);
    }
  }
  vfloat=zld2zf(vldouble);
  vdouble=zld2zd(vldouble);
  vuchar=zum2zuc(vumax);
  vushort=zum2zus(vumax);
  vuint=zum2zui(vumax);
  vulong=zum2zul(vumax);
  vullong=zum2zull(vumax);
  vchar=zm2zc(vmax);
  vshort=zm2zs(vmax);
  vint=zm2zi(vmax);
  vlong=zm2zl(vmax);
  vllong=zm2zll(vmax);
}
#endif

function_info *new_fi(void)
/*  Belegt neue function_info-Struktur und initialisiert sie.  */
{
  function_info *new;
  new=mymalloc(sizeof(*new));
  new->first_ic=new->last_ic=new->opt_ic=0;
  new->vars=0;
  new->statics=0;
  new->inline_asm=0;
  new->flags=0;
  new->call_cnt=new->use_cnt=new->change_cnt=0;
  new->call_list=new->use_list=new->change_list=0;
  memset(new->regs_modified,0,sizeof(new->regs_modified));
#if HAVE_OSEK
/* removed */
/* removed */
/* removed */
/* removed */
#endif
  new->stack1=ul2zum(0UL);
  new->stack2=ul2zum(0UL);
  new->inline_size=-1;
  new->inline_depth=0;
  return new;
}
void free_fi(function_info *p)
/*  Gibt ein function_info mit Inhalt frei.                     */
{
  if(p->first_ic) free_IC(p->first_ic);
  if(p->opt_ic) free_IC(p->opt_ic);
  if(p->vars) free_var(p->vars);
  /* do not free statics */
  free(p->call_list);
  free(p->use_list);
  free(p->change_list);
  free(p->inline_asm);
  free(p);
}

void print_fi(FILE *f,function_info *p)
/*  Gibt function_info aus. */
{
  int i;
  fprintf(f,"function_info:\n");
  if(p->first_ic){
    IC *ic=p->first_ic;
    fprintf(f," inline_code:\n");
    pric2(f,ic);
    while(ic!=p->last_ic){
      ic=ic->next;
      pric2(f,ic);
    }
  }
  if(p->inline_asm)
    fprintf(f," inline_asm:\n%s\n",p->inline_asm);
  if(p->flags&ALL_CALLS)
    fprintf(f," all calls have been evaluated\n");
  if(p->flags&ALL_USES)
    fprintf(f," all uses have been evaluated\n");
  if(p->flags&ALL_MODS)
    fprintf(f," all changes have been evaluated\n");
  if(p->flags&ALL_REGS){
    fprintf(f," all reg-changes have been evaluated\n");
    for(i=1;i<=MAXR;i++)
      if(BTST(p->regs_modified,i)) fprintf(f,"  %s\n",regnames[i]);
  }
  fprintf(f," call_list:\n");print_varlist(f,p->call_list,p->call_cnt);
  fprintf(f," use_list:\n");print_varlist(f,p->use_list,p->use_cnt);
  fprintf(f," change_list:\n");print_varlist(f,p->change_list,p->change_cnt);
  if(p->flags&ALL_STACK){
    fprintf(f,"stack1: ");printzum(f,p->stack1);fprintf(f,"\n");
    fprintf(f,"stack2: ");printzum(f,p->stack2);fprintf(f,"\n");
  }
  if(p->flags&NEVER_RETURNS)
    fprintf(f," never returns\n");
  if(p->flags&ALWAYS_RETURNS)
    fprintf(f," always returns\n");
  if(p->flags&NOSIDEFX)
    fprintf(f," no side effects\n");
}

void print_varlist(FILE *f,varlist *p,int n)
{
  int i;
  char *s;
  for(i=0;i<n;i++){
    if(p[i].v) s=p[i].v->identifier; else s="<unknown>";
    fprintf(f,"  %s(%p), flags=%d\n",s,(void*)p[i].v,p[i].flags);
  }
}

int is_const(type *t)
/*  tested, ob ein Typ konstant (und damit evtl. in der Code-Section) ist   */
{
  if(!(t->flags&(CONST|STRINGCONST))){
    do{
      if(t->flags&(CONST|STRINGCONST)) return(1);
      if((t->flags&NQ)!=ARRAY) return 0;
      t=t->next;
    }while(1);
  }else return 1;
}

/* is object volatile? */
int is_volatile_obj(obj *o)
{
  if(o->flags&DREFOBJ){
    if(o->dtyp&(VOLATILE|PVOLATILE)){
      return 1;
    }
    if((o->flags&VAR)&&ISPOINTER(o->v->vtyp->flags)&&(o->v->vtyp->next->flags&VOLATILE)){
      return 1;
    }
  }
  if(o->flags&VAR){
    return o->v->vtyp->flags&VOLATILE;
  }else{
    return 0;
  }
}

/* is IC volatile? */
int is_volatile_ic(IC *p)
{
  if(p->q1.flags){
    if(is_volatile_obj(&p->q1)||(q1typ(p)&VOLATILE)) return 1;
  }
  if(p->q2.flags){
    if(is_volatile_obj(&p->q2)||(q2typ(p)&VOLATILE)) return 1;
  }
  if(p->z.flags){
    if(is_volatile_obj(&p->z)||(ztyp(p)&VOLATILE)) return 1;
  }
  return 0;
}

/* removes last asm-line from emit-buffer */
void remove_asm(void)
{
  emit_l--;
  if(emit_l<0) emit_l=EMIT_BUF_DEPTH-1;
}

/* flush the asm-output buffer */
void emit_flush(FILE *f)
{
  if(!f||no_emit) return;
  while(emit_f!=emit_l){
    fputs(emit_buffer[emit_f],f);
    emit_f++;
    if(emit_f>=EMIT_BUF_DEPTH) emit_f=0;
  }
  emit_l=emit_f=0;
  emit_p=emit_buffer[0];
}

/* emit inline-asm, depending on no_inline_peephole, feed it through
   asm_peephole() or flush the buffer and print it directly to the file */
void emit_inline_asm(FILE *f,char *p)
{
  if(!f||no_emit) return;
  if(no_inline_peephole){
    emit_flush(f);
    fprintf(f,"%s\n",p);
  }else{
    while(*p){
      emit(f,"%c",*p++);
    }
    emit(f,"\n");
  }
}

/* print output; this is only to be used for assembly output! */
void emit(FILE *f,const char *fmt,...)
{
  static char tmp[EMIT_BUF_LEN];
  char *p;
  va_list vl;
  if(!f||no_emit) return;
  va_start(vl,fmt);
  vsprintf(tmp,fmt,vl);
  p=tmp;
  while(*p){
    *emit_p++=*p++;
    if(p[-1]=='\n'){
      *emit_p=0;
#if HAVE_TARGET_PEEPHOLE
      while(emit_peephole());
#endif
      emit_l++;
      if(emit_l>=EMIT_BUF_DEPTH) emit_l=0;
      emit_p=emit_buffer[emit_l];
      if(emit_l==emit_f){
        /* FIXME: error check */
        fputs(emit_buffer[emit_f],f);
        emit_f++;
        if(emit_f>=EMIT_BUF_DEPTH) emit_f=0;
      }
    }
  }
  *emit_p=0;
}

void emit_char(FILE *f,int c)
{
  static char tmp[2];
  tmp[0]=c;
  emit(f,tmp);
}

/* detect whether the following code resembles a switch-case-statement */
/* will return the longest sequence which has at least min_density */
case_table *calc_case_table(IC *p,double min_density)
{
  static case_table ct;
  obj *o,*ccr;
  static union atyps *vals;
  union atyps min,max;
  zumax diff;
  static int *labels,cur_size;
  double cur_density;
  int t,j,num;
  if(p->code!=COMPARE||!(p->q2.flags&KONST))
    return 0;
  o=&p->q1;t=p->typf;
  if(!ISINT(t)||(t&VOLATILE)) return 0;
  num=0;
  ct.num=0;
  if(t&UNSIGNED){
    max.vumax=t_min(UNSIGNED|MAXINT);
    min.vumax=t_max(UNSIGNED|MAXINT);
  }else{
    max.vmax=t_min(MAXINT);
    min.vmax=t_max(MAXINT);
  }
  while(p&&p->code==COMPARE&&(p->q2.flags&KONST)&&p->typf==t&&objs_equal(o,&p->q1,t)){
    zumax zum;zmax zm;
    if(multiple_ccs) ccr=&p->z;
    if(num>=cur_size){
      cur_size+=64;
      labels=myrealloc(labels,cur_size*sizeof(*labels));
      vals=myrealloc(vals,cur_size*sizeof(*vals));
    }
    for(j=0;j<num;j++){
      if(!compare_const(&vals[j],&p->q2.val,t)){
        return 0; /* FIXME? Could simply ignore? */
      }
    }
    vals[num]=p->q2.val;
    p=p->next;
    while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next;
    if(p->code!=BEQ||(multiple_ccs&&!objs_equal(ccr,&p->q1,0))) break;
    labels[num]=p->typf;
    p=p->next;
    while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next;
    eval_const(&vals[num],t);
    num++;
    if(t&UNSIGNED){
      if(zumleq(vumax,min.vumax))
        insert_const(&min,UNSIGNED|MAXINT);
      if(zumleq(max.vumax,vumax))
        insert_const(&max,UNSIGNED|MAXINT);
      cur_density=num/(1+zld2d(zum2zld(zumsub(max.vumax,min.vumax))));
      if(cur_density>=min_density){
        ct.num=num;
        ct.next_ic=p;
        ct.min=min;
        ct.max=max;
        ct.diff=zumsub(max.vumax,min.vumax);
        ct.density=cur_density;
      }
    }else{
      if(zmleq(vmax,min.vmax))
        insert_const(&min,MAXINT);
      if(zmleq(max.vmax,vmax))
        insert_const(&max,MAXINT);
      cur_density=num/zld2d(zum2zld((1+zumsub(zm2zum(max.vmax),zm2zum(min.vmax)))));
      if(cur_density>=min_density){
        ct.num=num;
        ct.next_ic=p;
        ct.min=min;
        ct.max=max;
        ct.diff=zumsub(zm2zum(max.vmax),zm2zum(min.vmax));
        ct.density=cur_density;
      }
    }
  }
  ct.vals=vals;
  ct.labels=labels;
  ct.typf=t;
  return &ct;
}

/* emit a list of jump-table entries */
void emit_jump_table(FILE *f,case_table *ct,char *da,char *labprefix,int defl)
{
  unsigned long l,e;
  int i;
  zmax zm;zumax zum;
  if(ct->typf&UNSIGNED){
    zum=ct->min.vumax;
    zm=zum2zm(zum);
  }else{
    zm=ct->min.vmax;
    zum=zm2zum(zm);
  }
  e=zum2ul(ct->diff);
  for(l=0;l<=e;l++){
    emit(f,"%s",da);
    for(i=0;i<ct->num;i++){
      eval_const(&ct->vals[i],ct->typf);
      if(zmeqto(vmax,zm)&&zumeqto(vumax,zum)){
        emit(f,"%s%d\n",labprefix,ct->labels[i]);
        break;
      }
    }
    if(i>=ct->num)
      emit(f,"%s%d\n",labprefix,defl);
    zm=zmadd(zm,l2zm(1L));
    zum=zumadd(zum,ul2zum(1UL));
  }
}
/* display warnings if specified stack-size cannot be guaranteed */
void static_stack_check(Var *v)
{
  /*FIXME*/
}

#ifdef HAVE_REGPARMS
/* return the offset of the first variable-argument-macro to the
   beginning of the argument-area (i.e. the space occupied by
   normal arguments on the stack */
zmax va_offset(Var *v)
{
  int i;
  zmax offset=l2zm(0L);
  static type rp={0};
  treg_handle rh=empty_reg_handle;
  if((v->vtyp->next->flags&NQ)!=VOID&&!freturn(v->vtyp->next)){
    rp.next=v->vtyp->next;
    rp.flags=POINTER_TYPE(v->vtyp->next);
    if(!reg_parm(&rh,&rp,0,v->vtyp)){
      ierror(0);
    }
  }
  for(i=0;i<v->vtyp->exact->count;i++){
#if 0
    if((*v->vtyp->exact->sl)[i].reg!=0)
      continue;
#endif
    if(((*v->vtyp->exact->sl)[i].styp->flags&NQ)==VOID)
      ierror(0);
    if(reg_parm(&rh,(*v->vtyp->exact->sl)[i].styp,0,v->vtyp)!=0)
      continue;
    offset=zmadd(offset,szof((*v->vtyp->exact->sl)[i].styp));
    offset=zmmult(zmdiv(zmadd(offset,zmsub(stackalign,l2zm(1L))),stackalign),stackalign); 
  }
  return offset;
}
#endif

/* We provide an own qsort to get reproducable results. */
void vqsort (void *base,size_t nmemb,size_t size,int (*compar)(const void *,const void *))
{ char *base2=(char *)base;
  char tmp;
  size_t i,a,b,c;
  while(nmemb>1)
  { a=0;
    b=nmemb-1;
    c=(a+b)/2; /* Middle element */
    for(;;)
    { while((*compar)(&base2[size*c],&base2[size*a])>0)
        a++; /* Look for one >= middle */
      while((*compar)(&base2[size*c],&base2[size*b])<0)
        b--; /* Look for one <= middle */
      if(a>=b)
        break; /* We found no pair */
      for(i=0;i<size;i++) /* swap them */
      { tmp=base2[size*a+i];
        base2[size*a+i]=base2[size*b+i];
        base2[size*b+i]=tmp; }
      if(c==a) /* Keep track of middle element */
        c=b;
      else if(c==b)
        c=a;
      a++; /* These two are already sorted */
      b--;
    } /* a points to first element of right intervall now (b to last of left) */
    b++;
    if(b<nmemb-b) /* do recursion on smaller intervall and iteration on larger one */
    { vqsort(base2,b,size,compar);
      base2=&base2[size*b];
      nmemb=nmemb-b;
    }
    else
    { vqsort(&base2[size*b],nmemb-b,size,compar);
      nmemb=b; }
  }
  return;
}

/* calculates registers used by this call IC
   returns 0 if not possible */
int calc_regs(IC *p,int showwarnings)
{
  int i;
  if(p->call_cnt){
    for(i=0;i<p->call_cnt;i++){
      if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_REGS)){
        bvunite(regs_modified,p->call_list[i].v->fi->regs_modified,RSIZE);
#if HAVE_OSEK
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
      }else{
        int r;
        for(r=1;r<=MAXR;r++) if(regscratch[r]) BSET(regs_modified,r);
        err_ic=p;
        if(!p->call_list[i].v->fi) p->call_list[i].v->fi=new_fi();
        if(!(p->call_list[i].v->fi->flags&WARNED_REGS)){
          error(318,p->call_list[i].v->identifier);
          p->call_list[i].v->fi->flags|=WARNED_REGS;
        }
        return 0;
      }
    }
    return 1;
  }
  err_ic=p;if(showwarnings) error(320);
  return 0;
}



#ifndef HAVE_TARGET_BFLAYOUT
int bflayout(int bfoffset,int bfsize,int t)
{
  if(BIGENDIAN)
    return (int)zm2l(zmmult(sizetab[t&NQ],char_bit))-bfoffset-bfsize;
  else
    return bfoffset;
}
#endif

long get_pof2(zumax x)
/*  Yields log2(x)+1 oder 0. */
{
  zumax p;int ln=1,max=(int)zm2l(zmmult(sizetab[LLONG],char_bit));
  p=ul2zum(1L);
  while(ln<=max&&zumleq(p,x)){
    if(zumeqto(x,p)) return ln;
    ln++;p=zumadd(p,p);
  }
  return 0;
}

/* check if type is a varargs function */
int is_varargs(type *t)
{
  int c;
  if(t->exact&&(c=t->exact->count)!=0&&(*t->exact->sl)[c-1].styp->flags!=VOID)
    return 1;
  else
    return 0;
}

/* add string to type- oder variable-aatribute */
void add_attr(char **attr,char *new)
{
  int ln,lo;
  if(!new) return;
  if(*attr&&strstr(*attr,new)) return;
  if(add_attr_haddecl&&(!*attr||!strstr(*attr,new))) error(371,add_attr_haddecl->identifier,new);
  ln=strlen(new);
  if(*attr){
    lo=strlen(*attr);
    *attr=myrealloc(*attr,lo+ln+2);
  }else{
    lo=0;
    *attr=mymalloc(ln+2);
  }
  (*attr)[lo]=';';
  strcpy(*attr+lo+1,new);
}


hashtable *new_hashtable(size_t size)
{
  hashtable *new = mymalloc(sizeof(*new));

  new->size = size;
  new->collisions = 0;
  new->entries = mymalloc(size*sizeof(*new->entries));
  memset(new->entries,0,size*sizeof(*new->entries));
  return new;
}

size_t hashcode(char *name)
{
  size_t h = 5381;
  int c;

  while (c = (unsigned char)*name++)
    h = ((h << 5) + h) + c;
  return h;
}

/* add to hashtable; name must be unique */
void add_hashentry(hashtable *ht,char *name,hashdata data)
{
  size_t i=(hashcode(name)%ht->size);
  hashentry *new=mymalloc(sizeof(*new));
  new->name=name;
  new->data=data;
  if(DEBUG&1){
    if(ht->entries[i])
      ht->collisions++;
  }
  new->next=ht->entries[i];
  ht->entries[i]=new;
}

/* finds unique entry in hashtable */
hashdata find_name(hashtable *ht,char *name)
{
  size_t i=hashcode(name)%ht->size;
  hashentry *p;
  for(p=ht->entries[i];p;p=p->next){
    if(!strcmp(name,p->name)){
      return p->data;
    }else
      ht->collisions++;
  }
  return 0;
}

#ifndef CHARBACK
unsigned char CHARBACK(unsigned char x)
{
  static unsigned char tab[256],init=0;
  if(!init){
    int i,j;
    for(i=0;i<256;i++)
      for(j=0;j<256;j++)
	if(tab[j]==0&&CHARCONV(i)==j){
	  tab[j&255]=i;
	  break;
	}
    init=1;
  }
  return tab[x&255];
}

void STRBACK(unsigned char *p)
{
  while(p&&*p){
    *p=CHARBACK(*p);
    p++;
  }
}
#endif

int objs_equal(obj *o1,obj *o2,int t)
/*  Vergleicht die beiden Objekte; liefert 1, wenn sie gleich sind, sonst 0 */
{
    int i1,i2;
    i1=o1->flags&~SCRATCH;i2=o2->flags&~SCRATCH;
    if(i1!=i2) return 0;
    if(i1&DREFOBJ){
      if(o1->dtyp!=o2->dtyp) return 0;
    }
    if(i1&KONST) return(!compare_const(&o1->val,&o2->val,t));
    if(i1&VAR){
      if(o1->v!=o2->v) return 0;
      if(!zmeqto(o1->val.vmax,o2->val.vmax)) return 0;
    }
    return 1;
}


#ifdef HAVE_MISRA
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
/* removed */
#endif
