/*  $VER: vbcc (m68k/machine.c) $Revision: 1.139 $     */
/*  Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2    */
/*  and ColdFire.                                                           */
/*  vasm, PhxAss and the GNU assembler is supported.                        */


#include "supp.h"

#define NEW_RET 0

static char FILE_[]=__FILE__;

#include "dwarf2.c"

/*  Public data that MUST be there.                             */

/* Name and copyright. */
char cg_copyright[]="vbcc code-generator for m68k/ColdFire V1.15 (c) in 1995-2022 by Volker Barthelmann";

/*  Commandline-flags the code-generator accepts                */
int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char *g_flags_name[MAXGF]={
    "cpu","fpu","d2scratch","noa4","sc","sd","prof","const-in-data",
    "use-framepointer","no-peephole","no-delayed-popping",
    "gas","branch-opt","no-fp-return","no-mreg-return","hunkdebug",
    "no-intz","old-peephole","conservative-sr","elf","use-commons",
    "a2scratch","old-softfloat","amiga-softfloat","fastcall","fp2scratch",
    "no-reserve-regs","phxass","clean-fattr","old-libcalls","vbcccall",
    "float64"
};

union ppi g_flags_val[MAXGF];

/*  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[MAXR+1]={"noreg","a0","a1","a2","a3","a4","a5","a6","a7",
                               "d0","d1","d2","d3","d4","d5","d6","d7",
                        "fp0","fp1","fp2","fp3","fp4","fp5","fp6","fp7",
                        "d0/d1","d2/d3","d4/d5","d6/d7"};

static char *elfregnames[MAXR+1]={"noreg","%a0","%a1","%a2","%a3","%a4","%a5","%a6","%a7",
			   "%d0","%d1","%d2","%d3","%d4","%d5","%d6","%d7",
			   "%fp0","%fp1","%fp2","%fp3","%fp4","%fp5","%fp6","%fp7",
			   "%d0/%d1","%d2/%d3","%d4/%d5","%d6/%d7"};

static char *mregnames[MAXR+1];

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

/*  Type which can store each register. */
type *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]={0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

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

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

treg_handle empty_reg_handle={0,0,0};

/* Names of target-specific variable attributes.                */
char *g_attr_name[]={"__far","__near","__chip","__saveds",
                     "__interrupt","__amigainterrupt",0};
#define FAR 1
#define NEAR 2
#define CHIP 4
#define SAVEDS 8
#define INTERRUPT 16
#define AMIINTERRUPT 32
#define STDARGS 64 /* not used, just for compatibility */

int MINADDI2P=SHORT;

/****************************************/
/*  Some private data and functions.    */
/****************************************/
#define CPU             (g_flags_val[0].l)
#define FPU             (g_flags_val[1].l)
#define D2SCRATCH       (g_flags[2]&USEDFLAG)
#define NOA4            (g_flags[3]&USEDFLAG)
#define SMALLCODE       (g_flags[4]&USEDFLAG)
#define SMALLDATA       (g_flags[5]&USEDFLAG)
#define PROFILER        (g_flags[6]&USEDFLAG)
#define CONSTINDATA     (g_flags[7]&USEDFLAG)
#define USEFRAMEPOINTER (g_flags[8]&USEDFLAG)
#define NOPEEPHOLE      (g_flags[9]&USEDFLAG)
#define NODELAYEDPOP    (g_flags[10]&USEDFLAG)
#define GAS             (g_flags[11]&USEDFLAG)
#define BRANCHOPT       (g_flags[12]&USEDFLAG)
#define NOFPRETURN      (g_flags[13]&USEDFLAG)
#define NOMREGRETURN    (g_flags[14]&USEDFLAG)
#define HUNKDEBUG       (g_flags[15]&USEDFLAG)
#define NOINTZ          (g_flags[16]&USEDFLAG)
#define OLDPEEPHOLE     (g_flags[17]&USEDFLAG)
#define CONSERVATIVE_SR (g_flags[18]&USEDFLAG)
#define ELF             (g_flags[19]&USEDFLAG)
#define USE_COMMONS     (g_flags[20]&USEDFLAG)
#define A2SCRATCH       (g_flags[21]&USEDFLAG)
#define OLD_SOFTFLOAT   (g_flags[22]&USEDFLAG)
#define AMI_SOFTFLOAT   (g_flags[23]&USEDFLAG)
#define FASTCALL        (g_flags[24]&USEDFLAG)
#define FP2SCRATCH      (g_flags[25]&USEDFLAG)
#define RESERVEREGS     (g_flags[26]&USEDFLAG)
#define PHXASS          (g_flags[27]&USEDFLAG)
#define CLEANFATTR      (g_flags[28]&USEDFLAG)
#define OLDLIBCALLS     (g_flags[29]&USEDFLAG)
#define VBCCCALL        (g_flags[30]&USEDFLAG)
#define FLOAT64         (g_flags[31]&USEDFLAG)


static int use_sd;

#ifdef M68K_16BIT_INT
static long malign[MAX_TYPE+1]=  {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1};
static long msizetab[MAX_TYPE+1]={0,1,2,2,4,8,4,8,8,0,4,0,0,0,4,0};
#else
static long malign[MAX_TYPE+1]=  {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1};
static long msizetab[MAX_TYPE+1]={0,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0};
#endif

static type ltyp={LONG},larray={ARRAY,&ltyp},lltyp={LLONG};

static char cpu_macro[16],fpu_macro[16],*marray[16];

static char pushreglist[200],popreglist[200];

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

static char *labprefix,*idprefix;

static int reglabel,freglabel,section=-1;
enum {
  a0=1,a1,a2,a3,a4,a5,a6,a7,
  d0,d1,d2,d3,d4,d5,d6,d7,
  fp0,fp1,fp2,fp3,fp4,fp5,fp6,fp7,
  d0d1,d2d3,d4d5,d6d7
};
static int sp=8,fbp=6,framesize;
static int stack_valid;
static char *codename,*bssname,*dataname;
static char *m_bssname,*m_dataname;
static char *rprefix;

static void emit_obj(FILE *,obj *,int);
static IC *do_refs(FILE *,IC *);
static void pr(FILE *,IC *);
static int get_reg(FILE *,int,IC *,int);
static long pof2(zumax);
static void function_top(FILE *,Var *,long);
static void function_bottom(FILE *f,Var *,long);

#define saveregs(x,y) saveregswfp(x,y,0)
static void saveregswfp(FILE *,IC *,int);
static void restoreregsa(FILE *,IC *);
static void restoreregsd(FILE *,IC *);

static void assign(FILE *,IC *,obj *,obj *,int,long,int);
static int compare_objects(obj *o1,obj *o2);

static char x_s[]={'0','b','w','3','l'};
#ifdef M68K_16BIT_INT
static char x_t[]={'?','b','w','w','l','L','s','d','d','v','l','a','s','u','e','f'};
#else
static char x_t[]={'?','b','w','l','l','L','s','d','d','v','l','a','s','u','e','f'};
#endif

static char *quick[2]={"","q"};
static char *strshort[2]={"l","w"};

static char *ubranch[]={"eq","ne","cs","cc","ls","hi"};

static int pushedreg,stored_cc; /* pushedreg&2: aregsaved; 4: dreg; 8: freg */
                                /* 16: durch RESTOREREGS gepushed           */
static int comptyp;
static int pushflag;
static int geta4;
static int dscratch=1,ascratch=1,fscratch=1;

#define D16OFF 1024

static int newobj=0;   /*  um zu erkennen, ob neue section erlaubt ist */

static int cf;
static int add_stdargs;

static int isquickkonst(union atyps *,int),isquickkonst2(union atyps *,int),regavailable(int);
static void move(FILE *,obj *,int,obj *,int,int);
static void loadext(FILE *,int,obj *,int);
static void add(FILE *,obj *,int,obj *,int,int);
static void sub(FILE *,obj *,int,obj *,int,int);
static void mult(FILE *,obj *,int,obj *,int,int,int,IC *);

extern int static_cse;

static void scratch_modified(void)
{
  BSET(regs_modified,a0);
  BSET(regs_modified,a1);
  BSET(regs_modified,d0);
  BSET(regs_modified,d1);
  if(FPU>68000){
    BSET(regs_modified,fp0);
    BSET(regs_modified,fp1);
  }
  if(D2SCRATCH) BSET(regs_modified,d2);
  if(A2SCRATCH) BSET(regs_modified,a2);
  if(FP2SCRATCH) BSET(regs_modified,fp2);

}

static long pof2(zumax x)
/*  Yields log2(x)+1 oder 0. */
{
    zumax p;int ln=1;
    p=ul2zum(1UL);
    while(ln<=32&&zumleq(p,x)){
        if(zumeqto(x,p)) return ln;
        ln++;p=zumadd(p,p);
    }
    return 0;
}

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

#ifdef M68K_16BIT_INT
#define ISHWORD(x) ((x&NQ)<=INT)
#else
#define ISHWORD(x) ((x&NQ)<INT)
#endif

#define PEA -1
#define LEA -2

#define FUNCPREFIX(t) ((stdargs(t)&&rparmtype!=PARMVBCC)?idprefix:(rparmtype==PARMVBCC?"@$":"@"))

static void emit_lword(FILE *,obj *);
static void emit_hword(FILE *,obj *);
static int addressing(IC *);
static long notpopped,dontpop,stackoffset,loff,maxpushed,stack;
static int offlabel,regoffset;
/*  For keeping track of condition codes.   */
static obj *cc_set,*cc_set_tst;
static int cc_typ,cc_typ_tst;
static int missing,savedemit,savedalloc;
static int lastpush,unorderedpush,pushoff[MAXR+1];

static int vsec(FILE *f,Var *v)
{
  char *type="bss";
  if(!sec_per_obj||(v->tattr&CHIP)) return 0;
  if(ISFUNC(v->vtyp->flags)||(v->clist&&is_const(v->vtyp))) type="code"; else if(v->clist) type="data";
  emit(f,"\t%ssection\t\"DONTMERGE_%s.%s.%ld\"%s%s\n",GAS?".":"",type,v->identifier,v->storage_class==STATIC/*&&!ISFUNC(v->vtyp->flags)*/?(long)zm2l(v->offset):0L,GAS?"":",",GAS?"":type);
  if(f) section=SPECIAL;
  return 1;
}

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

static enum{
  PARMSTD,
  PARMVBCC,
  PARMSAS
} rparmtype;

static int stdargs(type *t)
{
  type *p;

  if(VBCCCALL) rparmtype=PARMVBCC;
  else if(FASTCALL) rparmtype=PARMSAS;
  else rparmtype=PARMSTD;

  for(p=t->next;p;p=p->next){
    if(p->attr&&strstr(p->attr,"__stdargs")) {rparmtype=PARMSTD;return 1;}
    if(p->attr&&strstr(p->attr,"__vbccargs")) {rparmtype=PARMVBCC;return 0;}
    if(p->attr&&strstr(p->attr,"__regargs")) {rparmtype=PARMSAS;return 0;}
    if(CLEANFATTR) break;
  }
  if((!FASTCALL&&!VBCCCALL)||add_stdargs) return 1;
  if(t->flags==FUNKT&&is_varargs(t)) return 1;
  return 0;
}

/* 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;
}

void title(FILE *f)
{
  static int done;
  extern char *inname; /*grmpf*/
  if(!done&&f){
    done=1;
    if(GAS)
      emit(f,"\t.file\t\"%s\"\n",inname);
    else
      emit(f,"\tidnt\t\"%s\"\n",inname);
  }
}      

static int is_arg_reg(IC *p,int r)
{
  int i,u;IC *a;
  for(i=0;i<p->arg_cnt;i++){
    a=p->arg_list[i];
    u=0;
    if((a->z.flags&(REG|DREFOBJ))==REG)
      u=a->z.reg;
    else if((a->z.flags&VAR)&&a->z.v->reg)
      u=a->z.v->reg;
    if(u){
      if(r==u||(reg_pair(u,&rp)&&r==rp.r1||r==rp.r2)){
	return 1;
      }
    }
  }
  return 0;
}

static int am_uses_reg(IC *p,int i)
{
  if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i))
     ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i))
     ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i)))
    return 1;
  return 0;
}

/* check if register can be scratched */
static int scratchreg(int r,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;
    if(am_uses_reg(p,r)) return 0;
  }
}



static int pget_reg(FILE *f,int flag,IC *p,int useq1)
{
  int i;

  flag=1+flag*8;

  if(useq1){
    if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p))
      return p->q1.reg;
  }

  for(i=flag;i<flag+8;i++){
    if(regs[i]==1&&(!p||(i!=p->q1.reg&&i!=p->q2.reg&&i!=p->z.reg))){
      if(p){
	if(am_uses_reg(p,i))
	  continue;
	if(p->code==CALL&&is_arg_reg(p,i))
	  continue;
      }
      regs[i]|=8;
      pushflag=1;
      emit(f,"\tmove.l\t%s,%ld(%s)\n",mregnames[i],-stackoffset,mregnames[sp]);
      if(i<d0) 
	pushedreg|=2;
      else if (i<fp0)
	pushedreg|=4;
      else
	pushedreg|=8;
      BSET(regs_modified,i);
      return i;
    }
  }
  ierror(0);
}

static int get_reg(FILE *f,int flag,IC *p,int useq1)
/*  Gets a register: flag=0=areg, 1=dreg, 2=fpreg           */
{
  int i;

  flag=1+flag*8;

  if(useq1){
    if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p))
      return p->q1.reg;
  }

  for(i=flag;i<flag+8;i++){
    if(regs[i]==0){
      if(p){
	if(am_uses_reg(p,i))
	  continue;
	if(p->code==CALL&&is_arg_reg(p,i))
	  continue;
      }
      regs[i]=2;pushedreg|=1;
      if(!regused[i]&&!regscratch[i]){regused[i]=1; }
      BSET(regs_modified,i);
      return i;
    }
  }
  for(i=flag;i<flag+8;i++){
    static rpair rp;
    if(regs[i]==1){
      if(p){
	if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i))
	   ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i))
	   ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i))){
	  continue;
	}
	if(p->code==CALL&&is_arg_reg(p,i))
	  continue;
	if(p->q1.flags&REG){
	  if(p->q1.reg==i) continue;
	  if(reg_pair(p->q1.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
	}
	if(p->q2.flags&REG){
	  if(p->q2.reg==i) continue;
	  if(reg_pair(p->q2.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
	}
	if(p->z.flags&REG){
	  if(p->z.reg==i) continue;
	  if(reg_pair(p->z.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
	}
      }
      regs[i]+=4;
      if(i<lastpush){
	unorderedpush=1;
	/*printf("%s %s\n",mregnames[lastpush],mregnames[i]);*/
      }
      if(i<fp0){
	emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[i],mregnames[sp]);
	push(4);
	pushoff[i]=pushoff[lastpush]+4;
      }else{
	emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[i],mregnames[sp]);
	push(12);
	pushoff[i]=pushoff[lastpush]+12;
      }
      lastpush=i;
      if(i<d0)
	pushedreg|=2;
      else if(i<fp0)
	pushedreg|=4;
      else
	pushedreg|=8;
      BSET(regs_modified,i);
      return i;
    }
  }
  ierror(0);
}
static int isquickkonst(union atyps *p,int t)
/*  Returns 1 if constant is between -128 and 127.   */
{
    zmax zm;zumax zum;
    if(ISFLOAT(t)) return 0;
    eval_const(p,t);
    if(t&UNSIGNED){
        zum=ul2zum(127UL);
        return zumleq(vumax,zum);
    }else{
        zm=l2zm(-129L);
        if(zmleq(vmax,zm)) return 0;
        zm=l2zm(127L);
        return zmleq(vmax,zm);
    }
}
static int isquickkonst2(union atyps *p,int t)
/*  Returns 1 if constant is between 1 and 8.   */
{
    zmax zm;zumax zum;
    if(ISFLOAT(t)) return 0;
    eval_const(p,t);
    if(t&UNSIGNED){
        if(zumeqto(ul2zum(0UL),vumax)) return 0;
        zum=ul2zum(8UL);
        return zumleq(vumax,zum);
    }else{
        if(zmeqto(l2zm(0L),vmax)) return 0;
        zm=l2zm(-1L);
        if(zmleq(vmax,zm)) return 0;
        zm=l2zm(8L);
        return zmleq(vmax,zm);
    }
}

static int pregavailable(IC *p,int art)
/*  Returns true if matching register is available. Handles arglist*/
{
    int i;
    art=1+art*8;
    for(i=art+1;i<art+8;i++)
      if(regs[i]==0&&!is_arg_reg(p,i)) return(1);
    return 0;
}

static int regavailable(int art)
/*  Returns true if matching register is available.     */
{
    int i;
    art=1+art*8;
    for(i=art+1;i<art+8;i++)
        if(regs[i]==0) return(1);
    return 0;
}
static int compare_objects(obj *o1,obj *o2)
/*  Tests if two objects are equal.     */
{
  if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg)
    return 1;
  if((o1->flags&(KONST|VAR|DREFOBJ|REG|VARADR))==(o2->flags&(KONST|VAR|DREFOBJ|REG|VARADR))&&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;
}
static IC *do_refs(FILE *f,IC *p)
/*  Loads DREFOBJs into address registers, if necessary.    */
/*  Small constants are loaded into data registers if this  */
/*  improves code.                                          */
{
    int reg,c=p->code,t=p->typf,equal;
    if((p->q1.flags&DREFOBJ)&&!(p->q1.flags&KONST)&&(!(p->q1.flags&REG)||p->q1.reg<1||p->q1.reg>8)){
        equal=0;
        if(compare_objects(&p->q1,&p->q2)) equal|=1;
        if(compare_objects(&p->q1,&p->z)) equal|=2;
	if(p->code==PUSH&&!pregavailable(p,0))
	  reg=pget_reg(f,0,p,0);
	else if(p->code==CALL&&!pregavailable(p,0))
	  return p;
	else
	  reg=get_reg(f,0,p,0);
        p->q1.flags&=~DREFOBJ;
        emit(f,"\tmove.l\t");emit_obj(f,&p->q1,POINTER);
        p->q1.flags=REG|DREFOBJ;
        p->q1.reg=reg;
        emit(f,",%s\n",mregnames[p->q1.reg]);
        if(equal&1) p->q2=p->q1;
        if(equal&2) p->z=p->q1;
	if(c==TEST) cc_set_tst=cc_set=0;
    }
    if((p->q2.flags&DREFOBJ)&&!(p->q2.flags&KONST)&&(!(p->q2.flags&REG)||p->q2.reg<1||p->q2.reg>8)){
        if(compare_objects(&p->q2,&p->z)) equal=1; else equal=0;
        reg=get_reg(f,0,p,0);
        p->q2.flags&=~DREFOBJ;
        emit(f,"\tmove.l\t");emit_obj(f,&p->q2,POINTER);
        p->q2.flags=REG|DREFOBJ;
        p->q2.reg=reg;
        emit(f,",%s\n",mregnames[p->q2.reg]);
        if(equal) p->z=p->q2;
    }
    if((p->z.flags&DREFOBJ)&&!(p->z.flags&KONST)&&(!(p->z.flags&REG)||p->z.reg<1||p->z.reg>8)){
      reg=get_reg(f,0,p,0);
        p->z.flags&=~DREFOBJ;
        emit(f,"\tmove.l\t");emit_obj(f,&p->z,POINTER);
        p->z.flags=REG|DREFOBJ;
        p->z.reg=reg;
        emit(f,",%s\n",mregnames[p->z.reg]);
    }
    if(CPU!=68040){
    /*  Don't do it on 040 because it's slower. */
        if(x_t[t&NQ]=='l'&&(t&NQ)!=FLOAT&&(c!=ASSIGN||!isreg(z))&&
           c!=MULT&&c!=DIV&&c!=MOD&&c!=LSHIFT&&c!=RSHIFT&&c!=SETRETURN&&c!=PUSH&&c!=ADDI2P&&c!=SUBIFP&&
           (!(p->z.flags&REG)||p->z.reg<d0||p->z.reg>d7)){
            /*  Constants into registers.    */
            if(isconst(q1)&&isquickkonst(&p->q1.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q1.val,t))){
                eval_const(&p->q1.val,t);
                if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&&regavailable(1)){
		  reg=get_reg(f,1,p,0);
		  move(f,&p->q1,0,0,reg,t);
		  p->q1.flags=REG;p->q1.reg=reg;
		  p->q1.val.vmax=l2zm(0L);
                }
            }
            if(isconst(q2)&&isquickkonst(&p->q2.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q2.val,t))){
                eval_const(&p->q2.val,t);
                if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&&regavailable(1)){
		  reg=get_reg(f,1,p,0);
		  move(f,&p->q2,0,0,reg,t);
		  p->q2.flags=REG;p->q2.reg=reg;
		  p->q2.val.vmax=l2zm(0L);
                }
            }
        }
    }
    return p;
}
static void pr(FILE *f,IC *p)
/*  Release registers and pop them from stack if necessary. */
{
  int i,size=0;char *s="";
    /*  To keep track of condition codes.   */
#if 0
  if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE)){
    char *fp;IC *branch;
    if(FPU>68000&&ISFLOAT(p->typf)) fp="f"; else fp="";
    branch=p;
    while(branch->code<BEQ||branch->code>=BRA) branch=branch->next;
    /*FIXME*/
    if((p->typf&UNSIGNED)||ISPOINTER(p->typf)){
      emit(f,"\ts%s\t-2(%s)\n",ubranch[branch->code-BEQ],mregnames[sp]);
    }else{
      emit(f,"\t%ss%s\t-2(%s)\n",fp,ename[branch->code]+1,mregnames[sp]);
    }
    stored_cc=1;
  }
#endif
  if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE||p->code==SETRETURN)){
    s="m";
    if(!GAS&&!PHXASS) emit(f,"\topt\tom-\n");
  }
  for(i=MAXR;i>0;i--){
    if(regs[i]==2) regs[i]=0;
    if(regs[i]&8){
      regs[i]&=~8;
      
      emit(f,"\tmove%s.l\t%ld(%s),%s\n",s,-stackoffset,mregnames[sp],mregnames[i]);
      if(i>=d0) cc_set=0;
      if(cc_set&&(cc_set->flags&REG)&&cc_set->reg==i)
	cc_set=0;
      missing++;
    }
    if(regs[i]&4){
      regs[i]&=~4;
      if(i>=1&&i<=d7){
	if(unorderedpush)
	  emit(f,"\tmove%s.l\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
	else{
	  if(cf&&*s=='m'){
	    emit(f,"\tmove%s.l\t(%s),%s\n\taddq.l\t#4,%s\n",s,mregnames[sp],mregnames[i],mregnames[sp]);
	  }else{
	    emit(f,"\tmove%s.l\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]);
	  }
	}
	pop(4);size+=4;
      }else if(i>=fp0&&i<=fp7){
	if(unorderedpush)
	  emit(f,"\tfmove%s.x\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
	else
	  emit(f,"\tfmove%s.x\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]);
	pop(12);size+=12;
      }else if(i>=25&&i<=28){
	if(unorderedpush)
	  emit(f,"\tmovem.l\t%d(%s),%s\n",pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]);
	else{
	  if(cf)
	    emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#8,%s\n",mregnames[sp],mregnames[i],mregnames[sp]);
	  else
	    emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[i]);
	}
	pop(8);size+=8;
      }else
	ierror(0);
      if(i>=d0) cc_set=0;
      if(cc_set&&(cc_set->flags&REG)&&cc_set->reg==i)
	cc_set=0;
      missing++;
    }
  }
  if(*s=='m'&&!GAS&&!PHXASS) emit(f,"\topt\tom+\n");
#if 0
  if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE))
    emit(f,"\ttst.b\t-%d(%s)\n",size+2,mregnames[sp]);
#endif
  if(unorderedpush)
    emit(f,"\tadd%s.%c\t#%d,%s\n",pushoff[lastpush]<=8?"q":"",cf?'l':'w',pushoff[lastpush],mregnames[sp]);
  lastpush=0;
  unorderedpush=0;
}
static void emit_obj(FILE *f,obj *p,int t)
/*  Write object.   */
{
  if(p->am){
    /*  Addressing modes.   */
    if(NOPEEPHOLE) {ierror(0);p->am=0;return;}
    if(p->am->skal>=0){
      long l=0;
      if(p->flags&D16OFF) l=zm2l(p->val.vmax);
      emit(f,"(%ld",p->am->dist+l);
      if(!GAS&&CPU>=68020&&((p->am->dist+l)>32767||(p->am->dist+l)<-32768))
	emit(f,".l");
      else if(!GAS&&CPU>=68020&&((p->am->dist+l)>127||(p->am->dist+l)<-128))
	emit(f,".w");
      emit(f,",%s",mregnames[p->am->basereg]);
      if(p->am->dreg){
	emit(f,",%s",mregnames[p->am->dreg&127]);
	if(p->am->dreg&128) emit(f,".w"); else emit(f,".l");
	if(p->am->skal) emit(f,"*%d",p->am->skal);
      }
      emit(f,")");
      return;
    }
    if((p->flags&D16OFF)&&p->am->skal<0&&!zmeqto(l2zm(0L),p->val.vmax)) ierror(0);
    if(p->am->skal==-1){
      emit(f,"(%s)+",mregnames[p->am->basereg]);
      return;
    }
    if(p->am->skal==-2){    /*  Noch nicht implementiert    */
      emit(f,"-(%s)",mregnames[p->am->basereg]);
      return;
    }
  }
  if(p->flags&DREFOBJ){
    if(p->flags&KONST){
      emitval(f,&p->val,p->dtyp&NU);
      return;
    }
    emit(f,"(");
    if((p->flags&D16OFF)&&!zmeqto(l2zm(0L),p->val.vmax)){
      emitval(f,&p->val,MAXINT);
      if(!zmleq(p->val.vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),p->val.vmax))
	emit(f,".l");
      else if(!zmleq(p->val.vmax,l2zm(127L))||!zmleq(l2zm(-128L),p->val.vmax))
	emit(f,".w");
      emit(f,",");
    }
  }
  if(p->flags&VARADR) emit(f,"#");
  if(p->flags&VAR) {
    if(p->flags&REG){
      emit(f,"%s",mregnames[p->reg]);
    }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
      long os;
      os=zm2l(p->val.vmax);
      if(!USEFRAMEPOINTER&&!vlas){
	if(!zmleq(l2zm(0L),p->v->offset)) 
	  os=os+loff-zm2l(p->v->offset)+(PROFILER?16:0);
	else
	  os=os+zm2l(p->v->offset);
	if(!GAS&&CPU>=68020&&(os-stackoffset)>0x7c00) /* +l%d max.1024? */
	  emit(f,"((%ld+%s%d).l,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]);
	else
	  emit(f,"(%ld+%s%d,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]); 
      }else{
	if(!zmleq(l2zm(0L),p->v->offset))
	  os=os-zm2l(p->v->offset)+4+(PROFILER?16:0);
	else
	  os=os-(zm2l(p->v->offset)+zm2l(szof(p->v->vtyp)));
	emit(f,"(%ld",os);
	if(!GAS&&CPU>=68020&&os>0x7fff)
	  emit(f,".l");
	emit(f,",%s)",mregnames[fbp]);
      }
    }else{
      if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");}
      if(p->v->storage_class==STATIC){
	emit(f,"%s%ld",labprefix,zm2l(p->v->offset));
      }else{
	if(ISFUNC(p->v->vtyp->flags))
	  emit(f,"%s%s",FUNCPREFIX(p->v->vtyp),p->v->identifier);
	else
	  emit(f,"%s%s",idprefix,p->v->identifier);
      }
      if(use_sd&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)
	 &&!(p->v->tattr&(CHIP|FAR))&&(CONSTINDATA||!is_const(p->v->vtyp))
	 &&zmleq(l2zm(0L),p->val.vmax)&&!zmleq(szof(p->v->vtyp),p->val.vmax))
	emit(f,"(a4)");
    }
  }
  if((p->flags&REG)&&!(p->flags&VAR)) emit(f,"%s",mregnames[p->reg]);
  if(p->flags&KONST){
    /*  This requires IEEE floats/doubles on the host compiler. */
    if(ISFLOAT(t)){
      unsigned char *ip=(unsigned char *)&p->val.vfloat;
      char *s;
      if(GAS) s="0x"; else s="$";
      emit(f,"#%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]);
      if((t&NQ)!=FLOAT){
	if(DEBUG&1) printf("doubleconst=%f\n",zld2d(zd2zld(p->val.vdouble)));
	emit(f,"%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]);
      }
    }else{
      emit(f,"#");emitval(f,&p->val,t&NU);
    }
  }
  if(p->flags&DREFOBJ) emit(f,")");
}
static void dwarf2_print_frame_location(FILE *f,Var *v)
{
  /*FIXME: needs a location list and correct register trabslation */
  obj o;
  o.flags=REG;
  if(USEFRAMEPOINTER||vlas)
    o.reg=fbp;
  else
    o.reg=sp;
  o.val.vmax=l2zm(0L);
  o.v=0;
  dwarf2_print_location(f,&o);
}
static int dwarf2_regnumber(int r)
{
  if(r<=8)
    return r+7;
  else if(r<=d7)
    return r-8;
  else if(r<=fp7)
    return r+1;
  else
    ierror(0);
}
static zmax dwarf2_fboffset(Var *v)
{
  long os;
  if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0);
  if(!USEFRAMEPOINTER&&!vlas){
    if(!zmleq(l2zm(0L),v->offset)) 
      os=loff-zm2l(v->offset);
    else
      os=zm2l(v->offset);
    return l2zm(os+framesize);
  }else{
    if(!zmleq(l2zm(0L),v->offset)) 
      return l2zm(-zm2l(v->offset)+4);
    else
      return l2zm(-(zm2l(v->offset)+zm2l(szof(v->vtyp))));
  }
}

static char tsh[]={'w','l'};
static int proflabel,stacksizelabel;
static void function_top(FILE *f,Var *v,long offset)
/*  Writes function header. */
{
    geta4=0;
    if(GAS){
    }else{
        if(debug_info&&HUNKDEBUG) emit(f,"\tsymdebug\n");
        if(CPU!=68000) emit(f,"\tmachine\t%ld\n",CPU);
        if(cf) strshort[1]="l";
        if(FPU>68000) emit(f,"\tfpu\t1\n");
        if(SMALLCODE) emit(f,"\tnear\tcode\n");
        if(use_sd) emit(f,"\tnear\ta4,-2\n");
	if(PHXASS){
	  emit(f,"\topt\t0\n\topt\tNQLPSM");
	  if(CPU!=68040) emit(f,"R");
	  if(1/*BRANCHOPT||(optflags&2)*/) emit(f,"BT");
	  emit(f,"\n");
	}else{
	  emit(f,"\topt o+,ol+,op+,oc+,ot+,oj+,ob+,om+");
	  if(CPU==68040) emit(f,",a-");
	  emit(f,"\n");
	}
    }
    if(!special_section(f,v)&&section!=CODE){emit(f,codename);if(f) section=CODE;}
    if(PROFILER){
        proflabel=++label;
        if(GAS){
            emit(f,"%s%d:\n\t.byte\t\"%s\",0\n",labprefix,proflabel,v->identifier);
        }else{
            emit(f,"%s%d\n\tdc.b\t\"%s\",0\n",labprefix,proflabel,v->identifier);
        }
    }
    if(v->storage_class==EXTERN){
      if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC){
        if(GAS){
	  emit(f,"\t.global\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
        }else{
	  emit(f,"\tpublic\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
        }
      }
    }
    if(v->storage_class==EXTERN){
      if(GAS){
        emit(f,"\t.align\t4\n%s%s:\n",FUNCPREFIX(v->vtyp),v->identifier);
      }else{
        emit(f,"\tcnop\t0,4\n%s%s\n",FUNCPREFIX(v->vtyp),v->identifier);
      }
    }else{
      if(GAS){
        emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
      }else{
        emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset));
      }
    }      
    if(stack_check&&!(v->tattr&AMIINTERRUPT)){
      stacksizelabel=++label;
      if(GAS){
	emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjbsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]);
      }else{
	emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]);
      }
    }      
    if(PROFILER){
        if(GAS){
            emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\t.global\t__startprof\n\tjbsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]);
        }else{
            emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\tpublic\t__startprof\n\tjsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]);
        }
    }
    offset=-((offset+4-1)/4)*4;
    loff=-offset;offlabel=++label;
    if(!USEFRAMEPOINTER&&!vlas){
      if(offset<0) emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[offset>=-8],strshort[offset>=-32768],-offset,mregnames[sp]);
    }else{
      if(offset>=-32768||CPU>=68020){
	emit(f,"\tlink.%c\t%s,#%ld\n",tsh[offset<-32768],mregnames[fbp],offset);
      }else{
	emit(f,"\tlink.w\t%s,#-32768\n",mregnames[fbp]);offset+=32768;
	  emit(f,"\tsub.%c\t#%ld,%s\n",tsh[offset<-32768],offset,mregnames[fbp]);
      }
    }
    if(FPU>68000&&float_used){
        if(GAS){
            emit(f,"\t.word\t0xf227,%s%d\n",labprefix,freglabel);
        }else{
            emit(f,"\tfmovem.x\t%s%d,-(%s)\n",labprefix,freglabel,mregnames[sp]);
        }
    }
    if(cf){
      emit(f,"\tsub.l\t#%s%d,%s\n",labprefix,offlabel,mregnames[sp]);
      if(GAS){
        emit(f,"\tmovem.l\t#%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]);
      }else{
        emit(f,"\tmovem.l\t%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]);
      }
    }else{
      if(GAS){
        emit(f,"\tmovem.l\t#%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]);
      }else{
        emit(f,"\tmovem.l\t%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]);
      }
    }
    if((v->tattr&SAVEDS)&&use_sd) emit(f,"\txref\t_LinkerDB\n\tlea\t_LinkerDB,a4\n");
    stack_valid=1;
    stack=0;
}
static void function_bottom(FILE *f,Var *v,long offset)
/*  Writes function footer. */
{
    int i,size=0;unsigned int pushval,popval;
    *pushreglist=0;*popreglist=0;
    pushval=popval=0;
    if((v->tattr&SAVEDS)&&use_sd) geta4=1;
    for(i=1;i<=16;i++){
        if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])||(i==5&&geta4)||(i==d0&&pushflag)){
            if(*pushreglist) strcat(pushreglist,"/");
            strcat(pushreglist,mregnames[i]);
	    if(i!=d0||(v->tattr&INTERRUPT)){
	      if(*popreglist) strcat(popreglist,"/");
	      strcat(popreglist,mregnames[i]);
	    }
            if(i<d0){
	      pushval|=(256>>i);popval|=(128<<i);
	    }else{
	      pushval|=(0x8000>>(i-9));
	      if(i!=d0) popval|=(1<<(i-9));
	    }
            size+=4;
        }
    }
    if(pushflag){
      emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]);
      if(v->tattr&INTERRUPT) ierror(0);
    }
    if(cf){
      if(GAS){
        if(popval)
	  emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s),#%u\n\tadd.l\t#%s%d%s,%s\n",labprefix,reglabel,pushval,mregnames[sp],popval,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]);
        else
	  emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel);
      }else{
        if(*pushreglist)
	  emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist);
	else
	  emit(f,"%s%d\treg\n",labprefix,reglabel);
	if(*popreglist)
	  emit(f,"\tmovem.l\t(%s),%s\n\tadd.l\t#%s%d%s,%s\n",mregnames[sp],popreglist,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]);
      }
    }else{
      if(GAS){
        if(popval)
	  emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s)+,#%u\n",labprefix,reglabel,pushval,mregnames[sp],popval);
        else
	  emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel);
      }else{
        if(*pushreglist)
	  emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist);
        else
	  emit(f,"%s%d\treg\n",labprefix,reglabel);
	if(*popreglist)
	  emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],popreglist);
      }
    }
    *pushreglist=0;*popreglist=0;pushval=0xe000;popval=0xd000;
    for(i=fp0;i<=fp7;i++){
      if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])){
	if(*popreglist) strcat(popreglist,"/");
	strcat(popreglist,mregnames[i]);
	pushval|=(1<<(i-17));popval|=(0x80>>(i-17));
	size+=12;
      }
    }
    if(FPU>68000&&(float_used||(v->tattr&INTERRUPT))){
      if(GAS){
	if(popval!=0xd000)
	  emit(f,"\t.equ\t%s%d,0x%x\n\t.word\t0xf21f,0x%x\n",labprefix,freglabel,(int)pushval,(int)popval);
	else
	  emit(f,"\t.equ\t%s%d,0xe000\n",labprefix,freglabel);
      }else{
	if(*popreglist)
	  emit(f,"%s%d\tfreg\t%s\n\tfmovem.x\t(%s)+,%s%d\n",labprefix,freglabel,popreglist,mregnames[sp],labprefix,freglabel);
	else
	  emit(f,"%s%d\tfreg\n",labprefix,freglabel);
        }
    }
    if(cf||(!USEFRAMEPOINTER&&!vlas)){
      if(GAS){
	emit(f,"\t.equ\t%s%d,%d\n",labprefix,offlabel,size);
      }else{
	emit(f,"%s%d\tequ\t%d\n",labprefix,offlabel,size);
      }
    }
    if(!USEFRAMEPOINTER&&!vlas){
      if(loff) emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[loff<=8],strshort[loff<32768],loff,mregnames[sp]);
      framesize=size;
    }else
      emit(f,"\tunlk\t%s\n",mregnames[fbp]);
    if(PROFILER){
        if(GAS){
            emit(f,"\tmove.l\t%s,-(%s)\n\t.global\t__endprof\n\tjbsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]);
        }else{
            emit(f,"\tmove.l\t%s,-(%s)\n\tpublic\t__endprof\n\tjsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]);
        }
    }
    if(v->tattr&INTERRUPT)
      emit(f,"\trte\n");
    else
      emit(f,"\trts\n");
    if(stack_check&&!(v->tattr&AMIINTERRUPT)){
      if(GAS)
	emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stacksizelabel,size+loff-maxpushed);
      else
	emit(f,"%s%d\tequ\t%ld\n",labprefix,stacksizelabel,size+loff-maxpushed);
    }
    if(stack_valid){
      if(!v->fi) v->fi=new_fi();
      v->fi->flags|=ALL_STACK;
      v->fi->stack1=l2zm(size+loff+stack);
      emit(f,"%c stacksize=%ld\n",GAS?'#':';',size+loff+stack);
    }
}
static void move(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
/*  erzeugt eine move Anweisung...Da sollen mal Optimierungen rein  */
{
    if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
    if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg;
    if(zreg==qreg&&zreg) return;
    if(q&&(q->flags&VARADR)&&zreg>=1&&zreg<=8){
        emit(f,"\tlea\t");
        q->flags&=~VARADR;emit_obj(f,q,t);q->flags|=VARADR;
        emit(f,",%s\n",mregnames[zreg]);
	BSET(regs_modified,zreg);
        return;
    }
    if(zreg>=d0&&zreg<fp0&&q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst(&q->val,t)){
        emit(f,"\tmoveq\t");
    }else{
        if((zreg>=fp0&&zreg<=fp7)||(qreg>=fp0&&qreg<=fp7)){
            if(qreg>=fp0&&qreg<=fp7&&zreg>=fp0&&zreg<=fp7) emit(f,"\tfmove.x\t");
             else emit(f,"\tfmove.%c\t",x_t[t&NQ]);
        }else{
	  if(!cf||qreg||zreg)
            emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]);
        }
    }
    if(cf&&!qreg&&!zreg){
        static IC dummy;
        dummy.code=ASSIGN;
        dummy.typf=t;
        dummy.q1=*q;
        dummy.q2.flags=0;
        dummy.z=*z;
        qreg=get_reg(f,1,&dummy,0);
	emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]);
        emit_obj(f,q,t);
        emit(f,",%s\n\tmove.%c\t%s,",mregnames[qreg],x_s[msizetab[t&NQ]],mregnames[qreg]);
        emit_obj(f,z,t);
        emit(f,"\n");
    }else{
      if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
      emit(f,",");
      if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
      emit(f,"\n");
      if(zreg) BSET(regs_modified,zreg);
    }
}
static void loadext(FILE *f,int r,obj *q,int t)
/*  laedt Objekt q vom Typ t in Register r und erweitert auf long   */
{
    if(t&UNSIGNED){
      if((q->flags&(REG|DREFOBJ))==REG&&q->reg==r)
        emit(f,"\tand.l\t#%u,%s\n",((t&NQ)==CHAR?0xffu:0xffffu),mregnames[r]);
      else
        emit(f,"\tmoveq\t#0,%s\n",mregnames[r]);
    }
    move(f,q,0,0,r,t);
#ifdef M68K_16BIT_INT
    if((t&NU)==SHORT||(t&NU)==INT) emit(f,"\text.l\t%s\n",mregnames[r]);
#else
    if((t&NU)==SHORT) emit(f,"\text.l\t%s\n",mregnames[r]);
#endif
    if((t&NU)==CHAR){
      if(cf||CPU>=68020)
        emit(f,"\textb.l\t%s\n",mregnames[r]);
      else
        emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[r],mregnames[r]);
    }
}

static void add(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
/*  erzeugt eine add Anweisung...Da sollen mal Optimierungen rein   */
{
    if(!qreg&&!q) ierror(0);
    if(!zreg&&!z) ierror(0);
    if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
    if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0);
    if(!qreg&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){
      emit(f,"\taddq.%c\t",cf?'l':x_t[t&NQ]);
    }else{
        /*  hier noch Abfrage, ob #c.w,ax   */
      emit(f,"\tadd.%c\t",cf?'l':x_t[t&NQ]);
    }
    if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
    emit(f,",");
    if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
    emit(f,"\n");
}
static void sub(FILE *f,obj *q,int qreg,obj *z,int zreg,int t)
/*  erzeugt eine sub Anweisung...Da sollen mal Optimierungen rein   */
{
    if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0);
    if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
    if(q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){
      emit(f,"\tsubq.%c\t",cf?'l':x_t[t&NQ]);
    }else{
        /*  hier noch Abfrage, ob #c.w,ax   */
      emit(f,"\tsub.%c\t",cf?'l':x_t[t&NQ]);
    }
    if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t);
    emit(f,",");
    if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t);
    emit(f,"\n");
}
static void mult(FILE *f,obj *q,int qreg,obj *z,int zreg, int t,int c,IC *p)
/*  erzeugt eine mult Anweisung...Da sollen mal Optimierungen rein  */
/*  erzeugt auch div/mod etc.                                       */
{
  int modreg;
  if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg;
  if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
  if(cf&&!qreg) {qreg=get_reg(f,1,p,0);move(f,q,0,0,qreg,t);}
  if((c==MULT||c==DIV||c==MOD)&&CPU<68020&&!cf&&msizetab[t&NQ]==4){
    if(c==MULT){
      /*  ist das mit get_reg(.,.,0) ok? nochmal ueberdenken...   */
      /*  ...die ganze Routine am besten...                       */
      /*  ...es war nicht, deshalb ist es jetzt geaendert         */
      int dx,dy,t1,t2;
      if(zreg>=d0&&zreg<=d7){
	dx=zreg;
      }else{
	dx=get_reg(f,1,p,0);
	move(f,z,0,0,dx,t);
      }
      if(qreg>=d0&&qreg<=d7&&qreg!=dx){
	dy=qreg;
      }else{
	dy=get_reg(f,1,p,0);
	move(f,q,0,0,dy,t);
      }
      t1=get_reg(f,1,p,0);t2=get_reg(f,1,p,0);
      if(t1==dx||t2==dx||t1==dy||t2==dy) ierror(0);
      emit(f,"\tmove.l\t%s,%s\n",mregnames[dx],mregnames[t1]);
      emit(f,"\tmove.l\t%s,%s\n",mregnames[dy],mregnames[t2]);
      emit(f,"\tswap\t%s\n",mregnames[t1]);
      emit(f,"\tswap\t%s\n",mregnames[t2]);
      emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[t1]);
      emit(f,"\tmulu.w\t%s,%s\n",mregnames[dx],mregnames[t2]);
      emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[dx]);
      emit(f,"\tadd.w\t%s,%s\n",mregnames[t2],mregnames[t1]);
      emit(f,"\tswap\t%s\n",mregnames[t1]);
      emit(f,"\tclr.w\t%s\n",mregnames[t1]);
      emit(f,"\tadd.l\t%s,%s\n",mregnames[t1],mregnames[dx]);
      if(zreg!=dx) move(f,0,t1,z,0,t);
    }else ierror(0);
    return;
  }
  if(c==MULT){
    /*  das duerfte nur der Aesthetik dienen... */
    if(t&UNSIGNED) 
      emit(f,"\tmulu.%c\t",x_t[t&NQ]);
    else 
      emit(f,"\tmuls.%c\t",x_t[t&NQ]);
    if((t&NQ)<=SHORT) cc_set=0;
  }
  if(c==DIV||(c==MOD&&ISHWORD(t))){
    if(t&UNSIGNED){
      if(ISHWORD(t)) emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
      emit(f,"\tdivu.%c\t",x_t[t&NQ]);
    }else{
      if(ISHWORD(t)) emit(f,"\text.l\t%s\n",mregnames[zreg]);
      emit(f,"\tdivs.%c\t",x_t[t&NQ]);
    }
  }  
  if(qreg) 
    emit(f,"%s",mregnames[qreg]); 
  else 
    emit_obj(f,q,t);
  emit(f,",");
  /*  eigentlich muss zreg!=0 sein...     */
  if(zreg) 
    emit(f,"%s",mregnames[zreg]); 
  else 
    emit_obj(f,z,t);
  emit(f,"\n");
  if(c==MOD){
    emit(f,"\tswap\t%s\n",mregnames[zreg]);
    cc_set=0;
  }
}
static IC *am_freedreg[9],*am_shiftdreg[9];
static IC *am_dist_ic[9],*am_dreg_ic[9],*am_use[9];
/*  am_dist_ic und am_dreg_ic werden auch fuer (ax)+ benutzt    */
static long am_dist[9],am_dreg[9],am_base[9],am_inc[9],am_skal[9],am_dbase[9];
#define AMS sizeof(AddressingMode)

static int mopsize(IC *p,int reg)
/*  Liefert die Groesse in Bytes, mit der im IC auf (reg) zugegriffen wird. */
{
    int c=p->code;
    if(c==ADDI2P||c==SUBIFP){
        if((p->q2.flags&REG)&&p->q2.reg==reg)
            return zm2l(sizetab[p->typf&NQ]);
        return 4;
    }
    if(c==CONVERT){
        if((p->z.flags&REG)&&p->z.reg==reg)
          return zm2l(sizetab[p->typf&NQ]);
        else
          return zm2l(sizetab[p->typf2&NQ]);
    }
    return zm2l(sizetab[p->typf&NQ]);
}
static void clear_am(int reg)
/*  loescht Werte fuer erweiterte Adressierungsarten fuer Register reg  */
{
    if(reg<0||reg>d7) ierror(0);
    if(DEBUG&32) printf("clear_am(%s)\n",mregnames[reg]);
    if(reg<=8){
        am_dist_ic[reg]=am_dreg_ic[reg]=am_use[reg]=0;
        am_dist[reg]=am_dreg[reg]=am_base[reg]=am_inc[reg]=0;
    }else{
        reg-=8;
        am_freedreg[reg]=am_shiftdreg[reg]=0;
        am_skal[reg]=am_dbase[reg]=0;
    }
}
static void mod_reg(int r)
{
  int i;
  for(i=1;i<=8;i++){
    if((!am_use[i]&&am_base[i]==r)||(am_dreg[i]&127)==r)
      clear_am(i);
  }
#if 0
  if(r>=9&&r<=16){
    for(i=9;i<=16;i++){
      if(am_dbase[i-8]==r)
	clear_am(i);
    }
  }
#endif
}
/* return non-zero if IC is implemented by a function call */
static int islibcall(IC *p)
{
  int c=p->code,t=p->typf/NQ;
  if((c==DIV||c==MOD)&&CPU<68020)
    return 1;
  if(t==LLONG&&c!=ADD&&c!=SUB&&c!=OR&&c!=AND&&c!=XOR&&c!=COMPARE)
    return 1;
  if(ISFLOAT(t)&&FPU<=68000)
    return 1;
  if(c==CONVERT){
    if(t==LLONG||ISFLOAT(t)) 
      return 1;
    t=p->typf2&NQ;
    if(t==LLONG||ISFLOAT(t))
      return 1;
  }
  return 0;
}

static int new_peephole(IC *first)
{
  int localused=0,c,r,t,c2;long sz;
  IC *p,*p2;
  AddressingMode *am;
  for(p=first;p;p=p->next){
    int c=p->code;
    if(!localused){
      if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset))
	localused=1;
      if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset))
	localused=1;
      if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset))
	localused=1;
      if(DEBUG&32&&localused==1) printf("localused=1\n");
    }
    /* -(ax) */
    if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=8&&isconst(q2)){
      r=p->q1.reg;
      eval_const(&p->q2.val,q2typ(p));
      sz=zm2l(vmax);
      if(sz==1||sz==2||sz==4||sz==8){
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)&&(c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){
	    t=(q1typ(p2)&NQ);
	    if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
	      p2->q1.am=am=mymalloc(sizeof(*am));
	      p2->q1.val.vmax=l2zm(0L);
	      am->basereg=r;
	      am->dist=0;
	      am->skal=-2;
	      am->dreg=0;
	      p->code=NOP;
	      p->q1.flags=p->q2.flags=p->z.flags=0;
	      break;
	    }
	  }
	  if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)&&(!(p2->z.flags&REG)||p2->z.reg!=r)){
	    t=(q2typ(p2)&NQ);
	    if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
	      p2->q2.am=am=mymalloc(sizeof(*am));
	      p2->q2.val.vmax=l2zm(0L);
	      am->basereg=r;
	      am->dist=0;
	      am->skal=-2;
	      am->dreg=0;
	      p->code=NOP;
	      p->q1.flags=p->q2.flags=p->z.flags=0;
	      break;
	    }
	  }
	  if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags&REG)||p2->q2.reg!=r)&&(!(p2->q1.flags&REG)||p2->q1.reg!=r)){
	    t=(ztyp(p2)&NQ);
	    if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))&&!islibcall(p2)){
	      p2->z.am=am=mymalloc(sizeof(*am));
	      p2->z.val.vmax=l2zm(0L);
	      am->basereg=r;
	      am->dist=0;
	      am->skal=-2;
	      am->dreg=0;
	      p->code=NOP;
	      p->q1.flags=p->q2.flags=p->z.flags=0;
	      break;
	    }
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
	}
      }
    }
    /* (ax)+ in q1 */
    if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg<=8&&(c!=CONVERT||(q1typ(p)&NQ)<=(ztyp(p)&NQ))){
      t=(q1typ(p)&NQ);
      sz=zm2l(sizetab[t]);
      r=p->q1.reg;
      if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
	    eval_const(&p2->q2.val,q2typ(p2));
	    if(zmeqto(vmax,l2zm(sz))){
	      p->q1.am=am=mymalloc(sizeof(*am));
	      p->q1.val.vmax=l2zm(0L);
	      am->basereg=r;
	      am->dist=0;
	      am->skal=-1;
	      am->dreg=0;
	      p2->code=NOP;
	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
	      break;
	    }
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
	  if(p2->q1.am&&p2->q1.am->basereg==r) break;
	  if(p2->q2.am&&p2->q2.am->basereg==r) break;
	  if(p2->z.am&&p2->z.am->basereg==r) break;
	}
      }
    }
    /* (ax)+ in q2 */
    if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg<=8){
      t=(q2typ(p)&NQ);
      sz=zm2l(sizetab[t]);
      r=p->q2.reg;
      if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||p->z.reg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
	    eval_const(&p2->q2.val,q2typ(p2));
	    if(zmeqto(vmax,l2zm(sz))){
	      p->q2.am=am=mymalloc(sizeof(*am));
	      p->q2.val.vmax=l2zm(0L);
	      am->basereg=r;
	      am->dist=0;
	      am->skal=-1;
	      am->dreg=0;
	      p2->code=NOP;
	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
	      break;
	    }
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
	  if(p2->q1.am&&p2->q1.am->basereg==r) break;
	  if(p2->q2.am&&p2->q2.am->basereg==r) break;
	  if(p2->z.am&&p2->z.am->basereg==r) break;
	}
      }
    }
    /* (ax)+ in z */
    if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg<=8){
      t=(ztyp(p)&NQ);
      sz=zm2l(sizetab[t]);
      r=p->z.reg;
      if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||p->q2.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)){
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){
	    eval_const(&p2->q2.val,q2typ(p2));
	    if(zmeqto(vmax,l2zm(sz))){
	      p->z.am=am=mymalloc(sizeof(*am));
	      p->z.val.vmax=l2zm(0L);
	      am->basereg=r;
	      am->dist=0;
	      am->skal=-1;
	      am->dreg=0;
	      p2->code=NOP;
	      p2->q1.flags=p2->q2.flags=p2->z.flags=0;
	      break;
	    }
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
	  if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
	  if((p2->z.flags&REG)&&p2->z.reg==r) break;
	  if(p2->q1.am&&p2->q1.am->basereg==r) break;
	  if(p2->q2.am&&p2->q2.am->basereg==r) break;
	  if(p2->z.am&&p2->z.am->basereg==r) break;
	}
      }
    }
    /* d(ax) (+d(ax,dy)) */
    if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&p->z.reg<=8&&(p->q2.flags&(KONST|DREFOBJ))==KONST){
      int base,idx=-1;zmax of;obj *o;
      IC *idx_ic=0,*free_idx=0,*free_base=0,*use=0;
      eval_const(&p->q2.val,p->typf);
      if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax;
      if(CPU>=68020||(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L)))){
	r=p->z.reg;
	if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r;
	o=0;
	for(p2=p->next;p2;p2=p2->next){
	  c2=p2->code;
	  if(!idx_ic&&c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg>=d0&&p2->q2.reg<fp0){
	    if(CPU>=68020||(zmleq(of,l2zm(127L))&&zmleq(l2zm(-128L),of))){
	      idx=p2->q2.reg;
	      idx_ic=p2;
	      continue;
	    }
	  }
	  if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	  if(!use&&idx_ic&&c2==FREEREG&&p2->q1.reg==idx){
	    free_idx=p2;
	    continue;
	  }
	  if(!use&&c2==FREEREG&&p2->q1.reg==base){
	    free_base=p2;
	    continue;
	  }
	  if(idx_ic){
	    if((p2->q1.flags&REG)&&p2->q1.reg==idx) break;
	    if((p2->q2.flags&REG)&&p2->q2.reg==idx) break;
	    if((p2->z.flags&REG)&&p2->z.reg==idx) break;
	    if(p2->q1.am&&(p2->q1.am->dreg&127)==idx) break;
	    if(p2->q2.am&&(p2->q2.am->dreg&127)==idx) break;
	    if(p2->z.am&&(p2->z.am->dreg&127)==idx) break;
	    if(c2==ALLOCREG&&p2->q1.reg==idx) break;
	  }

	  if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){
	    if(o) break;
	    o=&p2->q1;
	    use=p2;
	    continue;
	  }

	  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) break;
	      o=&p2->q1;
	      use=p2;
	    }
	    if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
	      if(o) break;
	      o=&p2->q2;
	      use=p2;
	    }
	    if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){

	      if(o) break;
	      if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break;
	      o=&p2->z;
	      use=p2;
	    }
	  }
	  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));
		o->val.vmax=l2zm(0L);
		am->basereg=base;
		am->dist=zm2l(of);
		am->skal=0;
		if(free_base) move_IC(use,free_base);
		if(idx_ic){
		  am->dreg=idx;
		  if(ISHWORD(idx_ic->typf)) am->dreg|=128;
		  if(free_idx) move_IC(use,free_idx);
		  idx_ic->code=NOP;
		  idx_ic->q1.flags=idx_ic->q2.flags=idx_ic->z.flags=0;
		}else
		  am->dreg=0;
		if(isreg(q1)&&p->q1.reg<=8){
		  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];
		}
		if(!(o->flags&DREFOBJ)){
		  o->flags|=DREFOBJ;
		  if(use->code==PUSH)
		    use->code=PEA;
		  else if(use->code==ASSIGN)
		    use->code=LEA;
		  else
		    ierror(0);
		}
	      }
	      break;
	    }
	    if(c2!=FREEREG&&m==base) break;
	    continue;
	  }
        }
      }
    }
    /* (ax,dy) (+d(ax,dy)) */
    if(c==ADDI2P&&isreg(q2)&&p->q2.reg>=d0&&isreg(z)&&p->z.reg<=8&&(isreg(q1)||p->q2.reg!=p->z.reg)){
      int base,idx;obj *o;
      long dist=0;
      IC *free_idx=0,*free_base=0,*use=0,*off=0;
      r=p->z.reg;idx=p->q2.reg;
      if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r;
      o=0;
      for(p2=p->next;p2;p2=p2->next){
        c2=p2->code;
	if(!off&&(c2==ADDI2P||c2==SUBIFP)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){
	  eval_const(&p2->q2.val,p2->typf);
	  if(c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
	  if(CPU>=68020||(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax))){
	    dist=zm2l(vmax);
	    off=p2;
	    continue;
	  }
	}
	
        if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;



	if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){
	  if(o) break;

	  o=&p2->q1;
	  use=p2;
	  continue;
	}

        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==ALLOCREG&&(p->q1.reg==idx||p->q1.reg==base)) break;
	if(!use&&c2==FREEREG&&p2->q1.reg==base) free_base=p2;
	if(!use&&c2==FREEREG&&p2->q1.reg==idx) free_idx=p2;


        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||(q1typ(p2)&NQ)==LLONG) break;
            o=&p2->q1;use=p2;
          }
          if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){
            if(o||(q2typ(p2)&NQ)==LLONG) break;
            o=&p2->q2;use=p2;
          }
          if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){
            if(o||(ztyp(p2)&NQ)==LLONG) break;
	    if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break;

            o=&p2->z;use=p2;
          }
        }
        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){
	    /* do not use addressing mode for libcalls */
	    if(FPU<=68000&&o&&o==&use->z&&(ISFLOAT(use->typf)||ISFLOAT(use->typf2))&&use->code!=ASSIGN)
	      break;
            if(o){
              o->am=am=mymalloc(sizeof(*am));
	      o->val.vmax=l2zm(0L);
              am->basereg=base;
              am->dreg=idx;
	      am->dist=dist;
	      am->skal=0;
	      if(ISHWORD(q2typ(p))) am->dreg|=128;
	      if(isreg(q1)&&p->q1.reg<=8){
		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];
	      }
	      if(off){
		off->code=NOP;
		off->q1.flags=off->q2.flags=off->z.flags=0;
	      }
	      if(!use) ierror(0);
	      if(free_idx) move_IC(use,free_idx);
	      if(free_base) move_IC(use,free_base);
	      if(free_idx&&use->next!=free_idx&&use->next->next!=free_idx) ierror(0);
	      if(free_base&&use->next!=free_base&&use->next->next!=free_base) ierror(0);
	      if(!(o->flags&DREFOBJ)){
		o->flags|=DREFOBJ;
		if(use->code==PUSH)
		  use->code=PEA;
		else if(use->code==ASSIGN)
		  use->code=LEA;
		else
		  ierror(0);
	      }		   
	    }

            break;
          }
          if(c2!=FREEREG&&m==base) break;
          continue;
        }
      }
    }
    

  }

  /* do an additional pass to search for scaled addressing-modes */
  if(CPU>=68020){
    for(p=first;p;p=p->next){
      c=p->code;t=p->typf;
      if((c==MULT||c==LSHIFT)&&isconst(q2)&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(t)&&(t&NQ)<=LONG){
	unsigned long ul;
	r=p->z.reg;
	eval_const(&p->q2.val,q2typ(p));
	ul=zum2ul(vumax);
	if(c==LSHIFT){
	  if(ul<=3)
	    ul=1<<ul;
	  else
	    ul=0;
	}
	if(ul==2||ul==4||ul==8){
	  AddressingMode *amuse=0;
	  IC *free_src=0,*free_rsrc=0,*use=0;
	  int src_mod=0;
	  for(p2=p->next;p2;p2=p2->next){
	    c2=p2->code;
	    if(!use&&p2->q1.am&&p2->q1.am->skal==0&&(p2->q1.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q2.flags&REG)||p2->q2.flags!=r)&&(!(p2->z.flags&REG)||p2->z.flags!=r)){
	      amuse=p2->q1.am;
	      use=p2;
	      continue;
	    }
	    if(!use&&p2->q2.am&&p2->q2.am->skal==0&&(p2->q2.am->dreg&127)==r&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q1.flags&REG)||p2->q1.flags!=r)&&(!(p2->z.flags&REG)||p2->z.flags!=r)){
	      amuse=p2->q2.am;
	      use=p2;
	      continue;
	    }
	    if(!use&&p2->z.am&&p2->z.am->skal==0&&(p2->z.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!(p2->q2.flags&REG)||p2->q2.flags!=r)&&(!(p2->z.flags&REG)||p2->z.flags!=r)){
	      amuse=p2->z.am;
	      use=p2;
	      continue;
	    }
	    if(!use&&c2==FREEREG&&p2->q1.reg==r){
	      free_src=p2;
	      continue;
	    }
	    if(!use&&c2==FREEREG&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7&&p2->q1.reg==p->q1.reg){
	      free_rsrc=p2;
	      continue;
	    }
	    if(use&&((c2==FREEREG&&p2->q1.reg==r)||((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r))){
	      amuse->skal=ul;
	      if(!src_mod&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7){
		amuse->dreg=p->q1.reg;
		p->code=NOP;
		p->q1.flags=p->q2.flags=p->z.flags=0;
	      }else{
		p->code=ASSIGN;
		p->q2.flags=0;
		p->q2.val.vmax=sizetab[p->typf&NQ];
	      }
	      if(free_src) move_IC(use,free_src);
	      if(free_rsrc) move_IC(use,free_rsrc);
	      break;
	    }
	    if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	    if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
	    if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
	    if((p2->z.flags&REG)&&p2->z.reg==r) break;
	    if(p2->q1.am&&(p2->q1.am->dreg&127)==r) break;
	    if(p2->q2.am&&(p2->q2.am->dreg&127)==r) break;
	    if(p2->z.am&&(p2->z.am->dreg&127)==r) break;
	    if((p2->z.flags&(REG|DREFOBJ))==REG&&(p->q1.flags&(REG|DREFOBJ))&&p2->z.reg==p->q1.reg)
	      src_mod=1;
	  }
	}
      }
    }	    
  }

  /* another pass to remove unnecessary ALLOCREGs */
  for(p=first;p;p=p->next){
    if(p->code==ALLOCREG){
      r=p->q1.reg;
      for(p2=p->next;p2;p2=p2->next){
	c2=p2->code;
	if(c2==ALLOCREG&&p2->q1.reg==r) ierror(0);
	if(c2==FREEREG&&p2->q1.reg==r){
	  p->code=NOP;
	  p->q1.flags=0;
	  p2->code=NOP;
	  p2->q1.flags=0;
	  savedalloc++;
	  break;
	}
	if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break;
	if((p2->q1.flags&REG)&&p2->q1.reg==r) break;
	if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
	if((p2->z.flags&REG)&&p2->z.reg==r) break;
	if((am=p2->q1.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
	if((am=p2->q2.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
	if((am=p2->z.am)&&(am->basereg==r||(am->dreg&127)==r)) break;
      }
    }
  }

  return localused;
}
static int addressing(IC *p)
/*  Untersucht ICs auf erweiterte Addresierungsarten    */
{
    int count,localused=0;
    if(!OLDPEEPHOLE) return new_peephole(p);
    if(DEBUG&32) printf("addressing() started\n");
    for(count=1;count<=16;count++) clear_am(count);
    for(count=0;p;p=p->next){
        int c=p->code,q1reg,q2reg,zreg;
        if(p->q1.flags&REG) q1reg=p->q1.reg; else q1reg=0;
        if(p->q2.flags&REG) q2reg=p->q2.reg; else q2reg=0;
        if(p->z.flags&REG) zreg=p->z.reg; else zreg=0;
        if(c==ADDI2P) c=ADD;
        if(c==SUBIFP) c=SUB;
        if(DEBUG&32) pric2(stdout,p);
        if(!localused){
            if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset))
                localused=1;
            if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset))
                localused=1;
            if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset))
                localused=1;
            if(DEBUG&32&&localused==1) printf("localused=1\n");
        }
        if(c==ASSIGN&&isreg(q1)&&isreg(z)&&q1reg>=1&&q1reg<=8&&zreg>=1&&zreg<=8){
        /*  fuer (ax)+  */
            int i;
            clear_am(q1reg);
            for(i=1;i<=8;i++)
                if(am_base[i]==zreg||am_base[i]==q1reg) clear_am(i);
	    mod_reg(zreg);
            clear_am(zreg);am_base[zreg]=q1reg;am_dreg_ic[zreg]=p;
            if(DEBUG&32) printf("move %s,%s found\n",mregnames[q1reg],mregnames[zreg]);
            continue;
        }
        if(c==MULT&&CPU>=68020&&isconst(q2)&&isreg(z)&&zreg>=d0&&zreg<=d7){
        /*  dx=a*const, fuer Skalierung    */
            int dreg=zreg-8;
            if(dreg<1||dreg>8) ierror(0);
            if(q1reg>=1&&q1reg<=d7){
                if(isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg);
                if((p->q1.flags&DREFOBJ)&&q1reg<=8&&am_use[q1reg]) clear_am(q1reg);
            }
            if(DEBUG&32) printf("mult x,const->dreg found\n");
	    mod_reg(zreg);
            if(am_skal[dreg]) {clear_am(zreg);continue;}
            eval_const(&p->q2.val,p->typf);
            am_skal[dreg]=zm2l(vmax);
            if(am_skal[dreg]!=2&&am_skal[dreg]!=4&&am_skal[dreg]!=8)
                {clear_am(zreg);continue;}
            am_shiftdreg[dreg]=p;
            if(isreg(q1)&&q1reg>=d0&&q1reg<=d7) am_dbase[dreg]=q1reg; else am_dbase[dreg]=zreg;
	    if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)) clear_am(p->q1.reg);
            if(DEBUG&32) printf("is usable\n");
            continue;
        }
        if((c==ADD||c==SUB)&&isconst(q2)&&zreg>=1&&zreg<=8&&isreg(z)){
        /*  add ax,#const,ax->az Test auf d8/16 fehlt noch (nicht mehr) */
            long l;
            if(zreg<1||zreg>8) ierror(0);
            eval_const(&p->q2.val,p->typf);
            l=zm2l(vmax);
            if(c==SUB) l=-l;
	    mod_reg(zreg);
            if(q1reg==zreg&&isreg(q1)&&am_use[zreg]&&(l==1||l==2||l==4)){
                if(l==mopsize(am_use[zreg],zreg)&&(am_use[zreg]->code!=CONVERT||zmleq(sizetab[am_use[zreg]->typf2&NQ],sizetab[am_use[zreg]->typf&NQ]))){
                    IC *op=am_use[zreg];
                    obj *o=0;
                    if(DEBUG&32){ printf("found postincrement:\n");pric2(stdout,op);pric2(stdout,p);}
                    if((op->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q1.reg==zreg){
                        if(DEBUG&32) printf("q1\n");
                        o=&op->q1;
                    }
                    if((op->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q2.reg==zreg){
                        if(DEBUG&32) printf("q2\n");
                        if(o) continue; else o=&op->q2;
                    }
                    if((op->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->z.reg==zreg){
                        if(DEBUG&32) printf("z\n");
                        if(o) continue; else o=&op->z;
                    }
                    o->am=mymalloc(AMS);
                    o->am->basereg=zreg;
                    o->am->skal=-1;
                    o->am->dist=0;
                    o->am->dreg=0;
                    p=p->prev;
                    remove_IC(p->next);
                    clear_am(zreg);continue;
                }
            }
            clear_am(q1reg);
            if(am_dist[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Offset */
            if(isreg(q1)&&q1reg==zreg&&(l==1||l==2||l==4)){
            /*  ax+=const, fuer (ax)+   */
                int i,f;
                for(f=0,i=1;i<=8;i++){
                    if(am_base[i]==zreg&&!am_dreg[i]&&!am_dist[i]){
                        if(f) ierror(0);
                        am_inc[i]=l;am_dist_ic[i]=p;f=i;
                        if(DEBUG&32) printf("inc %s found\n",mregnames[i]);
                    }
                }
                if(f) continue;
            }
            am_dist[zreg]=l;
            if(DEBUG&32) printf("dist=%ld\n",am_dist[zreg]);
            if(CPU<68020){
            /*  bei <68020 darf der Offset nur 16bit oder 8bit bei dreg sein */
                if((am_dreg[zreg]&&(am_dist[zreg]<-128||am_dist[zreg]>127))||am_dist[zreg]<-32768||am_dist[zreg]>32767)
                    {clear_am(zreg);continue;}
            }
            am_dist_ic[zreg]=p;
            if(am_base[zreg]){
                if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;}
            }else{
                if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg;
                if(DEBUG&32) printf("%s potential base for %s\n",mregnames[am_base[zreg]],mregnames[zreg]);
            }
            if(DEBUG&32) printf("add #const,%s found\n",mregnames[zreg]);
            continue;
        }
        if(c==ADD&&q2reg>=d0&&q2reg<=d7&&isreg(q2)&&zreg>=1&&zreg<=8&&isreg(z)&&(p->q1.flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){
        /*  add ax,dy->az   */
            int i;
            if(zreg<1||zreg>8) ierror(0);
            for(i=1;i<=8;i++)
                if(am_dreg[i]==q2reg){ clear_am(q2reg);clear_am(i);}
            clear_am(q1reg);
	    mod_reg(zreg);
            if(am_dreg[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Regoffset */
            if(CPU<68020&&(am_dist[zreg]<-128||am_dist[zreg]>127))
                {clear_am(zreg);continue;} /* bei <68020 nur 8bit Offset */
            am_dreg[zreg]=q2reg;
            if(ISHWORD(p->typf)) am_dreg[zreg]|=128; /* dx.w statt dx.l */
            am_dreg_ic[zreg]=p;
            if(am_base[zreg]){
                if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;}
            }else{
                if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg;
            }
            if(DEBUG&32) printf("add %s,%s found\n",mregnames[q2reg],mregnames[zreg]);
            continue;
        }
        if(c==FREEREG){
        /*  wir koennen den Modus tatsaechlich benutzen */
            AddressingMode *am;IC *p1,*p2;int dreg,i;
            if(DEBUG&32) printf("freereg %s found\n",mregnames[p->q1.reg]);
            if(q1reg>=d0&&q1reg<=d7) {am_freedreg[q1reg-8]=p;if(DEBUG&32) printf("freedreg[%d]=%lx\n",q1reg-8,(long)p);}
            if(q1reg>8) continue;
            if(DEBUG&32) printf("use=%p,base=%p,dist=%p,dreg=%p\n",(void*)am_use[q1reg],(void*)am_base[q1reg],(void*)am_dist[q1reg],(void*)am_dreg[q1reg]);
            for(i=1;i<=8;i++) if(am_base[i]==q1reg) clear_am(i);
            if(!am_use[q1reg]||!am_base[q1reg]) continue;
            if(am_inc[q1reg]&&am_inc[q1reg]!=mopsize(am_use[q1reg],q1reg))
                {clear_am(q1reg);continue;}
            if(!am_dist[q1reg]&&!am_dreg[q1reg]&&!am_inc[q1reg]) continue;
            p1=am_dist_ic[q1reg];p2=am_dreg_ic[q1reg];
            if(DEBUG&32){
                printf("could really use %s\n",mregnames[q1reg]);
                if(p1) pric2(stdout,p1);
                if(p2) pric2(stdout,p2);
            }
            if(am_base[q1reg]==q1reg){
                if(p1) {p1->q2.flags=0;p1->code=ASSIGN;p1->q2.val.vmax=l2zm(4L);p1->typf=POINTER;}
                if(p2) {p2->q2.flags=0;p2->code=ASSIGN;p2->q2.val.vmax=l2zm(4L);p2->typf=POINTER;}
            }else{
                if(p1) remove_IC(p1);
                if(p2) remove_IC(p2);
            }
            dreg=(am_dreg[q1reg]&127)-8;
            am=mymalloc(AMS);
            am->skal=0;
            am->basereg=am_base[q1reg];
            am->dist=am_dist[q1reg];
            am->dreg=am_dreg[q1reg];
            if(am_inc[q1reg]) am->skal=-1;
            if(dreg>0){
                /*  bei (d,ax,dy) das freereg dy nach hinten verschieben    */
                if(dreg<1||dreg>8) ierror(0);
                if(p1=am_freedreg[dreg]){
                    if(DEBUG&32){
                        printf("freereg %s moved from %p to %p\n",mregnames[dreg+8],(void*)p1,(void*)p);
                        pric2(stdout,p1);
                    }
                    if(p1->code!=FREEREG){ierror(0);printf("freereg[%d]=%p\n",dreg,(void*)p1);continue;}
                    if(!p1->next) {ierror(0);continue;}
                    if(!p1->prev) {ierror(0);continue;}
                    p1->prev->next=p1->next;
                    p1->next->prev=p1->prev;
                    p1->next=p->next;
                    p1->prev=p;
                    if(p->next) p->next->prev=p1;
                    p->next=p1;
                }
                if(am_skal[dreg]){
                /*  Skalierung bearbeiten   */
                    if(p1){
                        am->skal=am_skal[dreg];
                        am->dreg=am_dbase[dreg];
                        p1=am_shiftdreg[dreg];
                        if(DEBUG&32) pric2(stdout,p1);
                        if(am_dbase[dreg]==dreg+8){
                            p1->code=ASSIGN;p1->q2.flags=0;p1->q2.val.vmax=sizetab[p1->typf&NQ];
                        }else remove_IC(p1);
                    }
                    clear_am(dreg+8);
                }
            }
            /*  das hier duerfte unnoetig sein, da die Adressierungsart in  */
            /*  einem IC eigentlich hoechstens einmal vorkommen darf        */
            if(q1reg<0||q1reg>8) ierror(0);
            p1=am_use[q1reg];
            if(DEBUG&32) pric2(stdout,p1);
            if(p1->code==PUSH&&p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(REG))){
                p1->q1.am=mymalloc(AMS);
                memcpy(p1->q1.am,am,AMS);
                p->q1.val.vmax=l2zm(0L);
                p1->code=PEA;
                if(DEBUG&32) printf("q1 patched\n");
            }
            if(p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
                p1->q1.am=mymalloc(AMS);
                memcpy(p1->q1.am,am,AMS);
                p1->q1.val.vmax=l2zm(0L);
                if(DEBUG&32) printf("q1 patched\n");
            }
            if(p1->q2.reg==q1reg&&((p1->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
                p1->q2.am=mymalloc(AMS);
                memcpy(p1->q2.am,am,AMS);
                p1->q2.val.vmax=l2zm(0L);
                if(DEBUG&32) printf("q2 patched\n");
            }
            if(p1->z.reg==q1reg&&((p1->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
                p1->z.am=mymalloc(AMS);
                memcpy(p1->z.am,am,AMS);
                p1->z.val.vmax=l2zm(0L);
                if(DEBUG&32) printf("z patched\n");
            }
            free(am);count++;
            clear_am(q1reg);
            continue;
        }
        if(c>=LABEL&&c<=BRA){
            int i;      /*  ueber basic blocks hinweg unsicher  */
            for(i=1;i<=16;i++) clear_am(i);
            continue;
        }
        /*  Wenn Libraryaufrufe noetig sind (floating point ohne FPU oder   */
        /*  32bit mul/div/mod ohne 020+) keine Addressierungsarten nutzen   */
        if(FPU<=68000&&(ISFLOAT(p->typf)||(p->code==CONVERT&&ISFLOAT(p->typf2)))){
            int i;
            for(i=1;i<=16;i++) clear_am(i);
            continue;
        }
        if(CPU<68020&&(c==DIV||c==MOD)){
            int i;
            for(i=1;i<=16;i++) clear_am(i);
            continue;
        }
        if(c==PUSH&&((p->q1.flags&(DREFOBJ|REG))==REG&&q1reg<=8&&!am_use[q1reg]&&(am_inc[q1reg]||am_dist[q1reg]||am_dreg[q1reg]))){
            if(q1reg<1||q1reg>8) ierror(0);
            if(am_inc[q1reg]&&am_inc[q1reg]!=msizetab[p->typf&NQ]) clear_am(q1reg); else am_use[q1reg]=p;
            if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]);
            continue;
        }
        if(((p->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q1reg<=8)){
            if(q1reg<1||q1reg>8) ierror(0);
            if(am_use[q1reg]&&(am_use[q1reg]!=p||am_inc[q1reg])) clear_am(q1reg); else am_use[q1reg]=p;
            if(am_inc[q1reg]&&am_inc[q1reg]!=sizetab[p->typf&NQ]) clear_am(q1reg);
            if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]);
        }
        if(((p->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q2reg<=8)){
            if(q2reg<1||q2reg>8) ierror(0);
            if(am_use[q2reg]&&(am_use[q2reg]!=p||am_inc[q2reg])) clear_am(q2reg); else am_use[q2reg]=p;
            if(am_inc[q2reg]&&am_inc[q2reg]!=sizetab[p->typf&NQ]) clear_am(q2reg);
            if(DEBUG&32) printf("use of %s found\n",mregnames[q2reg]);
        }
        if(((p->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&zreg<=8)){
            if(zreg<1||zreg>8) ierror(0);
            if(am_use[zreg]&&(am_use[zreg]!=p||am_inc[zreg])) clear_am(zreg); else am_use[zreg]=p;
            if(am_inc[zreg]&&am_inc[zreg]!=sizetab[p->typf&NQ]) clear_am(zreg);
            if(DEBUG&32) printf("use of %s found\n",mregnames[zreg]);
        }
        if(c==ALLOCREG){
        /*  allocreg zaehlt als zerstoerung von reg */
            p->z.flags=REG;
            p->z.reg=zreg=q1reg=p->q1.reg;
        }
        if(q1reg>=1&&q1reg<=d7&&isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg);
        if(q2reg>=1&&q2reg<=d7&&isreg(q2)&&(q2reg>8||am_use[q2reg]!=p)) clear_am(q2reg);
        if(zreg>=1&&zreg<=d7&&isreg(z)) clear_am(zreg);
        if(isreg(z)&&zreg<=d7){
        /*  schauen, ob eines der Register ueberschrieben wird  */
        /*  wohl noch sehr langsam                              */
	  mod_reg(zreg);
        }
        if(c==ALLOCREG) p->z.flags=0;
    }
    if(DEBUG&1) printf("%d addressingmodes used, localused=%d\n",count,localused);
    return localused;
}
static int alignment(obj *o)
/*  versucht rauszufinden, wie ein Objekt alignet ist   */
{
    /*  wenn es keine Variable ist, kann man nichts aussagen    */
    long os;
    if(o->am||!(o->flags&VAR)) return -1;
    if((o->flags&DREFOBJ)){
      if(!(o->v->flags&NOTTYPESAFE)||!ISPOINTER(o->v->vtyp->flags)||zmeqto(falign(o->v->vtyp->next),l2zm(1L)))
	return -1;
      else
	return 0;
    }
    if(!o->v) ierror(0);
    os=zm2l(o->val.vmax);
    if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
        if(!USEFRAMEPOINTER&&!vlas){
            if(!zmleq(l2zm(0L),o->v->offset)) os=os+loff-zm2l(o->v->offset);
             else              os=os+zm2l(o->v->offset);
        }else{
            if(!zmleq(l2zm(0L),o->v->offset)) os=os-zm2l(o->v->offset);
             else              os=os-(zm2l(o->v->offset)+zm2l(szof(o->v->vtyp)));
        }
    }else{
      if(!(o->v->flags&(TENTATIVE|DEFINED))&&zmeqto(falign(o->v->vtyp),l2zm(1L)))
	return -1;
    }
    
    return os&3;
}
static void stored0d1(FILE *f,obj *o,int t)
{
  if((o->flags&(REG|DREFOBJ))==REG){
    if(!reg_pair(o->reg,&rp)) ierror(0);
    if(o->reg==25) return;
    emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[rp.r1]);
    emit(f,"\tmove.l\t%s,%s\n",mregnames[10],mregnames[rp.r2]);
  }else{
    if(cf&&(o->flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){
      emit(f,"\tmove.l\t%s,",mregnames[d0]);
      emit_obj(f,o,t);
      emit(f,"\n");
      emit(f,"\tmove.l\t%s,",mregnames[d1]);
      o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
      emit_obj(f,o,t);
      o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
      emit(f,"\n");
    }else{
      emit(f,"\tmovem.l\t%s,",mregnames[d0d1]);
      emit_obj(f,o,t);
      emit(f,"\n");
    }
  }
}
static void loadd0d1(FILE *f,obj *o,int t)
{
  if((o->flags&(REG|DREFOBJ))==REG){
    if(!reg_pair(o->reg,&rp)) 
      ierror(0);
    if(o->reg==25) return;
    emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r1],mregnames[d0]);
    emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r2],mregnames[10]);
  }else{
    if(cf){
      emit(f,"\tmove.l\t");
      emit_obj(f,o,t);
      emit(f,",%s\n",mregnames[d0]);
      emit(f,"\tmove.l\t");
      o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
      emit_obj(f,o,t);
      o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
      emit(f,",%s\n",mregnames[d1]);
    }else{
      emit(f,"\tmovem.l\t");
      emit_obj(f,o,t);
      emit(f,",%s\n",mregnames[d0d1]);
    }
  }
}
static void assign(FILE *f,IC *p,obj *q,obj *z,int c,long size,int t)
/*  Generiert Code fuer Zuweisungen und PUSH.   */
{
    /*  auch noch sehr fpu-spezifisch   */
  if(FPU<=68000&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&!((q->flags&(KONST|DREFOBJ))==KONST))
    t=LLONG;
  if(ISFLOAT(t)){
    if(q&&(q->flags&(KONST|DREFOBJ))==KONST){
      if(z&&(z->flags&(DREFOBJ|REG))==REG&&z->reg>=fp0&&z->reg<=fp7){
	/*  FP-Konstante->Register (muss immer reinpassen)  */
	if(z->reg>=fp0) emit(f,"\tfmove"); else emit(f,"\tmove");
	emit(f,".%c\t",x_t[t&NQ]);emit_obj(f,q,t);
	emit(f,",%s\n",mregnames[z->reg]);
      }else{
	/*  FP-Konstante->Speicher (evtl. auf zweimal)  */
	int m,r;unsigned char *ip=(unsigned char *)&q->val.vfloat; /* nicht sehr schoen  */
	char *s;
	if(cf&&c==ASSIGN) r=get_reg(f,1,p,0);
	if(GAS) s="0x"; else s="$";
	if(c==PUSH&&(t&NQ)!=FLOAT){
	  emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,-(%s)\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[sp]);
	  push(4);
	}
	emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[0],ip[1],ip[2],ip[3]);
	if(c==ASSIGN){
	  if(cf)
	    emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]);
	  if(isreg(z)&&reg_pair(p->z.reg,&rp))
	    emit(f,"%s",mregnames[rp.r1]);
	  else
	    emit_obj(f,z,t);
	}else{
	  emit(f,"-(%s)",mregnames[sp]);
	  push(4);
	}
	emit(f,"\n");
	if((t&NQ)==FLOAT||c==PUSH) return;
	m=0;
	if(z&&(z->flags&REG)){
	  m=1;z->flags|=D16OFF;
	  z->val.vmax=l2zm(0L);
	}
	vmax=l2zm(4L);
	z->val.vmax=zmadd(z->val.vmax,vmax);
	emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[4],ip[5],ip[6],ip[7]);
	if(cf)
	  emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]);
	if(isreg(z)&&reg_pair(p->z.reg,&rp))
	  emit(f,"%s",mregnames[rp.r2]);
	else
	  emit_obj(f,z,t);
	emit(f,"\n");
	if(m){
	  z->flags&=~D16OFF;vmax=l2zm(4L);
	  z->val.vmax=zmsub(z->val.vmax,vmax);
	}
      }
      return;
    }
    if((q&&(q->flags&REG)&&q->reg>=fp0)||(z&&(z->flags&REG)&&z->reg>=fp0)){
      if(c==ASSIGN&&(q->flags&REG)&&(z->flags&REG)&&q->reg==z->reg) return;
      if(c==ASSIGN){ move(f,q,0,z,0,t);return;}
      emit(f,"\tfmove.%c\t",x_t[t&NQ]);
      emit_obj(f,q,t);
      emit(f,",");
      if(c==PUSH){
	emit(f,"-(%s)",mregnames[sp]);
	push(size);
      } else 
	emit_obj(f,z,t);
      emit(f,"\n");return;
    }
    if(size==8) t=LLONG;
  }
  if((t&NQ)==LLONG){
    if(z&&compare_objects(q,z)) return;
    if(((cf&&c==ASSIGN)||(q->flags&(REG|DREFOBJ))==REG)&&(!z||(z->flags&(REG|DREFOBJ))!=REG)){
      if(cf){
	if(c==ASSIGN){
	  int r;
	  if((q->flags&(REG|DREFOBJ))==REG){
	    if(!reg_pair(q->reg,&rp)) ierror(0);
	    r=rp.r2;
	  }else{
	    r=get_reg(f,1,p,0);
	    emit(f,"\tmove.l\t");
	    emit_lword(f,q);
	    emit(f,",%s\n",mregnames[r]);
	  }
	  emit(f,"\tmove.l\t%s,",mregnames[r]);
	  emit_lword(f,z);
	  emit(f,"\n");
	  if((q->flags&(REG|DREFOBJ))==REG){
	    r=rp.r1;
	  }else{
	    emit(f,"\tmove.l\t");
	    emit_hword(f,q);
	    emit(f,",%s\n",mregnames[r]);
	  }
	  emit(f,"\tmove.l\t%s,",mregnames[r]);
	  emit_hword(f,z);
	  emit(f,"\n");
	}else{
	  emit(f,"\tsubq.l\t#8,%s\n",mregnames[sp]);
	  push(8);
	  emit(f,"\tmovem.l\t%s,(%s)\n",mregnames[q->reg],mregnames[sp]);
	}
      }else{
	emit(f,"\tmovem.l\t%s,",mregnames[q->reg]);
	if(c==ASSIGN){
	  emit_obj(f,z,t);
	}else{
	  emit(f,"-(%s)",mregnames[sp]);
	  push(8);
	}
	emit(f,"\n");
      }
      return;
    }
    if(!cf&&(q->flags&(REG|DREFOBJ))!=REG&&!((q->flags&(KONST|DREFOBJ))==KONST)&&z&&(z->flags&(REG|DREFOBJ))==REG){
      emit(f,"\tmovem.l\t");
      emit_obj(f,q,t);
      emit(f,",%s\n",mregnames[z->reg]);
      return;
    }
    emit(f,"\tmove.l\t");
    emit_lword(f,q);
    emit(f,",");
    if(c==ASSIGN){
      emit_lword(f,z);
    }else{
      emit(f,"-(%s)",mregnames[sp]);
      push(4);
    }
    emit(f,"\n");
    emit(f,"\tmove.l\t");
    emit_hword(f,q);
    emit(f,",");
    if(c==ASSIGN){
      emit_hword(f,z);
    }else{
      emit(f,"-(%s)",mregnames[sp]);
      push(4);
    }
    emit(f,"\n");    
    return;
  }
  if((size==1||size==2||size==4)&&!ISARRAY(t)&&(p->code!=PUSH||zm2l(p->z.val.vmax)!=3)&&((t&NQ)!=CHAR||size==1)){
    if(ISSTRUCT(t)||ISUNION(t)){
      if(p->code==PUSH&&!zmeqto(p->q2.val.vmax,p->z.val.vmax)){
	if(size!=4&&size!=2) ierror(size);
	emit(f,"\tsubq.%s\t#%d,%s\n",cf?"l":"w",size,mregnames[sp]);
	push(size);
	size=zm2l(p->z.val.vmax);
	if(size!=1&&size!=2) ierror(0);
	emit(f,"\tmove.%c\t",size==1?'b':'w');
	emit_obj(f,q,(size==1?CHAR:SHORT));
	emit(f,",(%s)\n",mregnames[sp]);
	return;
      }else{
	if(size==1)
	  t=CHAR;
	else if(size==2)
	  t=SHORT;
	else
	  t=LONG;
      }
    }
    if(c==ASSIGN){move(f,q,0,z,0,t);return;}
    /*  Sonderfall pea  */
    if((q->flags&VARADR)&&c==PUSH){
      emit(f,"\tpea\t");
      q->flags&=~VARADR; emit_obj(f,q,t); q->flags|=VARADR;
      emit(f,"\n"); 
      push(size);
      return;
    }
    emit(f,"\tmove.%c\t",x_s[size]);
    emit_obj(f,q,t);
    emit(f,",");
    if(c==PUSH){
      emit(f,"-(%s)",mregnames[sp]);
      push(size);
    } else 
      emit_obj(f,z,t);
    emit(f,"\n");return;
  }else{
    int a1,a2,qreg,zreg,dreg,loops,scratch=0,down=0;char *cpstr;
    long s=size,osize=size;
    IC *m;
    for(m=p->next;m&&m->code==FREEREG;m=m->next){
      if(q&&m->q1.reg==q->reg) scratch|=1;
      if(z&&m->q1.reg==z->reg) scratch|=2;
    }
    a1=alignment(q);
    if(c!=PUSH)  a2=alignment(z); else a2=0;
    if(a1<0||a2<0) {a1=1;a2=2;}
    if(p->typf2==2||p->typf2==4) {a1=a2=0;}
    if((c==PUSH||(scratch&1))&&(q->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&q->reg>=1&&q->reg<=8&&!q->am){
      qreg=q->reg;
      if(c==PUSH&&(a1&1)==0&&(a2&1)==0)
	emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[q->reg]);
    }else{
      if(c!=ASSIGN&&!regavailable(0))
	qreg=pget_reg(f,0,p,0);
      else
	qreg=get_reg(f,0,p,0);
      if(c==PUSH&&(a1&1)==0&&(a2&1)==0){
	q->flags|=D16OFF; 
	q->val.vmax=zmadd(q->val.vmax,l2zm((long)s));
	emit(f,"\tlea\t");emit_obj(f,q,POINTER);
	q->val.vmax=zmsub(q->val.vmax,l2zm((long)s));
	emit(f,",%s\n",mregnames[qreg]);
      }else{
	emit(f,"\tlea\t");emit_obj(f,q,POINTER);
	emit(f,",%s\n",mregnames[qreg]);
      }	      
    }
    if(c==PUSH){
      if((a1&1)==0&&(a2&1)==0){
	zreg=8;
      }else{
	emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[sp]);
	push(size);
	size=0;
	if(!regavailable(0))
	  zreg=pget_reg(f,0,p,0);
	else
	  zreg=get_reg(f,0,p,0);
	emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[zreg]);
      }
    }else{
      if((scratch&2)&&(z->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&z->reg>=1&&z->reg<=8&&!z->am){
	zreg=z->reg;
      }else{
	zreg=get_reg(f,0,p,0);
	emit(f,"\tlea\t");emit_obj(f,z,POINTER);
	emit(f,",%s\n",mregnames[zreg]);
      }
    }
    /*  wenn Typ==CHAR, dann ist das ein inline_memcpy und wir nehmen   */
    /*  das unguenstigste Alignment an                                  */
    /*if((t&NQ)==CHAR){ a1=1;a2=2;}*/
    
    if(c==PUSH&&(a1&1)==0&&(a2&1)==0){
      cpstr="\tmove.%c\t-(%s),-(%s)\n";
      down=1;
    }else
      cpstr="\tmove.%c\t(%s)+,(%s)+\n";
    
    if((a1&1)&&(a2&1)){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;a1&=~1;a2&=~1;}
    if((a1&2)&&(a2&2)){emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]);s-=2;a1&=~2;a2&=~2;}
    if(!(a1&1)&&!(a2&1)) loops=s/16-1; else loops=s/4-1;
    if(loops>0){
      if(c!=ASSIGN&&!regavailable(1)) dreg=pget_reg(f,1,p,0);
      else dreg=get_reg(f,1,p,0);
      emit(f,"\tmove%s.l\t#%d,%s\n%s%d:\n",quick[loops>=-128&&loops<=127],loops,mregnames[dreg],labprefix,++label);
    }
    if(loops>=0){
      int t;
      if(!(a1&1)&&!(a2&1)) t='l'; else t='b';
      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
      emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]);
    }
    if(loops>0){
      if(!cf&&loops<=32767&&loops>=-32768){
	emit(f,"\tdbra\t%s,%s%d\n",mregnames[dreg],labprefix,label);
      }else{
	emit(f,"\tsubq.l\t#1,%s\n\tbge\t%s%d\n",mregnames[dreg],labprefix,label);
      }
    }
    if(!(a1&1)&&!(a2&1)){
      if(s&8){
	emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
	emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
      }
      if(s&4) emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]);
      if(s&2) emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]);
      if(s&1) emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);
    }else{
      s&=3;
      while(s){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;}
    }
    if(c==PUSH&&qreg==q->reg&&(!(scratch&1))&&!down)
      emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[osize<=8],strshort[osize<=32767],osize,regnames[qreg]);
    if(c==PUSH) push(size);
  }
  return;
}
static int muststore(IC *p,int r)
{
  if(!regs[r])
    return 0;
#if 0
  /* mal bei Gelegenheit testen */
  while(p){
    if(p->code==FREEREG&&p->q1.reg==r)
      return 0;
    if((p->q1.flags&REG)&&p->q1.reg==r)
      return 1;
    if(p->q1.am&&(p->q1.am->basereg==r||(p->q1.am->dreg&127)==r))
      return 1;
    if((p->q2.flags&REG)&&p->q2.reg==r)
      return 1;
    if(p->q2.am&&(p->q2.am->basereg==r||(p->q2.am->dreg&127)==r))
      return 1;
    if(p->z.am&&(p->z.am->basereg==r||(p->z.am->dreg&127)==r))
      return 1;
    if((p->z.flags&REG)&&p->z.reg==r)
      return (p->z.flags&DREFOBJ)!=0;
    if(p->code>=LABEL&&p->code<=BRA)
      return 1;
    p=p->next;
  }
  return 0;
#else
  return 1;
#endif
}

static int store_saveregs;
static void saveregswfp(FILE *f,IC *p,int storefp)
{
    int dontsave;
    store_saveregs=0;
    if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0;
    if(dontsave!= d0&&dontsave!=25&&(muststore(p,d0)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d0],mregnames[sp]);push(4);store_saveregs|=1;}
    if(dontsave!=10&&dontsave!=25&&(muststore(p,d1)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d1],mregnames[sp]);push(4);store_saveregs|=2;}
    if(dontsave!= fp0&&muststore(p,fp0)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp0],mregnames[sp]);push(12);store_saveregs|=16;}
    if(dontsave!= fp1&&muststore(p,fp1)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp1],mregnames[sp]);push(12);store_saveregs|=32;}
    if(dontsave!= a0&&muststore(p,a0)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a0],mregnames[sp]);push(4);store_saveregs|=4;}
    if(dontsave!= a1&&muststore(p,a1)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a1],mregnames[sp]);push(4);store_saveregs|=8;}

}
static void restoreregsa(FILE *f,IC *p)
{
    if(store_saveregs&8) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a1]);pop(4);}
    if(store_saveregs&4) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a0]);pop(4);}
}
static void restoreregsd(FILE *f,IC *p)
{
    int dontsave;
    if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0;
    if(dontsave!=fp1&&(store_saveregs&32)){
      emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp1]);
      pop(12);
    }
    if(dontsave!=fp0&&(store_saveregs&16)){
      emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp0]);
      pop(12);
    }
    if(dontsave!=10&&(store_saveregs&2)){
      if(!GAS&&!PHXASS)
	emit(f,"\topt\tom-\n");
      if(cf)
        emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d1],mregnames[sp]);
      else
	emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d1]);
      pop(4);
      if(!GAS&&!PHXASS)
	emit(f,"\topt\tom+\n");
    }
    if(dontsave!=d0 &&(store_saveregs&1)){
      if(!GAS&&!PHXASS)
	emit(f,"\topt\tom-\n");
      if(cf)
        emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d0],mregnames[sp]);
      else
	emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d0]);
      pop(4);
      if(!GAS&&!PHXASS)
	emit(f,"\topt\tom+\n");
    }
}

/* emits the low word of a long long object */
static void emit_lword(FILE *f,obj *o)
{
  if((o->flags&(REG|DREFOBJ))==REG){
    if(!reg_pair(o->reg,&rp))
      ierror(0);
    emit(f,"%s",mregnames[rp.r2]);
  }else if((o->flags&(KONST|DREFOBJ))==KONST){
    eval_const(&o->val,UNSIGNED|LLONG);
    vumax=zumand(vumax,ul2zum(0xffffffff));
    insert_const(&gval,UNSIGNED|MAXINT);
    emit(f,"#");
    emitval(f,&gval,UNSIGNED|MAXINT);
  }else{
    if(o->am||(o->flags&REG)){
      o->flags|=D16OFF;
      o->val.vmax=l2zm(0L);
    }
    o->val.vmax=zmadd(o->val.vmax,l2zm(4L));
    emit_obj(f,o,LLONG);
    o->flags&=~D16OFF;
    o->val.vmax=zmsub(o->val.vmax,l2zm(4L));
  }
}
/* emits the high word of a long long object */
static void emit_hword(FILE *f,obj *o)
{
  if((o->flags&(REG|DREFOBJ))==REG){
    if(!reg_pair(o->reg,&rp)) 
      ierror(0);
    emit(f,"%s",mregnames[rp.r1]);
  }else if((o->flags&(KONST|DREFOBJ))==KONST){
    eval_const(&o->val,UNSIGNED|MAXINT);
    vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff));
    insert_const(&gval,UNSIGNED|MAXINT);
    emit(f,"#");
    emitval(f,&gval,UNSIGNED|MAXINT);
  }else{
    emit_obj(f,o,LONG);
  }
}
/* process ICs with long long; return 1 if IC has been handled */
static int handle_llong(FILE *f,IC *p)
{
  int c=p->code,r=0,t=p->typf&NU;
  char *libfuncname;

  if(c==ADDRESS) return 0;
  
  cc_set=0;
  if(c==GETRETURN){
    if(isreg(z)&&p->z.reg==25)
      return 1;
    emit(f,"\tmove.l\t%s,",mregnames[d1]);
    emit_lword(f,&p->z);
    emit(f,"\n");
    emit(f,"\tmove.l\t%s,",mregnames[d0]);
    emit_hword(f,&p->z);
    emit(f,"\n");
    return 1;
  }
  if(c==SETRETURN){
    if(isreg(q1)&&p->q1.reg==25)
      return 1;
    emit(f,"\tmove.l\t");
    emit_lword(f,&p->q1);
    emit(f,",%s\n",mregnames[d1]);
    emit(f,"\tmove.l\t");
    emit_hword(f,&p->q1);
    emit(f,",%s\n",mregnames[d0]);    
    return 1;
  }
  if(c==CONVERT){
    int told=q1typ(p),tnew=ztyp(p);
    if(ISPOINTER(told)) told=UNSIGNED|LONG;
    if(ISPOINTER(tnew)) tnew=UNSIGNED|LONG;
    if(ISFLOAT(told)){
      if(!OLD_SOFTFLOAT) ierror(0);
      saveregs(f,p);
      assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told);
      scratch_modified();
      if(GAS)
	emit(f,"\t.global\t__flt%ldto%cint64\n\tjbsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]);
      else
	emit(f,"\tpublic\t__flt%ldto%cint64\n\tjsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]);
      pop(msizetab[told]);
      restoreregsa(f,p);
      if(!isreg(z)||p->z.reg!=25){ /* d0/d1 */
	emit(f,"\tmove.l\t%s,",mregnames[d1]);
	emit_lword(f,&p->z);
	emit(f,"\n");
	emit(f,"\tmove.l\t%s,",mregnames[d0]);
	emit_hword(f,&p->z);
	emit(f,"\n");
      }
      restoreregsd(f,p);
      return 1;
    }
    if(ISFLOAT(tnew)){
      saveregswfp(f,p,1);
      assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told);
      scratch_modified();
      if(GAS)
	emit(f,"\t.global\t__%cint64toflt%ld\n\tjbsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]);
      else
	emit(f,"\tpublic\t__%cint64toflt%ld\n\tjsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]);
      pop(msizetab[told&NQ]);
      restoreregsa(f,p);
      if(FPU>68000){
	emit(f,"\tfmove.x\tfp0,");
	emit_obj(f,&p->z,tnew);
	emit(f,"\n");
      }else if((tnew&NQ)==FLOAT){
	emit(f,"\tmove.l\t%s,",mregnames[d0]);
	emit_obj(f,&p->z,tnew);
	emit(f,"\n");
      }else{
	emit(f,"\tmove.l\td1,");
	emit_lword(f,&p->z);
	emit(f,"\n");
	emit(f,"\tmove.l\t%s,",mregnames[d0]);
	emit_hword(f,&p->z);
	emit(f,"\n");
      }
      restoreregsd(f,p);
      return 1;
    }
    if((told&NQ)<LLONG){
      int destreg=0;
      if(ISHWORD(told)||!(told&UNSIGNED)){
	if(isreg(z)){
	  if(!reg_pair(p->z.reg,&rp)) ierror(0);
	  r=rp.r2;
	  destreg=1;
	}else{
	  r=get_reg(f,1,p,0);
	}
	loadext(f,r,&p->q1,told);
	p->q1.flags=REG;
	p->q1.reg=r;
	p->q1.am=0;
      }
      if(!destreg){
	emit(f,"\tmove.l\t");
	emit_obj(f,&p->q1,told);
	emit(f,",");
	emit_lword(f,&p->z);
	emit(f,"\n");
      }
      if(told&UNSIGNED){
	emit(f,"\tmove.l\t#0,");
	emit_hword(f,&p->z);
	emit(f,"\n");
      }else{
	int tmp;
	if(r==0)
	  ierror(0);
	if(destreg){
	  emit(f,"\tmove.l\t%s,%s\n",mregnames[r],mregnames[rp.r1]);
	  r=rp.r1;
	}
	tmp=get_reg(f,1,p,0);
	emit(f,"\tmoveq\t#31,%s\n",mregnames[tmp]);
	emit(f,"\tasr.l\t%s,%s\n",mregnames[tmp],mregnames[r]);
	if(!destreg){
	  emit(f,"\tmove.l\t%s,",mregnames[r]);
	  emit_hword(f,&p->z);
	  emit(f,"\n");
	}
      }
      return 1;
    }
    if((tnew&NQ)<LLONG){
      if((tnew&NQ)<INT&&!isreg(z)){
	r=get_reg(f,1,p,0);
	emit(f,"\tmove.l\t");
	emit_lword(f,&p->q1);
	emit(f,",%s\n",mregnames[r]);
	emit(f,"\tmove.%c\t%s,",x_t[tnew&NQ],mregnames[r]);
	emit_obj(f,&p->z,tnew);
	emit(f,"\n");
      }else{
	emit(f,"\tmove.%c\t",x_t[tnew&NQ]);
	p->q1.val.vmax=zmadd(p->q1.val.vmax,zmsub(sizetab[LONG],sizetab[tnew&NQ]));
	emit_lword(f,&p->q1);
	emit(f,",");
	emit_obj(f,&p->z,tnew);
	emit(f,"\n");
      }
      return 1;
    }
    assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
    return 1;
  }
  if(c==ASSIGN){
    assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
    return 1;
  }
  if(c==PUSH){
    dontpop+=zm2l(p->q2.val.vmax);
    assign(f,p,&p->q1,0,PUSH,msizetab[t],t);
    return 1;
  }  
  if(c==MINUS||c==KOMPLEMENT){
    char *sl,*sh;
    if(c==MINUS){
      sl="neg.l";
      sh="negx.l";
    }else
      sl=sh="not.l";
    if(!cf&&compare_objects(&p->q1,&p->z)){
      emit(f,"\t%s\t",sl);
      emit_lword(f,&p->z);
      emit(f,"\n");
      emit(f,"\t%s\t",sh);
      emit_hword(f,&p->z);
      emit(f,"\n");      
      return 1;
    }
    if(isreg(z)){
      if(!reg_pair(p->z.reg,&rp)) ierror(0);
      assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t);
      emit(f,"\t%s\t%s\n",sl,mregnames[rp.r2]);
      emit(f,"\t%s\t%s\n",sh,mregnames[rp.r1]);
      return 1;
    }
    r=get_reg(f,1,p,0);
    emit(f,"\tmove.l\t");
    emit_lword(f,&p->q1);
    emit(f,",%s\n",mregnames[r]);
    emit(f,"\t%s\t%s\n",sl,mregnames[r]);
    emit(f,"\tmove.l\t%s,",mregnames[r]);
    emit_lword(f,&p->z);
    emit(f,"\n");
    emit(f,"\tmove.l\t");
    emit_hword(f,&p->q1);
    emit(f,",%s\n",mregnames[r]);
    emit(f,"\t%s\t%s\n",sh,mregnames[r]);
    emit(f,"\tmove.l\t%s,",mregnames[r]);
    emit_hword(f,&p->z);    
    emit(f,"\n");
    return 1;
  }
  if((c>=OR&&c<=AND)||c==ADD||c==SUB){
    char *sl,*sh;int t2=0;
    switch_IC(p);
    if(c==ADD){sl="add.l";sh="addx.l";}
    else if(c==SUB){sl="sub.l";sh="subx.l";}
    else if(c==AND){sl=sh="and.l";}
    else if(c==OR){sl=sh="or.l";}
    else if(c==XOR){sl=sh="eor.l";}
    else
      ierror(0);
    if(isreg(q1)&&isreg(q2)&&isreg(z)&&p->q1.reg==p->q2.reg&&p->q1.reg==p->z.reg){
      if(!reg_pair(p->q1.reg,&rp)) ierror(0);
      emit(f,"\t%s\t%s,%s\n",sl,mregnames[rp.r2],mregnames[rp.r2]);
      emit(f,"\t%s\t%s,%s\n",sh,mregnames[rp.r1],mregnames[rp.r1]);
      return 1;
    }
    if(!isreg(z)&&compare_objects(&p->q1,&p->z)){
      if(isreg(q2)||(isconst(q2)&&(c==ADD||c==SUB)&&!cf)){
	if(!r) r=get_reg(f,1,p,0);
	emit(f,"\t%s\t",sl);
	emit_lword(f,&p->q2);
      }else{
	if(!r) r=get_reg(f,1,p,0);
	emit(f,"\tmove.l\t");
	emit_lword(f,&p->q2);
	emit(f,",%s\n",mregnames[r]);
	emit(f,"\t%s\t%s",sl,mregnames[r]);
      }
      emit(f,",");
      emit_lword(f,&p->z);
      emit(f,"\n");
      if(!isreg(q2)||c==ADD||c==SUB||c==XOR){
	emit(f,"\tmove.l\t");
	emit_hword(f,&p->q1);
	emit(f,",%s\n",mregnames[r]);
	if(isreg(q2)){
	  if(!reg_pair(p->q2.reg,&rp)) ierror(0);
	  t2=rp.r1;
	}else{
	  t2=get_reg(f,1,p,0);
	  emit(f,"\tmove.l\t");
	  emit_hword(f,&p->q2);
	  emit(f,",%s\n",mregnames[t2]);
	}
	emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]);
	emit(f,"\tmove.l\t%s,",mregnames[r]);
	emit_hword(f,&p->z);
	emit(f,"\n");
      }else{
	if(isreg(q2)){
	  emit(f,"\t%s\t",sh);
	  emit_hword(f,&p->q2);
	}else{
	  if(!r) r=get_reg(f,1,p,0);
	  emit(f,"\tmove.l\t");
	  emit_hword(f,&p->q2);
	  emit(f,",%s\n",mregnames[r]);
	  emit(f,"\t%s\t%s",sh,mregnames[r]);
	}
	emit(f,",");
	emit_hword(f,&p->z);
	emit(f,"\n");      
      }
      return 1;
    }
    if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
      if(!reg_pair(p->z.reg,&rp)) ierror(0);
      r=rp.r2;
    }else{
      r=get_reg(f,1,p,0);
    }
    if(!compare_objects(&p->q1,&p->z)){
      emit(f,"\tmove.l\t");
      emit_lword(f,&p->q1);
      emit(f,",%s\n",mregnames[r]);
    }
    if(c==XOR){
      t2=get_reg(f,1,p,0);
      emit(f,"\tmove.l\t");
      emit_lword(f,&p->q2);
      emit(f,",%s\n",mregnames[t2]);
      emit(f,"\t%s\t%s,%s\n",sl,mregnames[t2],mregnames[r]);
    }else{
      emit(f,"\t%s\t",sl);
      emit_lword(f,&p->q2);
      emit(f,",%s\n",mregnames[r]);
    }
    if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){
      if(!reg_pair(p->z.reg,&rp)) ierror(0);
      r=rp.r1;
    }else{
      emit(f,"\tmove.l\t%s,",mregnames[r]);
      emit_lword(f,&p->z);
      emit(f,"\n");
    }
    if(!compare_objects(&p->q1,&p->z)){
      emit(f,"\tmove.l\t");
      emit_hword(f,&p->q1);
      emit(f,",%s\n",mregnames[r]);
    }
    if(c==XOR||c==ADD||c==SUB){
      if(isreg(q2)){
	if(!reg_pair(p->q2.reg,&rp)) ierror(0);
	t2=rp.r1;
      }else{
	if(!t2) t2=get_reg(f,1,p,0);
	emit(f,"\tmove.l\t");
	emit_hword(f,&p->q2);
	emit(f,",%s\n",mregnames[t2]);
      }
      emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]);
    }else{
      emit(f,"\t%s\t",sh);
      emit_hword(f,&p->q2);
      emit(f,",%s\n",mregnames[r]);
    }
    if(!isreg(z)||(isreg(q2)&&p->z.reg==p->q2.reg)){
      emit(f,"\tmove.l\t%s,",mregnames[r]);
      emit_hword(f,&p->z);
      emit(f,"\n");
    }      
    return 1;
  }
  if(c==TEST){
    p->code=c=COMPARE;
    p->q2.flags=KONST;
    if((t&NU)==LLONG)
      p->q2.val.vllong=zm2zll(l2zm(0L));
    else if((t&NU)==(UNSIGNED|LLONG))
      p->q2.val.vullong=zum2zull(ul2zum(0UL));
    else
      ierror(0);
  }
  if(c==COMPARE){
    int rl,rh,t2;
    comptyp=p->typf;
    rl=get_reg(f,1,p,0);
    rh=get_reg(f,1,p,0);
    emit(f,"\tmove.l\t");
    emit_lword(f,&p->q1);
    emit(f,",%s\n",mregnames[rl]);
    emit(f,"\tmove.l\t");
    emit_hword(f,&p->q1);
    emit(f,",%s\n",mregnames[rh]);
    if(isreg(q2)){
      if(!reg_pair(p->q2.reg,&rp)) ierror(0);
      t2=rp.r1;
    }else{
      t2=get_reg(f,1,p,0);
      emit(f,"\tmove.l\t");
      emit_hword(f,&p->q2);
      emit(f,",%s\n",mregnames[t2]);
    }
    emit(f,"\tsub.l\t");
    emit_lword(f,&p->q2);
    emit(f,",%s\n",mregnames[rl]);
    emit(f,"\tsubx.l\t%s,%s\n",mregnames[t2],mregnames[rh]);
    return 1;
  }
  saveregs(f,p);
  if((c==LSHIFT||c==RSHIFT)&&(q2typ(p)&NQ)==LLONG){
    emit(f,"\tmove.l\t");
    emit_lword(f,&p->q2);
    emit(f,",-(%s)\n",mregnames[sp]);
    push(4);
  }else
    assign(f,p,&p->q2,0,PUSH,msizetab[q2typ(p)&NQ],q2typ(p));
  assign(f,p,&p->q1,0,PUSH,msizetab[q1typ(p)&NQ],q1typ(p));
  scratch_modified();
  if(c==MULT){
    if(CPU==68060)
      libfuncname="__mulint64_060";
    else if(CPU>=68020)
      libfuncname="__mulint64_020";
    else
      libfuncname="__mulint64";
  }else if(c==DIV){
    if(t&UNSIGNED){
      if(CPU==68060)
	libfuncname="__divuint64_060";
      else if(CPU>=68020)
	libfuncname="__divuint64_020";
      else
	libfuncname="__divuint64";
    }else{
      if(CPU==68060)
	libfuncname="__divsint64_060";
      else if(CPU>=68020)
	libfuncname="__divsint64_020";
      else
	libfuncname="__divsint64";
    }
  }else if(c==MOD){
    if(t&UNSIGNED){
      if(CPU==68060)
	libfuncname="__moduint64_060";
      else if(CPU>=68020)
	libfuncname="__moduint64_020";
      else
	libfuncname="__moduint64";
    }else{
      if(CPU==68060)
	libfuncname="__modsint64_060";
      else if(CPU>=68020)
	libfuncname="__modsint64_020";
      else
	libfuncname="__modsint64";
    }
  }else if(c==RSHIFT){
    if(t&UNSIGNED)
      libfuncname="__rshuint64";
    else
      libfuncname="__rshsint64";
  }else if(c==LSHIFT)
    libfuncname="__lshint64";
  else{
    printf("c=%d\n",c);
    ierror(0);
  }
  if(GAS)
    emit(f,"\t.global\t%s\n\tjbsr\t%s\n",libfuncname,libfuncname);
  else
    emit(f,"\tpublic\t%s\n\tjsr\t%s\n",libfuncname,libfuncname);
  if(c==LSHIFT||c==RSHIFT){
#ifdef M68K_16BIT_INT
    emit(f,"\tadd.%s\t#10,%s\n",strshort[1],mregnames[sp]);
    pop(10);
#else
    emit(f,"\tadd.%s\t#12,%s\n",strshort[1],mregnames[sp]);
    pop(12);
#endif
  }else{
    emit(f,"\tadd.%s\t#16,%s\n",strshort[1],mregnames[sp]);
    pop(16);
  }
  restoreregsa(f,p);
  if(!isreg(z)||p->z.reg!=25){
    emit(f,"\tmove.l\t%s,",mregnames[d0]);
    emit_hword(f,&p->z);
    emit(f,"\n");
    emit(f,"\tmove.l\t%s,",mregnames[10]);
    emit_lword(f,&p->z);
    emit(f,"\n");
  }    
  restoreregsd(f,p);
  return 1;
}

/* generate inlines for Amiga IEEE softcalls */
static char *ami_ieee(char *base,int off)
{
  char *s;
  if(cf) ierror(0);
  s=mymalloc(128);
  sprintf(s,"\tmove.l\t%s,-(%s)\n\tmove.l\t%sMathIeee%sBase%s,%s\n\tjsr\t%d(%s)\n\tmove.l\t(%s)+,%s",mregnames[a6],mregnames[sp],idprefix,base,use_sd?"(a4)":"",mregnames[a6],off,mregnames[a6],mregnames[sp],mregnames[a6]);
  return s;
}

/****************************************/
/*  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;
    larray.size=l2zm(3L);
    /*  Initialize some values which cannot be statically initialized   */
    /*  because they are stored in the target's arithmetic.             */
    maxalign=l2zm(4L);
    char_bit=l2zm(8L);
    for(i=0;i<=MAX_TYPE;i++){
        sizetab[i]=l2zm(msizetab[i]);
        align[i]=l2zm(malign[i]);
    }
    for(i= 1;i<=16;i++) {regsize[i]=l2zm( 4L);regtype[i]=&ltyp;}
    for(i=fp0;i<=fp7;i++) {regsize[i]=l2zm(12L);regtype[i]=&larray;}
    for(i=25;i<=28;i++) {regsize[i]=l2zm( 8L);regtype[i]=&lltyp;}

    if(ELF){
      for(i=1;i<=MAXR;i++)
	mregnames[i]=elfregnames[i];
      idprefix="";
      labprefix=".l";
      rprefix="%";
    }else{
      for(i=1;i<=MAXR;i++)
	mregnames[i]=regnames[i];
      idprefix="_";
      labprefix="l";
      rprefix="";
    }

    if(SMALLDATA) use_sd=1;


    /*  default CPU is 68000    */
    if(!(g_flags[0]&USEDFLAG)) CPU=68000;
    if(CPU==68040) static_cse=0; else static_cse=1;
    if(CPU<68000) cf=1;
    if(cf) MINADDI2P=INT; /* requires 32bit int! */
    /*  no FPU by default       */
    if(!(g_flags[1]&USEDFLAG)) FPU=0;
    if(FPU<=68000) {x_t[FLOAT]='l';}
    if(D2SCRATCH){regscratch[d2]=1;dscratch++;}
    if(A2SCRATCH) {regscratch[a2]=1;ascratch++;}
    if(FP2SCRATCH) {regscratch[fp2]=1;fscratch++;}

    if(NOA4) regsa[5]=1;
    if(GAS){
        codename="\t.text\n";
        bssname="";
        dataname="\t.data\n";
        if(use_sd) regsa[5]=1;
    }else{
        codename="\tsection\t\"CODE\",code\n";
        if(use_sd){
            /*  preparing small data    */
            regsa[5]=1;
            bssname= "\tsection\t\"__MERGED\",bss\n";
            dataname="\tsection\t\"__MERGED\",data\n";
        }else{
            bssname= "\tsection\t\"BSS\",bss\n";
            dataname="\tsection\t\"DATA\",data\n";
        }
    }
    m_dataname=dataname;
    m_bssname=bssname;
    /*  a5 can be used if no framepointer is used.  */
    if(!USEFRAMEPOINTER){ regsa[fbp]=0;/*fbp=sp;*/}
    if(DEBUG&1) printf("CPU=%ld FPU=%ld\n",CPU,FPU);
    /*  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.          */
    t_min[CHAR]=l2zm(-128L);
    t_min[SHORT]=l2zm(-32768L);
    t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L));
#ifdef M68K_16BIT_INT
    t_min[INT]=t_min(SHORT);
#else
    t_min[INT]=t_min(LONG);
#endif
    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[LONG]=ul2zum(2147483647UL);
#ifdef M68K_16BIT_INT
    t_max[INT]=t_max(SHORT);
#else
    t_max[INT]=t_max(LONG);
#endif
    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[LONG]=ul2zum(4294967295UL);
#ifdef M68K_16BIT_INT
    tu_max[INT]=t_max(UNSIGNED|SHORT);
#else
    tu_max[INT]=t_max(UNSIGNED|LONG);
#endif
    tu_max[LLONG]=zumkompl(ul2zum(0UL));
    tu_max[MAXINT]=t_max(UNSIGNED|LLONG);

#ifdef M68K_16BIT_INT
    stackalign=2;
#endif

    if(FLOAT64){
      sizetab[FLOAT]=sizetab[DOUBLE];
      align[FLOAT]=malign[DOUBLE];
    }

    marray[0]="__section(x)=__vattr(\"section(\"#x\")\")";
    marray[1]="__M68K__";

    if(CPU>=68000&&CPU<69000)
      sprintf(cpu_macro,"__M%ld=1",CPU);
    else
      sprintf(cpu_macro,"__COLDFIRE=1");
    marray[2]=cpu_macro;

#ifdef M68K_16BIT_INT
    marray[3]="__INTSIZE=16";
#else
    marray[3]="__INTSIZE=32";
#endif

    marray[4]="__stdargs=__attr(\"__stdargs;\")";
    marray[5]="__regargs=__attr(\"__regargs;\")";
    marray[6]="__vbccargs=__attr(\"__vbccargs;\")";
    marray[7]="__fp0ret=__attr(\"__fp0ret;\")";
    if(SMALLDATA) 
      marray[8]="__SMALL_DATA__";
    else
      marray[8]="__LARGE_DATA__";

    if(FPU==68881){
      sprintf(fpu_macro,"__M68881=1");
      marray[9]=fpu_macro;
    }else if(FPU>68000&&FPU<69000){
      sprintf(fpu_macro,"__M68882=1");
      marray[9]=fpu_macro;
    }else
      marray[9]=0;
    marray[10]=0;
    target_macros=marray;

    if(AMI_SOFTFLOAT&&!optsize){
      declare_builtin("_ieeeaddl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-66));
      declare_builtin("_ieeesubl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-72));
      declare_builtin("_ieeemull",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-78));
      declare_builtin("_ieeedivl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-84));
      declare_builtin("_ieeenegl",FLOAT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-60));
      declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-66));
      declare_builtin("_ieeesubd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-72));
      declare_builtin("_ieeemuld",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-78));
      declare_builtin("_ieeedivd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-84));
      declare_builtin("_ieeenegd",DOUBLE,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-60));
      declare_builtin("_ieees2d",DOUBLE,FLOAT,d0,0,0,1,ami_ieee("DoubTrans",-108));
      declare_builtin("_ieeed2s",FLOAT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubTrans",-102));
      declare_builtin("_ieeefltsl",FLOAT,LONG,d0,0,0,1,ami_ieee("SingBas",-36));
      declare_builtin("_ieeefltsd",DOUBLE,LONG,d0,0,0,1,ami_ieee("DoubBas",-36));
      declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,0,0,0,1,0);
      declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,0,0,0,1,0);
      declare_builtin("_ieeefixlsl",LONG,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
      declare_builtin("_ieeefixlsw",SHORT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
      declare_builtin("_ieeefixlsb",CHAR,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30));
      declare_builtin("_ieeefixdsl",LONG,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
      declare_builtin("_ieeefixdsw",SHORT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
      declare_builtin("_ieeefixdsb",CHAR,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30));
      declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,0,0,0,1,0);
      declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,0,0,0,1,0);
      declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,0,0,0,1,0);
      declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,0,0,0,1,0);
      declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,0,0,0,1,0);
      declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,0,0,0,1,0);
      declare_builtin("_ieeecmpl",INT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-42));
      declare_builtin("_ieeecmpd",INT,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-42));
#if 0
      declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0);
#endif
      declare_builtin("_ieeetstl",INT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-48));
      declare_builtin("_ieeetstd",INT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-48));
      declare_builtin("_flt32tosint64",LLONG,FLOAT,0,0,0,1,0);
      declare_builtin("_flt64tosint64",LLONG,DOUBLE,0,0,0,1,0);
      declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0);
      declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0);
      declare_builtin("_sint64toflt32",FLOAT,LLONG,0,0,0,1,0);
      declare_builtin("_sint64toflt64",DOUBLE,LLONG,0,0,0,1,0);
      declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0);
      declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0);
    }else{
      int pd0,pd1,pd0d1;
      if(VBCCCALL){
	pd0=d0;pd1=d1;pd0d1=d0d1;
      }else{
	pd0=pd1=pd0d1=0;
      }
	
      declare_builtin("_ieeeaddl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
      declare_builtin("_ieeesubl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
      declare_builtin("_ieeemull",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
      declare_builtin("_ieeedivl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0);
      declare_builtin("_ieeenegl",FLOAT,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
      declare_builtin("_ieeesubd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
      declare_builtin("_ieeemuld",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
      declare_builtin("_ieeedivd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0);
      declare_builtin("_ieeenegd",DOUBLE,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieees2d",DOUBLE,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeed2s",FLOAT,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeefltsl",FLOAT,LONG,pd0,0,0,1,0);
      declare_builtin("_ieeefltsd",DOUBLE,LONG,pd0,0,0,1,0);
      declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,pd0,0,0,1,0);
      declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,pd0,0,0,1,0);
      declare_builtin("_ieeefixlsl",LONG,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeefixlsw",SHORT,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeefixlsb",CHAR,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeefixdsl",LONG,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeefixdsw",SHORT,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeefixdsb",CHAR,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_ieeecmpl",INT,FLOAT,pd0,FLOAT,pd1,1,0);
      declare_builtin("_ieeecmpd",INT,DOUBLE,pd0d1,DOUBLE,0,1,0);
#if 0
      declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0);
      declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0);
      declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0);
#endif
      declare_builtin("_ieeetstl",INT,FLOAT,pd0,0,0,1,0);
      declare_builtin("_ieeetstd",INT,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_flt32tosint64",LLONG,FLOAT,pd0,0,0,1,0);
      declare_builtin("_flt64tosint64",LLONG,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,pd0,0,0,1,0);
      declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,pd0d1,0,0,1,0);
      declare_builtin("_sint64toflt32",FLOAT,LLONG,pd0d1,0,0,1,0);
      declare_builtin("_sint64toflt64",DOUBLE,LLONG,pd0d1,0,0,1,0);
      declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,pd0d1,0,0,1,0);
      declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,pd0d1,0,0,1,0);
    }
    {
      char *asm;
      declare_builtin("_divs",LONG,LONG,d0,LONG,d1,1,0);
      declare_builtin("_divu",LONG,LONG,d0,LONG,d1,1,0);
#define SMODS "\tjsr\t__divs\n\tmove.l\td1,d0"
#define SMODU "\tjsr\t__divu\n\tmove.l\td1,d0"
      asm=mymalloc(strlen(SMODS)+1);
      strcpy(asm,SMODS);
      declare_builtin("_mods",LONG,LONG,d0,LONG,d1,1,asm);
      asm=mymalloc(strlen(SMODU)+1);
      strcpy(asm,SMODU);
      declare_builtin("_modu",LONG,LONG,d0,LONG,d1,1,asm);
    }
    declare_builtin("_lshint64",LLONG,LLONG,0,INT,0,1,0);
    declare_builtin("_rshsint64",LLONG,LLONG,0,INT,0,1,0);
    declare_builtin("_rshuint64",(UNSIGNED|LLONG),(UNSIGNED|LLONG),0,INT,0,1,0);

    return 1;
}

int freturn(type *t)
/*  Returns the register in which variables of type t are returned. */
/*  If the value cannot be returned in a register returns 0.        */
{
    long l;int tu=t->flags&NQ;
    if(t->attr&&ISFLOAT(tu)&&FPU>68000&&strstr(t->attr,"__fp0ret;")) return fp0;
    if(tu==FLOAT&&FLOAT64) tu+=DOUBLE-FLOAT;
    if(tu==FLOAT){
        if(FPU>68000&&!NOFPRETURN)
            return fp0;
        else
            return d0;
    }
    if(tu==DOUBLE||tu==LDOUBLE){
        if(FPU>68000&&!NOFPRETURN){
            return fp0;
        }else{
            if(NOMREGRETURN) return 0;
#if NEW_RET
            return d0d1;
#else
	    return d0;
#endif
        }
    }
    if(tu==STRUCT||tu==UNION){
        if(!NOMREGRETURN){
            l=zm2l(szof(t));
#if NEW_RET
	    if(l==4) return d0;
	    if(l==8) return d0d1;
	    /* alte Variante; unschoen */
	    if(l==12) return d0;
	    if(l==16) return d0;
#else
            if(l==4||l==8||l==12||l==16) return d0;
#endif
        }
        return 0;
    }
    if(tu==LLONG)
      return d0d1;
    if(zmleq(szof(t),l2zm(4L))) return d0; else return 0;
}
int cost_savings(IC *p,int r,obj *o)
{
  int c=p->code;
  if((r==a6||r==d7||r==d6d7||r==fp7)&&!RESERVEREGS) return -1;
  if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3;
  if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3;
  if(o->flags&VKONST){
    int t;
    if(CPU==68040) return 0;
    t=o->v->ctyp&NQ;
    if(ISFLOAT(t)) return 2;
    if(t==CHAR&&r>=a0&&r<=a7) return 0/*INT_MIN*/;
    if(t==LLONG) return 0;
    if(cf&&(t<INT)&&p->q2.flags) return 0/*INT_MIN*/;
    eval_const(&o->v->cobj.val,t);
    if(zmeqto(vmax,Z0)) return 0;
    if(o->flags&DREFOBJ) return 2;
    if((p->code==ASSIGN&&o==&p->q1)||p->code==PUSH||p->code==SETRETURN){
      if(p->code==PUSH||(p->z.flags&DREFOBJ)||
	 ((p->z.flags&VAR)&&(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN))){
	if(r>=d0&&r<=d7)
	  return 2;
	else
	  return 1;
      }
      return 0;
    }
    if(c==ADDI2P||c==SUBIFP){
      if(zmleq(vmax,l2zm(32767L))&&zmleq(l2zm(-32768L),vmax)) return 0;
      if(r>=d0&&r<=d7)
	return 3;
      return CPU<68020?1:0;
    }
    if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==SUBPFP){
      if(zmleq(vmax,l2zm(8L))&&zmleq(l2zm(-8L),vmax)) return 0;
      if(p->flags&EFF_IC) return 0;
      if(r>=d0&&r<=d7)
	return 2;
      else
	return 1;
    }
    if(c==COMPARE){
      if(r>=d0&&r<=d7)
	return 2;
      else
	return 1;
    }
    if(r>=a0&&r<=a7) return INT_MIN;
    /* TODO: which allocations are useful? */
    return 0;
  }
  if(o->flags&DREFOBJ){
    if(r>=a0&&r<=a7){
      return 4;
    }
  }
  if((c==ADDI2P||c==SUBIFP||c==ADDRESS)&&(o==&p->q1||o==&p->z)&&r>=a0&&r<=a7){
    return 4;
  }
  if(r>=a0&&r<=a7){
    if(o->flags&DREFOBJ) ierror(0);
    if(c!=GETRETURN&&c!=SETRETURN&&c!=ASSIGN&&c!=PUSH&&c!=TEST&&c!=COMPARE&&c!=CONVERT){
      if(c==ADDI2P||c==SUBIFP){
	if(o==&p->q2)
	  return INT_MIN;
      }else if(c==SUBPFP){
	if(o==&p->z)
	  return INT_MIN;
      }else{
	return INT_MIN;
      }
    }
    if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR||ISFLOAT(p->typf)||ISFLOAT(p->typf2)))
      return INT_MIN;
  }

  if(c==TEST&&r>=d0&&r<=d7){
    return 3;
  }
  if(o==&p->z&&(p->q1.flags&VKONST)){
    eval_const(&p->q1.v->cobj.val,p->q1.v->ctyp&NQ);
    if(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax)&&r>=d0&&r<=d7)
      return 3;
  }
  return 2;
}

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(r==0) return 0;
  t&=NQ;
  if(ISFLOAT(t)){
    if(FPU>68000){
      if(r>=fp0&&r<=fp7) return(1); else return 0;
    }else{
      if(t==FLOAT&&!FLOAT64)
	return (r>=d0&&r<=d7);
      else
	return (r>=25&&r<=28);
    }
  }
  if(t==POINTER&&mode<=0&&r>=d0&&r<=d7) return 1;
  if(t==POINTER&&r>=1&&r<=8) return 1;
  if(t>=CHAR&&t<=LONG){
    if((r>=d0&&r<=d7)||(mode==-1&&t>=SHORT&&r>=1&&r<=8)) return 1;
  }
  if(t==LLONG&&r>=25&&r<=28) return 1;
  return 0;
}

int dangerous_IC(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;
}

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;
    /*  All pointers have the same representation.  */
    if(tp==POINTER&&op==POINTER) return 0;
    /*  Pointer and int/long as well   */
    if(const_expr){
#ifdef M68K_16BIT_INT
      if(tp==POINTER&&(op==LONG)) return 0;
      if(op==POINTER&&(tp==LONG)) return 0;
#else
      if(tp==POINTER&&(op==INT||op==LONG)) return 0;
      if(op==POINTER&&(tp==INT||tp==LONG)) return 0;
#endif
    }
    /*  Signed und Unsigned integers with the same size, too.  */
    if(op==tp) return 0;
#ifdef M68K_16BIT_INT
    /*  int==short   */
    if((tp==INT&&op==SHORT)||(tp==SHORT&&op==INT)) return 0;
#else
    /*  int==long   */
    if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return 0;
#endif
    if(FLOAT64&&ISFLOAT(op)&&ISFLOAT(tp)) return 0;
    /* long double==double */
    if((op==DOUBLE||op==LDOUBLE)&&(tp==DOUBLE||tp==LDOUBLE)) return 0;
    return 1;
}

void gen_ds(FILE *f,zmax size,type *t)
/*  This function has to create <size> bytes of storage */
/*  initialized with zero.                              */
{
  title(f);
  if(GAS){
    if(newobj&&section!=SPECIAL)
      emit(f,"%ld\n",zm2l(size));
    else
      emit(f,"\t.space\t%ld\n",zm2l(size));
    newobj=0;
  }else{
    /*if(section!=BSS&&section!=SPECIAL&&newobj){emit(f,bssname);if(f) section=BSS;}*/
    emit(f,"\tds.b\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.              */
{
  title(f);
  if(zm2l(align)>1){
    if(GAS){
      emit(f,"\t.align\t4\n");
    }else{
      emit(f,"\tcnop\t0,4\n");
    }
  }
}
void gen_var_head(FILE *f,Var *v)
/*  This function has to create the head of a variable  */
/*  definition, i.e. the label and information for      */
/*  linkage etc.                                        */
{
  int constflag;
  title(f);
  if(v->clist) constflag=is_const(v->vtyp);
  if(v->tattr&(FAR|CHIP)){
    if(v->tattr&CHIP){
      dataname="\tsection\t\"CHIP_DATA\",data,chip\n";
      bssname="\tsection\t\"CHIP_BSS\",bss,chip\n";
    }else{
      dataname="\tsection\t\"DATA\",data\n";
      bssname="\tsection\t\"BSS\",bss\n";
    }
    if(f) section=-1;
  }else{
    dataname=m_dataname;
    bssname=m_bssname;
  }
  if(v->storage_class==STATIC){
    if(ISFUNC(v->vtyp->flags)) return;
    if(!special_section(f,v)){
      if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
      if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&&section!=CODE){emit(f,codename);if(f) section=CODE;}
      if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
    }
    if(GAS){
      if(section!=BSS) emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset));
      else emit(f,"\t.comm\t%s%ld,",labprefix,zm2l(v->offset));
    }else{
      emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset));
    }
    newobj=1;
  }
  if(v->storage_class==EXTERN){
    if(GAS){
      emit(f,"\t.global\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier);
    }else{
      emit(f,"\tpublic\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier);
    }
    if(v->flags&(DEFINED|TENTATIVE)){
      if(!special_section(f,v)){
	if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
	if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&&section!=CODE){emit(f,codename);if(f) section=CODE;}
	if(!v->clist&&section!=BSS){emit(f,bssname);if(f) section=BSS;}
      }
      if(GAS){
	if(section!=BSS)
	  emit(f,"\t.align\t4\n%s%s:\n",idprefix,v->identifier);
	else
	  emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier);
      }else{
	emit(f,"\tcnop\t0,4\n%s%s\n",idprefix,v->identifier);
      }
      newobj=1;
    }
  }
  if(v->tattr&(FAR|CHIP)) {if(f) section=-1;newobj=0;}
}
void gen_dc(FILE *f,int t,const_list *p)
/*  This function has to create static storage          */
/*  initialized with const-list p.                      */
{
  char s;
  title(f);
  if(!p) ierror(0);
/*    if(section!=DATA){emit(f,dataname);if(f) section=DATA;}*/
  if(ISFLOAT(t)||(t&NQ)==LLONG) s='l'; else s=x_t[t&NQ];
  if(GAS){
    char *str;
    if(s=='b') str="\t.byte\t";
    else if(s=='w') str="\t.short\t";
    else if(s=='l') str="\t.long\t";
    else ierror(0);
    emit(f,"%s",str);
  }else{
    emit(f,"\tdc.%c\t",s);
  }
  if(!p->tree){
    if(ISFLOAT(t)){
      /*  auch wieder nicht sehr schoen und IEEE noetig   */
      unsigned char *ip;char *s;
      ip=(unsigned char *)&p->val.vdouble;
      if(GAS) s="0x"; else s="$";
      emit(f,"%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]);
      if((t&NQ)!=FLOAT){
	emit(f,",%s%02x%02x%02x%02x",s,ip[4],ip[5],ip[6],ip[7]);
      }
    }else if((t&NQ)==LLONG){
      zumax tmp;
      eval_const(&p->val,t);
      tmp=vumax;
      vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff)); 
      gval.vulong=zum2zul(vumax);
      emitval(f,&gval,UNSIGNED|LONG);
      emit(f,",");
      vumax=zumand(tmp,ul2zum(0xffffffff)); 
      gval.vulong=zum2zul(vumax);
      emitval(f,&gval,UNSIGNED|LONG);
    }else{
      emitval(f,&p->val,t&NU);
    }
  }else{
    int m,m2,m3;
    p->tree->o.am=0;
    m=p->tree->o.flags;
    p->tree->o.flags&=~VARADR;
    m2=g_flags[5];
    g_flags[5]&=~USEDFLAG;
    m3=use_sd;
    use_sd=0;
    emit_obj(f,&p->tree->o,t&NU);
    p->tree->o.flags=m;
    g_flags[5]=m2;
    use_sd=m3;
  }
  emit(f,"\n");newobj=0;
}

static void allocreg(int r)
{
  if(reg_pair(r,&rp)){
    regs[rp.r1]=1;
    regs[rp.r2]=1;
  }
  regs[r]=1;
}

static void freereg(int r)
{
  if(reg_pair(r,&rp)){
    regs[rp.r1]=0;
    regs[rp.r2]=0;
  }
  regs[r]=0;
}

/*  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,IC *p,Var *v,zmax offset)
{
  int c,t;char fp[2]="\0\0";
  int act_line=0;char *act_file=0;
  int shiftisdiv;
  if(DEBUG&1) printf("gen_code()\n");
  for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
  if(!NOPEEPHOLE){
    /*  Adressierungsarten benutzen */
    if(!addressing(p)) offset=l2zm(0L);
  }
  title(f);
  if(debug_info){
    if(HUNKDEBUG){
      if(!GAS){
	act_line=1;
	emit(f,"\tdsource\t\"%s\"\n",filename);
	emit(f,"\tdebug\t%d\n",act_line);
      }
    }
  }
  reglabel=++label;freglabel=++label;
  function_top(f,v,zm2l(offset));
  cc_set=cc_set_tst=0;
  stackoffset=notpopped=dontpop=maxpushed=0;
  for(c=1;c<=MAXR;c++){
    if(regsa[c]||regused[c]){
      BSET(regs_modified,c);
    }
  }
  for(;p;pr(f,p),p=p->next){
    if(debug_info){
      if(HUNKDEBUG){
	if(p->file&&p->file!=act_file){
	  act_file=p->file;
	  if(!GAS) emit(f,"\tdsource\t\"%s\"\n",act_file);
	}
	if(p->line&&p->line!=act_line){
	  act_line=p->line;
	  if(!GAS) emit(f,"\tdebug\t%d\n",act_line);
	}
      }else{
	dwarf2_line_info(f,p);
      }
    }

    if(FLOAT64){
      if(p->code==CONVERT)
	if((q1typ(p)&NQ)==FLOAT) p->typf2+=DOUBLE-FLOAT;
      if((ztyp(p)&NQ)==FLOAT) p->typf+=DOUBLE-FLOAT;
    }

    c=p->code;t=p->typf;
    if(c==NOP) continue;
    cc_set_tst=cc_set;
    cc_typ_tst=cc_typ;
    shiftisdiv=0;
    if(cc_set_tst&&(DEBUG&512)){emit(f,"; cc_set_tst=");emit_obj(f,cc_set_tst,t);emit(f,"\n");}
    if(cc_set&&(DEBUG&512)){emit(f,"; cc_set=");emit_obj(f,cc_set,t);emit(f,"\n");}
    pushedreg&=16;if(c==RESTOREREGS) pushedreg=0;
    if(DEBUG&256){emit(f,"; "); pric2(f,p);}
    if(DEBUG&512) emit(f,"; stackoffset=%ld, notpopped=%ld, pushedreg=%d, dontpop=%ld\n",stackoffset,notpopped,pushedreg,dontpop);
    /*  muessen wir Argumente poppen?   */
    if(notpopped&&!dontpop){
      int flag=0;
      if(c==LABEL||c==COMPARE||c==TEST||c==BRA){
	emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]);
	pop(notpopped);notpopped=0;/*cc_set_tst=cc_set=0;*/
      }
    }
    /*  na, ob das hier ok ist..?   */
    if(c==SUBPFP) c=SUB;
    if(c==PMULT) c=MULT;
    if(c==ALLOCREG){
      allocreg(p->q1.reg);
      continue;
    }
    if(c==FREEREG){
      freereg(p->q1.reg);
      continue;
    }
    if(c==LABEL){
      if(debug_info&&HUNKDEBUG) act_line=0;
      if(GAS){
	emit(f,"%s%d:\n",labprefix,t);
      }else{
	emit(f,"%s%d\n",labprefix,t);
      }
      cc_set=0;continue;
    }
    if(c==BRA){emit(f,"\t%sbra\t%s%d\n",(GAS?"j":""),labprefix,t);continue;}
    if(c>=BEQ&&c<BRA){
      if(GAS){
	if(stored_cc){emit(f,"\tjne\t%s%d\n",labprefix,t);stored_cc=0;continue;}
	if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){
	  emit(f,"\tj%s\t%s%d\n",ubranch[c-BEQ],labprefix,t);
	}else{
	  emit(f,"\t%sj%s\t%s%d\n",fp,ename[c]+1,labprefix,t);
	}
      }else{
	if(stored_cc){emit(f,"\tbne\t%s%d\n",labprefix,t);stored_cc=0;continue;}
	if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){
	  emit(f,"\tb%s\t%s%d\n",ubranch[c-BEQ],labprefix,t);
	}else{
	  emit(f,"\t%s%s\t%s%d\n",fp,ename[c],labprefix,t);
	}
      }
      continue;
    }
#if 0
    if(CPU>=68020&&(c==LSHIFT||c==MULT)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(p->typf)){
      int l=0;
      eval_const(&p->q2.val,q2typ(p));
      if(c==LSHIFT&&zmeqto(vmax,l2zm(1L))) l=2;
      if(c==LSHIFT&&zmeqto(vmax,l2zm(2L))) l=4;
      if(c==LSHIFT&&zmeqto(vmax,l2zm(3L))) l=8;
      if(c==MULT&&zmeqto(vmax,l2zm(2L))) l=2;
      if(c==MULT&&zmeqto(vmax,l2zm(4L))) l=4;
      if(c==MULT&&zmeqto(vmax,l2zm(8L))) l=8;
      if(l!=0){
	IC *p2=p->next;
	while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next;
	if((p2->code==ADD||p2->code==ADDI2P)&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==p->z.reg&&(p2->typf&NU)==(p->typf&NU)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg>=a0&&p2->q1.reg<=a7&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg>=a0&&p2->z.reg<=a7){
	  IC *p3=p2->next;
	  while(p3&&p3->code==FREEREG) if(p3&&p3->q1.reg==p->z.reg) break;
	  if(p3&&p3->code==FREEREG&&p3->q1.reg==p->z.reg){
	    int r;
	    if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7)
	      r=p->q1.reg;
	    else{
	      move(f,&p->q1,0,0,p->z.reg,p->typf);
	      r=p->z.reg;
	    }
	    emit(f,"\tlea\t(%s,%s.%c*%d),%s\n",mregnames[p2->q1.reg],mregnames[r],sizetab[p->typf&NQ]==2?'w':'l',l,mregnames[p2->z.reg]);
	    p->code=NOP;
	    p->q1.flags=p->q2.flags=p->z.flags=0;
	    p2->code=NOP;
	    p2->q1.flags=p2->q2.flags=p2->z.flags=0;
	    continue;
	  }
	}
      }
    }
#endif
    if(c==COMPARE&&isconst(q2)&&!cf&&(t&NQ)!=LLONG){
      case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY);
      IC *p2;
      if(ct&&(ct->num>=JUMP_TABLE_LENGTH||(!isreg(q1)&&ct->num>=JUMP_TABLE_LENGTH/2))){
	int r,defl,tabl=++label,rts=0,i,ar=0;
	if(ct->next_ic->code==BRA)
	  defl=ct->next_ic->typf;
	else
	  defl=++label;
	for(r=d0;r<=d7;r++)
	  if(!regs[r]) break;
	if(r>d7){
	  if((!(p->q1.flags&REG))||p->q1.reg!=d0)
	    r=d0;
	  else
	    r=d1;
	  emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]);
	  emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[r],mregnames[sp]);
	  push(8);
	}else{
	  regused[r]=1;
	  BSET(regs_modified,r);
	}
	if(!regs[r]||(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
	  for(ar=1;ar<sp;ar++)
	    if(!regs[ar]) break;
	  if(ar>=sp){
	    ar=a0;
	    if(!regs[r]){
	      emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]);
	      push(4);
	    }
	    emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[ar],mregnames[sp]);
	    push(4);
	  }else{
	    regused[ar]=1;
	    BSET(regs_modified,ar);
	  }
	}
	if(regs[r]||(ar&&regs[ar])) defl=++label;
	if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
	  p->q1.flags&=~DREFOBJ;
	  move(f,&p->q1,0,0,ar,POINTER);
	  p->q1.flags|=(REG|DREFOBJ);
	  p->q1.flags&=~VAR;
	  p->q1.reg=ar;
	}
	if((t&NU)==(UNSIGNED|CHAR))
	  emit(f,"\tmoveq\t#0,%s\n",mregnames[r]);
	move(f,&p->q1,0,0,r,t);
	if((t&NU)==CHAR){
	  emit(f,"\text.w\t%s\n",mregnames[r]);
	  t=SHORT;
	}
	if((t&NU)==(UNSIGNED|CHAR))
	  t=(UNSIGNED|SHORT);
	if(((t&UNSIGNED)&&!zumeqto(ct->min.vumax,ul2zum(0UL)))||
	   (!(t&UNSIGNED)&&!zmeqto(ct->min.vmax,l2zm(0L)))){
	  emit(f,"\tsub.%c\t#",x_t[t&NQ]);
	  if(t&UNSIGNED)
	    emitzum(f,ct->min.vumax);
	  else
	    emitzm(f,ct->min.vmax);
	  emit(f,",%s\n",mregnames[r]);
	}
	emit(f,"\tcmp.%c\t#",x_t[t&NQ]);
	emitzum(f,ct->diff);
	emit(f,",%s\n",mregnames[r]);
	if(regs[r]||regs[ar])
	  emit(f,"\tbhi\t%s%d\n",labprefix,++label);
	else
	  emit(f,"\tbhi\t%s%d\n",labprefix,defl);
	if(CPU<68020)
	  emit(f,"\tlsl.%c\t#2,%s\n",x_t[t&NQ],mregnames[r]);
	for(i=MAXR;i>=1;i--)
	  if(regs[i]&4) rts=1;
	if(regs[r]||regs[ar]){
	  int off;
	  if(regs[r]) off=4; else off=0;
	  if(ar&&regs[ar]) off+=4;
	  if(CPU>=68020)
	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]);
	  else
	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]);
	  if(ar&&regs[ar]){
	    emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]);
	    pop(4);
	  }	      
	  if(regs[r]){
	    emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]);
	    pop(4);
	  }
	  emit(f,"\trts\n");
	  pop(4);
	}else{
	  if(CPU>=68020)
	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]);
	  else
	    emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]);
	  emit(f,"\tjmp\t(%s)\n",mregnames[ar]);
	}
	if(GAS){
	  emit(f,"\t.align\t2\n");
	  emit(f,"%s%d:\n",labprefix,tabl);
	  emit_jump_table(f,ct,"\t.long\t","l",defl);
	}else{
	  emit(f,"\tcnop\t0,4\n");
	  emit(f,"%s%d\n",labprefix,tabl);
	  emit_jump_table(f,ct,"\tdc.l\t","l",defl);
	}
	if(ct->next_ic->code!=BRA||regs[r]||(ar&&regs[ar])){
	  if(regs[r]||(ar&&regs[ar])){
	    emit(f,"%s%d%s\n",labprefix,label,GAS?":":"");
	    if(ar&&regs[ar])
	      emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]);
	    if(regs[r])
	      emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]);
	    emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]);
	  }
	  emit(f,"%s%d%s\n",labprefix,defl,GAS?":":"");
	  p2=ct->next_ic->prev;
	}else
	  p2=ct->next_ic;
	if(p->prev) p=p->prev;
	do{
	  p=p->next;
	  if(p->code==ALLOCREG)
	    allocreg(p->q1.reg);
	  if(p->code==FREEREG)
	    freereg(p->q1.reg);
	}while(p!=p2);
	continue;
      }
    }
    if(p->q1.am){
      if(!regs[p->q1.am->basereg]){
	pric2(stdout,p);printf("%s\n",mregnames[p->q1.am->basereg]); ierror(0);
      }
      if(p->q1.am->dreg&&!regs[p->q1.am->dreg&127]){
	printf("Register %s:\n",mregnames[p->q1.am->dreg&127]);
	ierror(0);
      }
    }
    if(p->q2.am){
      if(!regs[p->q2.am->basereg]) {pric2(stdout,p);ierror(0);}
      if(p->q2.am->dreg&&!regs[p->q2.am->dreg&127]) {printf("Register %s:\n",mregnames[p->q2.am->dreg&127]);ierror(0);}
    }
    if(p->z.am){
      if(!regs[p->z.am->basereg]) {pric2(stdout,p);printf("am=%p b=%s,i=%s,o=%ld,s=%d\n",(void*)p->z.am,mregnames[p->z.am->basereg],mregnames[p->z.am->dreg&127],p->z.am->dist,p->z.am->skal);ierror(0);}
      if(p->z.am->dreg&&!regs[p->z.am->dreg&127]) {printf("Register %s:\n",mregnames[p->z.am->dreg&127]);ierror(0);}
    }
    if((p->q1.flags&REG)&&!regs[p->q1.reg]&&p->code!=MOVEFROMREG&&(!reg_pair(p->q1.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){
      printf("Register %s:\n",mregnames[p->q1.reg]);pric2(stdout,p);terror("illegal use of register");}
    if((p->q2.flags&REG)&&!regs[p->q2.reg]&&(!reg_pair(p->q2.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->q2.reg]);pric2(stdout,p);terror("illegal use of register");}
    if((p->z.flags&REG)&&!regs[p->z.reg]&&p->code!=MOVETOREG&&(!reg_pair(p->z.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->z.reg]);if(reg_pair(p->z.reg,&rp)) printf("%s=%d %s=%d\n",regnames[rp.r1],regs[rp.r1],regnames[rp.r2],regs[rp.r2]);pric2(stdout,p);terror("illegal use of register");}
    /*        if((p->q2.flags&REG)&&(p->z.flags&REG)&&p->q2.reg==p->z.reg){pric2(stdout,p);ierror(0);}*/
    /*if((p->q2.flags&VAR)&&(p->z.flags&VAR)&&p->q2.v==p->z.v&&compare_objects(&p->q2,&p->z)){pric2(stdout,p);ierror(0);}*/
    /*  COMPARE #0 durch TEST ersetzen (erlaubt, da tst alle Flags setzt)   */
    if(c==COMPARE&&isconst(q2)){
      eval_const(&p->q2.val,t);
      if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
	c=p->code=TEST;p->q2.flags=0;
      }
    }
    if(c==COMPARE&&isconst(q1)){
      eval_const(&p->q1.val,t);
      if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){
	IC *bp=p->next;int bc;
	c=p->code=TEST;p->q1=p->q2;p->q2.flags=0;p->q2.am=0;
	/*  Nachfolgenden Branch umdrehen   */
	while(bp&&bp->code==FREEREG) bp=bp->next;
	bc=bp->code;
	if(!bp||bc<BEQ||bc>BGT) ierror(0);
	if(bc==BLT) bp->code=BGT;
	if(bc==BGT) bp->code=BLT;
	if(bc==BLE) bp->code=BGE;
	if(bc==BGE) bp->code=BLE;
      }
    }
    /*  gesetzte ConditionCodes merken  */
    if(p->z.flags&&(!isreg(z)||p->z.reg>=d0)&&(c!=CONVERT||!ISFLOAT(p->typf2))&&((!ISFLOAT(t))||FPU>68000)){
      cc_set=&p->z;cc_typ=p->typf;
    }else{
      cc_set=0;
    }
    if(c==LEA){
      if(!isreg(z)||p->z.reg>8) ierror(0);
      emit(f,"\tlea\t");emit_obj(f,&p->q1,t);
      emit(f,",%s\n",mregnames[p->z.reg]);
      continue;
    }
    if(c==PEA){
      emit(f,"\tpea\t");emit_obj(f,&p->q1,t);emit(f,"\n");
      push(zm2l(p->q2.val.vmax));
      dontpop+=zm2l(p->q2.val.vmax);
      continue;
    }
    if(c==MOVEFROMREG){
      if(p->q1.reg<fp0)
	emit(f,"\tmove.l\t%s,",mregnames[p->q1.reg]);
      else if(p->q1.reg<25)
	emit(f,"\tfmove.x\t%s,",mregnames[p->q1.reg]);
      else
	emit(f,"\tmovem.l\t%s,",mregnames[p->q1.reg]);
      emit_obj(f,&p->z,t);emit(f,"\n");
      continue;
    }
    if(c==MOVETOREG){
      if(p->z.reg<fp0)
	emit(f,"\tmove.l\t");
      else if(p->z.reg<25)
	emit(f,"\tfmove.x\t");
      else
	emit(f,"\tmovem.l\t");
      emit_obj(f,&p->q1,t);emit(f,",%s\n",mregnames[p->z.reg]);
      continue;
    }
    if(NOPEEPHOLE){
      if(p->q1.am||p->q2.am||p->z.am){
	ierror(0);
	p->q1.am=p->q2.am=p->z.am=0;
      }
    }
    p=do_refs(f,p);
    if((p->q1.flags&&(q1typ(p)&NQ)==LLONG)||(p->q2.flags&&(q2typ(p)&NQ)==LLONG&&p->code!=LSHIFT&&p->code!=RSHIFT)||(p->z.flags&&(ztyp(p)&NQ)==LLONG)){
      if(handle_llong(f,p)){
	*fp=0;
	continue;
      }
    }
    if(NOPEEPHOLE){
      if(p->q1.am||p->q2.am||p->z.am){
	ierror(0);
	p->q1.am=p->q2.am=p->z.am=0;
      }
    }
#ifdef M68K_16BIT_INT
    if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==POINTER)){
      p->code=c=ASSIGN;
      p->q2.val.vmax=sizetab[LONG];
    }                 
#else
    if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==INT||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==INT||(p->typf2&NQ)==POINTER)){
      p->code=c=ASSIGN;
      p->q2.val.vmax=sizetab[LONG];
    }                 
#endif
    if(c==CONVERT){
      int to;
      if((t&NQ)==POINTER) t=(UNSIGNED|LONG);
      if((t&NQ)==LDOUBLE) t=DOUBLE;
      to=p->typf2&NU;
      if(to==POINTER) to=UNSIGNED|LONG;
      if(to==LDOUBLE) to=DOUBLE;
#ifdef M68K_16BIT_INT
      if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT)||to==(UNSIGNED|INT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ))
	cc_set=0;
#else
      if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ))
	cc_set=0;
#endif
      if(ISFLOAT(t)||ISFLOAT(to)){
	if(FPU>68000){
	  int zreg=0,freg=0;
	  if(ISFLOAT(t)&&ISFLOAT(to)){
	    if(isreg(q1)&&isreg(z)){
	      if(p->q1.reg!=p->z.reg)
		emit(f,"\tfmove.x\t%s,%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]);
	      continue;
	    }
	  }
	  if(isreg(z)&&p->z.reg>=fp0)
	    zreg=p->z.reg;
	  if(isreg(q1)&&p->q1.reg>=fp0){
	    if(!zreg&&(t&UNSIGNED)&&!ISHWORD(t))
	      zreg=p->q1.reg; 
	    else 
	      zreg=freg=get_reg(f,2,p,1);}
	  if(!zreg) zreg=freg=get_reg(f,2,p,0);
	  if((to&UNSIGNED)&&x_t[to&NQ]!='l'){
	    int dreg=get_reg(f,1,p,0);
	    emit(f,"\tmoveq\t#0,%s\n",mregnames[dreg]);
	    move(f,&p->q1,0,0,dreg,to);
	    move(f,0,dreg,0,zreg,LONG);
	  }else{
	    if(!isreg(q1)||p->q1.reg!=zreg)
	      move(f,&p->q1,0,0,zreg,to);
	  }
	  if(!ISFLOAT(t)){
	    if((t&UNSIGNED)&&!ISHWORD(t)){
	      char *s;
	      int dreg1,dreg2;
	      int l1=++label,l2=++label;
	      if(GAS) s="0x"; else s="$";
	      if(isreg(z)) 
		dreg1=p->z.reg;
	      else
		dreg1=get_reg(f,1,p,0);
	      if(FPU==68040)
		dreg2=get_reg(f,1,p,0);
	      if(!freg){
		if(!(isreg(q1)&&p->next&&p->next->code==FREEREG&&p->next->q1.reg==zreg)){
		  freg=get_reg(f,2,p,1);
		  emit(f,"\tfmove.x\t%s,%s\n",mregnames[zreg],mregnames[freg]);
		  zreg=freg;
		}		
	      }
	      emit(f,"\tfcmp.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]);
	      emit(f,"\tfbge\t%s%d\n",labprefix,l1);
	      if(FPU==68040){
		emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
		emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
		emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
		emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
	      }else{
		emit(f,"\tfintrz\t%s\n",mregnames[zreg]);
	      }
	      emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
	      emit(f,"\tbra\t%s%d\n",labprefix,l2);
	      emit(f,"%s%d:\n",labprefix,l1);
	      emit(f,"\tfsub.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]);
	      if(FPU==68040){
		emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
		emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
		emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
		emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
	      }else{
		emit(f,"\tfintrz\t%s\n",mregnames[zreg]);
	      }
	      emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
	      emit(f,"\tbchg\t#31,%s\n",mregnames[dreg1]);
	      emit(f,"%s%d:\n",labprefix,l2);
	      if(FPU==68040)
		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix);
	      move(f,0,dreg1,&p->z,0,t);
	      continue;
	    }	      
	    /*  nach integer, d.h. Kommastellen abschneiden */
	    if(FPU==68040/*||FPU==68060*/){
	      /*  bei 040 emuliert    */
	      int dreg1,dreg2;
	      if(!NOINTZ){
		if(isreg(z))
		  dreg1=p->z.reg;
		else
		  dreg1=get_reg(f,1,p,0);
		dreg2=get_reg(f,1,p,0);
		emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]);
		emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]);
		emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]);
		emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]);
		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix);
	      }else{
		dreg1=get_reg(f,1,p,0);
	      }
	      if((t&UNSIGNED)&&ISHWORD(t)){
		emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]);
		emit(f,"\tmove.%c\t%s,",x_t[t&NQ],mregnames[dreg1]);
	      }else{
		emit(f,"\tfmove.%c\t%s,",x_t[t&NQ],mregnames[zreg]);
	      }
	      emit_obj(f,&p->z,t);emit(f,"\n");
	      if(!NOINTZ)
		emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix);
	      continue;
	    }else{
	      if(!NOINTZ){
		if(!isreg(q1)||p->q1.reg!=zreg){
		  emit(f,"\tfintrz.x\t%s\n",mregnames[zreg]);
		}else{
		  int nreg=get_reg(f,2,p,1);
		  emit(f,"\tfintrz.x\t%s,%s\n",mregnames[zreg],mregnames[nreg]);
		  zreg=nreg;
		}
	      }
	      if((t&UNSIGNED)&&ISHWORD(t)){
		int r;
		if(isreg(z)) r=p->z.reg; else r=get_reg(f,1,p,0);
		move(f,0,zreg,0,r,LONG);
		move(f,0,r,&p->z,0,t);
	      }else{
		move(f,0,zreg,&p->z,0,t);
	      }
	      continue;
	    }
	  }
	  if((to&UNSIGNED)&&x_t[to&NQ]=='l'){
	    int nlabel;
	    emit(f,"\ttst.%c\t",x_t[to&NQ]);
	    emit_obj(f,&p->q1,to);emit(f,"\n");
	    nlabel=++label;
	    emit(f,"\tbge.s\t%s%d\n",labprefix,nlabel);
	    emit(f,"\tfadd.d\t#4294967296,%s\n",mregnames[zreg]);
	    emit(f,"%s%d:\n",labprefix,nlabel);
	  }
	  if(!(p->z.reg)||p->z.reg!=zreg){
	    move(f,0,zreg,&p->z,0,t);
	  }
	}else{
	  cc_set=0;
	  if((to&NQ)==(t&NQ)){
	    assign(f,p,&p->q1,&p->z,ASSIGN,sizetab[to&NQ],t);
	    continue;
	  }
	  if((to&NQ)==FLOAT&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)){
	    if(!OLD_SOFTFLOAT)
	      ierror(0);
	    saveregs(f,p);
	    assign(f,p,&p->q1,0,PUSH,msizetab[FLOAT],FLOAT);
	    scratch_modified();
	    if(GAS){
	      emit(f,"\t.global\t__ieees2d\n\tjbsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
	    }else{
	      emit(f,"\tpublic\t__ieees2d\n\tjsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
	    }
	    pop(4);
	    restoreregsa(f,p);
	    stored0d1(f,&p->z,t);
	    restoreregsd(f,p);
	    continue;
	  }
	  if(((to&NQ)==DOUBLE||(to&NQ)==LDOUBLE)&&(t&NQ)==FLOAT){
	    if(!OLD_SOFTFLOAT) ierror(0);
	    saveregs(f,p);
	    assign(f,p,&p->q1,0,PUSH,msizetab[DOUBLE],DOUBLE);
	    scratch_modified();
	    if(GAS){
	      emit(f,"\t.global\t__ieeed2s\n\tjbsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
	    }else{
	      emit(f,"\tpublic\t__ieeed2s\n\tjsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
	    }
	    pop(8);
	    restoreregsa(f,p);
	    move(f,0,d0,&p->z,0,t);
	    restoreregsd(f,p);
	    continue;
	  }
	  if(ISFLOAT(to)){
	    int uns;
	    if(!OLD_SOFTFLOAT) ierror(0);
	    saveregs(f,p);
	    if(t&UNSIGNED) uns='u'; else uns='s';
	    assign(f,p,&p->q1,0,PUSH,sizetab[to&NQ],to);
	    scratch_modified();
	    if(GAS){
	      emit(f,"\t.global\t__ieeefix%c%c\n\tjbsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]);
	    }else{
	      emit(f,"\tpublic\t__ieeefix%c%c\n\tjsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]);
	    }
	    pop(sizetab[to&NQ]);
	    restoreregsa(f,p);
	    move(f,0,d0,&p->z,0,t);
	    restoreregsd(f,p);
	    continue;
	  }else{
	    int uns,xt=x_t[to&NQ];
	    if(!OLD_SOFTFLOAT) ierror(0);
	    saveregs(f,p);
	    if(to&UNSIGNED) uns='u'; else uns='s';
	    if(xt!='l'){
	      emit(f,"\tsubq.%s\t#4,%s\n",strshort[1],mregnames[sp]);
	      push(4);
	    }
	    emit(f,"\tmove.%c\t",xt);
	    emit_obj(f,&p->q1,to);
	    if(xt!='l')
	      emit(f,",(%s)\n",mregnames[sp]); 
	    else{
	      emit(f,",-(%s)\n",mregnames[sp]);
	      push(4);
	    }
	    scratch_modified();
	    if(GAS){
	      emit(f,"\t.global\t__ieeeflt%c%c%c\n\tjbsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]);
	    }else{
	      emit(f,"\tpublic\t__ieeeflt%c%c%c\n\tjsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]);
	    }
	    pop(4);
	    restoreregsa(f,p);
	    if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)
	      stored0d1(f,&p->z,t);
	    else
	      move(f,0,d0,&p->z,0,t);
	    restoreregsd(f,p);
	    continue;
	  }
	}
	continue;
      }
      if((to&NQ)<(t&NQ)){
	int zreg;
	if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7){
	  zreg=p->z.reg;
	}else{
	  zreg=get_reg(f,1,p,0);
	}
	if(sizetab[t&NQ]!=sizetab[LONG]||sizetab[to&NQ]!=sizetab[LONG]){
	  /*  aufpassen, falls unsigned und Quelle==Ziel  */
	  if((to&UNSIGNED)&&isreg(q1)&&zreg==p->q1.reg){
	    unsigned long l;
	    if((to&NQ)==CHAR) l=0xff; else l=0xffff;
	    emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]);
	    continue;
	  }
	  if((to&UNSIGNED)&&p->q1.am&&(zreg==p->q1.am->basereg||zreg==(p->q1.am->dreg&127))){
	    /*  aufpassen, falls unsigned und Ziel im am  */
	    unsigned long l;
	    if((to&NQ)==CHAR) l=0xff; else l=0xffff;
	    move(f,&p->q1,0,0,zreg,to);
	    emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]);
	  }else{
	    if(to&UNSIGNED)
	      emit(f,"\tmoveq\t#0,%s\n",mregnames[zreg]);
	    move(f,&p->q1,0,0,zreg,to);
	  }
	  if(!(to&UNSIGNED)){
#ifdef M68K_16BIT_INT
	    if((to&NQ)==CHAR&&((t&NQ)==SHORT||(t&NQ)==INT)) emit(f,"\text.w\t%s\n",mregnames[zreg]);
	    if(((to&NQ)==SHORT||(to&NQ)==INT)&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]);
#else
	    if((to&NQ)==CHAR&&(t&NQ)==SHORT) emit(f,"\text.w\t%s\n",mregnames[zreg]);
	    if((to&NQ)==SHORT&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]);
#endif
	    if((to&NQ)==CHAR&&msizetab[t&NQ]==4){
	      if(cf||CPU>=68020)
		emit(f,"\textb.l\t%s\n",mregnames[zreg]);
	      else
		emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[zreg],mregnames[zreg]);
	    }
	  }
	}
	if(!isreg(z)||p->z.reg!=zreg){
	  move(f,0,zreg,&p->z,0,t);
	}
      }else{
	long diff;int m;
	m=0;
	if(p->q1.flags&REG){
	  p->q1.val.vmax=l2zm(0L);
	  p->q1.flags|=D16OFF;m=1;
	}
	diff=msizetab[to&NQ]-msizetab[t&NQ];
	vmax=l2zm(diff);
	p->q1.val.vmax=zmadd(p->q1.val.vmax,vmax);
	move(f,&p->q1,0,&p->z,0,t);
	vmax=l2zm(diff);
	p->q1.val.vmax=zmsub(p->q1.val.vmax,vmax);
	if(m) p->q1.flags&=~D16OFF;
	if(compare_objects(&p->q1,&p->z))
	  cc_set=0;
      }
      continue;
    }
    if(ISFLOAT(t)&&FPU>68000) *fp='f'; else *fp=0;
    if(c==MINUS||c==KOMPLEMENT){
      int zreg;
      if(ISFLOAT(t)){
	if(FPU>68000){
	  if(isreg(z)) zreg=p->z.reg; else zreg=get_reg(f,2,p,1);
	  emit(f,"\tfneg.");
	  if(isreg(q1)) emit(f,"x\t%s",mregnames[p->q1.reg]);
	  else    {emit(f,"%c\t",x_t[t&NQ]);emit_obj(f,&p->q1,t);}
	  emit(f,",%s\n",mregnames[zreg]);
	  if(!isreg(z)||p->z.reg!=zreg){
	    move(f,0,zreg,&p->z,0,t);
	  }
	  continue;
	}else{
	  if(!OLD_SOFTFLOAT) ierror(0);
	  saveregs(f,p);
	  assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
	  scratch_modified();
	  if(GAS){
	    emit(f,"\t.global\t__ieeeneg%c\n\tjbsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
	  }else{
	    emit(f,"\tpublic\t__ieeeneg%c\n\tjsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
	  }
	  pop(msizetab[t&NQ]);
	  restoreregsa(f,p);
	  if((t&NQ)!=FLOAT)
	    stored0d1(f,&p->z,t);
	  else
	    move(f,0,d0,&p->z,0,t);
	  restoreregsd(f,p);
	  continue;
	}
      }
      if(!cf&&compare_objects(&p->q1,&p->z)){
	emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]);
	emit_obj(f,&p->q1,t);emit(f,"\n");
	continue;
      }
      if(isreg(z)&&p->z.reg>=d0/*&&p->z.reg<=d7*/)
	zreg=p->z.reg; else zreg=get_reg(f,1,p,1);
      if(!isreg(q1)||p->q1.reg!=zreg){
	move(f,&p->q1,0,0,zreg,t);
      }
      emit(f,"\t%s.%c\t%s\n",ename[c],x_t[t&NQ],mregnames[zreg]);
      if(!isreg(z)||p->z.reg!=zreg){
	move(f,0,zreg,&p->z,0,t);
      }
      continue;
    }
    if(c==SETRETURN){
      /*  Returnwert setzen - q2.val.vmax==size, z.reg==Returnregister */
      if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&p->z.reg==d0){
	BSET(regs_modified,d0);BSET(regs_modified,10);
	if(isconst(q1)){
	  unsigned char *ip=(unsigned char *)&p->q1.val.vdouble;
	  char *s;
	  if(GAS) s="0x"; else s="$";
	  emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[0],ip[1],ip[2],ip[3],mregnames[d0]);
	  emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[d1]);
	  continue;
	}
	if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){
	  emit(f,"\tfmove.d\t%s,-(%s)\n\tmovem.l\t(%s)+,%s\n",mregnames[p->q1.reg],mregnames[sp],mregnames[sp],mregnames[d0d1]);
	}else{
	  loadd0d1(f,&p->q1,t);
	}
	continue;
      }
      if((ISSTRUCT(t)||ISUNION(t))&&p->z.reg==d0){
	long l=zm2l(p->q2.val.vmax);
	emit(f,"\tmovem.l\t");emit_obj(f,&p->q1,t);
	emit(f,",%s",mregnames[d0]);BSET(regs_modified,d0);
	if(l>=8) {emit(f,"/%s",mregnames[d1]);BSET(regs_modified,d1);}
	if(l>=12) {emit(f,"/%s",mregnames[a0]);BSET(regs_modified,a0);}
	if(l>=16) {emit(f,"/%s",mregnames[a1]);BSET(regs_modified,a1);}
	emit(f,"\n");
	continue;
      }
      /*  Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig    */
      if(p->z.reg){
	move(f,&p->q1,0,0,p->z.reg,p->typf);
	BSET(regs_modified,p->z.reg);
	if(v->tattr&AMIINTERRUPT){
	  /* if necessary, set condition-codes */
	  if(p->z.reg!=d0) ierror(0);
	  if(isreg(q1)&&p->q1.reg==d0)
	    emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[d0]);
	}
      }
      continue;
    }
    if(c==GETRETURN){
      /*  Returnwert holen - q2.val.vmax==size, q1.reg==Returnregister     */
      if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&(p->q1.reg==d0||p->q1.reg==d0d1)){
	if(isreg(z)&&p->z.reg>=fp0&&p->z.reg<=fp7){
	  emit(f,"\tmovem.l\t%s,-(%s)\n\tfmove.d\t(%s)+,%s\n",mregnames[d0d1],mregnames[sp],mregnames[sp],mregnames[p->z.reg]);
	}else{
	  stored0d1(f,&p->z,t);
	}
	continue;
      }
      if((ISSTRUCT(t)||ISUNION(t))&&p->q1.reg==d0){
	long l=zm2l(p->q2.val.vmax);
	emit(f,"\tmovem.l\t");
	emit(f,"%s",mregnames[d0]);
	if(l>=8) emit(f,"/%s",mregnames[d1]);
	if(l>=12) emit(f,"/%s",mregnames[a0]);
	if(l>=16) emit(f,"/%s",mregnames[a1]);
	emit(f,",");emit_obj(f,&p->z,t);emit(f,"\n");
	continue;
      }

      /*  Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig    */
      cc_set=0;
      if(p->q1.reg){
	move(f,0,p->q1.reg,&p->z,0,p->typf);
	if(!(p->z.flags&REG)||(p->z.reg!=p->q1.reg&&p->z.reg>=d0)){ cc_set=&p->z;cc_typ=p->typf;}
      }
      continue;
    }
    if(c==CALL){
      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){
	int sr=(USEFRAMEPOINTER||vlas)?fbp:sp;
	long va_off=0;
	if(USEFRAMEPOINTER||vlas){
	  emit(f,"\tmove.l\t%s,%s\n",mregnames[fbp],mregnames[d0]);
	  emit(f,"\tadd.l\t#%ld,%s\n",(long)(8+zm2l(va_offset(v)))+(PROFILER?16:0),mregnames[d0]);
	}else{
	  emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[d0]);
	  emit(f,"\tadd.l\t#%s%d+%ld,%s\n",labprefix,offlabel,(long)(4+zm2l(va_offset(v)))+loff+(PROFILER?16:0),mregnames[d0]);
	}
	BSET(regs_modified,d0);
	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);
	if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))
	  callee_push(zum2ul(p->q1.v->fi->stack1));
	else
	  stack_valid=0;
      }else{
	if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){
	  if(1/*CPU<68020*/){
	    emit(f,"\tpea\t%s%d(pc)\n",labprefix,++label);
	    emit(f,"\tmove.l\t");
	  }else
	    emit(f,"\t%s\t([",GAS?"jbsr":"jsr");
	  p->q1.flags&=~DREFOBJ;
	  emit_obj(f,&p->q1,POINTER);
	  p->q1.flags|=DREFOBJ;
	  if(1/*CPU<68020*/){
	    emit(f,",-(%s)\n",mregnames[sp]);
	    emit(f,"\trts\n");
	    emit(f,"%s%d%s\n",labprefix,label,GAS?":":"");
	  }else
	    emit(f,"])\n");
	}else{
	  if(GAS){
	    emit(f,"\tjbsr\t");
	  }else{
	    emit(f,"\tjsr\t");
	  }
	  /*  Wenn geta4() aufgerufen wurde, merken.  */
	  if(use_sd&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"geta4")&&p->q1.v->storage_class==EXTERN)
	    geta4=1;
	  if((p->q1.flags&(DREFOBJ|REG|KONST))==DREFOBJ) ierror(0);
	  emit_obj(f,&p->q1,t);
	  emit(f,"\n");
	}
	push(4);
	if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK))
	  callee_push(zum2ul(p->q1.v->fi->stack1));
	else
	  stack_valid=0;
	pop(4);
      }
      if(debug_info&&HUNKDEBUG) act_line=0;
      if(!zmeqto(p->q2.val.vmax,l2zm(0L))){
	notpopped+=zm2l(p->q2.val.vmax);
	dontpop-=zm2l(p->q2.val.vmax);
	if(!NODELAYEDPOP&&!(pushedreg&30)&&!vlas&&stackoffset==-notpopped){
	  /*  Entfernen der Parameter verzoegern  */
	}else{
	  if(debug_info&&HUNKDEBUG&&!GAS){ act_line=p->line; emit(f,"\tdebug\t%d\n",act_line);}
	  emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[zm2l(p->q2.val.vmax)<=8],strshort[zm2l(p->q2.val.vmax)<32768],zm2l(p->q2.val.vmax),mregnames[sp]);
	  pop(zm2l(p->q2.val.vmax));
	  notpopped-=zm2l(p->q2.val.vmax);
	}
      }
      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){
	bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE);
      }else{
	int i;
	for(i=1;i<=MAXR;i++){
	  if(regscratch[i])
	    if(i<fp0||i>fp7||FPU>68000) 
	      BSET(regs_modified,i);
	}
      }
      continue;
    }
    if(c==TEST){
      /*  ConditionCodes schon gesetzt?   */
      cc_set=&p->q1;cc_typ=t;
      comptyp=t;
      if(cc_set_tst&&t==cc_typ_tst){
	IC *branch;
	if(t&UNSIGNED){
	  branch=p->next;
	  while(branch&&(branch->code<BEQ||branch->code>BGT))
	    branch=branch->next;
	  if(!branch) continue;
	  if(branch->code==BLE) branch->code=BEQ;
	  if(branch->code==BGT) branch->code=BNE;
	  if(branch->code==BGE) {branch->code=BRA;continue;}
	  if(branch->code==BLT) {branch->code=NOP;continue;}
	}
	if(compare_objects(&p->q1,cc_set_tst)&&p->q1.am==cc_set_tst->am&&zmeqto(p->q1.val.vmax,cc_set_tst->val.vmax)){
	  if(DEBUG&512){emit(f,"; tst eliminated: cc=");emit_obj(f,cc_set_tst,t);
	  emit(f,", q1=");emit_obj(f,&p->q1,t);emit(f,"\n");}
	  continue;
	}
      }
      if(CPU<68020&&isreg(q1)&&p->q1.reg>=1&&p->q1.reg<=8){
	/*  tst ax gibt es nicht bei <68000 :-( */
	if(regavailable(1)){
	  emit(f,"\tmove.%c\t%s,%s\n",x_t[t&NQ],mregnames[p->q1.reg],mregnames[get_reg(f,1,p,0)]);
	}else{
	  emit(f,"\tcmp.%c\t#0,%s\n",cf?'l':'w',mregnames[p->q1.reg]);
	}
	continue;
      }
      if(ISFLOAT(t)&&FPU<=68000){
	/*  nicht sehr schoen   */
	int result=get_reg(f,1,p,0);
	if(!OLD_SOFTFLOAT) ierror(0);
	saveregs(f,p);
	assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
	scratch_modified();
	if(GAS){
	  emit(f,"\t.global\t__ieeetst%c\n\tjbsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
	}else{
	  emit(f,"\tpublic\t__ieeetst%c\n\tjsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]);
	}
	pop(msizetab[t&NQ]);
	restoreregsa(f,p);
	if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]);
	emit(f,"\ttst.l\t%s\n",mregnames[result]);
	restoreregsd(f,p);
	continue;
      }
      if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){
	emit(f,"\tftst.x\t%s\n",mregnames[p->q1.reg]);
      }else if(p->q1.flags&(VARADR|KONST)){
	int r=get_reg(f,1,p,0);
	emit(f,"\tmove.%c\t",x_t[t&NQ]);
	emit_obj(f,&p->q1,t);
	emit(f,",%s\n",mregnames[r]);
      }else{
	emit(f,"\t%stst.%c\t",fp,x_t[t&NQ]);emit_obj(f,&p->q1,t);
	emit(f,"\n");
      }
      continue;
    }
    if(c==ASSIGN||c==PUSH){
      if(c==ASSIGN&&compare_objects(&p->q1,&p->z)) cc_set=0;
      if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax);
      assign(f,p,&p->q1,&p->z,c,zm2l(p->q2.val.vmax),t);
      continue;
    }
    if(c==ADDRESS){
      int zreg;
      if(isreg(z)&&p->z.reg>=1&&p->z.reg<=8)
	zreg=p->z.reg; else zreg=get_reg(f,0,p,0);
      emit(f,"\tlea\t");emit_obj(f,&p->q1,t);
      emit(f,",%s\n",mregnames[zreg]);
      if(!isreg(z)||p->z.reg!=zreg){
	move(f,0,zreg,&p->z,0,POINTER);
      }
      continue;
    }
    if(c==COMPARE){
      int zreg;
      comptyp=t;
      if(isconst(q1)||isreg(q2)){
	/*  evtl. Argumente von cmp und nachfolgendes bcc umdrehen  */
	IC *n;obj m;
	n=p->next;
	while(n){
	  if(n->code>=BEQ&&n->code<BRA){
	    if(!p->z.flags){
	      if(DEBUG&1) printf("arguments of cmp exchanged\n");
	      m=p->q1;p->q1=p->q2;p->q2=m;
	      p->z.flags=1;
	    }
	    /*  nachfolgenden Branch umdrehen   */
	    switch(n->code){
	    case BGT: n->code=BLT;break;
	    case BLT: n->code=BGT;break;
	    case BGE: n->code=BLE;break;
	    case BLE: n->code=BGE;break;
	    }
	    break;
	  }
	  if(n->code==FREEREG) n=n->next; else break; /*  compare ohne branch => leerer Block o.ae.   */
	}
      }
      if(ISFLOAT(t)){
	if(FPU>68000){
	  if(isreg(q1)&&p->q1.reg>=fp0){
	    zreg=p->q1.reg;
	  }else{
	    zreg=get_reg(f,2,p,0);
	    move(f,&p->q1,0,0,zreg,t);
	  }
	  if(isreg(q2)){emit(f,"\tfcmp.x\t%s,%s\n",mregnames[p->q2.reg],mregnames[zreg]);continue;}
	  emit(f,"\tfcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
	  emit(f,",%s\n",mregnames[zreg]);
	  continue;
	}else{
	  /*  nicht sehr schoen   */
	  int result=get_reg(f,1,p,0);
	  if(!OLD_SOFTFLOAT) ierror(0);
	  saveregs(f,p);
	  assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t);
	  assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
	  scratch_modified();
	  if(GAS){
	    emit(f,"\t.global\t__ieeecmp%c\n\tjbsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
	  }else{
	    emit(f,"\tpublic\t__ieeecmp%c\n\tjsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
	  }
	  pop(2*msizetab[t&NQ]);
	  restoreregsa(f,p);
	  if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]);
	  emit(f,"\ttst.l\t%s\n",mregnames[result]);
	  restoreregsd(f,p);
	  continue;
	}
      }
      if(cf&&x_t[t&NQ]!='l'){
	if(isreg(q1)) zreg=p->q1.reg; else zreg=get_reg(f,1,p,0);
	loadext(f,zreg,&p->q1,t);
	if(isconst(q2)){
	  emit(f,"\tcmp.l\t");
	  emit_obj(f,&p->q2,t);
	}else{
	  int r;
	  if(isreg(q2)) r=p->q2.reg; else r=get_reg(f,1,p,0);
	  loadext(f,r,&p->q2,t);
	  emit(f,"\tcmp.l\t%s",mregnames[r]);
	}
	emit(f,",%s\n",mregnames[zreg]);
	continue;
      }
      if((p->q2.flags&(KONST|VARADR))&&!(p->q1.flags&(KONST|VARADR))&&(!cf||isreg(q1))){
	emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
	emit(f,",");emit_obj(f,&p->q1,t);emit(f,"\n");
	continue;
      }
      if(isreg(q1)){
	zreg=p->q1.reg;
      }else{
	zreg=get_reg(f,1,p,1);    /* hier evtl. auch Adressregister nehmen */
	move(f,&p->q1,0,0,zreg,t);
      }
      emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t);
      emit(f,",%s\n",mregnames[zreg]);
      continue;
    }
    if(c==ADDI2P||c==SUBIFP){
      int zreg=-1,r;

      /*  hier die zweite Alternative mit isreg() schreiben?  */
      if((((p->q2.flags&REG)&&(p->z.flags&REG)&&p->q2.reg==p->z.reg&&(!(p->q1.flags&REG)||p->q1.reg!=p->z.reg))||
	 (compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q1,&p->z)))){
	obj m;
	if(c==ADDI2P&&x_t[t&NQ]=='l'){
	  m=p->q1;p->q1=p->q2;p->q2=m;
	}else{
	  if(!cf&&x_t[t&NQ]=='l'&&isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
	    m=p->q1;p->q1=p->q2;p->q2=m;
	    c=ADDI2P;
	    emit(f,"\tneg.%c\t",x_t[t&NQ]);
	    emit_obj(f,&p->q1,t);emit(f,"\n");
	  }else{
	    zreg=get_reg(f,0,p,0);
	  }
	}
      }

      if(isreg(q1)&&p->q1.reg<=8&&isreg(z)&&p->z.reg<=8&&p->q1.reg!=p->z.reg){
	/*  q1 und z Adressregister => lea nehmen   */
	if(isconst(q2)){
	  eval_const(&p->q2.val,t);
	  if(c==SUBIFP) vmax=zmsub(l2zm(0L),vmax);
	  if(CPU>=68020||(zmleq(vmax,l2zm(32767))&&zmleq(l2zm(-32768),vmax))){
	    emit(f,"\tlea\t(%ld",zm2l(vmax));
	    if(!GAS&&zm2l(vmax)>0x7fff)
	      emit(f,".l");
	    emit(f,",%s),%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]);
	    continue;
	  }
	}else if(c==ADDI2P&&isreg(q2)){
	  emit(f,"\tlea\t(%s,%s.%c),%s\n",mregnames[p->q1.reg],mregnames[p->q2.reg],x_t[t&NQ],mregnames[p->z.reg]);
	  continue;
	}
      }
      if(compare_objects(&p->q1,&p->z)){
	if(isconst(q2)&&(!cf||isquickkonst2(&p->q2.val,t))){
	  if(c==ADDI2P)
	    emit(f,"\tadd%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
	  else
	    emit(f,"\tsub%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
	  emit_obj(f,&p->q2,t);emit(f,",");
	  emit_obj(f,&p->z,POINTER);emit(f,"\n");
	  continue;
	}
	if(isreg(q1)&&(x_t[t&NQ]=='l'||p->q1.reg<=8)){
	  if(c==ADDI2P)
	    emit(f,"\tadd.%c\t",x_t[t&NQ]);
	  else
	    emit(f,"\tsub.%c\t",x_t[t&NQ]);
	  emit_obj(f,&p->q2,t);emit(f,",%s\n",mregnames[p->z.reg]);
	  continue;
	}
	if(isreg(q2)&&p->q2.reg>=9&&p->q2.reg<=16){
	  r=p->q2.reg;
	}else{
	  r=get_reg(f,1,p,0);
	  move(f,&p->q2,0,0,r,t);
	}
	if(x_t[t&NQ]!='l'&&(!isreg(z)||p->z.reg<1||p->z.reg>8)){
	  /*  wenn Ziel kein Adressregister, muss short erst auf long */
	  /*  char darf hier nicht auftreteten und long passt schon   */
	  if(t&UNSIGNED){
	    if(CPU>=68040)
	      emit(f,"\tand.l\t#65535,%s\n",mregnames[r]);
	    else
	      emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[r],mregnames[r],mregnames[r]);
	  }else 
	    emit(f,"\text.l\t%s\n",mregnames[r]);
	  t=POINTER;
	}
	/*                if(c==ADDI2P)
			  emit(f,"\tadd.%c\t%s,",x_t[t&NQ],mregnames[r]);
			  else
			  emit(f,"\tsub.%c\t%s,",x_t[t&NQ],mregnames[r]);
			  emit_obj(f,&p->z,t);emit(f,"\n");*/
	if(c==ADDI2P) 
	  add(f,0,r,&p->z,0,t);
	else
	  sub(f,0,r,&p->z,0,t);
	continue;
      }
      if(isreg(z)&&zreg==-1&&p->z.reg>=1&&p->z.reg<=d7)
	zreg=p->z.reg; 
      else 
	zreg=get_reg(f,0,p,0);
      /*  Spezialfall, falls Ziel Datenregister und short */
      /*  nicht schoen, aber auf die Schnelle...          */
      if(x_t[t&NQ]!='l'&&zreg>8){
	move(f,&p->q2,0,0,zreg,t);
	if(t&UNSIGNED){
	  if(CPU>=68040)
	    emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
	  else
	    emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[zreg],mregnames[zreg],mregnames[zreg]);
	}else
	  emit(f,"\text.l\t%s\n",mregnames[zreg]);
	if(c==SUBIFP) emit(f,"\tneg.l\t%s\n",mregnames[zreg]);
	add(f,&p->q1,0,0,zreg,POINTER);
	if(!isreg(z)||p->z.reg!=zreg)
	  move(f,0,zreg,&p->z,0,POINTER);
	continue;
      }
      if(!isreg(q1)||p->q1.reg!=zreg){
	move(f,&p->q1,0,0,zreg,POINTER);
      }
      if(c==ADDI2P)
	add(f,&p->q2,0,0,zreg,t);
      else 
	sub(f,&p->q2,0,0,zreg,t);
      if(!isreg(z)||p->z.reg!=zreg){
	move(f,0,zreg,&p->z,0,POINTER);
      }
      continue;
    }
    if((c>=OR&&c<=AND)||c==MULT||c==ADD){
      if(!isreg(q1)&&!isreg(z)&&isreg(q2)){
	obj o;
	o=p->q1;p->q1=p->q2;p->q2=o;
      }
    }
    switch_IC(p);
    if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){
      int zreg,q1reg,q2reg;
      if(isconst(q2)&&
	 (!(p->q1.flags&REG)||!(p->z.flags&REG)||p->q1.reg!=p->z.reg)&&
	 (!(p->q1.flags&VAR)||!(p->z.flags&VAR)||p->q1.v!=p->z.v)&&
	 ((c>=OR&&c<=AND)||c==ADD||c==MULT)){
	obj o;
	if(c==MULT){
	  eval_const(&p->q2.val,t);
	  if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)&&!pof2(vumax)){
	    o=p->q1;p->q1=p->q2;p->q2=o;
	  }
	}else{
	  if(!cf||!ISHWORD(t)){
	    o=p->q1;p->q1=p->q2;p->q2=o;
	  }
	}
      }
      if(ISFLOAT(t)){
	if(FPU>68000){
	  if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){
	    obj m;
	    if(c==ADD||c==MULT){
	      m=p->q1;p->q1=p->q2;p->q2=m;
	    }else{
	      if(isreg(q2)){
		if(c==SUB){
		  emit(f,"\tfneg.x\t%s\n",mregnames[p->q2.reg]);
		  m=p->q1;p->q1=p->q2;p->q2=m;
		  p->code=c=ADD;
		}else{
		  int tmp=get_reg(f,2,p,0);
		  move(f,&p->q2,0,0,tmp,t);
		  p->q2.reg=tmp;
		  p->q2.flags=REG;
		}
	      }
	    }
	  }
	  if(isreg(z)&&p->z.reg>=fp0)
	    zreg=p->z.reg;
	  else 
	    zreg=get_reg(f,2,p,1);
	  if(!isreg(q1)||p->q1.reg!=p->z.reg)
	    move(f,&p->q1,0,0,zreg,t);
	  emit(f,"\tf%s.",ename[c]);
	  if(isreg(q2))
	    emit(f,"x\t");
	  else
	    emit(f,"%c\t",x_t[t&NQ]);
	  emit_obj(f,&p->q2,t);
	  emit(f,",%s\n",mregnames[zreg]);
	  if(!isreg(z)||p->z.reg!=zreg){
	    move(f,0,zreg,&p->z,0,t);
	  }
	  continue;
	}else{
	  if(!OLD_SOFTFLOAT) ierror(0);
	  saveregs(f,p);
	  assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t);
	  assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t);
	  scratch_modified();
	  if(GAS){
	    emit(f,"\t.global\t__ieee%s%c\n\tjbsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
	  }else{
	    emit(f,"\tpublic\t__ieee%s%c\n\tjsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]);
	  }
	  pop(2*msizetab[t&NQ]);
	  restoreregsa(f,p);
	  if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)
	    stored0d1(f,&p->z,t);
	  else
	    move(f,0,d0,&p->z,0,t);
	  restoreregsd(f,p);
	  continue;
	}
      }
      if(((c==MULT||c==DIV)||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){
	/*  ersetzt mul etc. mit Zweierpotenzen     */
	/*  hier evtl. noch Fehler                  */
	long ln;
	eval_const(&p->q2.val,t);
	if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){
	  if(ln=pof2(vumax)){
	    if(c==MOD){
	      vmax=zmsub(vmax,l2zm(1L));
	      p->code=AND;
	    }else{
	      vmax=l2zm(ln-1);
	      if(c==DIV){
		p->code=RSHIFT;
		shiftisdiv=1;
	      }else
		p->code=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,INT);
	      p->typf2=INT;
	    }
	  }
	}
      }
      if(c==DIV||c==MOD){
	if(x_t[t&NQ]=='l'&&CPU<68020){
	  /*  das hier ist auch nicht allzu schoen  */
	  char *fname;
	  cc_set=0;   /*  Library-Funktionen setzen cc nicht immer */
	  saveregs(f,p);
	  emit(f,"\tmove.l\t"); emit_obj(f,&p->q2,t);
	  emit(f,",-(%s)\n",mregnames[sp]);
	  push(4);
	  emit(f,"\tmove.l\t"); emit_obj(f,&p->q1,t);
	  emit(f,",-(%s)\n",mregnames[sp]);
	  push(4);
	  if(t&UNSIGNED) fname="divu"; else fname="divs";
	  scratch_modified();
	  if(GAS){
	    emit(f,"\t.global\t__l%s\n\tjbsr\t__l%s\n",fname,fname);
	  }else{
	    emit(f,"\tpublic\t__l%s\n\tjsr\t__l%s\n",fname,fname);
	  }
	  emit(f,"\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]);
	  if(c==MOD) emit(f,"\tmove.l\td1,d0\n");
	  pop(8);
	  restoreregsa(f,p);
	  move(f,0,d0,&p->z,0,t);
	  restoreregsd(f,p);
	  continue;
	}

      }
      /*  hier die zweite Alternative mit isreg() schreiben?  */
      if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){
	obj m;
	if((c>=OR&&c<=AND)||c==ADD||c==SUB){
	  if(c!=SUB){
	    m=p->q1;p->q1=p->q2;p->q2=m;
	  }else{
	    if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
	      m=p->q1;p->q1=p->q2;p->q2=m;
	      c=ADD;
	      emit(f,"\tneg.%c\t",x_t[t&NQ]);
	      emit_obj(f,&p->q1,t);emit(f,"\n");
	    }
	  }
	}
      }
      if(compare_objects(&p->q1,&p->z)){
	if((c>=OR&&c<=AND)||c==ADD||c==SUB){
	  int r;
	  if(isconst(q2)&&(!cf||isreg(z)||((c==ADD||c==SUB)&&isquickkonst2(&p->q2.val,t&NQ)))){
	    if(cf&&((t&NQ)==CHAR||ISHWORD(t))){
	      if(isreg(q1)) r=p->q1.reg; else r=get_reg(f,1,p,1);
	      loadext(f,r,&p->q1,t);
	      emit(f,"\t%s.l\t",ename[c]);
	      emit_obj(f,&p->q2,t);
	      emit(f,",%s\n",mregnames[r]);
	      move(f,0,r,&p->z,0,t);
	      continue;
	    }else{
	      if(c==ADD) {add(f,&p->q2,0,&p->z,0,t);continue;}
	      if(c==SUB) {sub(f,&p->q2,0,&p->z,0,t);continue;}
	      emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]);
	      emit_obj(f,&p->q2,t);emit(f,",");
	      emit_obj(f,&p->z,t);emit(f,"\n");
	    }
	    continue;
	  }
	  if(!isreg(z)&&(!cf||x_t[t&NQ]=='l')){
	    if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7)
	      r=p->q2.reg; else r=get_reg(f,1,p,0);
	    if(!isreg(q2)||p->q2.reg!=r){
	      move(f,&p->q2,0,0,r,t);
	    }
	    emit(f,"\t%s.%c\t%s,",ename[c],x_t[t&NQ],mregnames[r]);
	    emit_obj(f,&p->z,t);emit(f,"\n");
	    continue;
	  }
	}
      }
      /*  bei xor oder asl (ausser 0<=const<=8) muss q2 in Register   */
      if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){
	q2reg=p->q2.reg;
      }else{
	if(c==LSHIFT||c==RSHIFT||c==XOR){
	  int t2=q2typ(p)&NU;
	  eval_const(&p->q2.val,t2);
	  if(c==XOR||!isconst(q2)||!isquickkonst2(&p->q2.val,t2)){
	    if((c==LSHIFT||c==RSHIFT)&&(p->typf2&NQ)==LLONG){
	      if(!isreg(q2)){
		q2reg=get_reg(f,1,p,0);
		emit(f,"\tmove.l\t");
		emit_lword(f,&p->q2);
		emit(f,",%s\n",mregnames[q2reg]);
	      }else{
		if(!reg_pair(p->q2.reg,&rp)) ierror(0);
		q2reg=rp.r2;
	      }
	    }else{
	      q2reg=get_reg(f,1,p,0);
	      move(f,&p->q2,0,0,q2reg,t2);
	    }
	  }else q2reg=0;
	}else{
	  q2reg=0;
	}
      }
      if(c==MOD&&!ISHWORD(t)){
	int modreg;
	if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&p->z.reg!=q2reg)
	  zreg=p->z.reg; else zreg=get_reg(f,1,p,0);
	modreg=get_reg(f,1,p,1);
	if(modreg==zreg) modreg=get_reg(f,1,p,0);
	move(f,&p->q1,0,0,modreg,t);
	if(0 /*CPU==68060*/){
	  /*  div?l.l wird da emuliert?   */
	  emit(f,"\tsmi\t%s\n\textb.l\t%s\n",mregnames[zreg],mregnames[zreg]);
	  if(t&UNSIGNED) emit(f,"\tdivu.%c\t",x_t[t&NQ]); else emit(f,"\tdivs.%c\t",x_t[t&NQ]);
	}else{
	  if(t&UNSIGNED) emit(f,"\tdivul.%c\t",x_t[t&NQ]); else emit(f,"\tdivsl.%c\t",x_t[t&NQ]);
	}
	emit_obj(f,&p->q2,t);
	emit(f,",%s:%s\n",mregnames[zreg],mregnames[modreg]);
	move(f,0,zreg,&p->z,0,t);
	cc_set=0;
	continue;
      }
      if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&(p->z.reg!=q2reg||(isreg(q1)&&p->q1.reg==q2reg)))
	zreg=p->z.reg; else zreg=get_reg(f,1,p,1);
      if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7)
	q1reg=p->q1.reg; else q1reg=0;
      if(q1reg!=zreg){
	move(f,&p->q1,0,0,zreg,t);
      }
      if(c!=MULT&&c!=DIV&&c!=MOD&&c!=ADD&&c!=SUB){
	if(cf&&c==RSHIFT){
	  if(cf&&(t&NU)==CHAR)
	    emit(f,"\textb.l\t%s\n",mregnames[zreg]);
	  else if(cf&&(t&NU)==SHORT)
	    emit(f,"\text.w\t%s\n",mregnames[zreg]);
	  if(cf&&(t&NU)==(UNSIGNED|CHAR))
	    emit(f,"\tand.l\t#255,%s\n",mregnames[zreg]);
	  else if(cf&&(t&NU)==(UNSIGNED|SHORT))
	    emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]);
	}
	if(shiftisdiv&&!(t&UNSIGNED)){
	  unsigned long l;
	  eval_const(&p->q2.val,p->typf2);
	  l=(1<<zum2ul(vumax))-1;
	  if(isreg(q1)&&p->q1.reg==zreg)
	    emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[zreg]);
	  emit(f,"\tbge\t%s%d\n",labprefix,++label);
	  emit(f,"\tadd%s.%c\t#%ld,%s\n",(l<=7?"q":""),x_t[t&NQ],l,mregnames[zreg]);
	  emit(f,"%s%d:\n",labprefix,label);
	}
	if(c==RSHIFT&&!(t&UNSIGNED))
	  emit(f,"\tasr.%c\t",cf?'l':x_t[t&NQ]);
	else
	  emit(f,"\t%s.%c\t",ename[c],cf?'l':x_t[t&NQ]);
	if(q2reg)
	  emit(f,"%s",mregnames[q2reg]);
	else 
	  emit_obj(f,&p->q2,q2typ(p));
	emit(f,",%s\n",mregnames[zreg]);
      }else{
	if(c==ADD) add(f,&p->q2,q2reg,0,zreg,t);
	if(c==SUB) sub(f,&p->q2,q2reg,0,zreg,t);
	if(c==MULT||c==DIV||c==MOD) mult(f,&p->q2,q2reg,0,zreg,t,c,p);
      }
      if((!isreg(z)||p->z.reg!=zreg)){
	move(f,0,zreg,&p->z,0,t);
      }
      continue;
    }
    ierror(0);
  }
  if(notpopped){
    emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]);
    pop(notpopped);notpopped=0;
  }
  function_bottom(f,v,zm2l(offset));
  if(debug_info&&!HUNKDEBUG){
    emit(f,"%s%d:\n",labprefix,++label);
    dwarf2_function(f,v,label);
    if(f) section=-1;
  }
  pushflag=0;
}

/*FIXME*/
int shortcut(int code,int typ)
{
  if(!cf&&(code==COMPARE||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT)) return(1);
  if(!cf&&code==MULT&&(typ&NQ)!=CHAR) return 1;

  return 0;
}
void init_db(FILE *f)
{
  if(!HUNKDEBUG){
    if(GAS)
      dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte","l","_",".section");
    else
      dwarf2_setup(sizetab[POINTER],"dc.b","dc.w","dc.l","dc.l","l","_","section");
    dwarf2_print_comp_unit_header(f);
  }
}
void cleanup_db(FILE *f)
{
  if(!HUNKDEBUG&&f){
    dwarf2_cleanup(f);
    if(f) section=-1;
  }
}
void cleanup_cg(FILE *f)
{
  title(f);
  if(f&&stack_check){
    if(GAS)
      emit(f,"\t.global\t___stack_check\n");
    else
      emit(f,"\tpublic\t___stack_check\n");
  }
  /*printf("pushed %d, saved %d, removed allocreg %d\n",missing,savedemit,savedalloc);*/
  return;
}

/* mark instructions which can (probably) be implemented with faster
   machine-code than the IC migh suggest, e.g. an addition which can
   be merged with a load bz use of target addressing-modes;
   the optimizer should hesitate to modifz such instructions if it's not
   a definite win */

static int is_single_eff_ic(IC *p)
{
  Var *v;
  if(p->code!=ADDI2P&&p->code!=SUBIFP)
    return 0;
  if(!isconst(q2)){
    if(CONSERVATIVE_SR){
      if((p->q2.flags&(VAR|DREFOBJ))!=VAR)
	return 0;
      if(p->q2.v->storage_class==STATIC||p->q2.v->storage_class==EXTERN)
	return 0;
    }else
      return 0;
  }
  if((p->q1.flags&(VAR|DREFOBJ))!=VAR)
    return 0;
  if(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN)
    return 0;
  if((p->z.flags&(VAR|DREFOBJ))!=VAR)
    return 0;
  if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)
    return 0;
  v=p->z.v;
  for(p=p->next;p;p=p->next){
    int c=p->code;
    if(c==LABEL||(c>=BEQ&&c<=BRA))
      return 0;
    if((p->q1.flags&VAR)&&p->q1.v==v){
      if(p->q1.flags&DREFOBJ)
	return 1;
      else
	return 0;
    }
    if((p->q2.flags&VAR)&&p->q2.v==v){
      if(p->q2.flags&DREFOBJ)
	return 1;
      else
	return 0;
    }
    if((p->z.flags&VAR)&&p->z.v==v){
      if(p->z.flags&DREFOBJ)
	return 1;
      else
	return 0;
    }
  }
}
void mark_eff_ics(void)
{
  IC *p;
  for(p=first_ic;p;p=p->next){
    if(is_single_eff_ic(p))
      p->flags|=EFF_IC;
    else
      p->flags&=~EFF_IC;
  }
}

int reg_pair(int r,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<=fp7) return 0;
  if(p){
    switch(r){
    case d0d1: p->r1=d0;p->r2=d1;break;
    case d2d3: p->r1=d2;p->r2=d3;break;
    case d4d5: p->r1=d4;p->r2=d5;break;
    case d6d7: p->r1=d6;p->r2=d7;break;
    default: ierror(0);
    }
  }
  return 1;
}

int emit_peephole(void)
{
  int entries,i,r1,r2,r3,r4;
  char *asmline[EMIT_BUF_DEPTH],c1,c2,c3,c4,e;

  if(OLDPEEPHOLE) return 0;
  i=emit_l;
  if(emit_f==0)
    entries=i-emit_f+1;
  else
    entries=EMIT_BUF_DEPTH;
  asmline[0]=emit_buffer[i];
  if(entries>=2){
    i--;
    if(i<0) i=EMIT_BUF_DEPTH-1;
    asmline[1]=emit_buffer[i];
    if(sscanf(asmline[1],"\tmove.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&&
       sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&&
       c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){
      sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1);
      remove_asm();
      savedemit++;
      return 1;
    }
    if(sscanf(asmline[1],"\tmovem.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&&
       sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&&
       c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){
      sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1);
      remove_asm();
      savedemit++;
      return 1;
    }

    if(sscanf(asmline[1],"\tmove.l\t%c%d,%c%d\n%c",&c1,&r1,&c2,&r2,&e)==4&&
       sscanf(asmline[0],"\tmove.l\t%c%d,%c%d\n%c",&c3,&r3,&c4,&r4,&e)==4&&
       c1==c4&&r1==r4&&c2==c3&&r2==r3&&r1>=0&&r1<=7&&r2>=0&&r2<=7&&
       (c1=='a'||c1=='d')&&(c2=='a'||c2=='d')){
      /* create tst instruction if condition codes of address register are needed */
      if(c1=='d'&&c2=='a'&&cc_set!=0&&(cc_set->flags&(REG|DREFOBJ))==REG&&cc_set->reg==a0+r2)
	sprintf(asmline[0],"\ttst.l\t%s\n",mregnames[d0+r1]);
      else
	remove_asm();
      savedemit++;
      return 1;
    }
  }
  return 0;
}

char *use_libcall(int c,int t,int t2)
{
  static char fname[32];
  char *ret=0;
  int f;

  t&=NU;
  t2&=NU;

  if(c==LSHIFT&&((t&NQ)==LLONG)) return "_lshint64";
  if(c==RSHIFT&&t==LLONG) return "_rshsint64";
  if(c==RSHIFT&&t==(UNSIGNED|LLONG)) return "_rshuint64";


  if(FPU>68000){
    if(c!=CONVERT) return 0;
    if((!ISFLOAT(t)||(t2&NQ)!=LLONG)&&
       (!ISFLOAT(t2)||(t&NQ)!=LLONG))
      return 0;
  }
  if(OLD_SOFTFLOAT) return 0;

  if(t==LDOUBLE) t=DOUBLE;
  if(t2==LDOUBLE) t2=DOUBLE;
  if(FLOAT64){
    if(t==FLOAT) t=DOUBLE;
    if(t2==FLOAT) t2=DOUBLE;
  }

  if(c==COMPARE){
    if(ISFLOAT(t)){
      sprintf(fname,"_ieeecmp%c",x_t[t]);
      ret=fname;
    }
  }else if(c==CONVERT){
    if(t2==INT) t2=(zm2l(sizetab[INT])==4?LONG:SHORT);
    if(t2==(UNSIGNED|INT)) t2=(sizetab[INT]==4?(UNSIGNED|LONG):(UNSIGNED|SHORT));
    if(t==FLOAT&&t2==DOUBLE) return "_ieeed2s";
    if(t==DOUBLE&&t2==FLOAT) return "_ieees2d";
    if(t==DOUBLE&&t2==DOUBLE) return 0;
    if(t==FLOAT||t==DOUBLE){
      if((t2&NQ)==LLONG)
	sprintf(fname,"_%cint64toflt%s",(t2&UNSIGNED)?'u':'s',t==FLOAT?"32":"64");
      else
	sprintf(fname,"_ieeeflt%c%c",(t2&UNSIGNED)?'u':'s',x_t[t]);
      ret=fname;
    }
    if(t2==FLOAT||t2==DOUBLE){
      if((t&NQ)==LLONG)
	sprintf(fname,"_flt%sto%cint64",t2==FLOAT?"32":"64",(t&UNSIGNED)?'u':'s');
      else
	sprintf(fname,"_ieeefix%c%c%c",x_t[t2],(t2&UNSIGNED)?'u':'s',x_t[t&NQ]);
      ret=fname;
    }
  }else if(ISFLOAT(t)){
    if(c==MINUS){
      sprintf(fname,"_ieeeneg%c",x_t[t&NQ]);
      ret=fname;
    }else if(c>=ADD&&c<=DIV){
      sprintf(fname,"_ieee%s%c",ename[c],x_t[t&NQ]);
      ret=fname;
    }
    if(c==TEST){
      sprintf(fname,"_ieeetst%c",x_t[t&NQ]);
      ret=fname;
    }
  }else if(CPU<68020&&!OLDLIBCALLS){
    if((c==DIV||c==MOD)&&ISINT(t)&&zm2l(sizetab[t&NQ])==4){
      sprintf(fname,"_%s%c",ename[c],(t&UNSIGNED)?'u':'s');
      ret=fname;
    }
  }
  return ret;
}


int reg_parm(treg_handle *p,type *t,int mode,type *fkt)
{
  int f;

  if(!fkt||fkt->flags!=FUNKT)
    ierror(0);

  if(!fkt->next)
    ierror(0);

  if(stdargs(fkt))
     return 0;

  f=t->flags&NQ;
  if(mode/*||f==LLONG||!ISSCALAR(f)*/)
    return 0;
  if(ISPOINTER(f)){
    if(p->ar>ascratch)
      return 0;
    else
      return a0+p->ar++;
  }
  if(ISFLOAT(f)||f==LLONG){
    if(FPU<=68000||f==LLONG){
      if(rparmtype==PARMSAS) return 0;
      if(f!=FLOAT){
	if(p->dr!=0) return 0;
	p->dr+=2;
	return d0d1;
      }
      if(p->dr>dscratch)
	return 0;
      else
	return d0+p->dr++;
    }else{
      if(p->fr>fscratch)
	return 0;
      else
	return fp0+p->fr++;
    }
  }
  if(!ISINT(f)) return 0;
  if(p->dr>dscratch)
    return 0;
  else
    return d0+p->dr++;
}

int handle_pragma(const char *s)
{
  if(!strncmp("stdargs-on",s,10)){
    add_stdargs=1;
    return 1;
  }
  if(!strncmp("stdargs-off",s,11)){
    add_stdargs=0;
    return 1;
  }
  return 0;
}

void add_var_hook_pre(const char *identifier, type *t, int storage_class,const_list *clist)
{
  if(!add_stdargs) return;
  if(ISFUNC(t->flags))
    add_attr(&t->next->attr,"__stdargs");
}
