#include "vbc.h"

struct IC *first_ic=0,*last_ic=0;
int float_used;

int do_arith(np,struct IC *,np,struct obj *);

void add_IC(struct IC *new)
/*  fuegt ein IC ein                                            */
{
    int code;
    if(!new) return;
    if(nocode) {free(new);return;}
    new->next=0;
    new->q1.am=new->q2.am=new->z.am=0;
    code=new->code;
    if(code>=BEQ&&code<=BRA) new->q1.flags=new->q2.flags=new->z.flags=0;
    if(code==ALLOCREG||code==FREEREG||code==SAVEREGS||code==RESTOREREGS) new->typf=0;
    if(DEBUG&64) pric2(stdout,new);
    if(new->q1.flags&VAR){
        if(!new->q1.v) ierror(0);
        new->q1.v->flags|=USEDASSOURCE;
        if(code==ADDRESS||(new->q1.flags&VARADR)) new->q1.v->flags|=USEDASADR;
        new->q1.v->priority+=currentpri;
    }
    if(new->q2.flags&VAR){
        if(!new->q2.v) ierror(0);
        new->q2.v->flags|=USEDASSOURCE;
        if(code==ADDRESS||(new->q2.flags&VARADR)) new->q2.v->flags|=USEDASADR;
        new->q2.v->priority+=currentpri;
    }
    if(new->z.flags&VAR){
        if(!new->z.v) ierror(0);
        if(new->z.flags&DREFOBJ) new->z.v->flags|=USEDASSOURCE; else new->z.v->flags|=USEDASDEST;
        new->z.v->priority+=currentpri;
    }
    if(/*(c_flags_val[0].l&2)&&*/code==LABEL){
    /*  entfernt Spruenge zu direkt folgenden Labels    */
        struct IC *p=last_ic;
        while(p){
            if(p->typf==new->typf&&p->code>=BEQ&&p->code<=BRA){
                remove_IC(p);
                if(DEBUG&1) printf("%s l%d deleted\n",ename[p->code],p->typf);
            }else{
                if(p->code!=LABEL) break;
            }
            p=p->prev;
        }
    }
    if(last_ic){
/*    if(c_flags_val[0].l&2){*/
        if(code==ASSIGN){
            if((last_ic->z.flags&(REG|SCRATCH|DREFOBJ))==(REG|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.reg==new->q1.reg&&last_ic->code!=CALL){
                if(USEQ2ASZ||!(last_ic->q2.flags&REG)||!(new->z.flags&REG)||last_ic->q2.reg!=new->z.reg){
                    if(USEQ2ASZ||!(last_ic->q2.flags&VAR)||!(new->z.flags&VAR)||last_ic->q2.v!=new->z.v){
                    /*  verbindet op a,b->reg,move reg->c zu op a,b->c  */
                    /*  hier fehlt aber noch Registerfreigabe           */
                        last_ic->z=new->z;
                        if(DEBUG&1) printf("move and op combined\n");
                        if((new->q1.flags&SCRATCH)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))
                            free_reg(new->q1.reg);
                        free(new);
                        return;
                    }
                }
            }
        }
        if(last_ic->code==BRA){
            if(code!=LABEL&&code!=ALLOCREG&&code!=FREEREG){
            /*  loescht alles nach bra bis ein Label kommt  */
            /*  momentan noch nicht perfekt, da es bei alloc/freereg stoppt */
                free(new);
                if(DEBUG&1) printf("Unreachable Statement deleted\n");
                return;
            }
            if(last_ic->prev&&code==LABEL){
            /*  ersetzt bcc l1;bra l2;l1 durch b!cc l2      */
                if(last_ic->prev->code>=BEQ&&last_ic->prev->code<=BGT&&new->typf==last_ic->prev->typf){
                    if(DEBUG&1) printf("%s l%d;%s l%d; substituted\n",ename[last_ic->prev->code],last_ic->prev->typf,ename[last_ic->code],last_ic->typf);
                    if(last_ic->prev->code&1) last_ic->prev->code--;
                                    else      last_ic->prev->code++;
                    last_ic->prev->typf=last_ic->typf;
                    last_ic=last_ic->prev;
                    free(last_ic->next);
                    last_ic->next=new;new->prev=last_ic;
                    last_ic=new;
                    return;
                }
            }
        }
/*        }*/
        new->prev=last_ic;
        last_ic->next=new;
        last_ic=new;
    }else{
        last_ic=new;first_ic=new;new->prev=0;
    }
    /*  Merken, on Fliesskomma benutzt wurde    */
    if(code!=LABEL&&(code<BEQ||code>BRA))
        if((new->typf&15)==FLOAT||(new->typf&15)==DOUBLE) float_used=1;
    if((new->q1.flags&SCRATCH)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))
        free_reg(new->q1.reg);
    if((new->q2.flags&SCRATCH)&&(new->q2.reg!=new->z.reg||!(new->z.flags&REG)))
        free_reg(new->q2.reg);
}
void free_IC(struct IC *p)
/*  Gibt IC-Liste inkl. Typen frei                  */
{
    struct IC *merk;
    while(p){
        if(!(c_flags_val[0].l&128)){
            if(p->q1.am||p->q2.am||p->z.am)
                {p->q1.am=p->q2.am=p->z.am=0;ierror(0);}
        }else{
            if(p->q1.am) free(p->q1.am);
            if(p->q2.am) free(p->q2.am);
            if(p->z.am) free(p->z.am);
        }
        merk=p->next;
        free(p);
        p=merk;
    }
}
void gen_IC(np p,int ltrue,int lfalse)
/*  Erzeugt eine IC-Liste aus einer expression      */
{
    struct IC *new;
    if(!p) return;
    if(p->flags==STRING){
    /*  hier fehlt noch die Verwaltung der String-Inhalte   */
        p->o.v=add_var(empty,clone_typ(p->ntyp),STATIC,(struct const_list *)p->identifier);
        p->o.v->flags|=DEFINED;
        p->o.flags=VAR;
        p->o.reg=0;
        p->o.val=p->val;
        return;
    }
    if(p->flags==IDENTIFIER){
        p->o.v=find_var(p->identifier,0);
        p->o.flags=VAR;
        p->o.reg=0;
        p->o.val=p->val;
        return;
    }
    if(p->flags==CEXPR||p->flags==PCEXPR){
        if(p->left){
            if(p->left->flags==POSTINC) p->left->flags=PREINC;
            if(p->left->flags==POSTDEC) p->left->flags=PREDEC;
            gen_IC(p->left,0,0);
            if(p->left->o.flags&SCRATCH) free_reg(p->left->o.reg);
        }
        if(p->right){
            if(p->right->flags==POSTINC) p->right->flags=PREINC;
            if(p->right->flags==POSTDEC) p->right->flags=PREDEC;
            gen_IC(p->right,0,0);
            if(p->right->o.flags&SCRATCH) free_reg(p->right->o.reg);
        }
        p->o.flags=KONST;
        p->o.val=p->val;
        p->o.reg=0;
        return;
    }
    if(p->flags==KOMMA){
        if(p->left->sidefx){
            gen_IC(p->left,0,0);
            if(p->left->o.flags&SCRATCH) free_reg(p->left->o.reg);
        } else error(129);
        gen_IC(p->right,0,0);
        p->o=p->right->o;
        return;
    }
    if(p->flags==CAST){
        gen_IC(p->left,0,0);
        convert(p->left,p->ntyp->flags&31);
        p->o=p->left->o;
        return;
    }
    if(p->flags==FIRSTELEMENT){
        gen_IC(p->left,0,0);
        p->o=p->left->o;
        return;
    }
    new=(struct IC *)mymalloc(ICS);
    new->typf=p->ntyp->flags&31;
    new->q1.reg=new->q2.reg=new->z.reg=0;
    new->q1.flags=new->q2.flags=new->z.flags=0;
    if((p->flags>=LSHIFT&&p->flags<=MOD)||(p->flags>=OR&&p->flags<=AND)||p->flags==PMULT){
        do_arith(p,new,0,0);
        return;
    }
    if(p->flags==CONTENT){
        gen_IC(p->left,0,0);
        if(p->left->o.flags&VARADR){
            free(new);
            p->o=p->left->o;
            p->o.flags&=~VARADR;
            return;
        }
        if(!(p->left->o.flags&DREFOBJ)){
            free(new);
            p->o=p->left->o;
            p->o.flags|=DREFOBJ;
            return;
        }
        if(p->left->o.flags&SCRATCH){
            new->z=p->left->o;
            new->z.flags&=~DREFOBJ;
        }else{
            /*  hier muss man noch was aender, da das so nicht funktioniert */
            get_scratch(&new->z,p->left->ntyp->flags,p->ntyp->flags);
        }
        new->code=ASSIGN;new->typf=POINTER;
        new->q1=p->left->o;
        new->q2.reg=sizetab[POINTER];
        add_IC(new);
        p->o=new->z;
        p->o.flags|=DREFOBJ;
        return;
    }
    if(p->flags==ASSIGN){
        new->code=ASSIGN;
        gen_IC(p->right,0,0);
        gen_IC(p->left,0,0);
        convert(p->right,p->ntyp->flags&31);
        new->q1=p->right->o;
        new->z=p->left->o;
        new->q2.reg=szof(p->left->ntyp);
        add_IC(new);
        p->o=new->z;
        return;
    }
    if(p->flags==ASSIGNADD){
    /*  das hier ist nicht besonders schoen */
        struct obj o;struct IC *n;int f;
        if(p->right->right==0){
        /*  sowas wie a+=0 wurde wegoptimiert   */
            free(new);
            p->o=p->left->o;
            return;
        }
        f=do_arith(p->right,new,p->left,&o);
        if(!f) {ierror(0);return;}
        if(f>1) {ierror(0);return;}
        if(!nocode&&(o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&!regs[o.reg]){
        /*  ueberfluessiges FREEREG entfernen   */
            n=last_ic;
            while(n){
                if(n->code==FREEREG&&n->q1.reg==o.reg){
                    remove_IC(n);if(!nocode) regs[o.reg]=1;
                    break;
                }
                n=n->prev;
            }
        }
        convert(p->right,p->ntyp->flags&31);
        new=(struct IC *)mymalloc(ICS);
        new->typf=p->ntyp->flags&31;
        new->q2.flags=0;
        new->code=ASSIGN;
        new->q1=p->right->o;
        new->z=o;
        new->q2.reg=szof(p->left->ntyp);
        add_IC(new);
        p->o=new->z;
        return;
    }
    if(p->flags==MINUS||p->flags==KOMPLEMENT){
        new->code=p->flags;
        gen_IC(p->left,0,0);
        convert(p->left,p->ntyp->flags);
        if(regok(p->left->o.reg,p->ntyp->flags,0)&&(p->left->o.flags&SCRATCH)){
            new->z=p->left->o;
            new->z.flags&=~DREFOBJ;
        }else{
            get_scratch(&new->z,p->left->ntyp->flags,0);
        }
        new->q1=p->left->o;
        add_IC(new);
        p->o=new->z;
        return;
    }
    if(p->flags==ADDRESS||p->flags==ADDRESSA||p->flags==ADDRESSS){
        new->code=ADDRESS;
        new->typf=p->left->ntyp->flags&31;
        gen_IC(p->left,0,0);
        if(p->left->o.flags&VAR) p->left->o.v->flags|=USEDASSOURCE|USEDASDEST;
        if(p->left->o.flags&DREFOBJ){
            free(new);
            p->o=p->left->o;
            p->o.flags&=~DREFOBJ;
            return;
        }
        if((p->left->o.flags&VAR)&&!(p->left->o.flags&VARADR)
           &&(p->left->o.v->storage_class==EXTERN||p->left->o.v->storage_class==STATIC)){
            free(new);
            p->o=p->left->o;
            p->o.flags|=VARADR;
            return;
        }
        new->q1=p->left->o;
        get_scratch(&new->z,POINTER,p->ntyp->next->flags);
        add_IC(new);
        p->o=new->z;
        return;
    }
    if(p->flags==LAND||p->flags==LOR){
        int l1,l2,l3,l4;
/*        printf("%s true=%d false=%d\n",ename[p->flags],ltrue,lfalse);*/
        l1=++label;if(!ltrue) {l2=++label;l3=++label;l4=++label;}
        if(!ltrue){if(p->flags==LAND) gen_IC(p->left,l1,l3);
                    else gen_IC(p->left,l3,l1);
        }else     {if(p->flags==LAND) gen_IC(p->left,l1,lfalse);
                    else gen_IC(p->left,ltrue,l1);
        }
        if(p->left->o.flags!=0){
            new->code=TEST;
            new->q2.flags=new->z.flags=0;
            new->typf=p->left->ntyp->flags&31;
            new->q1=p->left->o;
            add_IC(new);
            new=(struct IC *)mymalloc(ICS);
            if(p->flags==LAND) new->code=BEQ; else new->code=BNE;
            if(!ltrue) new->typf=l3;
            else{if(p->flags==LAND) new->typf=lfalse; else new->typf=ltrue;}
            add_IC(new);
        }
        gen_label(l1);
        if(!ltrue){if(p->flags==LAND) gen_IC(p->right,l2,l3);
                    else gen_IC(p->right,l3,l2);
        }else      gen_IC(p->right,ltrue,lfalse);
        if(p->right->o.flags!=0){
            new=(struct IC *)mymalloc(ICS);
            new->code=TEST;
            new->q2.flags=new->z.flags=0;
            new->typf=p->right->ntyp->flags&31;
            new->q1=p->right->o;
            add_IC(new);
            new=(struct IC *)mymalloc(ICS);
            if(p->flags==LAND) new->code=BEQ; else new->code=BNE;
            if(!ltrue) new->typf=l3;
            else{if(p->flags==LAND) new->typf=lfalse; else new->typf=ltrue;}
            add_IC(new);
        }
        if(!ltrue){
            gen_label(l2);
            if(p->flags==LAND) p->o=gen_cond(0,l3,l4); else p->o=gen_cond(1,l3,l4);
        }else{
            new=(struct IC *)mymalloc(ICS);
            new->code=BRA;
            if(p->flags==LAND) new->typf=ltrue; else new->typf=lfalse;
            add_IC(new);
        }
        if(ltrue) p->o.flags=0;
        return;
    }
    if(p->flags==NEGATION){
        int l1,l2,l3;
        if(!ltrue) {l1=++label;l2=++label;l3=++label;}
        if(ltrue) gen_IC(p->left,lfalse,ltrue); else gen_IC(p->left,l1,l3);
        if(!p->left->o.flags) {free(new);p->o.flags=0;
        }else{
            new->code=TEST;
            new->q2.flags=new->z.flags=0;
            new->typf=p->left->ntyp->flags&31;
            new->q1=p->left->o;
            add_IC(new);
            new=(struct IC *)mymalloc(ICS);
            new->code=BNE;
            if(!ltrue) new->typf=l1; else new->typf=lfalse;
            add_IC(new);
        }
        if(ltrue){
            new=(struct IC *)mymalloc(ICS);
            new->code=BRA;
            if(!ltrue) new->typf=l2; else new->typf=ltrue;
            add_IC(new);
            p->o.flags=0;
        }else{
            gen_label(l3);
            p->o=gen_cond(0,l1,l2);
        }
        return;
    }
    if(p->flags>=EQUAL&&p->flags<=GREATEREQ){
        int l1,l2,l3,tl,tr,swapped;
        if(!ltrue) {l1=++label;l2=++label;l3=++label;}
        if(p->left->flags==CEXPR){
        /*  Konstanten nach rechts  */
            np merk;merk=p->left;p->left=p->right;p->right=merk;
            swapped=1;
        }else swapped=0;
        new->code=COMPARE;
        tl=p->left->ntyp->flags&31;tr=p->right->ntyp->flags&31;
        if(p->right->flags==CEXPR&&(tr&15)<FLOAT&&(tl&15)<FLOAT){
            zlong null;int negativ;
            eval_constn(p->right);
            null=l2zl(0L);
            if(zlleq(vlong,0)) negativ=1; else negativ=0;
            if(tr&UNSIGNED) negativ=0;
            if((!negativ||zlleq(t_min[tl],vlong))&&(negativ||zulleq(vulong,t_max[tl]))){
                convert(p->right,tl);
                tr=tl;
            }
        }
        if(arith(tl)&&tl!=tr){
            struct Typ *t;
            t=arith_typ(p->left->ntyp,p->right->ntyp);
            new->typf=t->flags&31;
            freetyp(t);
        }else{
            new->typf=p->left->ntyp->flags&31;
        }
        gen_IC(p->left,0,0);
        convert(p->left,new->typf);
        gen_IC(p->right,0,0);
        convert(p->right,new->typf);
        new->q1=p->left->o;
        new->q2=p->right->o;
        new->z.flags=0;
        add_IC(new);
        new=(struct IC *)mymalloc(ICS);
        if(p->flags==EQUAL) new->code=BEQ;
        if(p->flags==INEQUAL) new->code=BNE;
        if(p->flags==LESS) {if(swapped) new->code =BGT; else new->code=BLT;}
        if(p->flags==LESSEQ){if(swapped) new->code=BGE; else new->code=BLE;}
        if(p->flags==GREATER){if(swapped) new->code=BLT; else new->code=BGT;}
        if(p->flags==GREATEREQ){if(swapped) new->code=BLE; else new->code=BGE;}
        if(ltrue) new->typf=ltrue; else new->typf=l1;
        add_IC(new);
        if(ltrue){
            new=(struct IC *)mymalloc(ICS);
            new->code=BRA;
            new->typf=lfalse;
            add_IC(new);
            p->o.flags=0;
        }else{
            gen_label(l3);
            p->o=gen_cond(1,l1,l2);
        }
        return;
    }
    if(p->flags==CALL){
        int r,regused,sz;
        function_calls+=currentpri;
        gen_IC(p->left,0,0);
        if(!(p->left->o.flags&DREFOBJ)){
            free(new);
            p->o=p->left->o;
            if(p->o.flags&VARADR) p->o.flags&=~VARADR;
             else p->o.flags|=DREFOBJ;
        }else{
            if(p->left->o.flags&VARADR){
                free(new);
                p->o=p->left->o;
                p->o.flags&=~VARADR;
            }else{
                if(p->left->o.flags&SCRATCH){
                    new->z=p->left->o;
                    new->z.flags&=~DREFOBJ;
                }else{
                /* das hier funktioniert vermutlich auch nicht  */
                    get_scratch(&new->z,p->left->ntyp->flags,p->ntyp->flags);
                }
                new->code=ASSIGN;new->typf=POINTER;
                new->q1=p->left->o;
                new->q2.reg=sizetab[POINTER];
                new->q2.flags=0;
                add_IC(new);
                p->o=new->z;
                p->o.flags|=DREFOBJ;
            }
        }
/*            p->left->o.flags-=DREFOBJ|VARADR; Was sollte das??    */
        r=freturn(p->ntyp);
        if(!r){
            struct Typ *t=mymalloc(TYPS);
            t->flags=POINTER;t->next=p->ntyp;
            r=freturn(t);
            free(t);
        }
        if(!r) ierror(0);
        regused=regs[r];
        new=(struct IC *)mymalloc(ICS);
        new->code=SAVEREGS;
        new->typf=0;
        if((p->o.flags&(REG|SCRATCH))==(REG|SCRATCH)) new->q1.reg=p->o.reg;
            else new->q1.reg=0;
        new->q1.flags=new->q2.flags=new->z.flags=0;
        add_IC(new);
        sz=push_args(p->alist,p->left->ntyp->next->exact,0);
        if(!regused){
            if(!nocode) regs[r]=1;
            new=(struct IC *)mymalloc(ICS);
            new->code=ALLOCREG;
            new->typf=0;
            new->q1.flags=REG;
            new->q1.reg=r;
            new->q2.flags=new->z.flags=0;
            add_IC(new);regused=0;
        }
        new=(struct IC *)mymalloc(ICS);
        new->code=CALL;new->typf=FUNKT;
        new->q1=p->o;new->q2.flags=0;
        new->q2.reg=sz;
        new->z.reg=r;
        /*  hier noch Returnregister retten etc.        */
        new->z.flags=REG;
        if(!regused) new->z.flags|=SCRATCH;
        add_IC(new);
        p->o=new->z;
        if(!freturn(p->ntyp)) p->o.flags|=DREFOBJ;
        if(regused){
            if((p->ntyp->flags&15)!=VOID){
                new=(struct IC *)mymalloc(ICS);
                new->code=ASSIGN;
                new->typf=p->ntyp->flags&31;
                new->q1=p->o;
                new->q2.reg=szof(p->ntyp);
                new->q2.flags=0;
                get_scratch(&new->z,p->ntyp->flags&31,0);
                add_IC(new);
                p->o=new->z;
            }
        }
        new=(struct IC *)mymalloc(ICS);
        new->code=RESTOREREGS;
        new->typf=0;
        if(p->o.flags&REG) new->q1.reg=p->o.reg; else new->q1.reg=0;
        new->q1.flags=new->q2.flags=new->z.flags=0;
        add_IC(new);
        return;
    }
    if(p->flags>=PREINC&&p->flags<=POSTDEC){
        struct obj o;
        gen_IC(p->left,0,0);
        if(p->flags==POSTINC||p->flags==POSTDEC){
            new=(struct IC *)mymalloc(ICS);
            new->code=ASSIGN;
            new->typf=p->ntyp->flags&31;
            new->q2.reg=sizetab[p->ntyp->flags&15];
            new->q1=p->left->o;
            new->q1.flags&=~SCRATCH;
            get_scratch(&new->z,p->left->ntyp->flags&31,0);
            new->q2.flags=0;
            add_IC(new);
            o=new->z;
            new=(struct IC *)mymalloc(ICS);
        }else o=p->left->o;
        if((p->left->ntyp->flags&15)==POINTER){
            if(p->flags==PREINC||p->flags==POSTINC) new->code=ADDI2P; else new->code=SUBIFP;
            vlong=l2zl((long)szof(p->left->ntyp->next));
            new->q2.val.vint=zl2zi(vlong);
            new->typf=INT;
            new->q1=p->left->o;
            new->z=p->left->o;
            new->q2.flags=KONST;
            add_IC(new);
        }else{
            if(p->flags==PREINC||p->flags==POSTINC) new->code=ADD; else new->code=SUB;
            new->typf=p->ntyp->flags&31;
            new->q1=p->left->o;
            new->z=p->left->o;
            new->q2.flags=KONST;
            vlong=l2zl(1L);vulong=zl2zul(vlong);vdouble=zl2zd(vlong);
            if(new->typf==CHAR) new->q2.val.vchar=zl2zc(vlong);
            if(new->typf==SHORT) new->q2.val.vshort=zl2zs(vlong);
            if(new->typf==INT) new->q2.val.vint=zl2zi(vlong);
            if(new->typf==LONG) new->q2.val.vlong=vlong;
            if(new->typf==(UNSIGNED|CHAR)) new->q2.val.vuchar=zul2zuc(vulong);
            if(new->typf==(UNSIGNED|SHORT)) new->q2.val.vushort=zul2zus(vulong);
            if(new->typf==(UNSIGNED|INT)) new->q2.val.vuint=zul2zui(vulong);
            if(new->typf==(UNSIGNED|LONG)) new->q2.val.vulong=vulong;
            if(new->typf==DOUBLE) new->q2.val.vdouble=vdouble;
            if(new->typf==FLOAT) new->q2.val.vfloat=zd2zf(vdouble);
            add_IC(new);
        }
        if(p->flags==POSTINC||p->flags==POSTDEC){
            if(p->left->o.flags&SCRATCH) free_reg(p->left->o.reg);
        }
        p->o=o;
        return;
    }
    if(p->flags==COND){
        int ltrue,lfalse,lout;
        ltrue=++label;lfalse=++label;lout=++label;
        gen_IC(p->left,ltrue,lfalse);
        if(!p->left->o.flags){
            free(new);
        }else{
            if(p->left->flags!=CEXPR){
                new->code=TEST;
                new->typf=p->left->ntyp->flags&31;
                new->q1=p->left->o;
                new->q2.flags=new->z.flags=0;
                add_IC(new);
                new=(struct IC *)mymalloc(ICS);
                new->code=BEQ;
                new->typf=lfalse;
                add_IC(new);
            }else{
                eval_constn(p->left);
                if(zleq(vlong)&&zuleq(vulong)&&zdeq(vdouble)){
                    gen_IC(p->right->right,0,0);
                    p->o=p->right->right->o;
                }else{
                    gen_IC(p->right->left,0,0);
                    p->o=p->right->left->o;
                }
                return;
            }
        }
        gen_label(ltrue);
        gen_IC(p->right->left,0,0);
        convert(p->right->left,p->ntyp->flags&31);
        if(p->right->left->o.flags&SCRATCH){
            p->o=p->right->left->o;
        }else{
            get_scratch(&p->o,p->ntyp->flags&31,0);
            new=(struct IC *)mymalloc(ICS);
            new->code=ASSIGN;
            new->q1=p->right->left->o;
            new->z=p->o;
            new->q2.flags=0;
            new->q2.reg=szof(p->ntyp);
            new->typf=p->ntyp->flags&31;
            add_IC(new);
            p->o=new->z;
        }
        new=(struct IC *)mymalloc(ICS);
        new->code=BRA;
        new->typf=lout;
        add_IC(new);
        gen_label(lfalse);
        gen_IC(p->right->right,0,0);
        convert(p->right->right,p->ntyp->flags&31);
        new=(struct IC *)mymalloc(ICS);
        new->code=ASSIGN;
        new->q1=p->right->right->o;
        new->z=p->o;
        new->q2.flags=0;
        new->q2.reg=szof(p->ntyp);
        new->typf=p->ntyp->flags&31;
        add_IC(new);
        gen_label(lout);
        return;
    }
    printf("Operation: %d=%s\n",p->flags,ename[p->flags]);
    ierror(0);
    free(new);
    p->o.flags=0;
}
int push_args(struct argument_list *al,struct struct_declaration *sd,int n)
/*  Legt die Argumente eines Funktionsaufrufs in umgekehrter Reihenfolge    */
/*  auf den Stack. Es wird Integer-Erweiterung vorgenommen und float wird   */
/*  nach double konvertiert, falls kein Prototype da ist. Ausserdem werden  */
/*  alle Argumente in ihrer Groesse aligned. Das ist evtl. nicht fuer jede  */
/*  CPU ausreichend. Hier muss evtl. noch etwas getan werden.               */
{
    int of,t,sz;struct IC *new;
    if(!al) return(0);
    if(al->next) of=push_args(al->next,sd,n+1); else of=0;
    if(!al->arg) {ierror(0);return(of);}
    if(!sd) {ierror(0);return(of);}
    gen_IC(al->arg,0,0);
    if(n<sd->count){t=sd->sl[n].styp->flags&15;sz=szof(sd->sl[n].styp);}
     else {t=al->arg->ntyp->flags&15;sz=szof(al->arg->ntyp);}
    if(t>=CHAR&&t<=LONG) {t=int_erw(t);sz=sizetab[t&15];}
    if(t==FLOAT&&n>=sd->count) {t=DOUBLE;sz=sizetab[t];}
    convert(al->arg,t&31);
    new=(struct IC *)mymalloc(ICS);
    new->code=PUSH;
    new->typf=t;
    new->q1=al->arg->o;
    new->q2.flags=new->z.flags=0;
    new->q2.reg=((sz+maxalign-1)/maxalign)*maxalign;
    add_IC(new);
    return(of+sz);
}

void convert(np p,int f)
/*  konvertiert das Objekt in p->o in bestimmten Typ    */
{
    struct IC *new;
    if((f&15)==VOID||(p->ntyp->flags&31)==f) return;
    if(p->flags==CEXPR||p->flags==PCEXPR){
        eval_constn(p);
        p->ntyp->flags=f;
        insert_const(p);
        p->o.val=p->val;
        return;
    }
    if(!must_convert(p,f)) return;
    new=(struct IC *)mymalloc(ICS);
    new->q1=p->o;
    new->q2.flags=0;
    new->code=CONVCHAR+(p->ntyp->flags&15)-CHAR;
    if(p->ntyp->flags&UNSIGNED) new->code+=8;
    new->typf=f;
    if(!regok(p->o.reg,f,0)||!(p->o.flags&SCRATCH)){
        get_scratch(&new->z,f,0);
        add_IC(new);
    }else{
        new->z=p->o;new->z.flags&=~DREFOBJ;
        add_IC(new);
    }
    p->o=new->z;
}

int allocreg(int f,int mode)
/*  Fordert Register fuer Typ f an                      */
/*  evtl. maschinenabhaengig, aber hier fehlt noch viel */
/*  z.B. Eintragen eines IC                             */
{
    int i;struct IC *new;
    if(nocode) return(1);
    for(i=1;i<=MAXR;i++){
        if(!regs[i]&&regok(i,f,mode)){
            if(DEBUG&16) printf("alocated %s\n",regnames[i]);
            regs[i]=1;regused[i]++;
            new=(struct IC *)mymalloc(ICS);
            new->code=ALLOCREG;
            new->typf=0;
            new->q1.flags=REG;
            new->q1.reg=i;
            new->q2.flags=new->z.flags=0;
            add_IC(new);
            return(i);}
    }
    if(DEBUG&1) printf(">%sCouldn't allocate register for type %d\n",string,f);
    return(0);
}
void free_reg(int r)
/*  Gibt Register r frei                                */
/*  Eintrag eines IC fehlt noch                         */
{
    struct IC *new;
    if(!r||nocode) return;
    if(regs[r]==0) {printf("Register %s:\n",regnames[r]);ierror(0);}
    if(DEBUG&16) printf("freed %s\n",regnames[r]);
    new=(struct IC *)mymalloc(ICS);
    new->code=FREEREG;
    new->typf=0;
    new->q1.flags=REG;
    new->q1.reg=r;
    new->q2.flags=new->z.flags=0;
    add_IC(new);
    regs[r]=0;
}
void gen_label(int l)
/*  Erzeugt ein Label                                   */
{
    struct IC *new;
    new=(struct IC *)mymalloc(ICS);
    new->code=LABEL;
    new->typf=l;
    new->q1.flags=new->q2.flags=new->z.flags=0;
    add_IC(new);
}
struct obj gen_cond(int m,int l1,int l2)
/*  Generiert code, der 0 oder 1 in Register schreibt   */
{
    struct IC *new;
    struct obj omerk;
    new=(struct IC *)mymalloc(ICS);
    new->code=ASSIGN;
    new->typf=INT;
    new->q1.flags=KONST;
    new->q2.flags=0;
    new->q2.reg=sizetab[INT];
    if(!m) vlong=l2zl(1L); else vlong=l2zl(0L);
    new->q1.val.vint=zl2zi(vlong);
    get_scratch(&new->z,INT,0);
    omerk=new->z;
    add_IC(new);
    new=(struct IC *)mymalloc(ICS);
    new->code=BRA;
    new->typf=l2;
    add_IC(new);
    gen_label(l1);
    new=(struct IC *)mymalloc(ICS);
    new->code=ASSIGN;
    new->typf=INT;
    new->q1.flags=KONST;
    new->q2.flags=0;
    new->q2.reg=sizetab[INT];
    if(!m) vlong=l2zl(0L); else vlong=l2zl(1L);
    new->q1.val.vint=zl2zi(vlong);
    new->z=omerk;
/*    new->z.reg=r;
    new->z.flags=SCRATCH|REG;*/
    add_IC(new);
    gen_label(l2);
    return(omerk);
}
void scratch_var(struct obj *o,int t)
/*  liefert eine temporaere Variable                            */
/*  nicht effizient, aber wer hat schon so wenig Register...    */
{
    struct Typ *nt=(struct Typ *)mymalloc(TYPS);
    if((t&15)<CHAR||(t&15)>POINTER) ierror(0);
    nt->flags=t&31;
    if((t&15)==POINTER){
        nt->next=(struct Typ *)mymalloc(TYPS);
        nt->next->flags=VOID;
        nt->next->next=0;
    }else nt->next=0;
    o->flags=SCRATCH|VAR;o->reg=0;
    o->v=add_var(empty,nt,AUTO,0);
    o->val.vlong=l2zl(0L);
}
void get_scratch(struct obj *o,int t1,int t2)
/*  liefert ein Scratchregister oder eine Scratchvariable       */
{
    if(o->reg=allocreg(t1,t2)){
        o->flags=SCRATCH|REG;
    }else{
        scratch_var(o,t1);
    }
}
void remove_IC(struct IC *p)
/*  entfernt IC p aus Liste */
{
    if(p->prev) p->prev->next=p->next; else first_ic=p->next;
    if(p->next) p->next->prev=p->prev; else last_ic=p->prev;
    if(p->q1.am) free(p->q1.am);
    if(p->q2.am) free(p->q2.am);
    if(p->z.am) free(p->z.am);
    free(p);
}
int do_arith(np p,struct IC *new,np dest,struct obj *o)
/*  erzeugt IC new fuer einen arithmetischen Knoten und speichert das   */
/*  Resultat vom Unterknoten dest in o (fuer a op= b)               */
/*  liefert 0, wenn dest nicht gefunden                             */
{
    int f=0;
    new->code=p->flags;
    if(new->code==PMULT) new->code=MULT;
    gen_IC(p->left,0,0);
    if(dest&&p->left==dest) {*o=p->left->o;f++;}
    gen_IC(p->right,0,0);
    if(dest&&p->right==dest) {*o=p->right->o;f++;}

    if((p->left->ntyp->flags&15)==POINTER&&(p->right->ntyp->flags&15)==POINTER){
    /*  Subtrahieren zweier Pointer                                 */
        if(p->flags!=SUB) ierror(0);
        new->typf=INT;
        new->code=SUBPFP;
        new->q1=p->left->o;
        new->q2=p->right->o;
        if(p->left->o.flags&SCRATCH&&regok(p->left->o.reg,INT,0)){
            new->z=p->left->o;
            new->z.flags&=~DREFOBJ;
        }else{
            if(USEQ2ASZ&&(p->right->o.flags&SCRATCH)&&regok(p->right->o.reg,INT,0)){
                new->z=p->left->o;
                new->z.flags&=(~DREFOBJ);
            }else{
                get_scratch(&new->z,INT,0);
            }
        }
        add_IC(new);
        p->o=new->z;
        if(szof(p->left->ntyp->next)>1){
            new=(struct IC *)mymalloc(ICS);
            new->code=DIV;
            new->q1=p->o;
            new->q2.flags=KONST;
            vlong=l2zl((long)szof(p->left->ntyp->next));
            vint=zl2zi(vlong);
            new->q2.val.vint=vint;
            new->z=p->o;
            new->typf=INT;
            add_IC(new);
        }
        return(f);
    }
    if((p->flags==ADD||p->flags==SUB)&&(p->ntyp->flags&15)==POINTER){
    /*  Addieren und Subtrahieren eines Integers zu einem Pointer   */
        if(p->flags==ADD) new->code=ADDI2P; else new->code=SUBIFP;
        new->typf=p->right->ntyp->flags&31;
        new->q1=p->left->o;
        /*  kleinere Typen als MINADDI2P erst in diesen wandeln */
        if((new->typf&15)<MINADDI2P){convert(p->right,/*UNSIGNED|*/MINADDI2P);new->typf=/*UNSIGNED|*/MINADDI2P;}
        new->q2=p->right->o;
        if((p->left->o.flags&SCRATCH)&&regok(new->q1.reg,POINTER,p->left->ntyp->next->flags&31)){
            new->z=p->left->o;
            new->z.flags&=(~DREFOBJ);
        }else{
            get_scratch(&new->z,POINTER,p->left->ntyp->next->flags&31);
        }
        add_IC(new);
        p->o=new->z;
        return(f);
    }
    convert(p->left,p->ntyp->flags&31);
    convert(p->right,p->ntyp->flags&31);
    new->q1=p->left->o;
    new->q2=p->right->o;
    new->typf=p->ntyp->flags&31;
    if((new->q1.flags&SCRATCH)&&regok(new->q1.reg,p->ntyp->flags,0)){
        new->z=new->q1;
        new->z.flags&=~DREFOBJ;
    }else{
        if((new->q2.flags&SCRATCH)&&regok(new->q2.reg,p->ntyp->flags,0)){
            if((p->flags>=OR&&p->flags<=AND)||p->flags==ADD||p->flags==MULT||p->flags==PMULT){
            /*  bei kommutativen Operatoren vertauschen     */
                new->z=new->q2;
                new->q2=new->q1;
                new->q1=new->z;
                new->z.flags&=~DREFOBJ;
            }else{
                if(USEQ2ASZ){
                    new->z=new->q2;
                    new->z.flags&=~DREFOBJ;
                }else{
                    get_scratch(&new->z,new->typf,0);
                }
            }
        }else{
            get_scratch(&new->z,new->typf,0);
        }
    }
    add_IC(new);
    p->o=new->z;
    return(f);
}
