2571 lines · 74.5 KB · C
RawDownload
/*  $VER: vbcc (ic.c) V0.8  */ #include "vbc.h"#include "opt.h" static char FILE_[]=__FILE__; static struct IC *first_pushed;static unsigned int opushed;static int volatile_convert; int do_arith(np,struct IC *,np,struct obj *);np gen_libcall(char *fname,np arg1,struct Typ *t1,np arg2,struct Typ *t2); static void handle_reglist(struct regargs_list *,struct obj *); #if HAVE_LIBCALLS/* avoid calling use_libcall with illegal operands */static char *use_libcall_wrap(int c,int t,int t2){  if(optflags&2)    return 0;   if(c==PMULT) c=MULT;  if((c>=OR&&c<=XOR)||(c>=LSHIFT&&c<=KOMPLEMENT)||c==COMPARE||c==CONVERT||c==MINUS||c==TEST)    return use_libcall(c,t,t2);  return 0;}#endif void gen_test(struct obj *o,int t,int branch,int label)/*  Generiert ein test o, branch label und passt auf, dass      *//*  kein TEST const generiert wird.                             */{  struct IC *new;  if(o->flags&KONST){    eval_const(&o->val,t);    if(zldeqto(vldouble,d2zld(0.0))&&zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){      if(branch==BEQ) branch=BRA; else branch=0;    }else{      if(branch==BNE) branch=BRA; else branch=0;    }  }else{#if HAVE_LIBCALLS    static struct node n={TEST},nn={REINTERPRET};    static struct Typ nt,it={INT};    char *libname;    n.left=&nn;    n.ntyp=&it;    nn.ntyp=&nt;    nt.flags=t;    n.o=nn.o=*o;    if(libname=use_libcall_wrap(TEST,t,0)){      new=new_IC();      new->code=TEST;      new->q2.flags=new->z.flags=0;      new->typf=INT;      new->q1=gen_libcall(libname,&nn,&nt,0,0)->o;      add_IC(new);    }else{#endif      new=new_IC();      new->code=TEST;      new->q2.flags=new->z.flags=0;      new->typf=t;      new->q1=*o;      add_IC(new);#if HAVE_LIBCALLS    }#endif  }  if(branch){    new=new_IC();    new->code=branch;    new->typf=label;    add_IC(new);  }} /* remove a freereg if a scratch register is needed more than once */static void keep_reg(int r){  struct IC *n;  if(nocode) return;  n=last_ic;  while(n){    if(n->code==CALL&&regscratch[r]){      struct IC *ret;      regs[r]=1;      savescratch(MOVEFROMREG,n->prev,0,&n->q1);      ret=n->next;      while(ret->code==ALLOCREG||ret->code==FREEREG)        ret=ret->next;      if(ret->code==GETRETURN){        if((ret->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ret->z.reg==r)           ret->z.flags&=~REG;      }else        ret=ret->prev;      savescratch(MOVETOREG,ret,0,&n->q1);    }    if(n->code==FREEREG&&n->q1.reg==r){      remove_IC(n);      if(!nocode)        regs[r]=1;      break;    }    n=n->prev;  }} /* Generate code to insert a bitfield */void insert_bitfield(struct obj *dest,struct obj *src,struct obj *val,int bfs,int bfo,int t,int isclear){  /*FIXME: shortcut beachten? */  struct IC *new;  struct obj tmp1,tmp2,tmp3;  int vmerk;  bfo=bflayout(bfo,bfs,t);  if((dest->flags&REG)&&!regs[dest->reg])    keep_reg(dest->reg);  new=new_IC();  new->code=AND;  new->typf=t;  new->q1=*src;  new->q1.flags&=~SCRATCH;  new->q2.flags=KONST;  gval.vmax=zmsub(zmlshift(l2zm(1L),l2zm((int)bfs)),l2zm(1L));  eval_const(&gval,MAXINT);  insert_const(&new->q2.val,t);  get_scratch(&new->z,t,0,0);  tmp1=new->z;  if((new->q1.flags&(KONST|DREFOBJ))==KONST){    calc(AND,new->typf,&new->q1.val,&new->q2.val,&new->q1.val,0);    new->code=ASSIGN;    new->q2.flags=0;    new->q2.val.vmax=sizetab[new->typf&NQ];  }  *val=tmp1;  vmerk=val->flags;  tmp1.flags&=~SCRATCH;  add_IC(new);  if(bfo!=0){    new=new_IC();    new->code=LSHIFT;    new->typf=t;    new->typf2=INT;    new->q1=tmp1;    new->q2.flags=KONST;    new->q2.val.vint=zm2zi(l2zm((long)bfo));    get_scratch(&new->z,t,0,0);    tmp3=new->z;    add_IC(new);  }else{    tmp3=tmp1;  }  if(!isclear){    new=new_IC();    new->code=AND;    new->typf=t;    new->q1=*dest;    new->q1.flags&=~SCRATCH;    new->q2.flags=KONST;    gval.vmax=zmkompl(zmlshift(zmsub(zmlshift(l2zm(1L),l2zm((int)bfs)),l2zm(1L)),l2zm((long)bfo)));    eval_const(&gval,MAXINT);    insert_const(&new->q2.val,t);    get_scratch(&new->z,t,0,0);    tmp2=new->z;    add_IC(new);  }  new=new_IC();  new->code=OR;  new->typf=t;  if(isclear)    new->q1=*dest;  else    new->q1=tmp2;  new->q2=tmp3;  new->z=*dest;  add_IC(new);  if(dest->flags&(REG|SCRATCH)) free_reg(dest->reg);  val->flags=vmerk;} void inline_memcpy(np z,np q,zmax size)/*  fuegt ein ASSIGN-IC ein, das memcpy(z,q,size) entspricht    */{    struct IC *new=new_IC();    if(!ISPOINTER(z->ntyp->flags)) ierror(0);    if(!ISPOINTER(q->ntyp->flags)) ierror(0);     if(z->flags==ADDRESS||z->flags==ADDRESSA||z->flags==ADDRESSS){      gen_IC(z,0,0);      new->z=z->left->o;      if(z->flags!=ADDRESSS&&z->left->flags==IDENTIFIER&&is_vlength(z->left->ntyp)){	/* variable length array */	new->z.flags|=DREFOBJ;	new->z.dtyp=POINTER_TYPE(z->ntyp->next);      }    }else{      gen_IC(z,0,0);      if(z->o.flags&DREFOBJ){        struct IC *n2=new_IC();        n2->code=ASSIGN;        n2->typf=q->ntyp->flags;        n2->q1=z->o;        get_scratch(&n2->z,z->ntyp->flags,z->ntyp->next->flags,z->ntyp);        n2->q2.flags=0;        n2->q2.val.vmax=sizetab[POINTER_TYPE(z->ntyp->next)];        new->z=n2->z;        add_IC(n2);      }else{        new->z=z->o;      }      if(new->z.flags&VARADR){	new->z.flags&=~VARADR;       }else{	new->z.flags|=DREFOBJ;	new->z.dtyp=POINTER_TYPE(z->ntyp->next);      }    }    if(q->flags==ADDRESS||q->flags==ADDRESSA||q->flags==ADDRESSS){      gen_IC(q,0,0);      new->q1=q->left->o;      if(q->flags!=ADDRESSS&&q->left->flags==IDENTIFIER&&is_vlength(q->left->ntyp)){	/* variable length array */	new->q1.flags|=DREFOBJ;	new->q1.dtyp=POINTER_TYPE(q->ntyp->next);      }    }else{          gen_IC(q,0,0);      if(q->o.flags&DREFOBJ){        struct IC *n2=new_IC();        n2->code=ASSIGN;        n2->typf=q->ntyp->flags;        n2->q1=q->o;        get_scratch(&n2->z,q->ntyp->flags,q->ntyp->next->flags,q->ntyp);        n2->q2.flags=0;        n2->q2.val.vmax=sizetab[POINTER_TYPE(q->ntyp->next)];         new->q1=n2->z;        add_IC(n2);      }else{        new->q1=q->o;      }      if(new->q1.flags&VARADR){	new->q1.flags&=~VARADR;      }else{	new->q1.flags|=DREFOBJ;	new->q1.dtyp=POINTER_TYPE(q->ntyp->next);      }    }    new->code=ASSIGN;    new->typf=UNSIGNED|CHAR;    new->q2.flags=0;    new->q2.val.vmax=size;    add_IC(new);} void add_IC(struct IC *new)/*  fuegt ein IC ein                                            */{    int code;    if(!new) return;    if(nocode) {#ifdef HAVE_MISRA/* removed */#endif      /*free(new);*/ /* building a list to free later would be nice... */      return;    }    new->next=0;    new->q1.am=new->q2.am=new->z.am=0;    new->line=line; new->file=filename;    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){ pric(stdout,first_ic);printf("new\n");pric2(stdout,new);printf("-\n");}    if(new->q1.flags&VAR){        if(!new->q1.v) 	  ierror(0);        new->q1.v->flags|=USEDASSOURCE;        if(code==ADDRESS||(new->q1.flags&VARADR))	  if(!is_vlength(new->q1.v->vtyp))	    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))   	  if(!is_vlength(new->q2.v->vtyp))	    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(block_vla[nesting]){      /* special handling for blocks with variable-length arrays */      struct llist *p;      if(new->code==LABEL){	p=mymalloc(LSIZE);	p->label=new->typf;	p->next=vladeflabels[nesting];	vladeflabels[nesting]=p;      }else if(0&&new->code==BRA&&!(new->flags&LOOP_COND_TRUE)){	p=mymalloc(LSIZE);	p->label=new->typf;	p->next=vlajmplabels[nesting];	vlajmplabels[nesting]=p;	p=vladeflabels[nesting];	while(p){	  if(p->label==new->typf)	    break;	  p=p->next;	}	if(!p){ 	  /* label not declared in this block so far;	     re-adjust stack, but store the position - label may be	     declared later in the same block and adjustement must be	     removed */	  struct vlaadjust_list *vl;	  struct IC *first;	  first=last_ic;	  freevl();	  first=first->next;	  vl=mymalloc(sizeof(*vl));	  vl->branch=new;	  vl->first=first;	  vl->next=vlaadjusts[nesting];	  vlaadjusts[nesting]=vl;	}      }    }    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){                struct IC *n;		if(p->code!=BRA){		  struct IC *cmp=p->prev;		  while(cmp&&cmp->code==FREEREG) cmp=cmp->prev;		  if(cmp->code==TEST){		    if(is_volatile_obj(&cmp->q1))		      break;		    else{		      if(DEBUG&1) printf("preceding test removed\n");		      remove_IC(cmp);		    }		  }else if(cmp->code==COMPARE){		    if(is_volatile_obj(&cmp->q1)||is_volatile_obj(&cmp->q2))		      break;		    else{		      if(DEBUG&1) printf("preceding compare removed\n");		      remove_IC(cmp);		    }		  }else		    break;		}		if(vlaadjusts[nesting]){		  /* remove it from vlaadjusts-lists, if necessary */		  struct vlaadjust_list *vl=vlaadjusts[nesting];		  while(vl){		    if(vl->branch==p){		      struct IC *np=vl->branch->prev;		      while(np!=vl->first->prev){			if(!np) ierror(0);			np->code=NOP;			np->q1.flags=np->q2.flags=np->z.flags=0;			np=np->prev;		      }		      vl->branch=0;		    }		    vl=vl->next;		  }		}                if(DEBUG&1) printf("%s l%d deleted\n",ename[p->code],p->typf);                n=p->next;                remove_IC(p);                p=n;            }else{                if(p->code!=LABEL) break;                p=p->prev;            }        }    }    if(last_ic){        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|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))                            free_reg(new->q1.reg);                        free(new);                        return;                    }                }            }            if((last_ic->z.flags&(VAR|SCRATCH|DREFOBJ))==(VAR|SCRATCH)&&(new->q1.flags==last_ic->z.flags)&&last_ic->z.v==new->q1.v/*&&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->scratch,move scratch->c zu op a,b->c  */                    /*  hier fehlt aber noch Registerfreigabe           */                        last_ic->z=new->z;                        if(DEBUG&1) printf("move and op combined(2)\n");/*                        if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))                            free_reg(new->q1.reg);*/                        free(new);                        return;                    }                }            }         }        if(last_ic->code==BRA){            if(!dontdelete&&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);#ifdef HAVE_MISRA/* removed */#endif                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(last_ic->next) pric2(stdout,last_ic->next);                    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;    }    ic_count++;    /*  Merken, on Fliesskomma benutzt wurde    */    if(code!=LABEL&&(code<BEQ||code>BRA)){        if(ISFLOAT(new->typf)) float_used=1;        if(code==CONVERT&&ISFLOAT(new->typf2)) float_used=1;    }    if((new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q1.reg!=new->z.reg||!(new->z.flags&REG)))        free_reg(new->q1.reg);    if((new->q2.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q2.reg!=new->z.reg||!(new->z.flags&REG)))        free_reg(new->q2.reg);} np gen_libcall(char *fname,np arg1,struct Typ *t1,np arg2,struct Typ *t2)/* generate call to a library function (emulate operation) */{  np new;   struct argument_list *al=0,*t;  new=new_node();  new->flags=CALL;  new->right=0;  new->left=new_node();  new->left->flags=IDENTIFIER;  new->left->left=new->left->right=0;  new->left->identifier=add_identifier(fname,strlen(fname));  new->left->ntyp=0;  new->left->sidefx=0;  new->left->val.vmax=l2zm(0L);   new->alist=0;  if(arg1){    al=mymalloc(sizeof(*al));    al->arg=arg1;    al->next=0;    if(t1){      np cnv=new_node();      cnv->flags=CAST;      cnv->left=arg1;      cnv->right=0;      cnv->ntyp=t1;      al->arg=cnv;    }

Lines 1–500 of 2571.