/*  File, das maschinenabhaengige Daten und Routinen fuer Codeerzeugung */
/*  fuer Motorola 680x0-CPUs enthaelt (z.Z. auf 020+881 ausgerichtet).  */

#include "vbc.h"

/*  ab hier public Data, die vorhanden sein MUSS    */

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


/*  Codegenerator-Flags                                 */
int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,0,0,0,0,0,0};
char *g_flags_name[MAXGF]={"cpu","fpu","d2scratch","noa4","sc","sd","prof","-","-","-"};
union ppi g_flags_val[MAXGF];

/* Tabelle fuer alignment requirements, maschinenabhaengig */
int align[]={1,1,2,2,2,2,2,2,2,2,2,2,2,2,2};
int maxalign=2;

/*  Tabelle fuer die Groesse der einzelnen Typen    */
int sizetab[]={0,1,2,4,4,4,8,0,4,0,0,0,4,0};

/*  Tabelle fuer minimale und maximale Werte der Integer-Typen  */
zlong t_min[32];
zulong t_max[32];

/*  Namen der Register              */
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"};

/*  Anfangswerte fuer die Register  */
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};

/*  Werden Register von Funktionen evtl. zerstoert? */
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};

/*  Speicher fuer die Register      */
int regs[MAXR+1];

/*  Merker, ob Register benutzt wurden  */
int regused[MAXR+1];

/*  Variablen, die in Register liegen   */
struct Var *regsv[MAXR+1];

extern int float_used;

/*  Ab hier private Data, speziell fuer einen Codegenerator */

char reglist[200];

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

int reglabel,freglabel,section=-1;
char *codename,*bssname,*dataname;

struct IC *do_refs(FILE *,struct IC *);
void pr(FILE *,struct IC *);
int get_reg(FILE *,int,struct IC *);
long pof2(zulong);
void function_top(FILE *,struct Var *,int);
void function_bottom(FILE *f,struct Var *,int);

void saverestoreregs(FILE *,int,int);

void assign(FILE *,struct IC *,struct obj *,struct obj *,int,int,int);

char x_s[]={'0','b','w','3','l'};
char x_t[]={'?','b','w','l','l','s','d','v','l','a','s','u','e','f','?','?'};

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

char *ubranch[]={"beq","bne","blo","bhs","bls","bhi"};

int pushedreg,stored_cc; /* pushedreg&2: aregsaved; 4: dreg; 8: freg */

#define D16OFF 1024

#ifndef SEEK_SET
#define SEEK_SET 0
#endif

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

int init_cg(void)
/*  Initialisiert evtl. maschinenspezifische Sachen, liefert 0, */
/*  wenn etwas schiefgegangen ist                               */
{
    /*  default CPU ist 68000   */
    if(!(g_flags[0]&USEDFLAG)) g_flags_val[0].l=68000;
    /*  keine FPU per default   */
    if(!(g_flags[1]&USEDFLAG)) g_flags_val[1].l=0;
    if(g_flags_val[1].l<68000) {x_t[FLOAT]='l';}
    /*  d2 als Scratchregister markeiren, wenn cclib benutzt wird   */
    if(g_flags[2]&USEDFLAG) regscratch[11]=1;
    /*  a4 als Scratchregister markeiren, wenn sclib benutzt wird   */
    if(g_flags[3]&USEDFLAG) regsa[5]=1;
    codename="\tsection\t\"CODE\",code\n";
    /*  SmallData-Vorbereitungen    */
    if(g_flags[5]&USEDFLAG){
        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";
    }
    /*  a5 zur Nutzung freigeben, wenn kein Framepointer benutzt wird   */
    if(c_flags_val[0].l&256) regsa[6]=0;
    if(DEBUG&1) printf("CPU=%ld FPU=%ld\n",g_flags_val[0].l,g_flags_val[1].l);
    vlong=l2zl(0L);
    t_min[UNSIGNED|CHAR]=t_min[UNSIGNED|SHORT]=t_min[UNSIGNED|INT]=t_min[UNSIGNED|LONG]=vlong;
    vlong=l2zl((long)SCHAR_MIN); t_min[CHAR]=vlong;
    vlong=l2zl((long)SHRT_MIN ); t_min[SHORT]=vlong;
    vlong=l2zl((long)INT_MIN  ); t_min[INT]=vlong;
    vlong=l2zl((long)LONG_MIN ); t_min[LONG]=vlong;
    vulong=ul2zul((unsigned long)SCHAR_MAX); t_max[CHAR]=vulong;
    vulong=ul2zul((unsigned long)SHRT_MAX ); t_max[SHORT]=vulong;
    vulong=ul2zul((unsigned long)INT_MAX  ); t_max[INT]=vulong;
    vulong=ul2zul((unsigned long)LONG_MAX ); t_max[LONG]=vulong;
    vulong=ul2zul((unsigned long)UCHAR_MAX); t_max[UNSIGNED|CHAR]=vulong;
    vulong=ul2zul((unsigned long)USHRT_MAX); t_max[UNSIGNED|SHORT]=vulong;
    vulong=ul2zul((unsigned long)UINT_MAX ); t_max[UNSIGNED|INT]=vulong;
    vulong=ul2zul((unsigned long)ULONG_MAX); t_max[UNSIGNED|LONG]=vulong;
    return(1);
}

int freturn(struct Typ *t)
/*  Liefert Register zurueck, in dem Typ t von Funktionen zurueckgegeben    */
/*  wird. Liefert Null, wenn Wert auf Stack zurueckgegeben wird.            */
/*  Achtung! t kann pointer sein, aber trotzdem t->next==0!!                */
/*  maschinenabhaengig                                                      */
{
    if((t->flags&15)==FLOAT)
        {if(g_flags_val[1].l>=68000) return(17); else return(9);}
    if((t->flags&15)==DOUBLE)
        {if(g_flags_val[1].l>=68000) return(17); else return(0);}
    if((t->flags&15)==STRUCT||(t->flags&15)==UNION) return(0);
    if(szof(t)<=4) return(9); else return(0);
}


int regok(int r,int t,int mode)
/*  Testet, ob Register r den Typ t verkraftet          */
/*  mode!=0: mit Typ mode dereferenzierbar              */
/*  natuerlich maschinenabhaengig                       */
/*  Reg 1-8=a0-a7 9-16=d0-d7 und 17-24=FP0-FP7          */
/*  dn nur Integers, an nur Pointer und FPn nur FK      */
{
    if(r==0) return(0);
    t&=15;
    if(t==FLOAT||t==DOUBLE){
        if(g_flags_val[1].l>=68000){
            if(r>=17&&r<=24) return(1); else return(0);
        }else{
            if(t==FLOAT&&r>=9&&r<=16) return(1); else return(0);
        }
    }
    if(t==POINTER&&mode==0&&r>=9&&r<=16) return(1);
    if(t==POINTER&&r>=1&&r<=8) return(1);
    if(t>=CHAR&&t<=LONG&&r>=9&&r<=16) return(1);
    return(0);
}

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

long pof2(zulong x)
/*  gibt log2(x)+1 oder 0 zurueck */
{
    zulong p;int ln=1;
    p=ul2zul(1L);
    while(zulleq(p,x)){
        if(zuleqto(x,p)) return(ln);
        ln++;p=zuladd(p,p);
    }
    return(0);
}

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

int addressing(void);
long notpopped,stackoffset,loff;
int offlabel;

void gen_code(FILE *f,struct IC *p,struct Var *v,int offset)
/*  Eigentliche gen_code()-Routine                          */
{
    int c,t,comptyp;char *fp="\0\0";
    if(DEBUG&1) printf("gen_code()\n");
    for(c=1;c<=MAXR;c++) regs[c]=regsa[c];
    if(c_flags_val[0].l&128){
    /*  Adressierungsarten benutzen */
        if(!addressing()) offset=0;
    }
    reglabel=++label;freglabel=++label;
    function_top(f,v,offset);
    if(p!=first_ic) ierror(0);
    for(;p;pr(f,p),p=p->next){
        c=p->code;t=p->typf;pushedreg=0;
        if(DEBUG&256) pric2(stdout,p);
        if(DEBUG&512) fprintf(f,"; stackoffset=%ld, notpopped=%ld\n",stackoffset,notpopped);
        if(notpopped&&(c==LABEL||c==COMPARE||c==TEST||c==BRA)){
            fprintf(f,"\tadd%s.%s\t#%ld,a7\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped);
            stackoffset-=notpopped;notpopped=0;
        }
        /*  na, ob das hier ok ist..?   */
        if(c==SUBPFP) c=SUB;
        if(c==PMULT) c=MULT;
        if(c==ALLOCREG) {regs[p->q1.reg]=1;continue;}
        if(c==FREEREG) {regs[p->q1.reg]=0;continue;}
        if(c==LABEL) {fprintf(f,"l%d\n",t);continue;}
        if(c==BRA){fprintf(f,"\tbra\tl%d\n",t);continue;}
        if(c>=BEQ&&c<BRA){
            if(stored_cc){fprintf(f,"\tbne\tl%d\n",t);stored_cc=0;continue;}
            if((comptyp&UNSIGNED)||(comptyp&15)==POINTER){
                fprintf(f,"\t%s\tl%d\n",ubranch[c-BEQ],t);
            }else{
                fprintf(f,"\t%s%s\tl%d\n",fp,ename[c],t);
            }
            continue;
        }
        if(p->q1.am){
            if(!regs[p->q1.am->basereg]) ierror(0);
            if(p->q1.am->dreg&&!regs[p->q1.am->dreg&127]) {printf("Register %s:\n",regnames[p->q1.am->dreg&127]);ierror(0);}
        }
        if(p->q2.am){
            if(!regs[p->q2.am->basereg]) ierror(0);
            if(p->q2.am->dreg&&!regs[p->q2.am->dreg&127]) {printf("Register %s:\n",regnames[p->q2.am->dreg&127]);ierror(0);}
        }
        if(p->z.am){
            if(!regs[p->z.am->basereg]) ierror(0);
            if(p->z.am->dreg&&!regs[p->z.am->dreg&127]) {printf("Register %s:\n",regnames[p->z.am->dreg&127]);ierror(0);}
        }
        if((p->q1.flags&REG)&&!regs[p->q1.reg]){printf("Register %s:\n",regnames[p->q1.reg]);ierror(0);}
        if((p->q2.flags&REG)&&!regs[p->q2.reg]){printf("Register %s:\n",regnames[p->q2.reg]);ierror(0);}
        if((p->z.flags&REG)&&!regs[p->z.reg]){printf("Register %s:\n",regnames[p->z.reg]);ierror(0);}
        if((p->q2.flags&REG)&&(p->z.flags&REG)&&p->q2.reg==p->z.reg){printf("Register %s:\n",regnames[p->q2.reg]);ierror(0);}
        if((p->q2.flags&VAR)&&(p->z.flags&VAR)&&p->q2.v==p->z.v){printf("Var %s:\n",p->q2.v->identifier);ierror(0);}
        if(c==PUSHREG){
            if(p->q1.reg<17) {fprintf(f,"\tmove.l\t%s,-(a7)\n",regnames[p->q1.reg]);stackoffset-=4;}
             else {fprintf(f,"\tfmove.x\t%s,-(a7)\n",regnames[p->q1.reg]);stackoffset+=12;}
            continue;
        }
        if(c==POPREG){
            if(p->z.reg<17) {fprintf(f,"\tmove.l\t(a7)+,%s\n",regnames[p->z.reg]);stackoffset+=4;}
             else {fprintf(f,"\tfmove.x\t(a7)+,%s\n",regnames[p->z.reg]);stackoffset+=12;}
            continue;
        }
        if(c==SAVEREGS||c==RESTOREREGS){
            saverestoreregs(f,c,p->q1.reg);
            continue;
        }
        if(!(c_flags_val[0].l&128))
            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(!(c_flags_val[0].l&128))
            if(p->q1.am||p->q2.am||p->z.am){
                ierror(0);
                p->q1.am=p->q2.am=p->z.am=0;
            }
        if(c>=CONVCHAR&&c<=CONVULONG){
            int to;
            if(c==CONVCHAR) to=CHAR;
            if(c==CONVUCHAR) to=UNSIGNED|CHAR;
            if(c==CONVSHORT) to=SHORT;
            if(c==CONVUSHORT) to=UNSIGNED|SHORT;
            if(c==CONVINT) to=LONG;
            if(c==CONVUINT) to=UNSIGNED|LONG;
            if(c==CONVLONG) to=LONG;
            if(c==CONVULONG) to=UNSIGNED|LONG;
            if(c==CONVFLOAT) to=FLOAT;
            if(c==CONVDOUBLE) to=DOUBLE;
            if(c==CONVPOINTER) to=UNSIGNED|LONG;
            if(c==CONVVOID){ierror(0);continue;}
            if(t==FLOAT||t==DOUBLE||to==FLOAT||to==DOUBLE){
                if(g_flags_val[1].l>=68000){
                    int zreg=0;
                    if((t==FLOAT||t==DOUBLE)&&(to==FLOAT||to==DOUBLE)){
                        if(isreg(q1)&&isreg(z)){
                            if(p->q1.reg!=p->z.reg)
                                fprintf(f,"\tfmove.x\t%s,%s\n",regnames[p->q1.reg],regnames[p->z.reg]);
                            continue;
                        }
                    }
                    if(isreg(z)&&p->z.reg>=17)
                        zreg=p->z.reg;
                    if(isreg(q1)&&p->q1.reg>=17){
                        if(!zreg) zreg=p->q1.reg; else zreg=get_reg(f,2,p);}
                    if(!zreg) zreg=get_reg(f,2,p);
                    if((to&UNSIGNED)&&x_t[to&15]!='l'){
                        int dreg=get_reg(f,1,p);
                        fprintf(f,"\tmoveq\t#0,%s\n",regnames[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(t!=FLOAT&&t!=DOUBLE){
                    /*  nach integer, d.h. Kommastellen abschneiden */
                        if(g_flags_val[1].l==68040||g_flags_val[1].l==68060){
                        /*  bei 040/060 emuliert    */
                            int dreg1=get_reg(f,1,p),dreg2=get_reg(f,1,p);
                            fprintf(f,"\tfmove.l\tfpcr,%s\n",regnames[dreg2]);
                            fprintf(f,"\tmoveq\t#16,%s\n",regnames[dreg1]);
                            fprintf(f,"\tor.l\t%s,%s\n",regnames[dreg2],regnames[dreg1]);
                            fprintf(f,"\tand.w\t#-33,%s\n",regnames[dreg1]);
                            fprintf(f,"\tfmove.l\t%s,fpcr\n",regnames[dreg1]);
                            fprintf(f,"\tfmove.%c\t%s,",x_t[t&15],regnames[zreg]);
                            probj(f,&p->z,t,0);fprintf(f,"\n");
                            fprintf(f,"\tfmove.l\t%s,fpcr\n",regnames[dreg2]);
                            continue;
                        }else{
                            if(!isreg(q1)||p->q1.reg!=zreg){
                                fprintf(f,"\tfintrz\t%s\n",regnames[zreg]);
                            }else{
                                int nreg=get_reg(f,2,p);
                                fprintf(f,"\tfintrz\t%s,%s\n",regnames[zreg],regnames[nreg]);
                                zreg=nreg;
                            }
                        }
                    }
                    if(to&UNSIGNED&&x_t[to&15]=='l'){
                        int nlabel;
                        fprintf(f,"\ttst.%c\t",x_t[to&15]);
                        probj(f,&p->q1,to,0);fprintf(f,"\n");
                        nlabel=++label;
                        fprintf(f,"\tbge\tl%d\n",nlabel);
                        fprintf(f,"\tfadd.d\t#4294967296,%s\n",regnames[zreg]);
                        fprintf(f,"l%d\n",nlabel);
                    }
                    if(!(p->z.reg)||p->z.reg!=zreg){
                        move(f,0,zreg,&p->z,0,t);
                    }
                }else{
                    if(to==t){
                        assign(f,p,&p->q1,&p->z,ASSIGN,p->q2.reg,t);
                        continue;
                    }
                    if(to==FLOAT&&t==DOUBLE){
                        saverestoreregs(f,SAVEREGS,0); /* kein Zielregister */
                        assign(f,p,&p->q1,0,PUSH,sizetab[FLOAT],FLOAT);
                        fprintf(f,"\tpublic\t__ieees2d\n\tjsr\t__ieees2d\n\taddq.w\t#4,a7\n");
                        stackoffset+=4;
                        fprintf(f,"\tmovem.l\td0/d1,");
                        probj(f,&p->z,t,0);fprintf(f,"\n");
                        saverestoreregs(f,RESTOREREGS,0);
                        continue;
                    }
                    if(to==DOUBLE&&t==FLOAT){
                        saverestoreregs(f,SAVEREGS,p->z.reg);
                        assign(f,p,&p->q1,0,PUSH,sizetab[DOUBLE],DOUBLE);
                        fprintf(f,"\tpublic\t__ieeed2s\n\tjsr\t__ieeed2s\n\taddq.w\t#8,a7\n");
                        stackoffset+=8;
                        move(f,0,9,&p->z,0,t);
                        saverestoreregs(f,RESTOREREGS,p->z.reg);
                        continue;
                    }
                    if(to==FLOAT||to==DOUBLE){
                        saverestoreregs(f,SAVEREGS,p->z.reg);
                        assign(f,p,&p->q1,0,PUSH,sizetab[to&15],to);
                        fprintf(f,"\tpublic\t__ieeefix%c\n\tjsr\t__ieeefix%c\n\taddq.w\t#%d,a7\n",x_t[to&15],x_t[to&15],sizetab[to&15]);
                        stackoffset+=sizetab[to&15];
                        move(f,0,9,&p->z,0,t);
                        saverestoreregs(f,RESTOREREGS,p->z.reg);
                        continue;
                    }else{
                        int uns,xt=x_t[to&15];
                        if(to&UNSIGNED) uns='u'; else uns='s';
                        saverestoreregs(f,SAVEREGS,p->z.reg);
                        if(xt!='l') {fprintf(f,"\tsubq.w\t#4,a7\n");stackoffset-=4;}
                        fprintf(f,"\tmove.%c\t",xt);
                        probj(f,&p->q1,to,0);
                        if(xt!='l') fprintf(f,",(a7)\n"); else {fprintf(f,",-(a7)\n");stackoffset-=4;}
                        fprintf(f,"\tpublic\t__ieeeflt%c%c%c\n\tjsr\t__ieeeflt%c%c%c\n\taddq.w\t#4,a7\n",uns,xt,x_t[t&15],uns,xt,x_t[t&15]);
                        stackoffset+=4;
                        if(t==DOUBLE){
                            fprintf(f,"\tmovem.l\td0/d1,");
                            probj(f,&p->z,t,0);fprintf(f,"\n");
                        }else move(f,0,9,&p->z,0,t);
                        saverestoreregs(f,RESTOREREGS,p->z.reg);
                        continue;
                    }
                }
                continue;
            }
            if((to&15)<(t&15)){
                int zreg;
                if(isreg(z)&&p->z.reg>=9&&p->z.reg<=16)
                    zreg=p->z.reg; else zreg=get_reg(f,1,p);
                /*  aufpassen, falls unsigned und Quelle==Ziel  */
                if((to&UNSIGNED)&&isreg(q1)&&zreg==p->q1.reg){
                    unsigned long l;
                    if((to&15)==CHAR) l=0xff; else l=0xffff;
                    fprintf(f,"\tand.%c\t#%lu,%s\n",x_t[t&15],l,regnames[zreg]);
                    continue;
                }
                if(to&UNSIGNED) fprintf(f,"\tmoveq\t#0,%s\n",regnames[zreg]);
                move(f,&p->q1,0,0,zreg,to);
                if(!(to&UNSIGNED)){
                    if((to&15)==CHAR&&(t&15)==SHORT) fprintf(f,"\text.w\t%s\n",regnames[zreg]);
                    if((to&15)==SHORT&&sizetab[t&15]==4) fprintf(f,"\text.l\t%s\n",regnames[zreg]);
                    if((to&15)==CHAR&&sizetab[t&15]==4){
                        if(g_flags_val[0].l>=68020)
                            fprintf(f,"\textb.l\t%s\n",regnames[zreg]);
                        else
                            fprintf(f,"\text.w\t%s\n\text.l\t%s\n",regnames[zreg],regnames[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.vlong=l2zl(0L);
                    p->q1.flags|=D16OFF;m=1;
                }
                diff=sizetab[to&15]-sizetab[t&15];
                vlong=l2zl(diff);
                p->q1.val.vlong=zladd(p->q1.val.vlong,vlong);
                move(f,&p->q1,0,&p->z,0,t);
                vlong=l2zl(diff);
                p->q1.val.vlong=zlsub(p->q1.val.vlong,vlong);
                if(m) p->q1.flags&=~D16OFF;
            }
            continue;
        }
        if((t==FLOAT||t==DOUBLE)&&g_flags_val[1].l>=68000) *fp='f'; else *fp=0;
        if(c==MINUS||c==KOMPLEMENT){
            int zreg;
            if(t==FLOAT||t==DOUBLE){
                if(g_flags_val[1].l>=68000){
                    if(isreg(z)) zreg=p->z.reg; else zreg=get_reg(f,2,p);
                    fprintf(f,"\tfneg.%c\t",x_t[t&15]);probj(f,&p->q1,t,0);
                    fprintf(f,",%s\n",regnames[zreg]);
                    if(!isreg(z)||p->z.reg!=zreg){
                        move(f,0,zreg,&p->z,0,t);
                    }
                    continue;
                }else{
                    saverestoreregs(f,SAVEREGS,p->z.reg);
                    assign(f,p,&p->q1,0,PUSH,sizetab[t&15],t);
                    fprintf(f,"\tpublic\t__ieeeneg%c\n\tjsr\t__ieeeneg%c\n\taddq.w\t#%d,a7\n",x_t[t&15],x_t[t&15],sizetab[t&15]);
                    stackoffset+=sizetab[t&15];
                    if(t==DOUBLE){
                        fprintf(f,"\tmovem.l\td0/d1,");
                        probj(f,&p->z,t,0);fprintf(f,"\n");
                    }else move(f,0,9,&p->z,0,t);
                    saverestoreregs(f,RESTOREREGS,p->z.reg);
                    continue;
                }
            }
            if(p->q1.flags==p->z.flags){
                if(!(p->q1.flags&VAR)||(p->q1.v==p->z.v&&zleqto(p->q1.val.vlong,p->z.val.vlong))){
                    if(!isreg(q1)||p->q1.reg==p->z.reg){
                        fprintf(f,"\t%s.%c\t",ename[c],x_t[t&15]);
                        probj(f,&p->q1,t,0);fprintf(f,"\n");
                        continue;
                    }
                }
            }
            if(isreg(z)&&p->z.reg>=9/*&&p->z.reg<=16*/)
                zreg=p->z.reg; else zreg=get_reg(f,1,p);
            if(!isreg(q1)||p->q1.reg!=zreg){
                move(f,&p->q1,0,0,zreg,t);
            }
            fprintf(f,"\t%s.%c\t%s\n",ename[c],x_t[t&15],regnames[zreg]);
            if(!isreg(z)||p->z.reg!=zreg){
                move(f,0,zreg,&p->z,0,t);
            }
            continue;
        }
        if(c==CALL){
            fprintf(f,"\tjsr\t");probj(f,&p->q1,t,0);
            fprintf(f,"\n");
            if(p->q2.reg){
                if((c_flags_val[0].l&256)&&(pushedreg&14)){
                /*  Entfernen der Parameter verzoegern  */
                    notpopped+=p->q2.reg;
                }else{
                    fprintf(f,"\tadd%s.%s\t#%d,a7\n",quick[p->q2.reg<=8],strshort[p->q2.reg<32768],p->q2.reg);
                    stackoffset+=p->q2.reg;
                }
            }
            continue;
        }
        /*  COMPARE #0 durch TEST ersetzen (erlaubt, da tst alle Flags setzt)   */
        if(c==COMPARE&&(p->q2.flags&KONST)){
            eval_const(&p->q2.val,t);
            if(zleq(vlong)&&zuleq(vulong)&&zdeq(vdouble)){
                c=p->code=TEST;p->q2.flags=0;
            }
        }
        if(c==COMPARE&&(p->q1.flags&KONST)){
            eval_const(&p->q1.val,t);
            if(zleq(vlong)&&zuleq(vulong)&&zdeq(vdouble)){
                c=p->code=TEST;p->q1=p->q2;p->q2.flags=0;
            }
        }
        if(c==TEST){
            comptyp=t;
            if(g_flags_val[0].l<68020&&isreg(q1)&&p->q1.reg>=1&&p->q1.reg<=8){
            /*  tst ax gibt es nicht bei <68000 :-( */
                if(regavailable(1)){
                    fprintf(f,"\tmove.%c\t%s,%s\n",x_t[t&15],regnames[p->q1.reg],regnames[get_reg(f,1,p)]);
                }else{
                    fprintf(f,"\tcmp.w\t#0,%s\n",regnames[p->q1.reg]);
                }
                continue;
            }
            if((t==DOUBLE||t==FLOAT)&&g_flags_val[1].l<68000){
            /*  nicht sehr schoen   */
                int result=get_reg(f,1,p);
                saverestoreregs(f,SAVEREGS,result);
                assign(f,p,&p->q1,0,PUSH,sizetab[t&15],t);
                fprintf(f,"\tpublic\t__ieeetst%c\n\tjsr\t__ieeetst%c\n\taddq.w\t#%d,a7\n",x_t[t&15],x_t[t&15],sizetab[t&15]);
                stackoffset+=sizetab[t&15];
                if(result!=9) fprintf(f,"\tmove.l\td0,%s\n",regnames[result]);
                saverestoreregs(f,RESTOREREGS,result);
                fprintf(f,"\ttst.l\t%s\n",regnames[result]);
                continue;
            }
            fprintf(f,"\t%stst.%c\t",fp,x_t[t&15]);probj(f,&p->q1,t,0);
            fprintf(f,"\n");
            continue;
        }
        if(c==ASSIGN||c==PUSH||c==POP){
            assign(f,p,&p->q1,&p->z,c,p->q2.reg,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);
            fprintf(f,"\tlea\t");probj(f,&p->q1,t,0);
            fprintf(f,",%s\n",regnames[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((p->q1.flags&KONST)||isreg(q2)){
            /*  evtl. Argumente von cmp und nachfolgendes bcc umdrehen  */
                struct IC *n;struct 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{ierror(0); break;}
                }
            }
            if(t==FLOAT||t==DOUBLE){
                if(g_flags_val[1].l>=68000){
                    if(isreg(q1)&&p->q1.reg>=17){
                        zreg=p->q1.reg;
                    }else{
                        zreg=get_reg(f,2,p);
                        move(f,&p->q1,0,0,zreg,t);
                    }
                    fprintf(f,"\tfcmp.%c\t",x_t[t&15]);probj(f,&p->q2,t,0);
                    fprintf(f,",%s\n",regnames[zreg]);
                    continue;
                }else{
                /*  nicht sehr schoen   */
                    int result=get_reg(f,1,p);
                    saverestoreregs(f,SAVEREGS,result);
                    assign(f,p,&p->q1,0,PUSH,sizetab[t&15],t);
                    assign(f,p,&p->q2,0,PUSH,sizetab[t&15],t);
                    fprintf(f,"\tpublic\t__ieeecmp%c\n\tjsr\t__ieeecmp%c\n\tadd.w\t#%d,a7\n",x_t[t&15],x_t[t&15],2*sizetab[t&15]);
                    stackoffset+=2*sizetab[t&15];
                    if(result!=9) fprintf(f,"\tmove.l\td0,%s\n",regnames[result]);
                    saverestoreregs(f,RESTOREREGS,result);
                    fprintf(f,"\ttst.l\t%s\n",regnames[result]);
                    continue;
                }
            }
            if(p->q2.flags&KONST){
                fprintf(f,"\tcmp.%c\t",x_t[t&15]);probj(f,&p->q2,t,0);
                fprintf(f,",");probj(f,&p->q1,t,0);fprintf(f,"\n");
                continue;
            }
            if(isreg(q1)){
                zreg=p->q1.reg;
            }else{
                zreg=get_reg(f,1,p);    /* hier evtl. auch Adressregister nehmen */
                move(f,&p->q1,0,0,zreg,t);
            }
            fprintf(f,"\tcmp.%c\t",x_t[t&15]);probj(f,&p->q2,t,0);
            fprintf(f,",%s\n",regnames[zreg]);
            continue;
        }
        if(c==ADDI2P||c==SUBIFP){
            int zreg;
            if(((p->q1.flags&VAR)&&(p->z.flags&VAR)&&p->q1.v==p->z.v)||
               (isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg)){
                int r;
                if(p->q2.flags&KONST){
                    if(c==ADDI2P)
                        fprintf(f,"\tadd%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
                    else
                        fprintf(f,"\tsub%s.l\t",quick[isquickkonst2(&p->q2.val,t)]);
                    probj(f,&p->q2,t,0);fprintf(f,",");
                    probj(f,&p->z,POINTER,0);fprintf(f,"\n");
                    continue;
                }
                if(isreg(q2)&&p->q2.reg>=1){
                    r=p->q2.reg;
                }else{
                    r=get_reg(f,1,p);
                    move(f,&p->q2,0,0,r,t);
                }
                if(x_t[t&15]!='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) fprintf(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",regnames[r],regnames[r],regnames[r]);
                     else          fprintf(f,"\text.l\t%s\n",regnames[r]);
                    t=POINTER;
                }
/*                if(c==ADDI2P)
                    fprintf(f,"\tadd.%c\t%s,",x_t[t&15],regnames[r]);
                else
                    fprintf(f,"\tsub.%c\t%s,",x_t[t&15],regnames[r]);
                probj(f,&p->z,t,0);fprintf(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)&&p->z.reg>=1&&p->z.reg<=16)
                zreg=p->z.reg; else zreg=get_reg(f,0,p);
            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>=LSHIFT&&c<=MOD)){
            int zreg,q1reg,q2reg,divflag=0;
            if(t==FLOAT||t==DOUBLE){
                if(g_flags_val[1].l>=68000){
                    if(isreg(z)&&p->z.reg>=17) zreg=p->z.reg;
                        else zreg=get_reg(f,2,p);
                    if(!isreg(q1)||p->q1.reg!=p->z.reg)
                        move(f,&p->q1,0,0,zreg,t);
                    fprintf(f,"\tf%s.%c\t",ename[c],x_t[t&15]);probj(f,&p->q2,t,0);
                    fprintf(f,",%s\n",regnames[zreg]);
                    if(!isreg(z)||p->z.reg!=zreg){
                        move(f,0,zreg,&p->z,0,t);
                    }
                    continue;
                }else{
                    saverestoreregs(f,SAVEREGS,p->z.reg);
                    assign(f,p,&p->q1,0,PUSH,sizetab[t&15],t);
                    assign(f,p,&p->q2,0,PUSH,sizetab[t&15],t);
                    fprintf(f,"\tpublic\t__ieee%s%c\n\tjsr\t__ieee%s%c\n\tadd.w\t#%d,a7\n",ename[c],x_t[t&15],ename[c],x_t[t&15],2*sizetab[t&15]);
                    stackoffset+=2*sizetab[t&15];
                    if(t==DOUBLE){
                        fprintf(f,"\tmovem.l\td0/d1,");
                        probj(f,&p->z,0,t);fprintf(f,"\n");
                    }else move(f,0,9,&p->z,0,t);
                    saverestoreregs(f,RESTOREREGS,p->z.reg);
                    continue;
                }
            }
            if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&(p->q2.flags&KONST)){
            /*  ersetzt mul etc. mit Zweierpotenzen     */
            /*  hier evtl. noch Fehler                  */
                long ln;zlong zl;
                eval_const(&p->q2.val,t&31);
                zl=l2zl(0L);
                if(zlleq(zl,vlong)&&zulleq(zl,vulong)){
                    if(ln=pof2(vulong)){
                        if(c==MOD){
                            zl=l2zl(1L);
                            vlong=zlsub(vlong,zl);
                            p->code=AND;
                        }else{
                            vlong=l2zl(ln-1);
                            if(c==DIV) {divflag=1;p->code=RSHIFT;} else p->code=LSHIFT;
                        }
                        c=p->code;
                        if((t&31)==CHAR) p->q2.val.vchar=zl2zc(vlong);
                        if((t&31)==SHORT) p->q2.val.vshort=zl2zs(vlong);
                        if((t&31)==INT) p->q2.val.vint=zl2zi(vlong);
                        if((t&31)==LONG) p->q2.val.vlong=vlong;
                        vulong=zl2zul(vlong);
                        if((t&31)==(UNSIGNED|CHAR)) p->q2.val.vuchar=zul2zuc(vulong);
                        if((t&31)==(UNSIGNED|SHORT)) p->q2.val.vushort=zul2zus(vulong);
                        if((t&31)==(UNSIGNED|INT))  p->q2.val.vuint=zul2zui(vulong);
                        if((t&31)==(UNSIGNED|LONG)) p->q2.val.vulong=vulong;
                    }
                }
            }
            if(c==DIV||c==MOD){
                if(x_t[t&15]=='l'&&g_flags_val[0].l<68020){
                /*  das hier ist auch nicht allzu schoen  */
                    char *fname;
                    saverestoreregs(f,SAVEREGS,p->z.reg);
                    fprintf(f,"\tmove.l\t"); probj(f,&p->q2,t,0);
                    fprintf(f,",-(a7)\n");
                    stackoffset-=4;
                    fprintf(f,"\tmove.l\t"); probj(f,&p->q1,t,0);
                    fprintf(f,",-(a7)\n");
                    stackoffset-=4;
                    if(c==DIV){
                        if(t&UNSIGNED) fname="divu"; else fname="divs";
                    }else{
                        if(t&UNSIGNED) fname="modu"; else fname="mods";
                    }
                    fprintf(f,"\tpublic\t__l%s\n",fname);
                    fprintf(f,"\tjsr\t__l%s\n",fname);
                    fprintf(f,"\taddq.w\t#8,a7\n");
                    stackoffset+=8;
                    move(f,0,9,&p->z,0,t);
                    saverestoreregs(f,RESTOREREGS,p->z.reg);
                    continue;
                }

            }
            /*  hier die zweite Alternative mit isreg() schreiben?  */
            if(((p->q2.flags&VAR)&&(p->z.flags&VAR)&&p->q2.v==p->z.v)||(p->q2.reg!=0&&p->q2.reg==p->z.reg)){
                struct 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>=9&&p->q2.reg<=16){
                            m=p->q1;p->q1=p->q2;p->q2=m;
                            c=ADD;
                            fprintf(f,"\tneg.%c\t",x_t[t&15]);
                            probj(f,&p->q1,t,0);fprintf(f,"\n");
                        }
                    }
                }
            }
            if(((p->q1.flags&VAR)&&p->z.flags==p->q1.flags&&p->q1.v==p->z.v&&zleqto(p->q1.val.vlong,p->z.val.vlong))||
               (isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg)){
                if((c>=OR&&c<=AND)||c==ADD||c==SUB){
                    int r;
                    if(p->q2.flags&KONST){
                        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;}
                        fprintf(f,"\t%s.%c\t",ename[c],x_t[t&15]);
                        probj(f,&p->q2,t,0);fprintf(f,",");
                        probj(f,&p->z,t,0);fprintf(f,"\n");
                        continue;
                    }
                    if(!isreg(z)){
                        if(isreg(q2)&&p->q2.reg>=9&&p->q2.reg<=16)
                            r=p->q2.reg; else r=get_reg(f,1,p);
                        if(!isreg(q2)||p->q2.reg!=r){
                            move(f,&p->q2,0,0,r,t);
                        }
                        fprintf(f,"\t%s.%c\t%s,",ename[c],x_t[t&15],regnames[r]);
                        probj(f,&p->z,t,0);fprintf(f,"\n");
                        continue;
                    }
                }
            }
            /*  bei xor oder asl (ausser 0<=const<=8) muss q2 in Register   */
            if(isreg(q2)&&p->q2.reg>=9&&p->q2.reg<=16){
                q2reg=p->q2.reg;
            }else{
                if(c==LSHIFT||c==RSHIFT||c==XOR){
                    eval_const(&p->q2.val,t&31);
                    if(c==XOR||!(p->q2.flags&KONST)||!isquickkonst2(&p->q2.val,t)){
                        q2reg=get_reg(f,1,p);
                        move(f,&p->q2,0,0,q2reg,t);
                    }else q2reg=0;
                }else{
                    q2reg=0;
                }
            }
            if(isreg(z)&&p->z.reg>=9&&p->z.reg<=16&&p->z.reg!=q2reg)
                zreg=p->z.reg; else zreg=get_reg(f,1,p);
            if(isreg(q1)&&p->q1.reg>=9&&p->q1.reg<=16)
                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(c==RSHIFT&&divflag&&!(t&UNSIGNED)) fprintf(f,"\tasr.%c\t",x_t[t&15]);
                 else fprintf(f,"\t%s.%c\t",ename[c],x_t[t&15]);
                if(q2reg) fprintf(f,"%s",regnames[q2reg]); else probj(f,&p->q2,t,0);
                fprintf(f,",%s\n",regnames[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);
    }
    function_bottom(f,v,offset);
}
int get_reg(FILE *f,int flag,struct IC *p)
/*  Besorgt Register flag=0=areg, 1=dreg, 2=fpreg           */
{
    int i;
    flag=1+flag*8;
    for(i=flag;i<flag+8;i++){
        if(regs[i]==0){
            if(p){
                if((p->q1.am&&(p->q1.am->dreg==i||p->q1.am->basereg==i))
                 ||(p->q2.am&&(p->q2.am->dreg==i||p->q2.am->basereg==i))
                 ||(p->z.am&&(p->z.am->dreg==i||p->z.am->basereg==i))){
/*                    iwarning("%s used in get_reg(1)",regnames[i]);*/
                    continue;
                }
            }
            regs[i]=2;pushedreg|=1;
            if(!regused[i]&&!regscratch[i]){regused[i]=1; }
            return(i);
        }
    }
    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((p->q1.am&&(p->q1.am->dreg==i||p->q1.am->basereg==i))
                 ||(p->q2.am&&(p->q2.am->dreg==i||p->q2.am->basereg==i))
                 ||(p->z.am&&(p->z.am->dreg==i||p->z.am->basereg==i))){
/*                    iwarning("%s used in get_reg(2)",regnames[i]);*/
                    continue;
                }
            }

            regs[i]+=4;
            if(i<17) {fprintf(f,"\tmove.l\t%s,-(a7)\n",regnames[i]);stackoffset-=4;}
             else {fprintf(f,"\tfmove.x\t%s,-(a7)\n",regnames[i]);stackoffset-=12;}
/*            if(p->code==COMPARE) ierror("corrupt code for compare generated - sorry");*/
            if(i<9) pushedreg|=2;
            else if (i<17) pushedreg|=4;
            else pushedreg|=8;
            return(i);
        }
    }
    ierror(0);
    for(i=flag;i<flag+8;i++) printf("%s: %d\n",regnames[i],regs[i]);
    return(0);
}

int isquickkonst(union atyps *p,int t)
/*  liefert 1, wenn p auf Konstante zwischen -128 und 127 ist   */
{
    zlong zl;zulong zul;
    eval_const(p,t);
    if(t&UNSIGNED){
        zul=ul2zul(127UL);
        return(zulleq(vulong,zul));
    }else{
        zl=l2zl(-129L);
        if(zlleq(vlong,zl)) return(0);
        zl=l2zl(127L);
        return(zlleq(vlong,zl));
    }
}
int isquickkonst2(union atyps *p,int t)
/*  liefert 1, wenn p auf Konstante zwischen 0 und 8 ist   */
{
    zlong zl;zulong zul;
    eval_const(p,t);
    if(t&UNSIGNED){
        zul=ul2zul(8UL);
        return(zulleq(vulong,zul));
    }else{
        zl=l2zl(-1L);
        if(zlleq(vlong,zl)) return(0);
        zl=l2zl(8L);
        return(zlleq(vlong,zl));
    }
}
int regavailable(int art)
/*  liefert true, wenn Register mit art frei ist, sonst 0       */
{
    int i;
    art=1+art*8;
    for(i=art+1;i<art+8;i++)
        if(regs[i]==0) return(1);
    return(0);
}

int compare_objects(struct obj *o1,struct obj *o2)
/*  Vergleicht, ob die beiden Objekte fuer d0_refs gleich sind  */
{
    if(o1->flags==o2->flags){
        if(!(o1->flags&VAR)||(o1->v==o2->v&&zleqto(o1->val.vlong,o2->val.vlong))){
            if(!(o1->flags&REG)||o1->reg==o2->reg){
                return(1);
            }
        }
    }
    return(0);
}

struct IC *do_refs(FILE *f,struct IC *p)
/*  Kopiert DREFOBJs in Adressregister, wenn noetig         */
/*  und kleine Konstanten in Datenregister                  */
/*  zerstoert die ICs dabei so, dass kein zweiter Pass      */
/*  moeglich ist (was aber durch reg/freg garantiert ist).  */
{
    int reg,c=p->code,t=p->typf,equal;
    if((p->q1.flags&DREFOBJ)&&(!(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;
        reg=get_reg(f,0,p);
        p->q1.flags&=~DREFOBJ;
        fprintf(f,"\tmove.l\t");probj(f,&p->q1,t,0);
        p->q1.flags=REG|SCRATCH|DREFOBJ;
        p->q1.reg=reg;
        fprintf(f,",%s\n",regnames[p->q1.reg]);
        if(equal&1) p->q2=p->q1;
        if(equal&2) p->z=p->q1;
    }
    if((p->q2.flags&DREFOBJ)&&(!(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);
        p->q2.flags&=~DREFOBJ;
        fprintf(f,"\tmove.l\t");probj(f,&p->q2,t,0);
        p->q2.flags=REG|SCRATCH|DREFOBJ;
        p->q2.reg=reg;
        fprintf(f,",%s\n",regnames[p->q2.reg]);
        if(equal) p->z=p->q2;
    }
    if((p->z.flags&DREFOBJ)&&(!(p->z.flags&REG)||p->z.reg<1||p->z.reg>8)){
        reg=get_reg(f,0,p);
        p->z.flags&=~DREFOBJ;
        fprintf(f,"\tmove.l\t");probj(f,&p->z,t,0);
        p->z.flags=REG|SCRATCH|DREFOBJ;
        p->z.reg=reg;
        fprintf(f,",%s\n",regnames[p->z.reg]);
    }

    if(x_t[t&15]=='l'&&(t&15)!=FLOAT&&(c!=ASSIGN||!isreg(z))&&c!=MULT&&c!=DIV&&c!=MOD&&c!=LSHIFT&&c!=RSHIFT){
    /*  Konstanten evtl. in Register, noch nicht getestet   */
        if((p->q1.flags&KONST)&&isquickkonst(&p->q1.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q1.val,t))){
            if(regavailable(1)){
                reg=get_reg(f,1,p);
                move(f,&p->q1,0,0,reg,t);
                p->q1.flags=REG|SCRATCH;p->q1.reg=reg;
                p->q1.val.vlong=l2zl(0L);
            }
        }
        if((p->q2.flags&KONST)&&isquickkonst(&p->q2.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q2.val,t))){
            if(regavailable(1)){
                reg=get_reg(f,1,p);
                move(f,&p->q2,0,0,reg,t);
                p->q2.flags=REG|SCRATCH;p->q2.reg=reg;
                p->q2.val.vlong=l2zl(0L);
            }
        }

    }
    return(p);
}
void pr(FILE *f,struct IC *p)
/*  Gibt Register frei, holt sie vom Stack                  */
{
    int i,size=0;
    /*  Haufen Gefummel um condition codes zu merken    */
    if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE)){
        char *fp;struct IC *branch;
        if(g_flags_val[1].l>=68000&&((p->typf&15)==FLOAT||(p->typf&15)==DOUBLE)) fp="f"; else fp="";
        branch=p;
        while(branch->code<BEQ||branch->code>=BRA) branch=branch->next;
        if((p->typf&UNSIGNED)||(p->typf&15)==POINTER){
            fprintf(f,"\ts%s\t-2(a7)\n",ubranch[branch->code-BEQ]+1);
        }else{
            fprintf(f,"\t%ss%s\t-2(a7)\n",fp,ename[branch->code]+1);
        }
        stored_cc=1;
    }
    for(i=MAXR;i>0;i--){
        if(regs[i]==2) regs[i]=0;
        if(regs[i]&4){
            regs[i]-=4;
            if(i<17) {fprintf(f,"\tmove.l\t(a7)+,%s\n",regnames[i]);stackoffset+=4;size+=4;}
             else {fprintf(f,"\tfmove.x\t(a7)+,%s\n",regnames[i]);stackoffset+=12;size+=12;}
        }
    }
    if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE))
        fprintf(f,"\ttst.b\t-%d(a7)\n",size+2);
}

void probj(FILE *f,struct obj *p,int t,int verbose)
/*  Gibt Objekt auf Bildschirm aus                      */
{
    if(p->am){
    /*  Ausgabe der erweiterten Adressierungsarten  */
        if(!(c_flags_val[0].l&128)) {ierror(0);p->am=0;return;}
        if(p->am->skal>=0){
            long l=0;
            if(p->flags&D16OFF) l=zl2l(p->val.vlong);
            fprintf(f,"(%ld,%s",p->am->dist+l,regnames[p->am->basereg]);
            if(p->am->dreg){
                fprintf(f,",%s",regnames[p->am->dreg&127]);
                if(p->am->dreg&128) fprintf(f,".w"); else fprintf(f,".l");
                if(p->am->skal) fprintf(f,"*%d",p->am->skal);
            }
            fprintf(f,")");
            return;
        }
        if((p->flags&D16OFF)&&!zleq(p->val.vlong)) ierror(0);
        if(p->am->skal==-1){
            fprintf(f,"(%s)+",regnames[p->am->basereg]);
            return;
        }
        if(p->am->skal==-2){    /*  Noch nicht implementiert    */
            fprintf(f,"-(%s)",regnames[p->am->basereg]);
            return;
        }
    }
    if(p->flags&DREFOBJ){
        fprintf(f,"(");
        if((p->flags&D16OFF)&&!zleq(p->val.vlong))
            {printval(f,&p->val,LONG,0);fprintf(f,",");}
    }
    if((p->flags&VARADR)&&!(verbose&2)) fprintf(f,"#");
    if(p->flags&VAR) {
        if(verbose&1){
            printval(f,&p->val,LONG,1);
            if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
                if(p->flags&REG)
                    fprintf(f,"+%s",regnames[p->reg]);
                else
                    fprintf(f,"+%d(FP)", p->v->offset);
            }else{
                if(p->v->storage_class==STATIC&&p->v->nesting>0){
                    fprintf(f,"+L%d",p->v->offset);
                }else{
                    fprintf(f,"+_%s",p->v->identifier);
                }
            }
            fprintf(f,"(%s)",p->v->identifier);
        }else{
            if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){
                if(p->flags&REG){
                    fprintf(f,"%s",regnames[p->reg]);
                }else{
                    long os;
                    os=zl2l(p->val.vlong);
                    if(c_flags_val[0].l&256){
                        if(p->v->offset<0) os=os+loff-p->v->offset;
                         else              os=os+p->v->offset;
                        fprintf(f,"(%ld+l%d,a7)",os-stackoffset,offlabel);
                    }else{
                        if(p->v->offset<0) os=os-p->v->offset+4;
                         else              os=os-(p->v->offset+szof(p->v->vtyp));
                        fprintf(f,"(%ld,a5)",os);
                    }
                }
            }else{
                if(!zleq(p->val.vlong)){printval(f,&p->val,LONG,0);fprintf(f,"+");}
                if(p->v->storage_class==STATIC&&(p->v->vtyp->flags&15)!=FUNKT){
                    fprintf(f,"l%d",p->v->offset);
                }else{
                    fprintf(f,"_%s",p->v->identifier);
                    if((g_flags[5]&USEDFLAG)&&!(p->flags&VARADR)&&(p->v->vtyp->flags&15)!=FUNKT)
                        fprintf(f,"(a4)");
                }
            }
        }
    }
    if((p->flags&REG)&&!(p->flags&VAR)) fprintf(f,"%s",regnames[p->reg]);
    if(p->flags&KONST){
        /*  Das hier setzt voraus, dass Compiler Datentypen im  */
        /*  IEEE-Format nachbildet                              */
        if(t==FLOAT||t==DOUBLE){
            char str[10];int i;
            int *ip=(int *)&p->val.vfloat; /*   nicht schoen, aber...   */
            fprintf(f,"#$");sprintf(str,"%8x",*ip);
            for(i=0;i<8;i++) if(str[i]==' ') str[i]='0';
            fprintf(f,"%s",str);
            if(t==DOUBLE){
                if(DEBUG&1) printf("doubleconst=%f\n",p->val.vdouble);
                ip++;sprintf(str,"%8x",*ip);
                for(i=0;i<10;i++) if(str[i]==' ') str[i]='0';
                fprintf(f,"%s",str);
            }
        }else {fprintf(f,"#");printval(f,&p->val,t&31,verbose);}
    }
    if(p->flags&STACK) fprintf(f,"Stack");
    if(p->flags&DREFOBJ) fprintf(f,")");
}
char tsh[]={'w','l'};
int proflabel;
void function_top(FILE *f,struct Var *v,int offset)
/*  erzeugt Funktionskopf                       */
{
    if(g_flags_val[0].l!=68000) fprintf(f,"\tmachine\t%ld\n",g_flags_val[0].l);
    if(g_flags_val[1].l>68000) fprintf(f,"\tfpu\t1\n");
    if(g_flags[4]&USEDFLAG) fprintf(f,"\tnear\tcode\n");
    if(g_flags[5]&USEDFLAG) fprintf(f,"\tnear\ta4,-2\n");
    if(section!=CODE){fprintf(f,codename);section=CODE;}
    if(g_flags[6]&USEDFLAG){
        proflabel=++label;
        fprintf(f,"l%d\n\tdc.b\t\"%s\",0\n",proflabel,v->identifier);
    }
    if(v->storage_class==EXTERN) fprintf(f,"\tpublic\t_%s\n",v->identifier);
    fprintf(f,"\tcnop\t0,4\n_%s\n",v->identifier);
    if(g_flags[6]&USEDFLAG)
        fprintf(f,"\tpea\tl%d\n\tpublic\t__startprof\n\tjsr\t__startprof\n\taddq.w\t#4,a7\n",proflabel);
    offset=-((offset+4-1)/4)*4;
    loff=-offset;offlabel=++label;
    if(c_flags_val[0].l&256){
        if(offset<0) fprintf(f,"\tsub%s.%s\t#%d,a7\n",quick[offset>=-8],strshort[offset>=-32768],-offset);
    }else{
        if(offset>=-32768||g_flags_val[0].l>=68020){
            fprintf(f,"\tlink.%c\ta5,#%d\n",tsh[offset<-32768],offset);
        }else{
            fprintf(f,"\tlink.w\ta5,#-32768\n");offset+=32768;
            fprintf(f,"\tsub.%c\t#%d,a5\n",tsh[offset<-32768],offset);
        }
    }
    if(g_flags_val[1].l>68000&&float_used) fprintf(f,"\tfmovem.x\tl%d,-(a7)\n",freglabel);
    fprintf(f,"\tmovem.l\tl%d,-(a7)\n",reglabel);
    /*  Was mach ich hier mit stackoffset?  */
}
void function_bottom(FILE *f,struct Var *v,int offset)
/*  erzeugt Funktionsende                       */
{
    int i,size=0;
    *reglist=0;
    for(i=1;i<=16;i++){
        if(regused[i]&&!regscratch[i]&&!regsa[i]){
            if(*reglist) strcat(reglist,"/");
            strcat(reglist,regnames[i]);size+=4;
        }
    }
    if(*reglist) fprintf(f,"l%d\treg\t%s\n\tmovem.l\t(a7)+,l%d\n",reglabel,reglist,reglabel);
        else fprintf(f,"l%d\treg\n",reglabel);
    *reglist=0;
    for(i=17;i<=MAXR;i++){
        if(regused[i]&&!regscratch[i]&&!regsa[i]){
            if(*reglist) strcat(reglist,"/");
            strcat(reglist,regnames[i]);size+=12;
        }
    }
    if(g_flags_val[1].l>68000&&float_used){
        if(*reglist) fprintf(f,"l%d\tfreg\t%s\n\tfmovem.x\t(a7)+,l%d\n",freglabel,reglist,freglabel);
            else fprintf(f,"l%d\tfreg\n",freglabel);
    }
    if(c_flags_val[0].l&256){
        if(loff) fprintf(f,"\tadd%s.%s\t#%ld,a7\n",quick[loff<=8],strshort[loff<32768],loff);
        fprintf(f,"l%d\tEQU\t%d\n",offlabel,size);
    }else fprintf(f,"\tunlk\ta5\n");
    if(g_flags[6]&USEDFLAG)
        fprintf(f,"\tpea\tl%d\n\tpublic\t__endprof\n\tjsr\t__endprof\n\taddq.w\t#4,a7\n",proflabel);
    fprintf(f,"\trts\n");
}
void gen_ds(FILE *f,int size,struct Typ *t)
/*  generiert Speicher fuer size Bytes mit Null initialisiert.  */
/*  Aufpassen, dass kein BSS in einem teilweise initialisierten */
/*  Array erzeugt wird.                                         */
/*  t darf 0 sein, dann sind es nur Fuellbytes                  */
{
    if(section!=BSS&&newobj){fprintf(f,bssname);section=BSS;}
    fprintf(f,"\tds.b\t%d\n",size);newobj=0;
}
void gen_align(FILE *f,int align)
/*  generiert alignment auf align Bytes (oder aehnlich)         */
{
    if(align>1) fprintf(f,"\tcnop\t0,4\n");
}
void gen_var_head(FILE *f,struct Var *v)
/*  generiert Kopf fuer eine Variable                           */
{
    if(v->storage_class==STATIC){
        if((v->vtyp->flags&15)==FUNKT) return;
        if(v->clist&&section!=DATA){fprintf(f,dataname);section=DATA;}
        if(!v->clist&&section!=BSS){fprintf(f,bssname);section=BSS;}
        fprintf(f,"\tcnop\t0,4\nl%d\n",v->offset);
        newobj=1;
    }
    if(v->storage_class==EXTERN){
        fprintf(f,"\tpublic\t_%s\n",v->identifier);
        if(v->flags&(DEFINED|TENTATIVE)){
            if(v->clist&&section!=DATA){fprintf(f,dataname);section=DATA;}
            if(!v->clist&&section!=BSS){fprintf(f,bssname);section=BSS;}
            fprintf(f,"\tcnop\t0,4\n_%s\n",v->identifier);
            newobj=1;
        }
    }
}
void gen_dc(FILE *f,int t,struct const_list *p)
/*  generiert Konstanten fuer Typ t aus clist p                 */
{
    char s;
    if(!p){ierror(0);return;}
    if(section!=DATA){fprintf(f,dataname);section=DATA;}
    if((t&15)==FLOAT||(t&15)==DOUBLE) s='l'; else s=x_t[t&15];
    fprintf(f,"\tdc.%c\t",s);
    if(!p->tree){
        if((t&15)==FLOAT||(t&15)==DOUBLE){
        /*  auch wieder nicht sehr schoen und IEEE noetig   */
            int *ip;
            ip=(int *)&p->val.vdouble;
            fprintf(f,"$%x",*ip);
            if((t&15)==DOUBLE) fprintf(f,",$%x",*(++ip));
        }else{
            printval(f,&p->val,t&31,0);
        }
    }else{
        p->tree->o.am=0;
        probj(f,&p->tree->o,t&31,2);
    }
    fprintf(f,"\n");newobj=0;
}

void move(FILE *f,struct obj *q,int qreg,struct 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){
        fprintf(f,"\tlea\t");
        q->flags&=~VARADR;probj(f,q,t,0);q->flags|=VARADR;
        fprintf(f,",%s\n",regnames[zreg]);
        return;
    }
    if(zreg>=9&&zreg<=16&&q&&(q->flags&KONST)&&isquickkonst(&q->val,t)){
        fprintf(f,"\tmoveq\t");
    }else{
        if(zreg>=17||qreg>=17){
            if(qreg>=17&&zreg>=17) fprintf(f,"\tfmove.x\t");
             else fprintf(f,"\tfmove.%c\t",x_t[t&15]);
        }else{
            fprintf(f,"\tmove.%c\t",x_s[sizetab[t&15]]);
        }
    }
    if(qreg) fprintf(f,"%s",regnames[qreg]); else probj(f,q,t,0);
    fprintf(f,",");
    if(zreg) fprintf(f,"%s",regnames[zreg]); else probj(f,z,t,0);
    fprintf(f,"\n");
}
void add(FILE *f,struct obj *q,int qreg,struct 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(!qreg&&(q->flags&KONST)&&isquickkonst2(&q->val,t)){
        fprintf(f,"\taddq.%c\t",x_t[t&15]);
    }else{
        /*  hier noch Abfrage, ob #c.w,ax   */
        fprintf(f,"\tadd.%c\t",x_t[t&15]);
    }
    if(qreg) fprintf(f,"%s",regnames[qreg]); else probj(f,q,t,0);
    fprintf(f,",");
    if(zreg) fprintf(f,"%s",regnames[zreg]); else probj(f,z,t,0);
    fprintf(f,"\n");
}
void sub(FILE *f,struct obj *q,int qreg,struct obj *z,int zreg,int t)
/*  erzeugt eine sub Anweisung...Da sollen mal Optimierungen rein   */
{
    if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg;
    if(q&&(q->flags&KONST)&&isquickkonst2(&q->val,t)){
        fprintf(f,"\tsubq.%c\t",x_t[t&15]);
    }else{
        /*  hier noch Abfrage, ob #c.w,ax   */
        fprintf(f,"\tsub.%c\t",x_t[t&15]);
    }
    if(qreg) fprintf(f,"%s",regnames[qreg]); else probj(f,q,t,0);
    fprintf(f,",");
    if(zreg) fprintf(f,"%s",regnames[zreg]); else probj(f,z,t,0);
    fprintf(f,"\n");
}
void mult(FILE *f,struct obj *q,int qreg,struct obj *z,int zreg, int t,int c,struct 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((c==MULT||c==DIV||c==MOD)&&g_flags_val[0].l<68020&&sizetab[t&15]==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>=9&&zreg<=16){
                dx=zreg;
            }else{
                dx=get_reg(f,1,p);
                move(f,z,0,0,dx,t);
            }
            if(qreg>=9&&qreg<=16&&qreg!=dx){
                dy=qreg;
            }else{
                dy=get_reg(f,1,p);
                move(f,q,0,0,dy,t);
            }
            t1=get_reg(f,1,p);t2=get_reg(f,1,p);
            if(t1==dx||t2==dx||t1==dy||t2==dy) ierror(0);
            fprintf(f,"\tmove.l\t%s,%s\n",regnames[dx],regnames[t1]);
            fprintf(f,"\tmove.l\t%s,%s\n",regnames[dy],regnames[t2]);
            fprintf(f,"\tswap\t%s\n",regnames[t1]);
            fprintf(f,"\tswap\t%s\n",regnames[t2]);
            fprintf(f,"\tmulu.w\t%s,%s\n",regnames[dy],regnames[t1]);
            fprintf(f,"\tmulu.w\t%s,%s\n",regnames[dx],regnames[t2]);
            fprintf(f,"\tmulu.w\t%s,%s\n",regnames[dy],regnames[dx]);
            fprintf(f,"\tadd.w\t%s,%s\n",regnames[t2],regnames[t1]);
            fprintf(f,"\tswap\t%s\n",regnames[t1]);
            fprintf(f,"\tclr.w\t%s\n",regnames[t1]);
            fprintf(f,"\tadd.l\t%s,%s\n",regnames[t1],regnames[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) fprintf(f,"\tmulu.%c\t",x_t[t&15]); else fprintf(f,"\tmuls.%c\t",x_t[t&15]);
    }
    if(c==DIV){
        if(t&UNSIGNED) fprintf(f,"\tdivu.%c\t",x_t[t&15]); else fprintf(f,"\tdivs.%c\t",x_t[t&15]);
    }
    if(c==MOD){
        /*  das hier ist nicht besonders toll geloest   */
        modreg=get_reg(f,1,p);
        if(t&UNSIGNED) fprintf(f,"\tdivul.%c\t",x_t[t&15]); else fprintf(f,"\tdivsl.%c\t",x_t[t&15]);
        if(qreg) fprintf(f,"%s",regnames[qreg]); else probj(f,q,t,0);
        fprintf(f,",%s:%s\n",regnames[modreg],regnames[zreg]);
        fprintf(f,"\tmove.l\t%s,%s\n",regnames[modreg],regnames[zreg]);
        return;
    }
    if(qreg) fprintf(f,"%s",regnames[qreg]); else probj(f,q,t,0);
    fprintf(f,",");
    /*  eigentlich muss zreg!=0 sein...     */
    if(zreg) fprintf(f,"%s",regnames[zreg]); else probj(f,z,t,0);
    fprintf(f,"\n");
}
void saverestoreregs(FILE *f,int c,int dontsave)
{
    int i,s,e,size=0;static char fp[4]="\0\0\0";
    if(c==SAVEREGS){s=17;e=MAXR;} else {s=1;e=16;}
    while(1){
        *reglist=0;
        for(i=s;i<=e;i++){
            if(regs[i]==1&&regscratch[i]&&i!=dontsave){
                if(*reglist) strcat(reglist,"/");
                strcat(reglist,regnames[i]);
                if(i<17) size+=4; else size+=12;
            }
        }
        if(*reglist){
            char s;
            if(e==MAXR) {*fp='f';s='x';} else {*fp=0;s='l';}
            if(c==SAVEREGS) fprintf(f,"\t%smovem.%c\t%s,-(a7)\n",fp,s,reglist);
             else fprintf(f,"\t%smovem.%c\t(a7)+,%s\n",fp,s,reglist);
        }
        if((s==17&&c==RESTOREREGS)||(s==1&&c==SAVEREGS)) break;
        if(s==17){s=1;e=16;} else {s=17;e=MAXR;}
    }
    if(c==SAVEREGS) stackoffset-=size; else stackoffset+=size;
}
struct IC *am_freedreg[9],*am_shiftdreg[9];
struct IC *am_dist_ic[9],*am_dreg_ic[9],*am_use[9];
/*  am_dist_ic und am_dreg_ic werden auch fuer (ax)+ benutzt    */
long am_dist[9],am_dreg[9],am_base[9],am_inc[9],am_skal[9],am_dbase[9];
#define AMS sizeof(struct AddressingMode)

void clear_am(int reg)
/*  loescht Werte fuer erweiterte Adressierungsarten fuer Register reg  */
{
    if(DEBUG&32) printf("clear_am(%s)\n",regnames[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;
    }
}
int addressing(void)
/*  Untersucht ICs auf erweiterte Addresierungsarten    */
{
    struct IC *p;int count,localused=0;
    if(DEBUG&32) printf("addressing() started\n");
    for(count=1;count<=16;count++) clear_am(count);
    for(count=0,p=first_ic;p;p=p->next){
        int c=p->code,q1reg=p->q1.reg,q2reg=p->q2.reg,zreg=p->z.reg;
        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)&&p->q1.v->offset>=0)
                localused=1;
            if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&p->q2.v->offset>=0)
                localused=1;
            if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&p->z.v->offset>=0)
                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;
            for(i=1;i<=8;i++)
                if(am_base[i]==zreg||am_base[i]==q1reg) clear_am(i);
            clear_am(zreg);am_base[zreg]=q1reg;am_dreg_ic[zreg]=p;
            if(DEBUG&32) printf("move %s,%s found\n",regnames[q1reg],regnames[zreg]);
            continue;
        }
        if(c==MULT&&g_flags_val[0].l>=68020&&(p->q2.flags&KONST)&&isreg(z)&&zreg>=9&&zreg<=16){
        /*  dx=a*const, fuer Skalierung    */
            int dreg=zreg-8;
            if(DEBUG&32) printf("mult x,const->dreg found\n");
            if(am_skal[dreg]) {clear_am(zreg);continue;}
            eval_const(&p->q2.val,p->typf&31);
            am_skal[dreg]=zl2l(vlong);
            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>=9&&q1reg<=16) am_dbase[dreg]=q1reg; else am_dbase[dreg]=zreg;
            if(DEBUG&32) printf("is usable\n");
            continue;
        }
        if((c==ADD||c==SUB)&&(p->q2.flags&KONST)&&zreg>=1&&zreg<=8&&isreg(z)){
        /*  add ax,#const,ax->az Test auf d8/16 fehlt noch    */
            long l;
            if(am_dist[zreg]||am_inc[zreg]) {clear_am(zreg);continue;} /* nur ein Offset */
            eval_const(&p->q2.val,p->typf&31);
            l=zl2l(vlong);
            if(c==SUB) l=-l;
            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",regnames[i]);
                    }
                }
                if(f) continue;
            }
            am_dist[zreg]=l;
            if(DEBUG&32) printf("dist=%ld\n",am_dist[zreg]);
            if(g_flags_val[0].l<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("add #const,%s found\n",regnames[zreg]);
            continue;
        }
        if(c==ADD&&q2reg>=9&&q2reg<=16&&isreg(q2)&&zreg>=1&&zreg<=8&&isreg(z)){
        /*  add ax,dy->az   */
            if(am_dreg[zreg]||am_inc[zreg]) {clear_am(zreg);continue;} /* nur ein Regoffset */
            if(g_flags_val[0].l<68020&&(am_dist[zreg]<-128||am_dist[zreg]>127))
                {clear_am(zreg);continue;} /* bei <68020 nur 8bit Offset */
            am_dreg[zreg]=q2reg;
            if((p->typf&15)==SHORT) 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",regnames[q2reg],regnames[zreg]);
            continue;
        }
        if(c==FREEREG){
        /*  wir koennen den Modus tatsaechlich benutzen */
            struct AddressingMode *am;struct IC *p1,*p2;int dreg;
            if(DEBUG&32) printf("freereg found, code=%d\n",p->code);
            if(q1reg>=9&&q1reg<=16) {am_freedreg[q1reg-8]=p;if(DEBUG&32) printf("freedreg[%d]=%lx\n",q1reg-8,(long)p);}
            if(q1reg>8||!am_use[q1reg]) continue;
            if(DEBUG&32) printf("could really use %s\n",regnames[q1reg]);
            p1=am_dist_ic[q1reg];p2=am_dreg_ic[q1reg];
            if(am_base[q1reg]==q1reg){
                if(p1) {p1->q2.flags=0;p1->code=ASSIGN;p1->q2.reg=4;p1->typf=POINTER;}
                if(p2) {p2->q2.flags=0;p2->code=ASSIGN;p2->q2.reg=4;p2->typf=POINTER;}
            }else{
                if(p1) remove_IC(p1);
                if(p2) remove_IC(p2);
            }
            dreg=(am_dreg[q1reg]&127)-8;
            am=(struct AddressingMode *)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(p1=am_freedreg[dreg]){
                    if(DEBUG&32) printf("freereg %s moved from %lx to %lx\n",regnames[dreg+8],(long)p1,(long)p);
                    if(p1->code!=FREEREG){ierror(0);printf("freereg[%d]=%lx\n",dreg,(long)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   */
                    am->skal=am_skal[dreg];
                    am->dreg=am_dbase[dreg];
                    p1=am_shiftdreg[dreg];
                    if(am_dbase[dreg]==dreg+8){
                        p1->code=ASSIGN;p1->q2.flags=0;p1->q2.reg=sizetab[p1->typf&15];
                    }else remove_IC(p1);
                    clear_am(dreg+8);
                }
            }
            /*  das hier duerfte unnoetig sein, da die Adressierungsart in  */
            /*  einem IC eigentlich hoechstens einmal vorkommen darf        */
            p1=am_use[q1reg];
            if(p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
                p1->q1.am=(struct AddressingMode *)mymalloc(AMS);
                memcpy(p1->q1.am,am,AMS);
                if(DEBUG&32) printf("q1 patched\n");
            }
            if(p1->q2.reg==q1reg&&((p1->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
                p1->q2.am=(struct AddressingMode *)mymalloc(AMS);
                memcpy(p1->q2.am,am,AMS);
                if(DEBUG&32) printf("q2 patched\n");
            }
            if(p1->z.reg==q1reg&&((p1->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){
                p1->z.am=(struct AddressingMode *)mymalloc(AMS);
                memcpy(p1->z.am,am,AMS);
                if(DEBUG&32) printf("z patched\n");
            }
            free(am);c++;
            clear_am(q1reg);
            continue;
        }
        if(c==LABEL){
            int i;      /*  ueber Labels hinweg ist das zu unsicher */
            for(i=1;i<=16;i++) clear_am(i);
            continue;
        }
        if(((p->q1.flags&(DREFOBJ|REG))&&q1reg<=8&&(am_inc[q1reg]||am_dist[q1reg]||am_dreg[q1reg]))){
            if(am_use[q1reg]) clear_am(q1reg); else am_use[q1reg]=p;
            if(am_inc[q1reg]&&am_inc[q1reg]!=sizetab[p->typf&15]) clear_am(q1reg);
            if(DEBUG&32) printf("use of %s found\n",regnames[q1reg]);
        }
        if(((p->q2.flags&(DREFOBJ|REG))&&q2reg<=8&&(am_inc[q2reg]||am_dist[q2reg]||am_dreg[q2reg]))){
            if(am_use[q2reg]) clear_am(q2reg); else am_use[q2reg]=p;
            if(am_inc[q2reg]&&am_inc[q2reg]!=sizetab[p->typf&15]) clear_am(q2reg);
            if(DEBUG&32) printf("use of %s found\n",regnames[q2reg]);
        }
        if(((p->z.flags&(DREFOBJ|REG))&&zreg<=8&&(am_inc[zreg]||am_dist[zreg]||am_dreg[zreg]))){
            if(am_use[zreg]) clear_am(zreg); else am_use[zreg]=p;
            if(am_inc[zreg]&&am_inc[zreg]!=sizetab[p->typf&15]) clear_am(zreg);
            if(DEBUG&32) printf("use of %s found\n",regnames[zreg]);
        }
        if(c==ALLOCREG){
        /*  allocreg zaehlt als zerstoerung von reg */
            p->z.flags=REG;
            p->z.reg=zreg=q1reg;
        }
        if(q1reg>=1&&q1reg<=16&&isreg(q1)) clear_am(q1reg);
        if(q2reg>=1&&q2reg<=16&&isreg(q2)) clear_am(q2reg);
        if(zreg>=1&&zreg<=16&&isreg(z)) clear_am(zreg);
        if(isreg(z)&&zreg<=16){
        /*  schauen, ob eines der Register ueberschrieben wird  */
        /*  wohl noch sehr langsam                              */
            int i;
            for(i=1;i<=8;i++)
                if(!am_use[i]&&(am_base[i]==zreg||(am_dreg[i]&127)==zreg)) clear_am(i);
        }
        if(c==ALLOCREG) p->z.flags=0;
    }
    if(DEBUG&1) printf("%d adderessingmodes used, localused=%d\n",count,localused);
    return(localused);
}
int alignment(struct obj *o)
/*  versucht rauszufinden, wie ein Objekt alignet ist   */
{
    /*  wenn es keine Variable ist, kann man nichts aussagen    */
    long os;
    if((o->flags&(DREFOBJ|VAR))!=VAR||o->am) return(0);
    if(!o->v) ierror(0);
    os=zl2l(o->val.vlong);
    if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){
        if(c_flags_val[0].l&256){
            if(o->v->offset<0) os=os+loff-o->v->offset;
             else              os=os+o->v->offset;
        }else{
            if(o->v->offset<0) os=os-o->v->offset+4;
             else              os=os-(o->v->offset+szof(o->v->vtyp));
        }
    }
    return(os&3);
}
void assign(FILE *f,struct IC *p,struct obj *q,struct obj *z,int c,int size,int t)
/*  Generiert Code fuer Zuweisungen und PUSH/POP; hier noch einiges zu tun  */
{
    /*  auch noch sehr fpu-spezifisch   */
    if(t==FLOAT||t==DOUBLE){
        if(q&&(q->flags&KONST)){
            if(z&&(z->flags&(DREFOBJ|REG))==REG){
            /*  FP-Konstante->Register (muss immer reinpassen)  */
                if(z->reg>=17) fprintf(f,"\tfmove"); else fprintf(f,"\tmove");
                fprintf(f,".%c\t",x_t[t&15]);probj(f,q,t,0);
                fprintf(f,",%s\n",regnames[z->reg]);
            }else{
            /*  FP-Konstante->Speicher (evtl. auf zweimal)  */
                int m,*ip=(int *)&q->val.vfloat; /* nicht sehr schoen  */
                if(c==PUSH&&t==DOUBLE) {fprintf(f,"\tmove.l\t#$%x,-(a7)\n",ip[1]);stackoffset-=4;}
                fprintf(f,"\tmove.l\t#$%x,",*ip);
                if(c==ASSIGN) probj(f,z,t,0); else {fprintf(f,"-(a7)");stackoffset-=4;}
                fprintf(f,"\n");
                if(t!=DOUBLE||c==PUSH) return;
                ip++;m=0;
                if(z&&z->flags&REG){
                    m=1;z->flags|=D16OFF;
                    z->val.vlong=l2zl(0L);
                }
                vlong=l2zl(4L);
                z->val.vlong=zladd(z->val.vlong,vlong);
                fprintf(f,"\tmove.l\t#$%x,",*ip);probj(f,z,t,0);
                fprintf(f,"\n");
                if(m){
                    z->flags&=~D16OFF;vlong=l2zl(4L);
                    z->val.vlong=zlsub(z->val.vlong,vlong);
                }
            }
            return;
        }
        if((q&&(q->flags&REG)&&q->reg>=17)||(z&&(z->flags&REG)&&z->reg>=17)){
            if(c==ASSIGN&&q->reg==z->reg) return;
            fprintf(f,"\tfmove.%c\t",x_t[t&15]);
            if(c==POP) {fprintf(f,"(a7)+");stackoffset+=size;} else probj(f,q,t,0);
            fprintf(f,",");
            if(c==PUSH) {fprintf(f,"-(a7)");stackoffset-=size;} else probj(f,z,t,0);
            fprintf(f,"\n");return;
        }
    }
    if(size<=4&&(t&15)!=ARRAY){
        if((t&15)==STRUCT||(t&15)==UNION){
            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){
            fprintf(f,"\tpea\t");
            q->flags&=~VARADR; probj(f,q,t,0); q->flags|=VARADR;
            fprintf(f,"\n"); stackoffset-=4;return;
        }
        fprintf(f,"\tmove.%c\t",x_s[size]);
        if(c==POP) {fprintf(f,"(a7)+");stackoffset+=size;} else probj(f,q,t,0);
        fprintf(f,",");
        if(c==PUSH) {fprintf(f,"-(a7)");stackoffset-=size;} else probj(f,z,t,0);
        fprintf(f,"\n");return;
    }else{
        int a1,a2,qreg,zreg,dreg,s=size,loops;char *cpstr;
        if(c==PUSH) cpstr="\tmove.%c\t-(%s),-(%s)\n"; else cpstr="\tmove.%c\t(%s)+,(%s)+\n";
        if(c==POP){
            qreg=8;
        }else{
            if(q->flags==(SCRATCH|REG|DREFOBJ)&&q->reg>=1&&q->reg<=8&&!q->am){
                qreg=q->reg;
            }else{
                if(c!=ASSIGN&&!regavailable(0)) printf("WARNING: PUSH PROBLEM(1)!\n");
                qreg=get_reg(f,0,p);
                fprintf(f,"\tlea\t");probj(f,q,POINTER,0);
                fprintf(f,",%s\n",regnames[qreg]);
            }
        }
        if(c==PUSH){
            zreg=8;
            fprintf(f,"\tadd%s.%s\t#%d,%s\n",quick[s<=8],strshort[s<=32767],s,regnames[qreg]);
        }else{
            zreg=get_reg(f,0,p);
            fprintf(f,"\tlea\t");probj(f,z,POINTER,0);
            fprintf(f,",%s\n",regnames[zreg]);
        }
        if(c!=POP) a1=alignment(q); else a1=0;
        if(c!=PUSH)  a2=alignment(z); else a2=0;
        if((a1&1)&&(a2&1)){fprintf(f,cpstr,'b',regnames[qreg],regnames[zreg]);s--;a1&=~1;a2&=~1;}
        if((a1&2)&&(a2&2)){fprintf(f,cpstr,'w',regnames[qreg],regnames[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)) printf("WARNING: PUSH PROBLEM(2)!\n");
            dreg=get_reg(f,1,p);
            fprintf(f,"\tmove%s.l\t#%d,%s\nl%d\n",quick[loops>=-128&&loops<=127],loops,regnames[dreg],++label);
        }
        if(loops>=0){
            int t;
            if(!(a1&1)&&!(a2&1)) t='l'; else t='b';
            fprintf(f,cpstr,t,regnames[qreg],regnames[zreg]);
            fprintf(f,cpstr,t,regnames[qreg],regnames[zreg]);
            fprintf(f,cpstr,t,regnames[qreg],regnames[zreg]);
            fprintf(f,cpstr,t,regnames[qreg],regnames[zreg]);
        }
        if(loops>0) fprintf(f,"\tdbra\t%s,l%d\n",regnames[dreg],label);
        if(!(a1&1)&&!(a2&1)){
            if(s&8){
                fprintf(f,cpstr,'l',regnames[qreg],regnames[zreg]);
                fprintf(f,cpstr,'l',regnames[qreg],regnames[zreg]);
            }
            if(s&4) fprintf(f,cpstr,'l',regnames[qreg],regnames[zreg]);
            if(s&2) fprintf(f,cpstr,'w',regnames[qreg],regnames[zreg]);
            if(s&1) fprintf(f,cpstr,'b',regnames[qreg],regnames[zreg]);
        }else{
            s&=3;
            while(s){fprintf(f,cpstr,'b',regnames[qreg],regnames[zreg]);s--;}
        }
        if(c==PUSH) stackoffset-=size;
        if(c==POP)  stackoffset+=size;
    }
    return;
}

int must_convert(np p,int t)
/*  liefert 1, wenn fuer Umwandlung von p->o nach Typ t tatsaechlich    */
/*  Code erzeugt werden muss, sonst 0                                   */
{
    int o=p->ntyp->flags,op=o&15,tp=t&15;
    /*  signed und unsigned integers der selben Groesse sind gleich */
    if((t&UNSIGNED)&&(o&UNSIGNED)&&(sizetab[tp]==sizetab[op])) return(0);
    /*  int==long   */
    if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return(0);
    /*  float und double gibt es in fp-Registern nicht  */
    if((tp==FLOAT||tp==DOUBLE)&&(op==FLOAT||op==DOUBLE)&&(p->o.flags&REG)&&p->o.reg>=17&&p->o.reg<=24)
        return(0);

    return(1);
}

