/*  Code generator for Motorola 68hc12 microcontrollers.               */

/*TODO:
  regs_modified bei struct-copy
  savings verfeinern
  4-Byte Copy
  [static] testen
  peephole-Pass um ALLOCREGs zu entfernen
  ACC_IND (Achtung?)
  struct-copy Problemfälle
  banked
  bit
  long long, float, double, long double

*/

#include "supp.h"
#include "vbc.h" /* nicht schoen, aber ... */

static char FILE_[]=__FILE__;

#include "dwarf2.c"

/*  Public data that MUST be there.                             */

/* Name and copyright. */
char cg_copyright[]="vbcc code-generator for 6809/6803/68hc12 V0.2 (c) in 2000-2022 by Volker Barthelmann";

/*  Commandline-flags the code-generator accepts                */
int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,
                    0,0,0,0,
		    0,0};
char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data",
                           "merge-constants","no-peephole","mem-cse","acc-glob",
			   "pcrel","drel","no-char-addi2p","nodx","nou"};
union ppi g_flags_val[MAXGF];

/* Typenames (needed because of HAVE_EXT_TYPES). */
char *typname[]={"strange","bit","char","short","int","long","long long",
		 "float","double","long double","void",
                 "near-pointer","far-pointer","huge-pointer",
		 "array","struct","union","enum","function"};

int bitsperbyte = 8;
int bytemask = 0xff;
int dbl_bytemask = 0xffff;

/*  Alignment-requirements for all types in bytes.              */
zmax align[MAX_TYPE+1];

/*  Alignment that is sufficient for every object.              */
zmax maxalign;

/*  CHAR_BIT of the target machine.                             */
zmax char_bit;

/*  Sizes of all elementary types in bytes.                     */
zmax sizetab[MAX_TYPE+1];

/*  Minimum and Maximum values each type can have.              */
/*  Must be initialized in init_cg().                           */
zmax t_min[MAX_TYPE+1];
zumax t_max[MAX_TYPE+1];
zumax tu_max[MAX_TYPE+1];

/*  Names of all registers.                                     */
char *regnames[]={"noreg","d","x","y","sp","u","d/x"};

/*  The Size of each register in bytes.                         */
zmax regsize[MAXR+1];

/*  Type which can store each register. */
struct Typ *regtype[MAXR+1];

/*  regsa[reg]!=0 if a certain register is allocated and should */
/*  not be used by the compiler pass.                           */
int regsa[MAXR+1];

/*  Specifies which registers may be scratched by functions.    */
int regscratch[MAXR+1]={0,1,1,0,1,0};

int reg_prio[MAXR+1]={0,0,1,1,0,0};

struct reg_handle empty_reg_handle={0};

/* Names of target-specific variable attributes.                */
char *g_attr_name[]={"__interrupt","__dpage","__far",0};
#define INTERRUPT 1
#define DPAGE     2
#define FAR				4

int MINADDI2P=CHAR;

/****************************************/
/*  Some private data and functions.    */
/****************************************/

static long malign[MAX_TYPE+1]=  {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,4,4,4,4,0,2,4,4,0,0,0,2,0};

struct Typ ityp={SHORT},ltyp={LONG};

#define DATA 0
#define BSS 1
#define CODE 2
#define RODATA 3
#define SPECIAL 4

static int section=-1,newobj,scnt,pushed_acc;
static char *codename="\t.text\n",
            *dataname="\t.data\n",
            *bssname="\t.section\t.bss\n",
            *rodataname="\t.section\t.rodata\n";

#define IMM_IND  1
#define VAR_IND  2
#define POST_INC 3
#define POST_DEC 4
#define PRE_INC  5
#define PRE_DEC  6
#define ACC_IND  7
#define KONSTINC 8

/* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */
static int acc=1,ix=2,iy=3,sp=4,iu=5,dx=6;
static void pr(FILE *,struct IC *);
static void function_top(FILE *,struct Var *,long);
static void function_bottom(FILE *f,struct Var *,long);

static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")",
		       "__HC12__",
		       "__SIZE_T_INT=1",
		       "__direct=__vattr(\"section(\\\"dpage\\\")\")",
		       0};

#define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG)
#define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST)

static long loff,roff,stackoffset,notpopped,dontpop,maxpushed,stack;

static char *x_t[]={"?","","b","","","","","","","","","","","","","",""};
static char *ccs[]={"eq","ne","lt","ge","le","gt"};
static char *uccs[]={"eq","ne","lo","hs","ls","hi"};
static char *logicals[]={"ora","eor","and"};
static char *dct[]={"",".bit",".byte",".2byte",".2byte",".4byte",".8byte",".4byte",".8byte",".8byte",
		    "(void)",".2byte",".34byte",".34byte"};
static char *idprefix="",*labprefix=".l";
static int exit_label,have_frame;
static char *ret;
static int stackchecklabel;
static int frame_used,stack_valid;
static int CPU=6812;
static int pcrel,drel;
static int skip_rel;
static char *jsrinst="jsr";
static char *jmpinst="jmp";
static int nodx,nou;
int switchsubs;

static int cc_t;
static struct obj *cc;

static struct obj mobj;

#define STR_NEAR "near"
#define STR_FAR "far"
#define STR_HUGE "huge"
#define STR_BADDR "baddr"

#define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
#define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT)
#define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER)
#define ISCHWORD(t) ((t&NQ)==CHAR||ISHWORD(t))
#define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC)
#define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr))
/*FIXME*/
#define ISFAR(v) ((v)->vtyp->attr&&(strstr(STR_FAR,(v)->vtyp->attr)||strstr(STR_HUGE,(v)->vtyp->attr)))

#define ISACC(x) ((x)==acc)
#define ISX(x) ((x)==ix)
#define ISY(x) ((x)==iy)
#define ISU(x) ((x)==iu)
#define ISIDX(x) (ISX(x)||ISY(x)||(ISU(x)&&CPU!=6812))
#define ISRACC(x) (isreg(x)&&ISACC(p->x.reg))
#define ISRX(x) (isreg(x)&&ISX(p->x.reg))
#define ISRY(x) (isreg(x)&&ISY(p->x.reg))
#define ISRU(x) (isreg(x)&&ISU(p->x.reg))
#define ISRIDX(x) (isreg(x)&&ISIDX(p->x.reg))

#define CPUOPT ((g_flags[0]&USEDFLAG)?g_flags_val[0].l:6812)

#define SPUSH(x) (CPU==6812?"\tpsh" x "\n":"\tpshs\t" x "\n")
#define SPUSHD   (CPU==6812?"\tpshd\n":"\tpshs\tb,a\n")
#define SPULL(x) (CPU==6812?"\tpul" x "\n":"\tpuls\t" x "\n")
#define SPULLD   (CPU==6812?"\tpuld\n":"\tpuls\ta,b\n")
#define SCMP(x)  (CPU==6812?"\tcp" x "\t":"\tcmp" x "\t")
#define SEX      (CPU==6812?"\tsex\tb,d\n":"\tsex\n")

#define SGN16(x) (zm2l(zi2zm(zm2zi(l2zm((long)(x))))))

enum peepf { NEEDSAME = 1, REMOVE1ST = 2, ALLOWSFX = 4};
struct peeps {char *s1,*s2,*r;enum peepf flags;};

static int check_sfx(char *s)
{
  if(!*s) return 0;
  s+=strlen(s)-1;
  if(*s=='+'||*s=='-') return 1;
  if(*s!='s'&&*s!='x'&&*s!='y'&&*s!='u') return 0;
  s--;
  if(*s!=',') return 0;
  s--;
  if(*s=='+'||*s=='-') return 1;
  return 0;
}

static int setszflag(char *op,char r)
{
  static char *zb[]={"adcb","addb","andb","aslb","asrb","clrb","comb","decb","eorb","incb",
		"ldab","ldb","lslb","lsrb","negb","orb","orab","rolb","rorb","sbcb",
		"stb","stab","subb","tstb"};
  static char *zd[]={"addd","ldd","sex","std","subd"};

  int i;

  if(r=='b'){
    for(i=0;i<sizeof(zb)/sizeof(*zb);i++)
      if(!strcmp(op,zb[i]))
	return 1;
  }
  if(r=='d'){
    for(i=0;i<sizeof(zd)/sizeof(*zd);i++)
      if(!strcmp(op,zd[i]))
	return 1;
  }
  if(r=='x'&&(!strcmp(op,"leax")||!strcmp(op,"ldx"))) return 1;
  if(r=='y'&&(!strcmp(op,"leay")||!strcmp(op,"ldy"))) return 1;
  if(CPU==6812){
    if(r=='x'&&(!strcmp(op,"dex")||!strcmp(op,"inx"))) return 1;
    if(r=='y'&&(!strcmp(op,"dey")||!strcmp(op,"iny"))) return 1;
  }
  return 0;
}

int emit_peephole(void)
{
  int entries,i,j,v1,v2;
  char *asmline[EMIT_BUF_DEPTH];
  char buf1[1024],buf2[1024];
  char op1[8],op2[8];


  /* TODO: adapt better */
  static struct peeps elim[]={
    "lda","sta",0,NEEDSAME,
    "ldb","stb",0,NEEDSAME,
    "ldaa","staa",0,NEEDSAME,
    "ldab","stab",0,NEEDSAME,
    "ldd","std",0,NEEDSAME,
    "ldx","stx",0,NEEDSAME,
    "ldy","sty",0,NEEDSAME,
    "ldu","stu",0,NEEDSAME,
    "sta","sta",0,NEEDSAME,
    "stb","stb",0,NEEDSAME,
    "staa","staa",0,NEEDSAME,
    "stab","stab",0,NEEDSAME,
    "std","std",0,NEEDSAME,
    "stx","stx",0,NEEDSAME,
    "sty","sty",0,NEEDSAME,
    "stu","stu",0,NEEDSAME,
    "sta","lda",0,NEEDSAME,
    "stb","ldb",0,NEEDSAME,
    "staa","ldaa",0,NEEDSAME,
    "stab","ldab",0,NEEDSAME,
    "std","ldd",0,NEEDSAME,
    "stx","ldx",0,NEEDSAME,
    "sty","ldy",0,NEEDSAME,
    "stu","ldu",0,NEEDSAME,
#if 0
    "lda","lda",0,REMOVE1ST,
    "ldaa","ldaa",0,REMOVE1ST,
    "ldab","ldab",0,REMOVE1ST,
    "ldb","ldb",0,REMOVE1ST,
    "ldd","ldd",0,REMOVE1ST,
    "ldx","ldx",0,REMOVE1ST,
    "ldy","ldy",0,REMOVE1ST,
    "ldu","ldu",0,REMOVE1ST,
    "lda","pla",0,REMOVE1ST,
    "lda","txa",0,REMOVE1ST,
    "lda","tya",0,REMOVE1ST,
    "ldx","tax",0,REMOVE1ST,
    "ldy","tay",0,REMOVE1ST,
    "tay","ldy",0,REMOVE1ST,
    "tax","ldx",0,REMOVE1ST,
    "txa","lda",0,REMOVE1ST,
    "tya","lda",0,REMOVE1ST,
#endif
  };


  i=emit_l;
  if(emit_f==0)
    entries=i-emit_f+1;
  else
    entries=EMIT_BUF_DEPTH;
  asmline[0]=emit_buffer[i];
  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpb")&&!strcmp(buf1,"#0"))
    strcpy(asmline[0],"\ttstb\n");
  if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpd")&&!strcmp(buf1,"#0"))
    strcpy(asmline[0],"\tsubd\t#0\n");

  if(entries>=2){
    i--;
    if(i<0) i=EMIT_BUF_DEPTH-1;
    asmline[1]=emit_buffer[i];

    for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){
      if(elim[j].flags&NEEDSAME){
	if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&&
	   sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&
	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&&
	   !strcmp(buf1,buf2)){
	  if(!check_sfx(buf1)&&!check_sfx(buf2)){
	    if(elim[j].r){
	      strcpy(asmline[0],elim[j].r);
	    }else{
	      if(elim[j].flags&REMOVE1ST)
		strcpy(asmline[1],asmline[0]);
	      remove_asm();
	    }
	    return 1;
	  }
	}
      }else{
	*buf1=0;*buf2=0;
	if(sscanf(asmline[1]," %6s %999s",op1,buf1)>=1&&
	   sscanf(asmline[0]," %6s %999s",op2,buf2)>=1&&
	   !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){
	  if((elim[j].flags&ALLOWSFX)||(!check_sfx(buf1)&&!check_sfx(buf2))){
	    if(elim[j].flags&REMOVE1ST)
	      strcpy(asmline[1],asmline[0]);
	    remove_asm();
	    return 1;
	  }
	}
      }
    }

    if(!strcmp(asmline[0],"\trts\n")&&sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"puls")){
      sprintf(asmline[1]+strlen(asmline[1])-1,",pc\n");
      remove_asm();
      return 1;
    }

    if(!strcmp(asmline[0],"\tstb\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-1,s\n")){
      strcpy(asmline[1],"\tpshs\tb\n");
      remove_asm();
      return 1;
    }

    if(!strcmp(asmline[0],"\tstd\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-2,s\n")){
      strcpy(asmline[1],"\tpshs\tb,a\n");
      remove_asm();
      return 1;
    }

    if(!strcmp(asmline[0],"\tldb\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb\n")){
      remove_asm();
      return 1;
    }

    if(!strcmp(asmline[0],"\tldd\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb,a\n")){
      remove_asm();
      return 1;
    }

    if(!strcmp(asmline[0],"\tpshs\tb,a\n")&&!strcmp(asmline[1],"\tpuls\ta,b\n")){
      strcpy(asmline[1],"\tldd\t0,s\n");
      remove_asm();
      return 1;
    }

    if(sscanf(asmline[1]," ldd %999s",op1)>=1&&sscanf(asmline[0]," ldd %999s",op2)>=1){
      if(!((op2[0]=='a'||op2[0]=='b'||op2[0]=='d')&&op2[1]==',')){
	strcpy(asmline[1],asmline[0]);
	remove_asm();
	return 1;
      }
    }

    if(!strcmp(asmline[0],"\ttfr\tx,d\n")&&!strcmp(asmline[1],"\ttfr\td,x\n")){
      remove_asm();
      return 1;
    }
    if(!strcmp(asmline[0],"\ttfr\ty,d\n")&&!strcmp(asmline[1],"\ttfr\td,y\n")){
      remove_asm();
      return 1;
    }
    if(!strcmp(asmline[0],"\tstd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
      remove_asm();
      return 1;
    }
    if(!strcmp(asmline[0],"\tldd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){
      remove_asm();
      return 1;
    }

    if(sscanf(asmline[0]," leas %d,s",&v1)==1&&sscanf(asmline[1]," leas %d,s",&v2)==1){
      sprintf(asmline[1],"\tleas\t%ld,s\n",SGN16(v1+v2));
      remove_asm();
      return 1;
    }

    if(CPU!=6812&&sscanf(asmline[0]," tfr %c,%c",buf1,buf2)==2){
      if((*buf1=='x'||*buf1=='y'||*buf1=='u'||*buf1=='s')&&
	 (*buf2=='x'||*buf2=='y'||*buf2=='u'||*buf2=='s')){
	sprintf(asmline[0],"\tlea%c\t,%c\n",*buf2,*buf1);
      }
    }
    if(CPU==6812&&(!strcmp(asmline[1],"\tdex\n")||!strcmp(asmline[1],"\tdey\n")||!strcmp(asmline[1],"\tsubd\t#1\n"))&&
       (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
      char r=asmline[1][3];
      if(r=='b') r='d';
      strcpy(asmline[1],"\td");
      strncpy(asmline[1]+2,asmline[0]+1,4);
      asmline[1][6]=r;asmline[1][7]=',';
      strcpy(asmline[1]+8,asmline[0]+5);
      remove_asm();
      return 1;
    }
    if(CPU==6812&&(!strcmp(asmline[1],"\tinx\n")||!strcmp(asmline[1],"\tiny\n")||!strcmp(asmline[1],"\taddd\t#1\n"))&&
       (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){
      char r=asmline[1][3];
      strcpy(asmline[1],"\ti");
      strncpy(asmline[1]+2,asmline[0]+1,4);
      asmline[1][6]=r;asmline[1][7]=',';
      strcpy(asmline[1]+8,asmline[0]+5);
      remove_asm();
      return 1;
    }
  }
  if(entries>=3){
    i--;
    if(i<0) i=EMIT_BUF_DEPTH-1;
    asmline[2]=emit_buffer[i];
    if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){
      if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){
	if(!strcmp(asmline[1],"\ttstb\n")||!strcmp(asmline[1],"\tcpb\t#0\n")){
	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
	     setszflag(op2,'b')){
	    strcpy(asmline[1],asmline[0]);
	    remove_asm();
	    return 1;
	  }
	}
	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
	   (!strcmp(op2,"subd")||!strcmp(op2,"cpd"))&&!strcmp(buf2,"#0")){
	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
	     setszflag(op2,'d')){
	    strcpy(asmline[1],asmline[0]);
	    remove_asm();
	    return 1;
	  }
	}
	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
	   !strcmp(op2,(CPU==6812)?"cpx":"cmpx")&&!strcmp(buf2,"#0")){
	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
	     setszflag(op2,'x')){
	    strcpy(asmline[1],asmline[0]);
	    remove_asm();
	    return 1;
	  }
	}
	if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&&
	   !strcmp(op2,(CPU==6812)?"cpy":"cmpy")&&!strcmp(buf2,"#0")){
	  if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&&
	     setszflag(op2,'y')){
	    strcpy(asmline[1],asmline[0]);
	    remove_asm();
	    return 1;
	  }
	}
      }
    }
  }
  return 0;
}

static int special_section(FILE *f,struct Var *v)
{
  char *sec;
  if(v->tattr&DPAGE){
    emit(f,"\t.section\t.dpage\n");
  }else{
    if(!v->vattr) return 0;
    sec=strstr(v->vattr,"section(");
    if(!sec) return 0;
    sec+=strlen("section(");
    emit(f,"\t.section\t");
    while(*sec&&*sec!=')') emit_char(f,*sec++);
    emit(f,"\n");
  }
  if(f) section=SPECIAL;
  return 1;
}

static struct fpconstlist {
    struct fpconstlist *next;
    int label,typ;
    union atyps val;
} *firstfpc;

static int addfpconst(struct obj *o,int t)
{
  struct fpconstlist *p=firstfpc;
  t&=NQ;
  if(g_flags[4]&USEDFLAG){
    for(p=firstfpc;p;p=p->next){
      if(t==p->typ){
	eval_const(&p->val,t);
	if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label;
	if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label;
	if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label;
      }
    }
  }
  p=mymalloc(sizeof(struct fpconstlist));
  p->next=firstfpc;
  p->label=++label;
  p->typ=t;
  p->val=o->val;
  firstfpc=p;
  return p->label;
}

int pointer_type(struct Typ *p)
{
  if(!p) ierror(0);
  while((p->flags&NQ)==ARRAY) p=p->next;
  if((p->flags&NQ)==FUNKT) {
  	if(p->attr)
    	if(strstr(p->attr,STR_FAR)) return FPOINTER;
  	if (p->flags&FAR)
  		return FPOINTER;
  	return NPOINTER; /*FIXME: banked*/
  }
  if(p->attr){
    if(strstr(p->attr,STR_HUGE)) return HPOINTER;
    if(strstr(p->attr,STR_FAR)) return FPOINTER;
    if(strstr(p->attr,STR_NEAR)) return NPOINTER;
  }
  /*FIXME*/
  return NPOINTER;
}
static long voff(struct obj *p)
{
  if(zm2l(p->v->offset)<0) 
    return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+1;
  else
    return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset;
}

static void emit_obj(FILE *f,struct obj *p,int t)
/*  Gibt Objekt auf Bildschirm aus                      */
{
  if(p->am){
    int flags=p->am->flags;
    if(flags==ACC_IND){
      emit(f,"%s,%s",regnames[acc],regnames[p->am->base]);
      return;
    }
    if(flags==KONSTINC){
      eval_const(&p->val,p->am->base);
      if((t&NQ)==CHAR){
	vumax=zumrshift(vumax,bitsperbyte*3-bitsperbyte*p->am->offset);
	vumax=zumand(vumax,ul2zum(tu_max[CHAR]));
      }else{
	vumax=zumrshift(vumax,bitsperbyte*2-bitsperbyte*p->am->offset);
	vumax=zumand(vumax,ul2zum(tu_max[SHORT]));
      }
      emit(f,"#%lu",zum2ul(vumax));
      return;
    }
    if(flags<POST_INC||flags>PRE_DEC||CPU==6812)
      emit(f,"%ld",p->am->offset&tu_max[SHORT]);
    if(p->am->v){
      if(p->am->v->storage_class==STATIC)
	emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset));
      else
	emit(f,"+(%s%s)",idprefix,p->am->v->identifier);
    }
    emit(f,",");
    if(flags==PRE_INC){
      emit(f,"+");
      if(p->am->offset==2&&CPU!=6812) emit(f,"+");
    }else if(flags==PRE_DEC){
      emit(f,"-");
      if(p->am->offset==2&&CPU!=6812) emit(f,"-");
    }
    emit(f,"%s",regnames[p->am->base]);
    if(flags==POST_INC){
      emit(f,"+");
      if(p->am->offset==2&&CPU!=6812) emit(f,"+");
    }else if(flags==POST_DEC){
      emit(f,"-");
      if(p->am->offset==2&&CPU!=6812) emit(f,"-");
    }
    return;
  }
  if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
    emitval(f,&p->val,p->dtyp&NU);
    return;
  }
  if(p->flags&VARADR) emit(f,"#");
  if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"0,");
  if((p->flags&(DREFOBJ|REG))==DREFOBJ) emit(f,"[");
  if((p->flags&(VAR|REG))==VAR){
    if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
      emit(f,"%ld,%s",voff(p),regnames[sp]);
    }else{
      if(!zmeqto(l2zm(0L),p->val.vmax)){
	emit(f,"%ld",zm2l(zi2zm(zm2zi(p->val.vmax))));
	emit(f,"+");
      }
      if(p->v->storage_class==STATIC){
	emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
      }else{
	emit(f,"(%s%s)",idprefix,p->v->identifier);
      }
      if(pcrel&&!(p->flags&VARADR)&&ISFUNC(p->v->vtyp->flags))
	emit(f,",pc");
      if(drel&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)){
	if(CPU==6812) ierror(0);
	emit(f,",%s",regnames[iu]);
      }
    }
  }
  if(p->flags&REG){
    if(ISACC(p->reg)&&(t&NQ)==CHAR)
      emit(f,"b");
    else
      emit(f,"%s",regnames[p->reg]);
  }
  if(p->flags&KONST){
    if(ISFLOAT(t)){
      emit(f,"%s%d",labprefix,addfpconst(p,t));
    }else{
      emit(f,"#");emitval(f,&p->val,t&NU);
    }
  }
  if((p->flags&(DREFOBJ|REG))==DREFOBJ){
    if(p->v->storage_class==EXTERN||p->v->storage_class==STATIC){
      if(is_const(p->v->vtyp)){
	if(!pcrel&&CPU==6812) emit(f,",pc");
      }else{
	if(!drel&&CPU==6812) emit(f,",pc");
      }
    }
    emit(f,"]");
  }
}

static void dwarf2_print_frame_location(FILE *f,struct Var *v)
{
  /*FIXME: needs a location list and correct register translation */
  struct obj o;
  o.flags=REG;
  o.reg=sp;
  o.val.vmax=l2zm(0L);
  o.v=0;
  dwarf2_print_location(f,&o);
}
static int dwarf2_regnumber(int r)
{
  /*FIXME: always returns D as accumulator, even if byte size */
  static int dwarf_regs[MAXR+1]={-1,3,7,8,15};
  return dwarf_regs[r];
}
static zmax dwarf2_fboffset(struct Var *v)
{
  /*FIXME*/
  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
  if(!zmleq(l2zm(0L),v->offset))
    return l2zm((long)(loff-zm2l(v->offset)));
  else
    return v->offset;
} 

/* test operand for mov instruction */
static int mov_op(struct obj *o)
{
  long off;
  if(CPU!=6812) return 0;
  if(o->am){
    int f=o->am->flags;
    if(f==POST_INC||f==PRE_INC||f==POST_DEC||f==PRE_DEC||f==ACC_IND)
      return 1;
    if(f==IMM_IND){
      if(o->am->v) return 0;
      off=o->am->offset;
      if(off>=-256&&off<=255)
	return 1;
      else
	return 0;
    }
    ierror(0);
  }
  if(o->flags&(KONST|VARADR)) return 1;
  if((o->flags&(REG|DREFOBJ))==(REG|DREFOBJ)) return 1;
  if((o->flags&(VAR|REG|DREFOBJ))==VAR){
    if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN)
      return 1;
    off=voff(o);
    if(off>=-256&&off<=255)
      return 1;
    else
      return 0;
  }
  return 0;
}

/* add an offset to an object describing a memory address */
static void inc_addr(struct obj *o,long val,int t)
{
  if(o->am){
    int f=o->am->flags;
    if(f==IMM_IND||f==KONSTINC)
      o->am->offset+=val;
    else if(f==POST_INC||f==POST_DEC||f==PRE_INC||f==PRE_DEC){
      struct AddressingMode *old=o->am;
      o->am=mymalloc(sizeof(*o->am));
      o->am->flags=IMM_IND;
      o->am->base=old->base;
      o->am->v=0;
      if(f==POST_DEC) o->am->offset=old->offset-val;
      else if(f==POST_INC) o->am->offset=-old->offset+val;
      else if(f==PRE_DEC) o->am->offset=val;
      else o->am->offset=-val;
    }else
      ierror(0);
  }else if(o->flags&DREFOBJ){
    struct AddressingMode *am;
    o->am=am=mymalloc(sizeof(*am));
    am->flags=IMM_IND;
    if(!o->reg) ierror(0);
    am->base=o->reg;
    am->offset=zm2l(val);
    am->v=0;
  }else if(o->flags&KONST){
    struct AddressingMode *am;
    if(o->am) ierror(0);
    o->am=am=mymalloc(sizeof(*am));
    am->flags=KONSTINC;
    am->offset=zm2l(val);
    am->base=t;
  }else{
    o->val.vmax=zmadd(o->val.vmax,val);
  }
}

/* pushed on the stack by a callee, no pop needed */
static void callee_push(long l)
{
  if(l-stackoffset>stack)
    stack=l-stackoffset;
}
static void push(long l)
{
  stackoffset-=l;
  if(stackoffset<maxpushed) maxpushed=stackoffset;
  if(-maxpushed>stack) stack=-maxpushed;
}
static void pop(long l)
{
  stackoffset+=l;
}
static void gen_pop(FILE *f,long l)
{
  if(l==0) return;
  if(l==1&&CPU==6812){
    emit(f,"\tins\n");
#if 0 /* might clobber return register */
  }else if(l==2&&!regs[acc]){
    emit(f,SPULLD);
    BSET(regs_modified,acc);
  }else if(l==2&&!regs[ix]){
    emit(f,SPULL("x"));
    BSET(regs_modified,ix);
  }else if(l==2&&!regs[iy]){
    emit(f,SPULL("y"));
    BSET(regs_modified,iy);
#endif
  }else{
    emit(f,"\tleas\t%u,%s\n",SGN16(l),regnames[sp]);
  }
  pop(l);
}
static void pr(FILE *f,struct IC *p)
{
  int r;
  if(pushed_acc){
    emit(f,SPULLD);
    pop(2);
    pushed_acc=0;
  }
  for(r=MAXR;r>=1;r--){
    if(regs[r]&8){
      emit(f,"\t%s%s\n",CPU==6812?"pul":"puls\t",regnames[r]);
      pop(2);
    }
    regs[r]&=~12;
  }
}
static void function_top(FILE *f,struct Var *v,long offset)
/*  erzeugt Funktionskopf                       */
{
  int i;
  emit(f,"# offset=%ld\n",offset);
  have_frame=0;stack_valid=1;stack=0;
  if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
  if(v->storage_class==EXTERN){
    if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC)
      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
    emit(f,"%s%s:\n",idprefix,v->identifier);
  }else{
    emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
  }
  roff=0;
  for(i=MAXR;i>0;i--){
    if(regused[i]&&!regscratch[i]&&!regsa[i]){
      have_frame=1;
      loff+=2;
      roff+=2;
      if(i==iy) emit(f,SPUSH("y"));
      else if(i==iu){
	if(CPU!=6812&&regused[iy]){
	  emit(f,"\tpshs\tu,y\n");
	  loff+=2;roff+=2;i=iy;
	}else
	  emit(f,SPUSH("u"));
      }else
	ierror(0);
    }
  }
  if(stack_check){
    stackchecklabel=++label;
    emit(f,"\tldy\t#%s%d\n",labprefix,stackchecklabel);
    /* FIXME: banked */
    emit(f,"\t%s\t%s__stack_check\n",jsrinst,idprefix);
  }
  if(offset){
    if(CPU==6812&&offset==1)
      emit(f,SPUSH("b"));
    else if(CPU==6812&&offset==2)
      emit(f,SPUSHD);
    else
      emit(f,"\tleas\t%ld,%s\n",SGN16(-offset),regnames[sp]);
    have_frame=1;
  }
}
static void function_bottom(FILE *f,struct Var *v,long offset)
/*  erzeugt Funktionsende                       */
{
  int i;
  offset-=roff;
  if(offset){
    if(offset==1&&CPU==6812)
      emit(f,"\tins\n");
    else if(offset==2&&CPU==6812&&!zmeqto(szof(v->vtyp->next),l2zm(4L)))
      emit(f,SPULL("x"));
    else if(offset==2&&CPU==6812&&regused[iy])
      emit(f,SPULL("y"));
    else
      emit(f,"\tleas\t%ld,%s\n",SGN16(offset),regnames[sp]);
  }
  for(i=1;i<=MAXR;i++){
    if(regused[i]&&!regscratch[i]&&!regsa[i]){
      have_frame=1;
      if(i==iy){
	if(CPU!=6812&&regused[iu]&&!regscratch[iu]&&!regsa[iu]){
	  emit(f,"\tpuls\tu,y\n");
	  i=iu;
	}else
	  emit(f,SPULL("y"));
      }else if(i==iu) emit(f,SPULL("u"));
      else
	ierror(0);
    }
  }
  if(ret) emit(f,"\t%s\n",ret);
  if(v->storage_class==EXTERN){
    emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier);
    emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier);
  }else{
    emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset));
    emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset));
  }
  if(stack_check)
    emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stackchecklabel,offset-maxpushed);
  if(stack_valid){
    if(!v->fi) v->fi=new_fi();
    v->fi->flags|=ALL_STACK;
    v->fi->stack1=l2zm(stack+offset);
    emit(f,"# stacksize=%ld\n",stack+offset);
    emit(f,"\t.equ\t%s__stack_%s,%ld\n",idprefix,v->identifier,stack+offset);
  }
}
static int compare_objects(struct obj *o1,struct obj *o2)
{
  if(o1->flags==o2->flags&&o1->am==o2->am){
    if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){
      if(!(o1->flags&REG)||o1->reg==o2->reg){
	return 1;
      }
    }
  }
  return 0;
}

/*FIXME*/
static void clear_ext_ic(struct ext_ic *p)
{
  p->flags=0;
  p->r=0;
  p->offset=0;
}
static long pof2(zumax x)
/*  Yields log2(x)+1 oder 0. */
{
  zumax p;int ln=1;
  p=ul2zum(1L);
  while(ln<=32&&zumleq(p,x)){
    if(zumeqto(x,p)) return ln;
    ln++;p=zumadd(p,p);
  }
  return 0;
}
static void peephole(struct IC *p)
{
  int c,c2,r,t;struct IC *p2;
  struct AddressingMode *am;
  zmax incmin,incmax;
  if(CPU==6812){
    incmin=l2zm(-8L);
    incmax=l2zm(8L);
  }else{
    incmin=l2zm(-2L);
    incmax=l2zm(2L);
  }
  frame_used=0;
  for(;p;p=p->next){
    c=p->code;
    if(!frame_used){
      if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1;
      if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1;
      if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1;
    }
    /* letztes Label merken */
    if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0;
    if(c==LABEL) exit_label=p->typf;
#if 0
    /* and x,#const;bne/beq, FIXME */
    if(c==AND&&isconst(q2)&&isreg(z)){
      long bit;
      eval_const(&p->q2.val,p->typf);
      if(bit=pof2(vumax)){
	struct IC *cmp=0;int fr=0;
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if(c2==TEST){
	    if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){
	      cmp=p2;continue;
	    }
	  }
	  if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
	    eval_const(&p2->q2.val,p2->typf);
	    if(ISNULL()){
	      cmp=p2;continue;
	    }
	    break;
	  }
	  if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;}
	  if((c2==BNE||c2==BEQ)&&cmp&&fr==1){
	    p->ext.flags=EXT_IC_BTST;
	    p2->ext.flags=EXT_IC_BTST;
	    p2->ext.offset=bit-1;
	    cmp->code=NOP;
	    cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0;
	    break;
	  }
	  if(((p2->q1.flags&REG)&&p2->q1.reg==p->z.reg)||((p2->q2.flags&REG)&&p2->q2.reg==p->z.reg)||((p2->z.flags&REG)&&p2->z.reg==p->z.reg)) break;
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	}
      }
    }
#endif
    /* Try d,idx */
    if(c==ADDI2P&&ISRACC(q2)&&ISRIDX(z)&&(ISRIDX(q1)||p->q2.reg!=p->z.reg)){
      int base,idx;struct obj *o;
      r=p->z.reg;idx=p->q2.reg;
      if(isreg(q1)) base=p->q1.reg; else base=r;
      o=0;
      for(p2=p->next;p2;p2=p2->next){
        c2=p2->code;
        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
        if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
        if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
        if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break;
	
        if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
          if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
            if(o||!ISCHWORD(q1typ(p2))) break;
            o=&p2->q1;
          }
          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
	    break; /*TODO: check what is possible */
            if(o||!ISCHWORD(q2typ(p2))) break;
            o=&p2->q2;
          }
          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
	    break; /*TODO: check what is possible */
            if(o||!ISCHWORD(ztyp(p2))) break;
            o=&p2->z;
          }
        }
        if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
          int m;
          if(c2==FREEREG)
            m=p2->q1.reg;
          else
            m=p2->z.reg;
          if(m==r){
            if(o){
              o->am=am=mymalloc(sizeof(*am));
              am->flags=ACC_IND;
              am->base=base;
	      if(idx!=acc) ierror(0);
              am->offset=idx;
	      if(isreg(q1)){
		p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
	      }else{
		p->code=c=ASSIGN;p->q2.flags=0;
		p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
	      }
            }
            break;
          }
          if(c2!=FREEREG&&m==base) break;
	  continue;
	}
	/* better no instructions between, accu used too much */
	if(c2!=FREEREG&&c2!=ALLOCREG&&!o) break;
      }
    }
    /* POST_INC/DEC in q1 */
    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
      r=p->q1.reg; t=q1typ(p);
      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
	    eval_const(&p2->q2.val,p2->typf2);
	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
	      p2->code=NOP;
	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
	      p->q1.am=mymalloc(sizeof(*am));
	      p->q1.am->base=r;
	      p->q1.am->v=0;
	      if(zmleq(vmax,l2zm(0L))){
		p->q1.am->flags=POST_DEC;
		p->q1.am->offset=-zm2l(vmax);
	      }else{
		p->q1.am->flags=POST_INC;
		p->q1.am->offset=zm2l(vmax);
	      }
	    }else break;
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
	}
      }
    }
    /* POST_INC/DEC in q2 */
    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
      r=p->q2.reg; t=q2typ(p);
      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)){
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
	    eval_const(&p2->q2.val,p2->typf2);
	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
	      p2->code=NOP;
	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
	      p->q2.am=mymalloc(sizeof(*am));
	      p->q2.am->base=r;
	      p->q2.am->v=0;
	      if(zmleq(vmax,l2zm(0L))){
		p->q2.am->flags=POST_DEC;
		p->q2.am->offset=-zm2l(vmax);
	      }else{
		p->q2.am->flags=POST_INC;
		p->q2.am->offset=zm2l(vmax);
	      }
	    }else break;
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
	}
      }
    }
    /* POST_INC/DEC in z */
    if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){
      r=p->z.reg; t=ztyp(p);
      if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)){
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
	    eval_const(&p2->q2.val,p2->typf2);
	    if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
	    if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){
	      p2->code=NOP;
	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
	      p->z.am=mymalloc(sizeof(*am));
	      p->z.am->base=r;
	      p->z.am->v=0;
	      if(zmleq(vmax,l2zm(0L))){
		p->z.am->flags=POST_DEC;
		p->z.am->offset=-zm2l(vmax);
	      }else{
		p->z.am->flags=POST_INC;
		p->z.am->offset=zm2l(vmax);
	      }
	    }else break;
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if(((p2->q1.flags&REG)&&p2->q1.reg==r)||((p2->q2.flags&REG)&&p2->q2.reg==r)||((p2->z.flags&REG)&&p2->z.reg==r)) break;
	}
      }
    }

    /* R,#c */
    if((c==ADDI2P||c==SUBIFP)&&ISHWORD(p->typf)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(!drel&&(p->q1.flags&VARADR)))){
      int base;zmax of;struct obj *o;struct Var *v;
      if(p->q1.flags&VARADR){
	v=p->q1.v;
	of=p->q1.val.vmax;
	r=p->z.reg;
	if(isreg(q2)&&ISIDX(p->q2.reg))
	  base=p->q2.reg;
	else
	  base=r;
      }else{
	eval_const(&p->q2.val,p->typf);
	if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
	v=0;
	r=p->z.reg;
	if(isreg(q1)&&ISIDX(p->q1.reg)) base=p->q1.reg; else base=r;
      }
      o=0;
      for(p2=p->next;p2;p2=p2->next){
	c2=p2->code;
	if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break;
	if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break;
	if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){
	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){
	    if(o||!ISHWORD(q1typ(p2))) break;
	    o=&p2->q1;
	  }
	  if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
	    if(o||!ISHWORD(q2typ(p2))) break;
	    o=&p2->q2;
	  }
	  if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
	    if(o||!ISHWORD(ztyp(p2))) break;
	    o=&p2->z;
	  }
	}
	if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){
	  int m;
	  if(c2==FREEREG) 
	    m=p2->q1.reg;
	  else
	    m=p2->z.reg;
	  if(m==r){
	    if(o){
	      o->am=am=mymalloc(sizeof(*am));
	      am->flags=IMM_IND;
	      am->base=base;
	      am->offset=zm2l(of);
	      am->v=v;
	      if(!v){
		if(isreg(q1)&&ISIDX(p->q1.reg)){
		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
		}else{
		  p->code=c=ASSIGN;p->q2.flags=0;
		  p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ];
		}
	      }else{
		if(isreg(q2)&&ISIDX(p->q2.reg)){
		  p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0;
		}else{
		  p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0;
		  p->q2.val.vmax=sizetab[p->typf&NQ];
		}
	      }
	    }
	    break;
	  }
	  if(/*get_reg!! c2!=FREEREG&&*/m==base) break;
	  continue;
	}
      }
    }      
  }
}

static struct obj *cam(int flags,int base,long offset,struct Var *v)
/*  Initializes an addressing-mode structure and returns a pointer to   */
/*  that object. Will not survive a second call!                        */
{
  static struct obj obj;
  static struct AddressingMode am;
  obj.am=&am;
  am.flags=flags;
  am.base=base;
  am.offset=offset;
  am.v=v;
  return &obj;
}

static void get_acc(FILE *f,struct IC *p)
{
  if(regs[acc]){
    if(p->q2.am)
      if(p->q2.am->flags==ACC_IND) ierror(0);
    else
      if((p->q2.flags&REG)&&ISACC(p->q2.reg)) ierror(0);
    if(p->z.am)
      if(p->z.am->flags==ACC_IND) ierror(0);
    else
      if((p->z.flags&REG)&&ISACC(p->z.reg)) ierror(0);
    if(regs[acc]){
      emit(f,SPUSHD);
      push(2);
      pushed_acc=1;
    }
  }
}
static int get_idx(FILE *f,IC *p)
{
  int r;
  for(r=1;r<=MAXR;r++){
    if(ISIDX(r)){
      if(!regs[r]){
	regs[r]|=4;
	return r;
      }
    }
  }
  for(r=1;r<=MAXR;r++){
    if(ISIDX(r)){
      if((!(p->q1.flags&REG)||p->q1.reg!=r)&&
	 (!(p->q2.flags&REG)||p->q2.reg!=r)&&
	 (!(p->z.flags&REG)||p->z.reg!=r)){
	emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[r]);
	regs[r]|=8;
	push(2);
	return r;
      }
    }
  }
  ierror(0);
}
static int get_reg(FILE *f,struct IC *p,int t)
{
  int reg;
  if(!regs[acc])
    reg=acc;
  else if(ISHWORD(t)&&!regs[ix])
    reg=ix;
#if 0
  else if(ISHWORD(t)&&!regs[iy])
    reg=iy;
#endif
  else{
    get_acc(f,p);
    reg=acc;
  }
  BSET(regs_modified,reg);
  return reg;
}
static void load_reg(FILE *f,int r,struct obj *o,int t)
{
  if(!o->am){
    if((o->flags&(REG|DREFOBJ))==REG){
      if(o->reg==r) return;
      emit(f,"\ttfr\t%s,%s\n",regnames[o->reg],regnames[r]);
      return;
    }
    if(r==acc&&(o->flags&(KONST|DREFOBJ))==KONST){
      eval_const(&o->val,t);
      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){
	if(CPU!=6812&&!optsize)
	  emit(f,"\tldd\t#0\n");
	else
	  emit(f,"\tclra\n\tclrb\n"); 
	cc=o;cc_t=t;
	return;
      }
    }
  }
  if(o->flags&VARADR){
    char *base=0;
    if(pcrel&&ISFUNC(o->v->vtyp->flags))
      base="pc";
    if(drel&&!ISFUNC(o->v->vtyp->flags))
      base=regnames[iu];
    if(base&&!skip_rel){
      if(ISACC(r))
	emit(f,"\ttfr\t%s,d\n",base);
      if(ISIDX(r))
	emit(f,"\tlea%s\t",regnames[r]);
      else{
	if(*base=='p') emit(f,"%s%d:\n",labprefix,++label);
	emit(f,"\taddd\t#");
      }
      emitzm(f,o->val.vmax);
      emit(f,"+");
      if(o->v->storage_class==EXTERN)
	emit(f,"%s%s",idprefix,o->v->identifier);
      else
	emit(f,"%s%ld",labprefix,zm2l(o->v->offset));
      if(ISIDX(r))
	emit(f,",%s",base);
      else if(*base=='p')
	emit(f,"-%s%d",labprefix,label);
      emit(f,"\n");
      cc=o;cc_t=t;
      return;
    }
    skip_rel=0;
  }
  emit(f,"\tld%s\t",(r==acc&&(t&NQ)==CHAR)?(CPU==6812?"ab":"b"):regnames[r]);
  emit_obj(f,o,t);emit(f,"\n");
  cc=o;cc_t=t;
}
static void store_reg(FILE *f,int r,struct obj *o,int t)
{
  if((o->flags&(REG|DREFOBJ))==REG){
    if(o->reg==r) return;
    emit(f,"\ttfr\t%s,%s\n",regnames[r],regnames[o->reg]);
  }else{
    if(r==acc&&(t&NQ)==CHAR)
      emit(f,"\tst%s\t",(CPU==6812)?"ab":"b");
    else
      emit(f,"\tst%s\t",regnames[r]);
    emit_obj(f,o,t);emit(f,"\n");
    cc=o;cc_t=t;
  }
}
static void load_addr(FILE *f,int r,struct obj *o)
{
  if(o->am){
    if(o->am->flags==IMM_IND){
      if(o->am->base==r&&o->am->offset==0&&!o->am->v) return;
      if(ISIDX(r)){
	emit(f,"\tlea%s\t",regnames[r]);
	emit_obj(f,o,0);
	emit(f,"\n");
      }else{
	if(r!=acc) ierror(0);
	emit(f,"\ttfr\t%s,%s\n",regnames[o->am->base],regnames[r]);
	emit(f,"\taddd\t#%ld\n",o->am->offset);
	if(o->am->v){
	  if(o->am->v->storage_class==STATIC)
	    emit(f,"+%s%ld",labprefix,zm2l(o->am->v->offset));
	  else
	    emit(f,"+%s%s",idprefix,o->am->v->identifier);
	}
	emit(f,"\n");
	cc=0;
      }
      return;
    }
    ierror(0);
  }
  if(o->flags&DREFOBJ){
    o->flags&=~DREFOBJ;
    load_reg(f,r,o,o->dtyp);
    o->flags|=DREFOBJ;
    return;
  }
  if((o->flags&(VAR|VARADR))==VAR){
    if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){
      o->flags|=VARADR;
      load_reg(f,r,o,POINTER_TYPE(o->v->vtyp));
      o->flags&=~VARADR;
      return;
    }
    if(voff(o)==0){
      emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
      return;
    }
    if(ISIDX(r)){
      emit(f,"\tlea%s\t",regnames[r]);
      emit_obj(f,o,0);
      emit(f,"\n");
    }else{
      if(r!=acc) ierror(0);
      emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]);
      emit(f,"\taddd\t#%ld\n",voff(o));
      cc=0;
    }
    return;
  }
  ierror(0);
}

static int scratchreg(int r,struct IC *p)
{
  int c;
  while(1){
    p=p->next;
    if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1;
    if(c==CALL||(c>=BEQ&&c<=BRA)) return 0;
    if((p->q1.flags&REG)&&p->q1.reg==r) return 0;
    if((p->q2.flags&REG)&&p->q2.reg==r) return 0;
    if((p->z.flags&REG)&&p->z.reg==r) return 0;
  }
}

/****************************************/
/*  End of private fata and functions.  */
/****************************************/


int init_cg(void)
/*  Does necessary initializations for the code-generator. Gets called  */
/*  once at the beginning and should return 0 in case of problems.      */
{
  int i;

  CPU=CPUOPT;

	if (CPU==680912) {
		bitsperbyte = 12;
		bytemask = 0xfff;
		dbl_bytemask = 0xffffff;
	}
	
  /*  Initialize some values which cannot be statically initialized   */
  /*  because they are stored in the target's arithmetic.             */
  maxalign=l2zm(1L);
  char_bit=l2zm((long)bitsperbyte);
  for(i=0;i<=MAX_TYPE;i++){
    sizetab[i]=l2zm(msizetab[i]);
    align[i]=l2zm(malign[i]);
  }
  for(i=1;i<=iu;i++){
    regsize[i]=l2zm(2L);regtype[i]=&ityp;
  }	
  regsize[dx]=l2zm(4L);regtype[i]=&ltyp;

  /*  Initialize the min/max-settings. Note that the types of the     */
  /*  host system may be different from the target system and you may */
  /*  only use the smallest maximum values ANSI guarantees if you     */
  /*  want to be portable.                                            */
  /*  That's the reason for the subtraction in t_min[INT]. Long could */
  /*  be unable to represent -2147483648 on the host system.          */
  if (CPU==680912) {
	  t_min[CHAR]=l2zm(-2048L);
	  t_min[SHORT]=l2zm(-8388608L);
	  t_min[INT]=t_min[SHORT];
	  t_min[LONG]=zmsub(l2zm(0x800000000000LL),l2zm(1L));
	  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
	  t_min[MAXINT]=t_min(LLONG);
	  t_max[CHAR]=ul2zum(2047L);
	  t_max[SHORT]=ul2zum(8388607UL);
	  t_max[INT]=t_max[SHORT];
	  t_max[LONG]=ul2zum(0x7fffffffffffULL);
	  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
	  t_max[MAXINT]=t_max(LLONG);
	  tu_max[CHAR]=ul2zum(4095UL);
	  tu_max[SHORT]=ul2zum(16777215UL);
	  tu_max[INT]=tu_max[SHORT];
	  tu_max[LONG]=ul2zum(0xffffffffffffULL);
	  tu_max[LLONG]=zumkompl(ul2zum(0UL));
	  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
	}
	else {
	  t_min[CHAR]=l2zm(-128L);
	  t_min[SHORT]=l2zm(-32768L);
	  t_min[INT]=t_min[SHORT];
	  t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
	  t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L));
	  t_min[MAXINT]=t_min(LLONG);
	  t_max[CHAR]=ul2zum(127L);
	  t_max[SHORT]=ul2zum(32767UL);
	  t_max[INT]=t_max[SHORT];
	  t_max[LONG]=ul2zum(2147483647UL);
	  t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL));
	  t_max[MAXINT]=t_max(LLONG);
	  tu_max[CHAR]=ul2zum(255UL);
	  tu_max[SHORT]=ul2zum(65535UL);
	  tu_max[INT]=tu_max[SHORT];
	  tu_max[LONG]=ul2zum(4294967295UL);
	  tu_max[LLONG]=zumkompl(ul2zum(0UL));
	  tu_max[MAXINT]=t_max(UNSIGNED|LLONG);
	}

  if(g_flags[9]&USEDFLAG) drel=1;
  if(g_flags[10]&USEDFLAG) MINADDI2P=SHORT;
  if(g_flags[11]&USEDFLAG) nodx=1;
  if(g_flags[12]&USEDFLAG) nou=1;

  if(CPU==6812) switchsubs=1;

  /*  Reserve a few registers for use by the code-generator.      */
  regsa[sp]=REGSA_NEVER;
  regscratch[sp]=0;

  if(CPU==6812||drel||nou){
    regsa[iu]=REGSA_NEVER;
    regscratch[iu]=0;
  }

  if(CPU!=6812){
    regnames[sp]="s";
    logicals[0]="or";
  }

  if(!(g_flags[6]&USEDFLAG)){
    extern int static_cse,dref_cse;
    static_cse=0;
    dref_cse=0;
  }

  if(!(g_flags[7]&USEDFLAG)){
    regsa[acc]=REGSA_TEMPS;
    regsa[dx]=REGSA_TEMPS;
  }

  if(g_flags[8]&USEDFLAG){
    pcrel=1;
    jsrinst="lbsr";
    jmpinst="lbra";
    rodataname="\t.data\n";
  }

  if(CPU==6809)
    marray[1]="__6809__";
  if(CPU==6309)
    marray[1]="__6309__";
  if(CPU==680912)
    marray[1]="__680912__";
  target_macros=marray;


  declare_builtin("__mulint16",INT,INT,acc,INT,0,1,0);
  declare_builtin("__divint16",INT,INT,ix,INT,acc,1,0);
  declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);
  declare_builtin("__modint16",INT,INT,ix,INT,acc,1,0);
  declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0);


  /* TODO: set argument registers */
  declare_builtin("__mulint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__addint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__subint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__andint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__orint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__eorint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__negint32",LONG,LONG,0,0,0,1,0);
  declare_builtin("__lslint32",LONG,LONG,0,INT,0,1,0);

  declare_builtin("__divint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
  declare_builtin("__modint32",LONG,LONG,0,LONG,0,1,0);
  declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
  declare_builtin("__lsrsint32",LONG,LONG,0,INT,0,1,0);
  declare_builtin("__lsruint32",UNSIGNED|LONG,UNSIGNED|LONG,0,INT,0,1,0);
  declare_builtin("__cmpsint32",INT,LONG,0,LONG,0,1,0);
  declare_builtin("__cmpuint32",INT,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0);
  declare_builtin("__sint32toflt32",FLOAT,LONG,0,0,0,1,0);
  declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
  declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0);
  declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
  declare_builtin("__flt32tosint32",LONG,FLOAT,0,0,0,1,0);
  declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
  declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0);
  declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);



  declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0);
  declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0);

  declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
  declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0);
  declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
  declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0);
  declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0);
  declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0);
  declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0);
  declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
  declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
  declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
  declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
  declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
  declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
  declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
  declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);

  declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0);
  declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0);


  declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
  declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
  declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
  declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
  declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0);
  declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0);

  declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
  declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
  declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
  declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
  declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0);
  declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0);


  return 1;
}

int freturn(struct Typ *t)
/*  Returns the register in which variables of type t are returned. */
/*  If the value cannot be returned in a register returns 0.        */
{
  int f=t->flags&NQ;
  if(ISSCALAR(f)){
    if(ISHWORD(f)||f==CHAR)
      return acc;
    else if(ISLWORD(f))
      return dx;
  }
  return 0;
}

int regok(int r,int t,int mode)
/*  Returns 0 if register r cannot store variables of   */
/*  type t. If t==POINTER and mode!=0 then it returns   */
/*  non-zero only if the register can store a pointer   */
/*  and dereference a pointer to mode.                  */
{
  if(!ISSCALAR(t)) return 0;
  if(r==dx){
    if(ISLWORD(t)&&(optflags&2)&&!nodx) return 1;
    return 0;
  }
  if(mode==-1){
    if(ISHWORD(t)) return 1;
    if((t&NQ)==CHAR&&ISACC(r)) return 1;
  }else{
    if(ISIDX(r)){
      if(ISPOINTER(t)&&ISHWORD(t))
	return 1;
    }
    if(ISACC(r)){
      if((t&NQ)==CHAR)
	return 1;
      if(ISINT(t)&&ISHWORD(t))
	return 1;
    }
  }
  return 0;
}

int reg_pair(int r,struct rpair *p)
/* Returns 0 if the register is no register pair. If r  */
/* is a register pair non-zero will be returned and the */
/* structure pointed to p will be filled with the two   */
/* elements.                                            */
{
  if(r==dx){
    p->r1=acc;
    p->r2=ix;
    return 1;
  }
  return 0;
}

int cost_savings(struct IC *p,int r,struct obj *o)
{
  /*FIXME*/
  int c=p->code;
  if(r==dx){
    if(c==GETRETURN||c==SETRETURN||c==PUSH||c==ASSIGN) return 8;
    return INT_MIN;
  }
  if(o->flags&VKONST){
    struct obj *co=&o->v->cobj;
    if(o->flags&DREFOBJ)
      return 0;
    if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){
      return 2;
    }
    return 0;
  }
  if((o->flags&DREFOBJ)){
    if(!ISIDX(r)) return INT_MIN;
    if(p->q2.flags&&o!=&p->z)
      return 6;
    else
      return 6;
  }else if(c==GETRETURN&&p->q1.reg==r){
    return 4;
  }else if(c==SETRETURN&&p->z.reg==r){
    return 4;
  }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&&regok(r,CHAR,0)){
    return 3;
  }
  if(o==&p->z&&r==acc){
    if(c==SUB||c==SUBIFP||c==SUBPFP||c==AND||c==OR||c==XOR)
      return 6;
    if((c==ADD||c==ADDI2P)&&!(p->q1.flags&(KONST|VKONST))&&!(p->q2.flags&(KONST|VKONST)))
      return 4;
    if(c==MULT) return 5;
    if(c==ASSIGN&&(p->q1.flags&KONST)){
      eval_const(&p->q1.val,p->typf);
      if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL)))
	return 3;
    }
  }
#if 1
  if((o==&p->q2/*||o==&p->z*/)&&!(o->flags&DREFOBJ)&&!ISACC(o->reg)&&(c==MULT||c==DIV||c==MOD))
    return INT_MIN;
#endif
  if(c==COMPARE||c==TEST){
    if(r==ix) return 3;
    if(r==iy) return 2;
    if(r==iu) return 1;
  }
  return 2;
}

int dangerous_IC(struct IC *p)
/*  Returns zero if the IC p can be safely executed     */
/*  without danger of exceptions or similar things.     */
/*  vbcc may generate code in which non-dangerous ICs   */
/*  are sometimes executed although control-flow may    */
/*  never reach them (mainly when moving computations   */
/*  out of loops).                                      */
/*  Typical ICs that generate exceptions on some        */
/*  machines are:                                       */
/*      - accesses via pointers                         */
/*      - division/modulo                               */
/*      - overflow on signed integer/floats             */
{
  int c=p->code;
  if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ))
    return 1;
  if((c==DIV||c==MOD)&&!isconst(q2))
    return 1;
  return 0;
}

/* Return name of library function, if this node should be
   implemented via libcall. */
char *use_libcall(int c,int t,int t2)
{
  static char fname[16];
  char *ret=0;

  if(c==COMPARE){
    if((t&NQ)==LLONG||ISFLOAT(t)){
      sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
      ret=fname;
    }
  }else{
    t&=NU;
    t2&=NU;
    if(t==LDOUBLE) t=DOUBLE;
    if(t2==LDOUBLE) t2=DOUBLE;
    if(c==CONVERT){
      if(t==t2) return 0;
      if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32";
      if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64";

      if(ISFLOAT(t)){
        sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64);
        ret=fname;
      }
      if(ISFLOAT(t2)){
        sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8);
        ret=fname;
      }
    }
    if((t&NQ)==LLONG||ISFLOAT(t)){
      if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){
	if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){
	  sprintf(fname,"__%suint64",ename[c]);
	  ret=fname;
	}else if((t&NQ)==LLONG){
          sprintf(fname,"__%sint64",ename[c]);
          ret=fname;
	}else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){
	  sprintf(fname,"__%suint32",ename[c]);
	  ret=fname;
	}else if((t&NQ)==LONG){
          sprintf(fname,"__%sint32",ename[c]);
          ret=fname;
        }else{
	  sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
          ret=fname;
	}
      }
    }
    if((c==MULT&&(CPU==6809||(t&NQ)==LONG))||c==DIV||c==MOD){
      sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8);
      ret=fname;
    }
  }

  return ret;
}



int must_convert(int o,int t,int const_expr)
/*  Returns zero if code for converting np to type t    */
/*  can be omitted.                                     */
{
  int op=o&NQ,tp=t&NQ;
  if(op==tp) return 0;
  if(ISHWORD(op)&&ISHWORD(tp)) return 0;
  if(ISFLOAT(op)||ISFLOAT(tp)) return 1;
  if(ISLWORD(op)&&ISLWORD(tp)) return 0;
  return 1;
}

void gen_ds(FILE *f,zmax size,struct Typ *t)
/*  This function has to create <size> bytes of storage */
/*  initialized with zero.                              */
{
  if(newobj&&section!=SPECIAL)
    emit(f,"%ld\n",zm2l(size));
  else
    emit(f,"\t.space\t%ld\n",zm2l(size));
  newobj=0;  
}

void gen_align(FILE *f,zmax align)
/*  This function has to make sure the next data is     */
/*  aligned to multiples of <align> bytes.              */
{
  /* nothing to do */
}

void gen_var_head(FILE *f,struct Var *v)
/*  This function has to create the head of a variable  */
/*  definition, i.e. the label and information for      */
/*  linkage etc.                                        */
{
  int constflag;
  if(v->clist) constflag=is_const(v->vtyp);
  if(v->storage_class==STATIC){
    if(ISFUNC(v->vtyp->flags)) return;
    if(v->tattr&DPAGE)
      emit(f,"\t.direct\t%s%ld\n",labprefix,zm2l(v->offset));
    if(!special_section(f,v)){
      if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){
	emit(f,dataname);if(f) section=DATA;
      }
      if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=RODATA){
	emit(f,rodataname);if(f) section=RODATA;
      }
      if(!v->clist&&section!=BSS){
	emit(f,bssname);if(f) section=BSS;
      }
    }
    emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset));
    emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp)));
    if(v->clist||section==SPECIAL)
      emit(f,"%s%ld:\n",labprefix,zm2l(v->offset));
    else
      emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset));
    newobj=1; 
  }
  if(v->storage_class==EXTERN){
    if(v->flags&(DEFINED|TENTATIVE)){
      emit(f,"\t.global\t%s%s\n",idprefix,v->identifier);
      if(v->tattr&DPAGE)
	emit(f,"\t.direct\t%s%s\n",idprefix,v->identifier);
      if(!special_section(f,v)){
	if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&&section!=DATA){
	  emit(f,dataname);if(f) section=DATA;
	}
	if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&&section!=RODATA){
	  emit(f,rodataname);if(f) section=RODATA;
	}
	if(!v->clist&&section!=BSS){
	  emit(f,bssname);if(f) section=BSS;
	}
      }
      emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier);
      emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp)));
      if(v->clist||section==SPECIAL)
        emit(f,"%s%s:\n",idprefix,v->identifier);
      else
        emit(f,"\t.global\t%s%s\n\t.lcomm\t%s%s,",idprefix,v->identifier,idprefix,v->identifier);
      newobj=1;   
    }
  }
}

void gen_dc(FILE *f,int t,struct const_list *p)
/*  This function has to create static storage          */
/*  initialized with const-list p.                      */
{
  emit(f,"\t%s\t",dct[t&NQ]);
  if(!p->tree){
    if(ISFLOAT(t)){
      /*  auch wieder nicht sehr schoen und IEEE noetig   */
      unsigned char *ip;
      ip=(unsigned char *)&p->val.vdouble;
      emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]);
      if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){
	emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]);
      }
    }else{
      emitval(f,&p->val,(t&NU)|UNSIGNED);
    }
  }else{
    int m=p->tree->o.flags,md=drel,mp=pcrel;
    p->tree->o.flags&=~VARADR;
    drel=0;pcrel=0;
    emit_obj(f,&p->tree->o,t&NU);
    p->tree->o.flags=m;
    drel=md;pcrel=mp;
  }
  emit(f,"\n");newobj=0;
}


static void preload(FILE *f,IC *p)
{
  int t,r;

  if((p->typf&VOLATILE)||(p->typf2&VOLATILE)||
     ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))||
     ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))||
     ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE))))
    emit(f,"; volatile barrier\n");

  t=q1typ(p);
  if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
    r=get_idx(f,p);
    p->q1.flags&=~DREFOBJ;
    load_reg(f,r,&p->q1,INT);
    p->q1.flags|=(REG|DREFOBJ);
    p->q1.reg=r;
  }
  t=q2typ(p);
  if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
    r=get_idx(f,p);
    p->q2.flags&=~DREFOBJ;
    load_reg(f,r,&p->q2,INT);
    p->q2.flags|=(REG|DREFOBJ);
    p->q2.reg=r;
  }else if(isreg(z)&&(((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg)||(p->q2.am&&p->q2.am->base==p->z.reg))){
    r=get_idx(f,p);
    p->q2.flags&=~DREFOBJ;
    load_reg(f,r,&p->q2,INT);
    p->q2.flags|=(REG|DREFOBJ);
    p->q2.reg=r;
  }
  t=ztyp(p);
  if(!p->z.am&&(p->z.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){
    r=get_idx(f,p);
    p->z .flags&=~DREFOBJ;
    load_reg(f,r,&p->z ,INT);
    p->z .flags|=(REG|DREFOBJ);
    p->z .reg=r;
  }
}

/*  The main code-generation routine.                   */
/*  f is the stream the code should be written to.      */
/*  p is a pointer to a doubly linked list of ICs       */
/*  containing the function body to generate code for.  */
/*  v is a pointer to the function.                     */
/*  offset is the size of the stackframe the function   */
/*  needs for local variables.                          */
void gen_code(FILE *f,struct IC *fp,struct Var *v,zmax offset)
{
  int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0;
  struct obj *bit_obj;char *bit_reg;
  static int idone;
  struct obj o;
  IC *p,*p2;
  if(v->tattr&INTERRUPT)
    ret="rti";
  else if (v->tattr&FAR)
  	ret="rtf";
  else
    ret="rts"; /*FIXME: banked */
  if(DEBUG&1) printf("gen_code()\n");
  for(p=fp;p;p=p->next) clear_ext_ic(&p->ext);
  emit(f,"#off1=%ld\n",zm2l(offset));
  if(!(g_flags[5]&USEDFLAG)){
    peephole(fp);
    if(!frame_used) offset=l2zm(0L);
  }
  for(c=1;c<=MAXR;c++) regs[c]=(regsa[c]==REGSA_NEVER)?1:0;
  for(c=1;c<=MAXR;c++){
    if(regscratch[c]&&(regsa[c]||regused[c])){
      BSET(regs_modified,c);
    }
  }
  t=0;
  for(p=fp;p;p=p->next){
    c=p->code;
    if(c==ALLOCREG){ regs[p->q1.reg]=1; if(p->q1.reg==dx) regs[acc]=regs[ix]=1;}
    if(c==FREEREG){ regs[p->q1.reg]=0; if(p->q1.reg==dx) regs[acc]=regs[ix]=0;}
    if((c==LSHIFT||c==RSHIFT)&&(p->typf&NQ)>=LONG) regused[iy]=1;
    if(c==PUSH&&(p->q1.flags&(REG|DREFOBJ))!=REG){
      if(zmeqto(p->q2.val.vmax,Z1)){
	if(regs[acc]) t=(t>2)?t:2;
      }else if(zmeqto(p->q2.val.vmax,l2zm(2L))){
	if(regs[acc]&&regs[ix]&&regs[iy]&&(CPU==6812||regs[iu])) t=(t>2)?t:2;
      }else if(zmeqto(p->q2.val.vmax,l2zm(4L))){
	if(regs[acc]) t=(t>2)?t:2;
      }else{
	/* TODO: finer check */
	if(drel||!regsa[iu])
	  t=(t>8)?t:8;
	else
	  t=(t>6)?t:6;
      }
    }
  }
  emit(f,"#toff=%d\n",t);
  loff=zm2l(offset)+t;
  function_top(f,v,loff);
  stackoffset=notpopped=dontpop=maxpushed=0;
  for(p=fp;p;pr(f,p),p=p->next){
    c=p->code;t=p->typf;
    if(debug_info)
      dwarf2_line_info(f,p); 
    short_add=0;
    if(c==NOP) continue;
    if(c==ALLOCREG){
      regs[p->q1.reg]=1;
      if(p->q1.reg==dx) regs[acc]=regs[ix]=1;
      continue;
    }
    if(c==FREEREG){
      regs[p->q1.reg]=0;
      if(p->q1.reg==dx) regs[acc]=regs[ix]=0;
      continue;
    }
    if(notpopped&&!dontpop){
      int flag=0;
      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
	gen_pop(f,notpopped);
	notpopped=0;
      }
    }
    if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;}
    if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1;
    if(c==BRA){
      if(p->typf==exit_label&&!have_frame){
	emit(f,"\t%s\n",ret);
      }else{
	if(t==exit_label) need_return=1;
	emit(f,"\tbra\t%s%d\n",labprefix,t);
      }
      cc=0;continue;
    }
    if(c>=BEQ&&c<BRA){      
      if((lastcomp&UNSIGNED)||ISPOINTER(lastcomp))
        emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,t);
      else
        emit(f,"\tb%s\t%s%d\n",ccs[c-BEQ],labprefix,t);
      continue;
    }
    if(c==MOVETOREG){
      load_reg(f,p->z.reg,&p->q1,SHORT);
      continue;
    }
    if(c==MOVEFROMREG){
      store_reg(f,p->q1.reg,&p->z,SHORT);
      continue;
    }
    
    /*if(ISFLOAT(t)) {pric2(stdout,p);ierror(0);}*/

    if((t&NQ)==BIT){
      ierror(0);
    }

    if(c==CONVERT&&ISLWORD(t)&&ISLWORD(p->typf2)){
      p->code=c=ASSIGN;
      p->q2.val.vmax=l2zm(4L);
    }

    if((p->q2.flags&REG)&&ISACC(p->q2.reg)&&(c==ADD||c==MULT||c==AND||c==OR||c==XOR)){
      obj o=p->q1;
      p->q1=p->q2;
      p->q2=o;
    }

    if(c==TEST){
      lastcomp=t;
      p->code=c=COMPARE;
      gval.vmax=l2zm(0L);
      p->q2.flags=KONST;
      eval_const(&gval,MAXINT);
      insert_const(&p->q2.val,t);
    }

    if(c==SUBPFP){
      p->code=c=SUB;
      p->typf=t=(UNSIGNED|INT);
    }



    if((c==ASSIGN||c==PUSH)&&zmeqto(p->q2.val.vmax,l2zm(4L)))
      p->typf=t=LONG;

    preload(f,p);

    if(c==ADDI2P||c==SUBIFP){
      if((p->typf2&NQ)!=HPOINTER){
	if(p->q2.flags&KONST){
	  eval_const(&p->q2.val,p->typf);
	  insert_const(&p->q2.val,p->typf2);
	  p->typf=t=(UNSIGNED|SHORT);
	}else{
	  if(ISLWORD(t)) inc_addr(&p->q2,2,t);
	  if((t&NQ)==CHAR) short_add=t;
	  p->typf=t=(UNSIGNED|SHORT);
	}
      }else if(ISHWORD(t)){
	if((t&NQ)==LLONG) 
	  inc_addr(&p->q2,4,t);
	else if((t&NQ)!=LONG) 
	  short_add=t;
	p->typf=t=(UNSIGNED|LONG);
      }
      p->code=c=(c==ADDI2P)?ADD:SUB;
    }

    if(c==COMPARE&&ISLWORD(t)){
      IC *branch=p->next;
      int r;
      while(branch&&branch->code==FREEREG) branch=branch->next;
      if(!branch) ierror(0);
      c=branch->code;
      if(c<BEQ||c>BGT) ierror(0);
      if(!regs[ix])
	r=ix;
      else
	r=get_reg(f,p,INT);
      
      if(c==BEQ||c==BNE){
	inc_addr(&p->q1,0,t);
	inc_addr(&p->q2,0,t);
	load_reg(f,r,&p->q1,INT);
	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
	emit_obj(f,&p->q2,INT);
	emit(f,"\n");
	if(pushed_acc) emit(f,SPULLD);
	emit(f,"\tbne\t%s%d\n",labprefix,c==BEQ?++label:branch->typf);
	if(pushed_acc) emit(f,SPUSHD);
	inc_addr(&p->q1,2,t);
	inc_addr(&p->q2,2,t);
	load_reg(f,r,&p->q1,INT);
	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
	emit_obj(f,&p->q2,INT);
	emit(f,"\n");
	pr(f,p);
	if(c==BEQ){
	  emit(f,"\tbeq\t%s%d\n",labprefix,branch->typf);
	  emit(f,"%s%d:\n",labprefix,label);
	}else
	  emit(f,"\tbne\t%s%d\n",labprefix,branch->typf);
      }else{
	inc_addr(&p->q1,0,t);
	inc_addr(&p->q2,0,t);
	load_reg(f,r,&p->q1,INT);
	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
	emit_obj(f,&p->q2,INT);
	emit(f,"\n");
	label++;
	if(pushed_acc) emit(f,SPULLD);
	if(t&UNSIGNED){
	  if(c==BLT||c==BGT)
	    emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lo":"hi",labprefix,branch->typf);
	  else
	    emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lo":"hi",labprefix,label);
	}else{
	  if(c==BLT||c==BGT)
	    emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lt":"gt",labprefix,branch->typf);
	  else
	    emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lt":"gt",labprefix,label);
	}
	emit(f,"\tbne\t%s%d\n",labprefix,(c==BLT||c==BGT)?label:branch->typf);
	if(pushed_acc) emit(f,SPUSHD);
	inc_addr(&p->q1,2,t);
	inc_addr(&p->q2,2,t);
	load_reg(f,r,&p->q1,INT);
	emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]);
	emit_obj(f,&p->q2,INT);
	emit(f,"\n");
	pr(f,p);
	emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,branch->typf);
	emit(f,"%s%d:\n",labprefix,label);
      }
      branch->code=NOP;
      continue;
    }

    if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){
      int cnt=-1000,i,r=0;
      int px=0,py=0,pa=0;
      if(isconst(q2)){
	eval_const(&p->q2.val,p->typf2);
	cnt=(int)zm2l(vmax);
	if(cnt==1&&compare_objects(&p->q1,&p->z)){
	  if(c==LSHIFT)
	    emit(f,"\tlsl\t");
	  else
	    emit(f,"\t%s\t",(t&UNSIGNED)?"lsr":"asr");
	  inc_addr(&p->z,c==LSHIFT?3:0,t);
	  emit_obj(f,&p->z,t);
	  emit(f,"\n");
	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
	  emit_obj(f,&p->z,t);
	  emit(f,"\n");
	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
	  emit_obj(f,&p->z,t);
	  emit(f,"\n");
	  emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror");
	  inc_addr(&p->z,c==LSHIFT?-1:1,t);
	  emit_obj(f,&p->z,t);
	  emit(f,"\n");
	  continue;
	}
      }
      inc_addr(&p->q1,2,t);
      inc_addr(&p->z,2,t);

      if(ISRACC(q2)||(regs[acc]&&!scratchreg(acc,p))){
	emit(f,SPUSHD);
	push(2);
	pa=1;
      }

      if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
	if(regs[ix]&&!scratchreg(ix,p)) {px=1;emit(f,SPUSH("x"));push(2);}
	if(regs[iy]&&!scratchreg(iy,p)) {py=1;emit(f,SPUSH("y"));push(2);}
      }

      if(!compare_objects(&p->q1,&p->z)){
	load_reg(f,acc,&p->q1,INT);
	store_reg(f,acc,&p->z,INT);
      }
      inc_addr(&p->q1,-2,t);
      inc_addr(&p->z,-2,t);
      load_reg(f,acc,&p->q1,INT);
      if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){
	if((p->q2.flags&REG)&&p->q2.reg==ix){
	  if((p->z.flags&REG)&&p->z.reg==iy) ierror(0);
	}else
	  load_addr(f,ix,&p->z);
	if(ISRACC(q2)){
	  if(scratchreg(acc,p)&&(px+py==0)){
	    emit(f,SPULL("y"));
	    pop(2);pa=0;
	  }else
	    emit(f,"\tldy\t%d,%s\n",(px+py)*2,regnames[sp]);
	}else
	  load_reg(f,iy,&p->q2,p->typf2); /*TODO: types!=INT?? */
	if((p->q2.flags&REG)&&p->q2.reg==ix)
	  load_addr(f,ix,&p->z);
	if(c==LSHIFT)
	  emit(f,"\t%s\t%s__lsll\n",jsrinst,idprefix);
	else
	  emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,(t&UNSIGNED)?"lsrl":"asrl");
	if(py) {emit(f,SPULL("y"));pop(2);}
	if(px) {emit(f,SPULL("x"));pop(2);}
      }else{
	inc_addr(&p->z,c==LSHIFT?3:2,t);
	for(i=0;i<cnt;i++){
	  if(c==LSHIFT){
	    emit(f,"\tlsl\t");
	    emit_obj(f,&p->z,CHAR);
	    emit(f,"\n");
	    inc_addr(&p->z,-1,t);
	    emit(f,"\trol\t");
	    emit_obj(f,&p->z,CHAR);
	    emit(f,"\n");
	    inc_addr(&p->z,1,t);
	    emit(f,"\trolb\n");
	    emit(f,"\trola\n");
	  }else{
	    emit(f,"\t%s\n",(t&UNSIGNED)?"lsra":"asra");
	    emit(f,"\trorb\n");
	    emit(f,"\tror\t");
	    emit_obj(f,&p->z,CHAR);
	    emit(f,"\n");
	    inc_addr(&p->z,1,t);
	    emit(f,"\tror\t");
	    emit_obj(f,&p->z,CHAR);
	    emit(f,"\n");
	    inc_addr(&p->z,-1,t);
	  }
	}
	inc_addr(&p->z,c==LSHIFT?-3:-2,t);
	store_reg(f,acc,&p->z,INT);
      }
      if(pa) {emit(f,SPULLD);pop(2);}
      continue;
    }

    if(ISLWORD(t)&&c!=GETRETURN&&c!=SETRETURN&&c!=COMPARE&&c!=CONVERT&&c!=ADDRESS){
      if(c==PUSH&&isreg(q1)&&p->q1.reg==dx){
	if(CPU==6812){
	  emit(f,"\tpshd\n");
	  emit(f,"\tpshx\n");
	}else{
	  //emit(f,"\tpshs\ta,b,x\n");
	  emit(f,"\tpshs\tb,a\n");
	  emit(f,"\tpshs\tx\n");
	}
	push(4);
	continue;
      }
      if(c==ASSIGN&&isreg(q1)&&p->q1.reg==dx){
	inc_addr(&p->z,2,t);
	store_reg(f,ix,&p->z,INT);
	inc_addr(&p->z,-2,t);
	store_reg(f,acc,&p->z,INT);
	continue;
      }
      if(c==ASSIGN&&isreg(z)&&p->z.reg==dx){
	inc_addr(&p->q1,2,t);
	load_reg(f,ix,&p->q1,INT);
	inc_addr(&p->q1,-2,t);
	load_reg(f,acc,&p->q1,INT);
	continue;
      }
      if(c==PUSH){
	if(regs[acc]) emit(f,"\tstd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
      }else
	get_acc(f,p);
      /*TODO: acc in IC, constants */
      inc_addr(&p->q1,2,t);
      if(c==MINUS){
	if(CPU!=6812&&!optsize)
	  emit(f,"\tldd\t#0\n");
	else
	  emit(f,"\tclra\n\tclrb\n");
      }else
	load_reg(f,acc,&p->q1,INT);
      if(c==ADD||c==SUB){
	inc_addr(&p->q2,2,t);
	emit(f,"\t%s\t",c==ADD?"addd":"subd");
	emit_obj(f,&p->q2,INT);
	emit(f,"\n");
      }else if(c==ASSIGN||c==PUSH){
      }else if(c==MINUS){
	emit(f,"\tsubd\t");
	emit_obj(f,&p->q1,INT);
	emit(f,"\n");
      }else if(c==KOMPLEMENT){
	emit(f,"\tcoma\n");
	emit(f,"\tcomb\n");
      }else{
	if(c==AND)
	  emit(f,"\tandb\t");
	else if(c==OR)
	  emit(f,"\tor%sb\t",CPU==6812?"a":"");
	else if(c==XOR)
	  emit(f,"\teorb\t");
	inc_addr(&p->q2,3,t);
	emit_obj(f,&p->q2,CHAR);
	emit(f,"\n");
	if(c==AND)
	  emit(f,"\tanda\t");
	else if(c==OR)
	  emit(f,"\tor%sa\t",CPU==6812?"a":"");
	else if(c==XOR)
	  emit(f,"\teora\t");
	inc_addr(&p->q2,-1,t);
	emit_obj(f,&p->q2,CHAR);
	emit(f,"\n");
      }
      if(c==PUSH){
	if(CPU==6812)
	  emit(f,"\tpshd\n");
	else
	  emit(f,"\tpshs\tb,a\n");
	push(2);dontpop+=2;
      }else{
	inc_addr(&p->z,2,t);
	store_reg(f,acc,&p->z,INT);
      }
      inc_addr(&p->q1,-2,t);
      if(c==MINUS)
	emit(f,"\tldd\t#0\n");
      else
	load_reg(f,acc,&p->q1,INT);
      if(c==ADD)
	emit(f,"\tadcb\t");
      else if(c==SUB)
	emit(f,"\tsbcb\t");
      else if(c==AND)
	emit(f,"\tandb\t");
      else if(c==OR)
	emit(f,"\tor%sb\t",CPU==6812?"a":"");
      else if(c==XOR)
	emit(f,"\teorb\t");
      else if(c==KOMPLEMENT)
	emit(f,"\tcomb\n");
      else if(c==MINUS){
	inc_addr(&p->q1,1,t);
	emit(f,"\tsbcb\t");
	emit_obj(f,&p->q1,CHAR);
	emit(f,"\n");
      }
      if(p->q2.flags){
	inc_addr(&p->q2,-1,t);
	emit_obj(f,&p->q2,CHAR);
	emit(f,"\n");
      }
      if(c==ADD)
	emit(f,"\tadca\t");
      else if(c==SUB)
	emit(f,"\tsbca\t");
      else if(c==AND)
	emit(f,"\tanda\t");
      else if(c==OR)
	emit(f,"\tor%sa\t",CPU==6812?"a":"");
      else if(c==XOR)
	emit(f,"\teora\t");
      else if(c==KOMPLEMENT)
	emit(f,"\tcoma\n");
      else if(c==MINUS){
	inc_addr(&p->q1,-1,t);
	emit(f,"\tsbca\t");
	emit_obj(f,&p->q1,CHAR);
	emit(f,"\n");
      }
      if(p->q2.flags){
	inc_addr(&p->q2,-1,t);
	emit_obj(f,&p->q2,CHAR);
	emit(f,"\n");
      }
      if(c==PUSH){
	if(CPU==6812)
	  emit(f,"\tpshd\n");
	else
	  emit(f,"\tpshs\tb,a\n");
	push(2);dontpop+=2;
	if(regs[acc]) emit(f,"\tldd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
      }else{
	inc_addr(&p->z,-2,t);
	store_reg(f,acc,&p->z,INT);
      }
      continue;
    }

 
    if(c==COMPARE){
      int vadr;
      if(drel&&(p->q1.flags&VARADR)&&!ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
      else if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
      else if(pcrel&&(p->q1.flags&VARADR)&&ISFUNC(p->q1.v->vtyp->flags)) vadr=1;
      else if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) vadr=2;
      else vadr=0;
      if(vadr!=1&&(vadr==2||isconst(q1)||ISRACC(q2))){
	struct IC *p2;
	o=p->q1;p->q1=p->q2;p->q2=o;
	p2=p->next;
	while(p2&&p2->code==FREEREG) p2=p2->next;
	if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0);
	if(p2->code==BLT) p2->code=BGT;
	else if(p2->code==BGT) p2->code=BLT;
	else if(p2->code==BLE) p2->code=BGE;
	else if(p2->code==BGE) p2->code=BLE;
      }
      /* case with two relative addresses */
      if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
      if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1;
    }
#if 0
    /* TODO: fix cc */
    if(c==COMPARE&&isconst(q2)){
      eval_const(&p->q2.val,t);
      if(ISNULL()){
	if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){
	  lastcomp=t;continue;
	}
      }
    }
#endif

    if(!short_add)
      switch_IC(p);

    if(c==CONVERT){
      int to=p->typf2&NU;
      if(to==INT) to=SHORT;
      if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT);
      if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG);
      if((t&NU)==INT) t=SHORT;
      if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT);
      if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG);
      /*if((t&NQ)>=LONG||(to&NQ)>=LONG) ierror(0);*/
      if((to&NQ)<=LONG&&(t&NQ)<=LONG){
	if((to&NQ)<(t&NQ)){
	  if(ISLWORD(t)){
	    get_acc(f,p);
	    load_reg(f,acc,&p->q1,to);
	    if((to&NU)==CHAR)
	      emit(f,SEX);
	    else if((to&NU)==(UNSIGNED|CHAR))
	      emit(f,"\tclra\n");
	    inc_addr(&p->z,2,t);
	    store_reg(f,acc,&p->z,INT);
	    inc_addr(&p->z,-2,t);
	    if(to&UNSIGNED){
	      emit(f,"\tclra\n\tclrb\n");
	    }else{
	      if(CPU==6812)
		emit(f,"\texg\ta,b\n");
	      else
		emit(f,"\ttfr\ta,b\n");
	      emit(f,SEX);
	      emit(f,"\ttfr\ta,b\n");
	    }
	    store_reg(f,acc,&p->z,INT);
	    continue;
	  }
	  /*emit(f,"#conv RACC=%d, regs=%d scratch=%d\n",(int)ISRACC(z),regs[acc],scratchreg(acc,p));*/
	  if(!ISRACC(z))
	    get_acc(f,p);
	  load_reg(f,acc,&p->q1,to);
	  if(to&UNSIGNED)
	    emit(f,"\tclra\n");
	  else
	    emit(f,SEX);
	  store_reg(f,acc,&p->z,t);
	  cc=&p->z;cc_t=t;
	  continue;
	}else if((to&NQ)>(t&NQ)){
	  if(!ISRACC(z)&&!ISRACC(q1))
	    get_acc(f,p);
	  if(ISLWORD(to))
	    inc_addr(&p->q1,2,to);
	  load_reg(f,acc,&p->q1,to);
	  store_reg(f,acc,&p->z,t);
	  continue;
	}else{
	  c=ASSIGN;
	  p->q2.val.vmax=sizetab[t&NQ];
	}
      }
    }
    if(c==KOMPLEMENT){
      cc=0;
      if(compare_objects(&p->q1,&p->z)&&!isreg(q1)&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&(!p->q1.am||p->q1.am->flags!=ACC_IND)){
	emit(f,"\tcom\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	if(ISHWORD(t)){
	  mobj=p->z;
	  inc_addr(&mobj,1,t);
	  emit(f,"\tcom\t");
	  emit_obj(f,&mobj,INT);
	  emit(f,"\n");
	}
	continue;
      }
      if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
	get_acc(f,p);
      load_reg(f,acc,&p->q1,t);
      emit(f,"\tcoma\n\tcomb\n");
      store_reg(f,acc,&p->z,t);
      continue;
    }
    if(c==MINUS){
      if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
	get_acc(f,p);
      if(isreg(q1)){
	load_reg(f,acc,&p->q1,t);
	emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
      }else{
	if(CPU!=6812&&!optsize)
	  emit(f,"\tldd\t#0\n");
	else
	  emit(f,"\tclra\n\tclrb\n");
	emit(f,"\tsubd\t");
	emit_obj(f,&p->q1,t);
	emit(f,"\n");
      }
      cc=&p->z;cc_t=t;
      store_reg(f,acc,&p->z,t);
      continue;
    }
    if(c==SETRETURN){
      if(isreg(q1)&&p->q1.reg==p->z.reg) continue;
      if(p->z.reg){
	if(ISLWORD(t)){
	  inc_addr(&p->q1,0,t);
	  load_reg(f,ix,&p->q1,INT);
	  BSET(regs_modified,ix);
	  inc_addr(&p->q1,2,t);
	}
	load_reg(f,acc,&p->q1,t);
	BSET(regs_modified,acc);

      }
      continue;
    }
    if(c==GETRETURN){
      if(isreg(z)&&p->z.reg==p->q1.reg) continue;
      if(p->q1.reg){
	if(ISLWORD(t)){
	  store_reg(f,ix,&p->z,INT);
	  BSET(regs_modified,ix);
	  inc_addr(&p->z,2,t);
	}
	store_reg(f,acc,&p->z,(t&NQ)==CHAR?t:INT);
      }
      continue;
    }
    if(c==CALL){
      int reg,jmp=0;
      cc=0;
      if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS;
      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
	long of=va_offset(v)+loff+2;
	emit(f,"\ttfr\t%s,d\n",regnames[sp]);
	if(of) emit(f,"\taddd\t#%ld\n",of);
	continue;
      }
      if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){
	emit_inline_asm(f,p->q1.v->fi->inline_asm);
	jmp=1;
      }else{
	if(stackoffset==0&&!have_frame&&!strcmp(ret,"rts")){
	  struct IC *p2;
	  jmp=1;
	  for(p2=p->next;p2;p2=p2->next){
	    if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL){
	      jmp=0;break;
	    }
	  }
	}
	if(p->q1.flags&DREFOBJ){
	  /*FIXME: test this*/
	  if(jmp)
	    emit(f,"\tjmp\t");
	  else
	    emit(f,"\tjsr\t");
	  if (p->q1.v->tattr&FAR)
	  	emit(f,"\tfar\t");
	  emit_obj(f,&p->q1,t);
	  emit(f,"\n");
	}else{
	  if(jmp){
	    emit(f,"\t%s\t",jmpinst); /*emit(f,"\tbra\t");*/
	    /*if(!need_return) ret=0;*/ /*TODO: works with optimizer? */
	  }else{
	    emit(f,"\t%s\t",jsrinst); /*emit(f,"\tbsr\t");*/
	  }
	  if (p->q1.v->tattr&FAR)
	  	emit(f,"\tfar\t");
	  if(pcrel){
	    pcrel=0;
	    emit_obj(f,&p->q1,t);
	    pcrel=1;
	  }else
	    emit_obj(f,&p->q1,t);
	  emit(f,"\n");
	}
      }
      if(stack_valid){
        int i;
        if(p->call_cnt<=0){
          err_ic=p;if(f) error(320);
          stack_valid=0;
        }
        for(i=0;stack_valid&&i<p->call_cnt;i++){
          if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){
	    /*FIXME: size of return addr depends on mode */
	    if(!jmp) push(2);
	    callee_push(zm2l(p->call_list[i].v->fi->stack1));
	    if(!jmp) pop(2);
          }else{
            err_ic=p;if(f) error(317,p->call_list[i].v->identifier);
            stack_valid=0;
          }
        }
      }
      if(!zmeqto(l2zm(0L),p->q2.val.vmax)){
	notpopped+=zm2l(p->q2.val.vmax);
	dontpop-=zm2l(p->q2.val.vmax);
	if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){
	  /*  Entfernen der Parameter verzoegern  */
	}else{
	  gen_pop(f,zm2l(p->q2.val.vmax));
	  notpopped-=zm2l(p->q2.val.vmax);
	}
      }
      continue;
    }
    if(c==ASSIGN||c==PUSH){
      if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
      if(!zmleq(p->q2.val.vmax,l2zm(2L))){
	unsigned long size;int qr=0,zr=0,cr=0,px=0,py=0,pu=0,pd=0,lq=0,lz=0;
	size=zm2l(p->q2.val.vmax);
	if(c==ASSIGN){
	  if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->z.reg)){
	    zr=p->z.reg;lz=1;
	  }
	}
	if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->q1.reg)&&p->q1.reg!=zr){
	  qr=p->q1.reg;lq=1;
	}
	if(!qr){
	  if(zr==ix) qr=iy;
	  else if(zr==iy||zr==iu) qr=ix;
	  else{qr=ix;zr=iy;}
	}else if(!zr){
	  if(qr==ix) zr=iy; else zr=ix;
	}
	if(CPU!=6812){
	  if(qr!=iu&&zr!=iu) cr=iu;
	  if(qr!=ix&&zr!=ix) cr=ix;
	  if(qr!=iy&&zr!=iy) cr=iy;
	  if(!cr) ierror(0);
	}
	if(c==PUSH){
	  emit(f,"\tleas\t%ld,%s\n",SGN16(-size),regnames[sp]);
	  push(size);
	}
	if(CPU!=6812&&(drel||!regused[iu]||(regs[iu]&&!scratchreg(iu,p)))){
	  if(c==PUSH)
	    emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
	  else{
	    emit(f,SPUSH("u"));
	    push(2);
	  }
	  pu=1;
	}
	if(!regused[iy]||(regs[iy]&&!scratchreg(iy,p))){
	  if(c==PUSH)
	    emit(f,"\tsty\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
	  else{
	    emit(f,SPUSH("y"));
	    push(2);
	  }
	  py=1;
	}
	if(regs[ix]&&!scratchreg(ix,p)){
	  if(c==PUSH)
	    emit(f,"\tstx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
	  else{
	    emit(f,SPUSH("x"));
	    push(2);
	  }
	  px=1;
	}
	if(!lq) load_addr(f,qr,&p->q1);
	if(c==PUSH)
	  emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[zr]);
	else
	  if(!lz) load_addr(f,zr,&p->z);
	if(size<=6||(size<=16&&!optsize)){
	  if(CPU!=6812){
	    if(!scratchreg(acc,p)){
	      if(c==PUSH)
		emit(f,"\tstd\t%ld,%s\n",loff-roff-6-stackoffset,regnames[sp]);
	      else{
		emit(f,SPUSHD);
		push(2);
	      }
	      pd=2;
	    }
	  }
	  while(size>2){
	    if(CPU==6812)
	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
	    else
	      emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
	    size-=2;
	  }
	  if(CPU==6812)
	    emit(f,"\tmov%c\t0,%s,0,%s\n",size==2?'w':'b',regnames[qr],regnames[zr]);
	  else
	    emit(f,"\tld%c\t,%s\n\tst%c\t,%s\n",size==2?'d':'b',regnames[qr],size==2?'d':'b',regnames[zr]);
	}else{
	  int l=++label,cnt=(int)(optsize?size:size/8);
	  if(regs[acc]&&!scratchreg(acc,p)){
	    if(c==PUSH)
	      emit(f,"\tst%c\t%ld,%s\n",(CPU!=6812&&cnt<=bytemask)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
	    else{
	      if(CPU!=6812&&cnt<=bytemask){
		emit(f,SPUSH("b"));
		push(1);
	      }else{
		emit(f,SPUSHD);
		push(2);
	      }
	    }
	    pd=(CPU!=6812&&cnt<=bytemask)?1:2;
	  }
	  if(CPU!=6812&&cnt<=bytemask)
	    emit(f,"\tldb\t#%lu\n",cnt);
	  else
	    emit(f,"\tldd\t#%lu\n",cnt);
	  cc=0;
#if 0
	  if(CPU!=6812&&((!regsa[iu]&&regs[iu])||drel)){
	    if(c==PUSH){
	      emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]); 
	    }else{
	      emit(f,SPUSH("u"));push(2);
	    }
	  }
#endif
	  emit(f,"%s%d:\n",labprefix,l);
	  if(CPU==6812){
	    if(optsize){
	      emit(f,"\tmovb\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
	    }else{
	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
	      size=size&7;
	    }
	    emit(f,"\tdbne\td,%s%d\n",labprefix,l);
	  }else{
	    if(optsize){
	      emit(f,"\tld%s\t,%s+\n\tst%s\t,%s+\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
	      size&=1;
	    }else{
	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
	      emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]);
	      size&=7;
	    }
	    if(cnt<=bytemask)
	      emit(f,"\tdecb\n");
	    else
	      emit(f,"\tsubd\t#1\n");
	    emit(f,"\tbne\t%s%d\n",labprefix,l);
	  }
#if 0
	  if(CPU!=6812&&((!regsa[iu]&&regs[iu])||drel)){
	    if(c==PUSH){
	      emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
	    }else{
	      emit(f,SPULL("u"));pop(2);
	    }
	  }
#endif
	  while(size>=2){
	    if(CPU==6812)
	      emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]);
	    else
	      emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]);
	    size-=2;
	  }
	  if(size){
	    if(CPU==6812)
	      emit(f,"\tmovb\t0,%s,0,%s\n",regnames[qr],regnames[zr]);
	    else
	      emit(f,"\tldb\t,%s\n\tstb\t,%s\n",regnames[qr],regnames[zr]);
	  }
	}
	if(pd){
	  if(c==PUSH) 
	    emit(f,"\tld%c\t%ld,%s\n",(pd==1)?'b':'d',loff-roff-6-stackoffset,regnames[sp]);
	  else{
	    if(pd==1){
	      emit(f,SPULL("b"));
	      pop(1);
	    }else{
	      emit(f,SPULLD);
	      pop(2);
	    }
	  }
	}
	if(px){
	  if(c==PUSH) 
	    emit(f,"\tldx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]);
	  else{
	    emit(f,SPULL("x"));
	    pop(2);
	  }
	}
	if(py){
	  if(c==PUSH) 
	    emit(f,"\tldy\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]);
	  else{
	    emit(f,SPULL("y"));
	    pop(2);
	  }
	}
	if(pu){
	  if(c==PUSH) 
	    emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]);
	  else{
	    emit(f,SPULL("u"));
	    pop(2);
	  }
	}
	continue;
      }
      if(!ISSCALAR(t)) t=zmeqto(p->q2.val.vmax,l2zm(1L))?CHAR:INT;
      if((t&NQ)==CHAR&&!zmeqto(p->q2.val.vmax,l2zm(1L))) t=INT;	
      if(mov_op(&p->q1)&&(c==PUSH||mov_op(&p->z))){
	emit(f,"\tmov%c\t",ISHWORD(t)?'w':'b');
	emit_obj(f,&p->q1,t);
	if(c==ASSIGN){
	  emit(f,",");
	  emit_obj(f,&p->z,t);
	  emit(f,"\n");
	}else{
	  emit(f,",%d,-%s\n",ISHWORD(t)?2:1,regnames[sp]);
	  push(ISHWORD(t)?2:1);
	}
	continue;
      }
      if(((regs[acc]&&regs[ix])||(t&NQ)==CHAR)&&(p->q1.flags&KONST)&&!isreg(z)){
	eval_const(&p->q1.val,t);
	if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&((p->z.flags&(REG|DREFOBJ))!=DREFOBJ||(t&NQ)==CHAR)&&(!p->z.am||p->z.am->flags!=ACC_IND||(t&NQ)==CHAR)){
	  emit(f,"\tclr\t");
	  if(c==ASSIGN){
	    emit_obj(f,&p->z,t);emit(f,"\n");
	  }else{
	    emit(f,CPU==6812?"1,-sp\n":",-s\n");
	    push(1);
	  }
	  if(!ISHWORD(t)) continue;
	  emit(f,"\tclr\t");
	  if(c==ASSIGN){
	    mobj=p->z;
	    inc_addr(&mobj,1,t);
	    emit_obj(f,&mobj,t);emit(f,"\n");
	  }else{
	    emit(f,CPU==6812?"1,-sp\n":",-s\n");
	    push(1);
	  }
	  continue;
	}

      }
      if(c==PUSH){
	int st=0;
	if(isreg(q1)){
	  reg=p->q1.reg;
	}else{
	  if((t&NQ)==CHAR||!regs[acc]||scratchreg(acc,p)) reg=acc;
	  else if(!regs[ix]||scratchreg(ix,p)) reg=ix;
	  else if(regused[iy]&&(!regs[iy]||scratchreg(iy,p))) reg=iy;
	  else if(regused[iu]&&!drel&&CPU!=6812&&(!regs[iu]||scratchreg(iu,p))) reg=iu;
	  else reg=acc;
	  if(regs[reg]&&!scratchreg(reg,p)){
	    st=1;
	    emit(f,"\tst%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
	  }
	  load_reg(f,reg,&p->q1,t);
	}
	if((t&NQ)==CHAR)
	  emit(f,SPUSH("b"));
	else if(reg==ix)
	  emit(f,SPUSH("x"));
	else if(reg==iy)
	  emit(f,SPUSH("y"));
	else if(reg==iu)
	  emit(f,SPUSH("u"));
	else
	  emit(f,SPUSHD);
	push(zm2l(p->q2.val.vmax));
	if(st)
	  emit(f,"\tld%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]);
	continue;
      }
      if(c==ASSIGN){
	if(isreg(q1)&&isreg(z)){
	  if(p->q1.reg!=p->z.reg)
	    emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[p->z.reg]);
	}else if(isreg(q1)){
	  store_reg(f,p->q1.reg,&p->z,t);
	}else if(isreg(z)){
	  load_reg(f,p->z.reg,&p->q1,t);
	}else{
	  reg=get_reg(f,p,t);
	  load_reg(f,reg,&p->q1,t);
	  store_reg(f,reg,&p->z,t);
	}
	continue;
      }
      ierror(0);
    }
    if(c==ADDRESS){
      int px=0;
      if(isreg(z)){
	reg=p->z.reg;
      }else if(!regs[ix]){
	reg=ix;
      }else if(!regs[iy]){
	reg=iy;
      }else{
	/*FIXME: test if x used in q1 */
	px=1;
	emit(f,SPUSH("x"));
	reg=ix;
	push(2);
      }
      load_addr(f,reg,&p->q1);
      if(!(p->z.flags&REG)||p->z.reg!=reg)
	store_reg(f,reg,&p->z,p->typf2);
      if(px){
	emit(f,SPULL("x"));
	pop(2);
      }
      continue;
    }

    if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
      long ln;
      eval_const(&p->q2.val,t);
      if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
	if((ln=pof2(vumax))&&ln<5){
	  if(c==MOD){
	    vmax=zmsub(vmax,l2zm(1L));
	    c=p->code=c=AND;
	  }else{
	    vmax=l2zm(ln-1);
	    if(c==DIV) p->code=c=RSHIFT; else p->code=c=LSHIFT;
	  }
	  c=p->code;
	  gval.vmax=vmax;
	  eval_const(&gval,MAXINT);
	  if(c==AND){
	    insert_const(&p->q2.val,t);
	  }else{
	    insert_const(&p->q2.val,t);
	    p->typf2=INT;
	  }
	}
      }
    }
    if(c==MOD||c==DIV){
      ierror(0);
      continue;
    }


    if((c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(p->q1.flags&(REG|DREFOBJ))!=REG&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&!p->q1.am&&!p->z.am&&compare_objects(&p->q1,&p->z)){
      eval_const(&p->q2.val,t);
      if(c==SUB) vmax=zmsub(Z0,vmax);
      if((t&NQ)==CHAR&&zmeqto(vmax,Z1)){
	emit(f,"\tinc\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	continue;
      }else if((t&NQ)==CHAR&&zmeqto(vmax,l2zm(-1L))){
	emit(f,"\tdec\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	continue;
      }else if(((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(1L))){
	inc_addr(&p->z,1,t);
	emit(f,"\tinc\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	emit(f,"\tbne\t%s%d\n",labprefix,++label);
	inc_addr(&p->z,-1,t);
	emit(f,"\tinc\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	emit(f,"%s%d:\n",labprefix,label);
	continue;
      }else if(regs[acc]&&((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(-1L))){
	inc_addr(&p->z,1,t);
	emit(f,"\ttst\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	emit(f,"\tbne\t%s%d\n",labprefix,++label);
	inc_addr(&p->z,-1,t);
	emit(f,"\tdec\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	emit(f,"%s%d:\n",labprefix,label);
	inc_addr(&p->z,1,t);
	emit(f,"\tdec\t");
	emit_obj(f,&p->z,t);
	emit(f,"\n");
	continue;
      }
    }

    if((c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP||c==SUBPFP||(c>=OR&&c<=AND)||c==COMPARE){
      char *s;
      /*FIXME: nicht immer besser*/
      if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){
	eval_const(&p->q2.val,t);
	if(zm2l(vmax)==1){
	  p->code=c=ADD;
	  p->q2=p->q1;
	}
      }
      if((c==ADD||c==ADDI2P||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&!isreg(q1)&&!short_add){
	o=p->q1;p->q1=p->q2;p->q2=o;
      }
      if((c==ADD||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&p->q2.reg==acc&&!short_add){
	o=p->q1;p->q1=p->q2;p->q2=o;
      }
      if(c==MULT||c==MOD){
	if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
	  get_acc(f,p);
	reg=acc;
	/*FIXME: y bzw. x-Register*/
      }else if(c==LSHIFT||c==RSHIFT||c==AND||c==OR||c==XOR){
	if((!isreg(z)||p->z.reg!=acc)&&regs[acc]&&!scratchreg(acc,p))
	  get_acc(f,p);
	reg=acc;
      }else if(c==DIV){
	reg=ix;
	ierror(0);
      }else if(isreg(z)){
	reg=p->z.reg;
      }else if(isreg(q1)&&(c==COMPARE||scratchreg(p->q1.reg,p))){
	reg=p->q1.reg;
      }else{
	if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==COMPARE){
	  if(ISRACC(q2))
	    reg=acc;
	  else
	    reg=get_reg(f,p,t);
	}else{
	  get_acc(f,p);
	  reg=acc;
	}
      }
      if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){
	int opdone=0;
	if(isreg(q1)){
	  if(ISIDX(reg)&&ISIDX(p->q1.reg)&&isconst(q2)){
	    eval_const(&p->q2.val,short_add?short_add:q2typ(p));
	    if(CPU==6812&&p->q1.reg==reg&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){
	      emit(f,"\t%s%s\n",c==SUB?"de":"in",regnames[reg]);
	      /*FIXME: condition-codes for bne/beq could be used */
	    }else{
	      emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],c==SUB?SGN16(-zm2l(vmax)):SGN16(zm2l(vmax)),regnames[p->q1.reg]);
	    }
	    opdone=1;
	  }else	if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISIDX(p->q1.reg)&&ISRACC(q2)){
	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NQ)==CHAR||(short_add&NQ)==CHAR)?"b":"d",regnames[p->q1.reg]);
	    opdone=1;
	  }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISACC(p->q1.reg)&&ISRIDX(q2)){
	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[p->q2.reg]);
	    opdone=1;
	  }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&!short_add){
	    load_reg(f,reg,&p->q2,t);
	    emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
	    opdone=1;
	  }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&(short_add&NU)==(UNSIGNED|CHAR)&&scratchreg(acc,p)){
	    emit(f,"\taddb\t");
	    emit_obj(f,&p->q2,short_add);
	    emit(f,"\n");
	    emit(f,"\tadca\t#0\n");
	    emit(f,"\ttfr\td,y\n");
	    opdone=1;
	  }else if((c==ADD||c==ADDI2P)&&ISACC(p->q1.reg)&&ISRACC(z)&&isreg(q2)&&ISIDX(p->q2.reg)){
	    if(!scratchreg(p->q2.reg,p)) emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
	    emit(f,"\tlea%s\t%s,%s\n",regnames[p->q2.reg],regnames[acc],regnames[p->q2.reg]);
	    emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]);
	    opdone=1;
	  }else	if(p->q1.reg!=reg){
	    if(c==ADD||c==ADDI2P||!ISRACC(q2))
	      emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[reg]);
	  }
	}else if(short_add&&c==SUB&&reg==acc&&!(short_add&UNSIGNED)){
	  load_reg(f,reg,&p->q2,short_add);
	  emit(f,"\tclra\n");
	  emit(f,"\tnegb\n");
	  emit(f,"\tsbca\t#0\n");
	  emit(f,"\taddd\t");
	  emit_obj(f,&p->q1,t);
	  emit(f,"\n");
	  store_reg(f,reg,&p->z,ztyp(p));
	  continue;
	}else if(short_add&&c==ADD&&reg==acc){
	  load_reg(f,reg,&p->q2,short_add);
	  if(short_add&UNSIGNED)
	    emit(f,"\tclra\n");
	  else
	    emit(f,SEX);
	  emit(f,"\taddd\t");
	  emit_obj(f,&p->q1,t);
	  emit(f,"\n");
	  store_reg(f,reg,&p->z,ztyp(p));
	  continue;
	}else{
	  if(!ISRACC(q2))
	    load_reg(f,reg,&p->q1,q1typ(p));
	}
	if(!opdone){
	  if(reg==acc){
	    if(ISRACC(q2)){
	      if(!ISRACC(z)) get_acc(f,p);
	      if(c==ADD||c==ADDI2P){
		if(short_add){
		  if(short_add&UNSIGNED)
		    emit(f,"\tclra\n");
		  else
		    emit(f,SEX);
		  emit(f,"\taddd\t");
		  emit_obj(f,&p->q1,t);
		  emit(f,"\n");
		}else{
		  if(CPU==6812)
		    emit(f,"\tasld\n"); /* only cases with q1=q2=acc should remain */
		  else{
		    emit(f,"\taslb\n");
		    if((t&NQ)!=CHAR)
		      emit(f,"\trola\n");
		  }
		}
	      }else{
		if(short_add){
		  if(short_add&UNSIGNED)
		    emit(f,"\tld%sa\t#255\n",(CPU==6812)?"a":"");
		  else{
		    emit(f,SEX);
		    emit(f,"\tnega\n");
		  }
		  emit(f,"\tnegb\n\tsbca\t#0\n");
		}else if((t&NQ)!=CHAR){
		  emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
		}else{
		  emit(f,"\tnegb\n");
		}
		
		if(ISRIDX(q1)){
		  emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[p->q1.reg]);
		  emit(f,"\taddd\t%s\n",CPU==6812?"1,s+":",s++");
		}else{
		  emit(f,"\taddd\t");
		  emit_obj(f,&p->q1,t);
		  emit(f,"\n");
		}
	      }
	    }else{
	      if(ISRIDX(q2)){
		if(CPU==6812)
		  emit(f,"\tpsh%s\n",regnames[p->q2.reg]);
		else
		  emit(f,"\tpshs\t%s\n",regnames[p->q2.reg]);
		push(2);pop(2);
		if(CPU==6812)
		  emit(f,"\t%sd\t2,%s+\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
		else
		  emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
	      }else{
		emit(f,"\t%s%s\t",(c==ADD||c==ADDI2P)?"add":"sub",(short_add||(t&NQ)==CHAR)?"b":"d");
		emit_obj(f,&p->q2,short_add?short_add:t);emit(f,"\n");
		if(short_add){
		  if(short_add&UNSIGNED)
		    emit(f,"\t%s\t#0\n",c==ADD?"adca":"sbca");
		  else
		    ierror(0);
		}
		if(drel&&(p->q2.flags&VARADR)){
		  if(CPU==6812) ierror(0);
		  emit(f,"\tpshs\t%s\n",regnames[iu]);push(2);
		  emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]);
		  pop(2);
		}
	      }
	    }
	    cc=&p->z;cc_t=t;
	  }else{
	    if(isconst(q2)){
	      long l;
	      eval_const(&p->q2.val,short_add?short_add:t);
	      l=zm2l(vmax);
	      if(c==SUB) l=-l;
	      /*FIXME: condition-codes for bne/beq could be used */
	      if(l==1&&reg==ix&&CPU==6812){
		emit(f,"\tinx\n");
	      }else if(l==1&&reg==iy&&CPU==6812){
		emit(f,"\tiny\n");
	      }else if(l==-1&&reg==ix&&CPU==6812){
		emit(f,"\tdex\n");
	      }else if(l==-1&&reg==iy&&CPU==6812){
		emit(f,"\tdey\n");
	      }else{
		emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],SGN16(l),regnames[reg]);
	      }
	    }else{
	      if(c!=ADD&&c!=ADDI2P){
		if(!ISRACC(q2)){
		  if(!scratchreg(acc,p))
		    get_acc(f,p);
		  load_reg(f,acc,&p->q2,t);
		  if((t&NQ)!=CHAR){
		    emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
		  }else{
		    emit(f,"\tnegb\n");
		  }
		  /*load_reg(f,reg,&p->q1,t);*/
		}else{
		  get_acc(f,p);
		  load_reg(f,reg,&p->q1,t);
		  if((t&NQ)==CHAR)
		    emit(f,"\tnegb\n");
		  else
		    emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n");
		}  
	      }else if(!ISRACC(q2)){
		get_acc(f,p);
		if(short_add){
		  load_reg(f,acc,&p->q2,short_add);
		  if(short_add&UNSIGNED){
		    if(reg==ix){
		      emit(f,"\tabx\n");
		      store_reg(f,reg,&p->z,ztyp(p));
		      continue;
		    }else{
		      emit(f,"\tclra\n");
		    }
		  }else
		    t=CHAR;
		}else
		  load_reg(f,acc,&p->q2,t);
	      }else{
		load_reg(f,reg,&p->q1,t);
		if(short_add&UNSIGNED)
		  emit(f,"\tclra\n");
		emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NU)==CHAR||(short_add&NU)==CHAR)?"b":"d",regnames[reg]);
		store_reg(f,reg,&p->z,ztyp(p));
		continue;
	      }
	      emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]);
	    }
	  }
	}
	store_reg(f,reg,&p->z,ztyp(p));
	continue;
      }
      if(c!=LSHIFT&&c!=RSHIFT)
	load_reg(f,reg,&p->q1,t);
      if(c==MULT){
	if(CPU==6812){
	  int py=0;
	  if(reg!=acc) ierror(reg);
	  if(!ISRY(q2)&&regs[iy]){
	    emit(f,"\tpshy\n");
	    push(2);
	    py=1;
	  }
	  load_reg(f,iy,&p->q2,t);
	  emit(f,"\temul\n");
	  if(py){
	    emit(f,SPULL("y"));
	    pop(2);
	  }
	  store_reg(f,acc,&p->z,t);
	  continue;
	}else
	  ierror(0);
      }
      if(c==LSHIFT||c==RSHIFT){
	if(isconst(q2)){
	  int l,oldl;
	  load_reg(f,acc,&p->q1,t);
	  eval_const(&p->q2.val,t);
	  oldl=l=zm2l(vmax);
	  if(l>=24){
	    if(CPU!=6812&&!optsize)
	      emit(f,"\tldd\t#0\n");
	    else
	      emit(f,"\tclra\n\tclrb\n");
	    l=0;
	  }
	  if(l>=8){
	    if(c==LSHIFT)
	      emit(f,"\t%s\n\tclrb\n",(CPU==6812)?"tba":"tfr\tb,a");
	    else{
	      if(t&UNSIGNED)
		emit(f,"\ttfr\ta,b\n\tclra\n");
	      else{
		emit(f,"\ttfr\ta,b\n");
		emit(f,SEX);
	      }
	    }
	    l-=8;
	  }
	  while(l--){
	    if(c==RSHIFT){
	      if(t&UNSIGNED){
		if((t&NQ)==CHAR)
		  emit(f,"\tlsrb\n");
		else
		  emit(f,CPU==6809?"\tlsra\n\trorb\n":"\tlsrd\n");
	      }else{
		if(oldl>12||(t&NQ)==CHAR)
		  emit(f,"\tasrb\n");
		else
		  emit(f,"\tasra\n\trorb\n");
	      }
	    }else{
	      if((t&NQ)==CHAR)
		emit(f,"\taslb\n");
	      else
		emit(f,CPU==6809?"\taslb\n\trola\n":"\tasld\n");
	    }
	  }
	}else{
	  int px;char *s;
	  if(regs[ix]&&!scratchreg(ix,p)&&(!isreg(z)||p->z.reg!=ix)){
	    emit(f,SPUSH("x"));
	    push(2);px=1;
	  }else
	    px=0;
	  if((p->typf2&NQ)==CHAR){
	    load_reg(f,acc,&p->q2,p->typf2);
	    emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX);
	    emit(f,"\ttfr\td,x\n");
	  }else
	    load_reg(f,ix,&p->q2,t);
	  load_reg(f,acc,&p->q1,p->typf);
	  if((t&NQ)==CHAR)
	    emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX);
	  if(c==LSHIFT) s="lsl";
	  else if(t&UNSIGNED) s="lsr";
	  else s="asr";
	  emit(f,"\t.global\t%s__%s\n",idprefix,s);
	  emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,s);
	  if(px){
	    emit(f,SPULL("x"));
	    /*emit(f,"\tpul%s\n",regnames[ix]);*/
	    pop(2);
	  }
	}
	cc=0;
	store_reg(f,acc,&p->z,t);
	continue;
      }
      if(c>=OR&&c<=AND){
	s=logicals[c-OR];
	if(p->q2.am&&p->q2.am->flags==ACC_IND){
	  mobj=p->q1;p->q1=p->q2;p->q2=mobj;
	}
	if(p->q2.flags&KONST){
	  unsigned long l,h;
	  eval_const(&p->q2.val,t);
	  l=zum2ul(vumax);
	  if((t&NQ)!=CHAR){
	    h=(l>>bitsperbyte)&bytemask;
	    if(c==AND&&h==0)
	      emit(f,"\tclra\n");
	    else if(c==XOR&&h==bytemask)
	      emit(f,"\tcoma\n");
	    else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0))
	      emit(f,"\t%sa\t#%lu\n",s,h);
	  }
	  h=l&bytemask;
	  if(c==AND&&h==0)
	    emit(f,"\tclrb\n");
	  else if(c==XOR&&h==bytemask)
	    emit(f,"\tcomb\n");
	  else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0))
	    emit(f,"\t%sb\t#%lu\n",s,h);
	}else{
	  if(isreg(q2)){
	    if(p->q2.reg==acc){
	      if(c==XOR){
		emit(f,"\tclrb\n");
		if((t&NQ)!=CHAR) emit(f,"\tclra\n");
	      }
	    }else{
	      if((t&NQ)==CHAR){
		emit(f,SPUSH("a"));
		push(1);
		emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
		pop(1);
	      }else{
		emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
		push(2);
		emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
		emit(f,"\t%sb\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]);
		pop(2);
	      }
	    }
	  }else if((p->q2.flags&(REG|DREFOBJ))==DREFOBJ&&(t&NQ)!=CHAR){
	    int xr=0;
	    if(!regs[ix]) xr=ix;
	    else if(!regs[iy]) xr=iy;
	    else{
	      xr=ix;
	      emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[xr]);
	      push(2);

	    }
	    BSET(regs_modified,xr);
	    load_addr(f,xr,&p->q2);
	    if((t&NQ)==CHAR)
	      emit(f,"\t%sb\t0,%s\n",s,regnames[xr]);
	    else{
	      emit(f,"\t%sa\t0,%s\n",s,regnames[xr]);
	      emit(f,"\t%sb\t1,%s\n",s,regnames[xr]);
	    }
	    if(regs[ix]&&xr==ix){
	      emit(f,SPULL("x"));
	      pop(2);
	    }
	  }else{
	    emit(f,"\t%sb\t",s);
	    if((t&NQ)!=CHAR) inc_addr(&p->q2,1,t);
	    emit_obj(f,&p->q2,t);
	    emit(f,"\n");
	    if((t&NQ)!=CHAR){
	      inc_addr(&p->q2,-1,t);
	      emit(f,"\t%sa\t",s);
	      emit_obj(f,&p->q2,t);
	      emit(f,"\n");
	    }
	  }
	}
	cc=0;
	store_reg(f,reg,&p->z,t);
	continue;
      }else if(c==COMPARE){
	lastcomp=t;
	if(isreg(q2)){
	  emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]);
	  push(2);
	}
	if(reg==acc){
	  if((t&NQ)==CHAR)
	    emit(f,"\tcmpb\t");
	  else
	    emit(f,SCMP("d"));
	}else if(reg==ix){
	  emit(f,SCMP("x"));
	}else if(reg==iy){
	  emit(f,SCMP("y"));
	}else if(reg==iu){
	  emit(f,SCMP("u"));
	}else
	  ierror(0);
	if(isreg(q2)){
	  if(CPU==6812)
	    emit(f,"2,%s+\n",regnames[sp]);
	  else
	    emit(f,",%s++\n",regnames[sp]);
	  pop(2);
	}else{
	  emit_obj(f,&p->q2,t);emit(f,"\n");
	}
	continue;
      }
      ierror(0);
    }
    pric2(stdout,p);
    ierror(0);
  }
  if(notpopped){
    gen_pop(f,notpopped);
    notpopped=0;
  }
  function_bottom(f,v,loff);
  if(debug_info){
    emit(f,"%s%d:\n",labprefix,++label);
    dwarf2_function(f,v,label);
    if(f) section=-1;
  }     
}

int shortcut(int c,int t)
{
  if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1;
  if((c==LSHIFT||c==RSHIFT)&&ISCHWORD(t&NQ)) return 1;
  return 0;
}

void cleanup_cg(FILE *f)
{
  struct fpconstlist *p;
  unsigned char *ip;
  if(f&&stack_check)
    emit(f,"\t.global\t%s__stack_check\n",idprefix);
  while(p=firstfpc){
    if(f){
      if(section!=RODATA){
	emit(f,rodataname);if(f) section=RODATA;
      }
      emit(f,"%s%d\n\t%s\t",labprefix,p->label,dct[LONG]);
      ip=(unsigned char *)&p->val.vdouble;
      emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]);
      if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){
	emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
      }
      emit(f,"\n");
    }
    firstfpc=p->next;
    free(p);
  }
}

int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt)
{
  if(p->gpr) return 0;
  if(ISSCALAR(t->flags)&&!ISFLOAT(t->flags)&&!ISLWORD(t->flags)){
    p->gpr=1;
    return acc;
  }
  return 0;
}

void insert_const(union atyps *p,int t)
/*  Traegt Konstante in entprechendes Feld ein.       */
{
  if(!p) ierror(0);
  t&=NU;
  if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;}
  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|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));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==NPOINTER) {p->vuint=vuint;return;}
  if(t==FPOINTER||t==HPOINTER) {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>=BIT&&f<=LLONG)){
    if(!(t&UNSIGNED)){
      if(f==BIT){
	if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L);
      }else 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==BIT){
	if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL);
      }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)){
      if(f==NPOINTER)
	vumax=zui2zum(p->vuint);
      else
	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);
}
void printval(FILE *f,union atyps *p,int t)
/*  Gibt atyps aus.                                     */
{
  t&=NU;
  if(t==BIT){vmax=zc2zm(p->vchar);fprintf(f,"B%d",!zmeqto(vmax,l2zm(0L)));}
  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);fprintf(f,"UB%d",!zumeqto(vmax,ul2zum(0UL)));}
  if(t==CHAR){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)||t==NPOINTER){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)||t==FPOINTER||t==HPOINTER){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) printzm(f,p->vmax);
  if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax);
} 
void emitval(FILE *f,union atyps *p,int t)
{
  t&=NU;
  if((t&NQ)==NPOINTER) t=(UNSIGNED|INT);
  if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));}
  if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vmax,ul2zum(0UL)));}
  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)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);}
  if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);}
  if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){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);
}

void conv_typ(struct Typ *p)
/* Erzeugt extended types in einem Typ. */
{
  char *attr;
  while(p){
    if(ISPOINTER(p->flags)){
      p->flags=((p->flags&~NU)|POINTER_TYPE(p->next));
      if(attr=p->next->attr){
	if(strstr(attr,STR_NEAR))
	  p->flags=((p->flags&~NU)|NPOINTER);
	if(strstr(attr,STR_FAR))
	  p->flags=((p->flags&~NU)|FPOINTER);
	if(strstr(attr,STR_HUGE))
	  p->flags=((p->flags&~NU)|HPOINTER);
      }
    }
    if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit"))
      p->flags=((p->flags&~NU)|BIT);
    p=p->next;
  }
}

void init_db(FILE *f)
{
  dwarf2_setup(sizetab[HPOINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section");
  dwarf2_print_comp_unit_header(f);
}
void cleanup_db(FILE *f)
{
  dwarf2_cleanup(f);
  if(f) section=-1;
} 
