| /* $VER: vbcc (ic.c) $Revision: 1.65 $ */ |
| |
| #include "vbc.h" |
| #include "opt.h" |
| |
| #define RNOSAVE 32 /* register does not have to be saved across call */ |
| #define RHALF 64 /* half of a register pair was already allocated */ |
| |
| static char FILE_[]=__FILE__; |
| |
| static IC *first_pushed; |
| static unsigned int opushed; |
| static int volatile_convert; |
| |
| int do_arith(np,IC *,np,obj *); |
| static obj *postop_obj; |
| static int postop_type; |
| np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2); |
| |
| static void handle_reglist(regargs_list *,obj *); |
| |
| static void fix_pushic(IC **pushic,IC *new) |
| { |
| IC *p=last_ic; |
| while(p&&p->code==FREEREG) p=p->prev; |
| if(new==*pushic&&new!=p){ |
| if(DEBUG&1){ |
| printf("pushic converted to:\n"); |
| pric2(stdout,p); |
| } |
| *pushic=p; |
| } |
| } |
| |
| #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<=AND)||(c>=LSHIFT&&c<=KOMPLEMENT)||c==COMPARE||c==CONVERT||c==MINUS||c==TEST) |
| return use_libcall(c,t,t2); |
| return 0; |
| } |
| #endif |
| |
| void gen_test(obj *o,int t,int branch,int label) |
| /* Generiert ein test o, branch label und passt auf, dass */ |
| /* kein TEST const generiert wird. */ |
| { |
| 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 node n={TEST},nn={REINTERPRET}; |
| static type nt,it={INT}; |
| char *libname; |
| n.left=&nn; |
| n.ntyp=⁢ |
| 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) |
| { |
| IC *n; |
| if(nocode) return; |
| n=last_ic; |
| while(n){ |
| if(n->code==CALL&®scratch[r]){ |
| 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(obj *dest,obj *src,obj *val,int bfs,int bfo,int t,int isclear) |
| { |
| /*FIXME: shortcut beachten? */ |
| IC *new; |
| obj tmp1,tmp2,tmp3; |
| int vmerk; |
| bfo=bflayout(bfo,bfs,t); |
| if((dest->flags®)&&!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 */ |
| { |
| IC *new=new_IC(); |
| if(!ISPOINTER(z->ntyp->flags)) {error(39);return;} |
| if(!ISPOINTER(q->ntyp->flags)) {error(39);return;} |
| |
| 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){ |
| 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(z->ntyp->next->flags&VOLATILE){ |
| if(new->z.flags&DREFOBJ) |
| new->z.dtyp|=PVOLATILE; |
| } |
| 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){ |
| 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); |
| } |
| } |
| if(q->ntyp->next->flags&VOLATILE){ |
| if(new->q1.flags&DREFOBJ) |
| new->q1.dtyp|=PVOLATILE; |
| } |
| new->code=ASSIGN; |
| new->typf=UNSIGNED|CHAR; |
| new->q2.flags=0; |
| new->q2.val.vmax=size; |
| |
| if(!zmeqto(size,Z0)) |
| add_IC(new); |
| } |
| |
| void add_IC(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 */ |
| 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 */ |
| vlaadjust_list *vl; |
| 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 */ |
| IC *p=last_ic; |
| while(p){ |
| if(p->typf==new->typf&&p->code>=BEQ&&p->code<=BRA){ |
| IC *n; |
| if(p->code!=BRA){ |
| 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 */ |
| vlaadjust_list *vl=vlaadjusts[nesting]; |
| while(vl){ |
| if(vl->branch==p){ |
| 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®)||!(new->z.flags®)||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®))) |
| 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®)||!(new->z.flags®)||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®))) |
| 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++; |
| |
| #if HAVE_POF2OPT |
| if(((new->code==MULT)||((new->code==DIV||new->code==MOD)&&(new->typf&UNSIGNED)))&&(new->q2.flags&KONST)&&ISINT(new->typf)){ |
| /* ersetzt mul etc. mit Zweierpotenzen */ |
| long ln; |
| eval_const(&new->q2.val,new->typf); |
| if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){ |
| if(ln=get_pof2(vumax)){ |
| if(new->code==MOD){ |
| vmax=zmsub(vmax,l2zm(1L)); |
| new->code=AND; |
| }else{ |
| if(new->code==DIV) new->code=RSHIFT; else new->code=LSHIFT; |
| vmax=l2zm(ln-1); |
| } |
| gval.vmax=vmax; |
| eval_const(&gval,MAXINT); |
| insert_const(&new->q2.val,new->typf); |
| new->typf2=new->typf; |
| } |
| } |
| } |
| #endif |
| |
| /* 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->z.flags®)||new->q1.reg!=new->z.reg)) |
| free_reg(new->q1.reg); |
| if((new->q2.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(!(new->z.flags®)||new->q2.reg!=new->z.reg)) |
| free_reg(new->q2.reg); |
| } |
| |
| np gen_libcall(char *fname,np arg1,type *t1,np arg2,type *t2) |
| /* generate call to a library function (emulate operation) */ |
| { |
| np new; |
| 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)); |
| if(postop_obj){ |
| al->arg=new_node(); |
| al->arg->o=*postop_obj; |
| al->arg->ntyp=new_typ(); |
| al->arg->ntyp->flags=postop_type; |
| al->arg->flags=REINTERPRET; |
| }else |
| 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; |
| } |
| } |
| if(arg2){ |
| t=mymalloc(sizeof(*t)); |
| t->arg=arg2; |
| t->next=0; |
| al->next=t; |
| if(t2){ |
| np cnv=new_node(); |
| cnv->flags=CAST; |
| cnv->left=arg2; |
| cnv->right=0; |
| cnv->ntyp=t2; |
| t->arg=cnv; |
| } |
| } |
| new->alist=al; |
| /* Kann man type_expr nochmal auf die Argumente anwenden? */ |
| if(t1||t2) |
| no_cast_free=1; |
| if(!type_expression(new,0)) |
| ierror(0); |
| no_cast_free=0; |
| gen_IC(new,0,0); |
| return new; |
| } |
| |
| |
| void gen_IC(np p,int ltrue,int lfalse) |
| /* Erzeugt eine IC-Liste aus einer expression */ |
| { |
| IC *new; regargs_list *rl; |
| if(!p) return; |
| |
| if(p->flags==STRING){ |
| Var *v=0; |
| if(merge_strings){ |
| for(v=first_var[0];v;v=v->next){ |
| if(v->vtyp->flags==ARRAY&&(v->vtyp->next->flags&STRINGCONST)&&zmleq(p->ntyp->size,v->vtyp->size)){ |
| zmax i;const_list *cl1=p->cl,*cl2=v->clist; |
| for(i=Z0;!zmleq(p->ntyp->size,i)&&cl1&&cl2;cl1=cl1->next,cl2=cl2->next,i=zmadd(i,Z1)){ |
| if(!zumeqto(zuc2zum(cl1->other->val.vuchar),zuc2zum(cl2->other->val.vuchar))) |
| break; |
| } |
| if(zmleq(p->ntyp->size,i)) break; |
| } |
| } |
| } |
| if(!v){ |
| p->o.v=add_var(empty,clone_typ(p->ntyp),STATIC,p->cl); |
| p->o.v->flags|=DEFINED; |
| }else |
| p->o.v=v; |
| p->o.flags=VAR; |
| p->o.reg=0; |
| p->o.val=p->val; |
| return; |
| } |
| if(p->flags==LITERAL){ |
| int sc; |
| if(nesting==0||(is_const(p->ntyp)&&zmeqto(p->val.vmax,l2zm(0L)))) |
| sc=STATIC; |
| else |
| sc=AUTO; |
| p->o.v=add_var(empty,clone_typ(p->ntyp),sc,p->cl); |
| p->o.v->flags|=DEFINED; |
| p->o.flags=VAR; |
| p->o.reg=0; |
| p->o.val.vmax=l2zm(0L); |
| if(sc==AUTO) |
| init_local_compound(p->o.v); |
| 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|REG))==(SCRATCH|REG)) 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|REG))==(SCRATCH|REG)) 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|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg); |
| }else if(!(p->left->ntyp->flags&VOLATILE)) |
| error(129); |
| gen_IC(p->right,0,0); |
| p->o=p->right->o; |
| return; |
| } |
| if(p->flags==REINTERPRET){ |
| if(p->left){ |
| gen_IC(p->left,0,0); |
| p->o=p->left->o; |
| } |
| /* if no left, do nothing, use just object */ |
| return; |
| } |
| if(p->flags==CAST){ |
| gen_IC(p->left,0,0); |
| if((p->ntyp->flags&NQ)==VOID){ |
| if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) free_reg(p->left->o.reg); |
| p->o.flags=0; |
| }else{ |
| if(ISPOINTER(p->ntyp->flags)&&(p->ntyp->next->flags&VOLATILE)) |
| volatile_convert=1; |
| convert(p->left,p->ntyp->flags); |
| if(volatile_convert){ |
| if((p->left->o.flags&VAR)&&p->left->o.v->vtyp->next) |
| p->left->o.v->vtyp->next->flags|=VOLATILE; |
| volatile_convert=0; |
| } |
| p->o=p->left->o; |
| } |
| return; |
| } |
| if(p->flags==FIRSTELEMENT){ |
| gen_IC(p->left,0,0); |
| p->o=p->left->o; |
| return; |
| } |
| |
| #if HAVE_POF2OPT |
| if(((p->flags==MULT||p->flags==PMULT)||((p->flags==DIV||p->flags==MOD)&&(p->ntyp->flags&UNSIGNED)))&&(p->right->flags==CEXPR||p->right->flags==PCEXPR)&&ISINT(p->ntyp->flags)){ |
| /* ersetzt mul etc. mit Zweierpotenzen */ |
| long ln; |
| eval_constn(p->right); |
| if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){ |
| if(ln=get_pof2(vumax)){ |
| if(p->flags==MOD){ |
| vmax=zmsub(vmax,l2zm(1L)); |
| p->flags=AND; |
| }else{ |
| if(p->flags==DIV) p->flags=RSHIFT; else p->flags=LSHIFT; |
| vmax=l2zm(ln-1); |
| } |
| gval.vmax=vmax; |
| eval_const(&gval,MAXINT); |
| insert_constn(p->right); |
| } |
| } |
| } |
| #endif |
| |
| #if HAVE_LIBCALLS |
| if(!(optflags&2)){ |
| char *libname; |
| if(libname=use_libcall_wrap(p->flags,p->ntyp->flags,0)){ |
| np lc;type *t1,*t2; |
| if(p->flags==LSHIFT||p->flags==RSHIFT){ |
| t1=clone_typ(p->ntyp); |
| t2=new_typ(); |
| t2->flags=INT; |
| }else{ |
| if(p->right){ |
| t1=arith_typ(p->left->ntyp,p->right->ntyp); |
| t2=clone_typ(t1); |
| }else{ |
| t1=arith_typ(p->left->ntyp,p->left->ntyp); |
| t2=0; |
| } |
| } |
| lc=gen_libcall(libname,p->left,t1,p->right,t2); |
| *p=*lc; |
| free(lc); |
| return; |
| } |
| } |
| #endif |
| new=new_IC(); |
| new->typf=p->ntyp->flags; |
| 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; |
| p->o.dtyp=p->left->ntyp->flags; |
| }else{ |
| if((p->left->o.flags&SCRATCH)&&p->left->o.dtyp==POINTER_TYPE(p->ntyp)){ |
| new->z=p->left->o; |
| new->z.flags&=~DREFOBJ; |
| }else{ |
| get_scratch(&new->z,p->left->ntyp->flags,p->ntyp->flags,p->left->ntyp); |
| } |
| new->code=ASSIGN;new->typf=POINTER_TYPE(p->ntyp); |
| new->q1=p->left->o; |
| new->q2.val.vmax=sizetab[new->typf&NQ]; |
| p->o=new->z; |
| add_IC(new); |
| p->o.flags|=DREFOBJ; |
| p->o.dtyp=POINTER_TYPE(p->ntyp); |
| } |
| if(p->left->ntyp->next->flags&VOLATILE) p->o.dtyp|=PVOLATILE; |
| return; |
| } |
| if(p->flags==ASSIGN){ |
| if(p->left->flags==BITFIELD){ |
| gen_IC(p->right,0,0); |
| gen_IC(p->left->left,0,0); |
| convert(p->right,p->ntyp->flags); |
| insert_bitfield(&p->left->left->o,&p->right->o,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags&NU,0); |
| return; |
| } |
| new->code=ASSIGN; |
| gen_IC(p->right,0,0); |
| gen_IC(p->left,0,0); |
| convert(p->right,p->ntyp->flags); |
| new->q1=p->right->o; |
| new->z=p->left->o; |
| new->q2.val.vmax=szof(p->left->ntyp); |
| p->o=new->z; |
| if(!ISSCALAR(p->ntyp->flags)) |
| new->typf2=zm2l(falign(p->ntyp)); |
| add_IC(new); |
| return; |
| } |
| if(p->flags==ASSIGNOP){ |
| /* das hier ist nicht besonders schoen */ |
| obj o,q;IC *n;int f;char *libname; |
| np lc; |
| if(p->right->right==0){ |
| /* sowas wie a+=0 wurde wegoptimiert */ |
| free(new); |
| p->o=p->left->o; |
| return; |
| } |
| #if HAVE_LIBCALLS |
| if(libname=use_libcall_wrap(p->right->flags,p->right->ntyp->flags,(p->right->flags==LSHIFT||p->right->flags==RSHIFT)?INT:0)){ |
| type *t1,*t2; |
| np a1; |
| gen_IC(p->left,0,0); |
| a1=new_node(); |
| a1->o=p->left->o; |
| a1->flags=REINTERPRET; |
| a1->o.flags&=~SCRATCH; |
| a1->ntyp=clone_typ(p->left->ntyp); |
| t1=clone_typ(p->right->ntyp); |
| if(p->right->flags==LSHIFT||p->right->flags==RSHIFT){ |
| t2=new_typ(); |
| t2->flags=INT; |
| }else |
| t2=clone_typ(t1); |
| lc=gen_libcall(libname,a1/*p->right->left*/,t1,p->right->right,t2); |
| /**p->right=*lc;*/ |
| o=p->left->o; |
| free(a1); |
| /*p->left=0;*/ |
| /*free(lc);*/ |
| }else |
| #endif |
| { |
| lc=0; |
| f=do_arith(p->right,new,p->left,&o); |
| if(!f) ierror(0); |
| if(f>1) ierror(0); |
| } |
| if((o.flags&(SCRATCH|REG))==(SCRATCH|REG)&&!regs[o.reg]) |
| keep_reg(o.reg); |
| if(lc) |
| convert(lc,p->ntyp->flags); |
| else |
| convert(p->right,p->ntyp->flags); |
| if(p->left&&p->left->flags==BITFIELD){ |
| if(lc) ierror(0); |
| insert_bitfield(&p->left->left->o,&p->right->o,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags&NU,0); |
| if((p->right->o.flags&(REG|SCRATCH))==(REG|SCRATCH)&®s[p->right->o.reg]) |
| free_reg(p->right->o.reg); |
| return; |
| } |
| new=new_IC(); |
| new->typf=p->ntyp->flags; |
| new->q2.flags=0; |
| new->code=ASSIGN; |
| if(lc){ |
| new->q1=lc->o; |
| /*free(lc);*/ |
| }else |
| new->q1=p->right->o; |
| new->z=o; |
| new->q2.val.vmax=szof(p->ntyp); |
| p->o=new->z; |
| add_IC(new); |
| 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((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,p->ntyp->flags,0)){ |
| new->z=p->left->o; |
| new->z.flags&=~DREFOBJ; |
| }else{ |
| get_scratch(&new->z,p->ntyp->flags,0,p->ntyp); |
| } |
| new->q1=p->left->o; |
| p->o=new->z; |
| add_IC(new); |
| return; |
| } |
| if(p->flags==ADDRESS||p->flags==ADDRESSA||p->flags==ADDRESSS){ |
| if(p->flags!=ADDRESSS&&p->left->flags==IDENTIFIER&&is_vlength(p->left->ntyp)){ |
| gen_IC(p->left,0,0); |
| if(!(p->left->o.flags&VAR)) |
| ierror(0); |
| free(new); |
| p->o=p->left->o; |
| return; |
| } |
| new->code=ADDRESS; |
| new->typf=p->left->ntyp->flags; |
| new->typf2=POINTER_TYPE(p->left->ntyp); |
| 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_TYPE(p->ntyp->next),p->ntyp->next->flags,0); |
| p->o=new->z; |
| add_IC(new); |
| 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);*/ |
| |
| if(ISVECTOR(p->ntyp->flags)){ |
| do_arith(p,new,0,0); |
| return; |
| } |
| |
| 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){ |
| if(p->flags==LAND) |
| gen_test(&p->left->o,p->left->ntyp->flags,BEQ,((!ltrue)?l3:lfalse)); |
| else |
| gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l3:ltrue)); |
| } |
| 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){ |
| if(p->flags==LAND) |
| gen_test(&p->right->o,p->right->ntyp->flags,BEQ,((!ltrue)?l3:lfalse)); |
| else |
| gen_test(&p->right->o,p->right->ntyp->flags,BNE,((!ltrue)?l3:ltrue)); |
| } |
| if(!ltrue){ |
| gen_label(l2); |
| if(p->flags==LAND) gen_cond(&p->o,0,l3,l4); else gen_cond(&p->o,1,l3,l4); |
| }else{ |
| new=new_IC(); |
| 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(ISVECTOR(p->ntyp->flags)){ |
| gen_IC(p->left,0,0); |
| if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,p->ntyp->flags,0)){ |
| new->z=p->left->o; |
| new->z.flags&=~DREFOBJ; |
| }else{ |
| get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp); |
| } |
| new->typf=p->left->ntyp->flags; |
| new->q1=p->left->o; |
| p->o=new->z; |
| new->code=NEGATION; |
| add_IC(new); |
| return; |
| } |
| 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{ |
| gen_test(&p->left->o,p->left->ntyp->flags,BNE,((!ltrue)?l1:lfalse)); |
| } |
| if(ltrue){ |
| new=new_IC(); |
| new->code=BRA; |
| if(!ltrue) new->typf=l2; else new->typf=ltrue; |
| add_IC(new); |
| p->o.flags=0; |
| }else{ |
| gen_label(l3); |
| gen_cond(&p->o,0,l1,l2); |
| } |
| return; |
| } |
| if(p->flags>=EQUAL&&p->flags<=GREATEREQ){ |
| int l1,l2,l3,tl,tr; |
| type *at=0; |
| char *libname; |
| if(ISVECTOR(p->ntyp->flags)){ |
| do_arith(p,new,0,0); |
| return; |
| } |
| 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; |
| if(p->flags==LESS) p->flags=GREATER; |
| else if(p->flags==LESSEQ) p->flags=GREATEREQ; |
| else if(p->flags==GREATER) p->flags=LESS; |
| else if(p->flags==GREATEREQ) p->flags=LESSEQ; |
| } |
| #if HAVE_LIBCALLS |
| at=arith_typ(p->left->ntyp,p->right->ntyp); |
| if(libname=use_libcall_wrap(COMPARE,at->flags,0)){ |
| new->q1=gen_libcall(libname,p->left,at,p->right,clone_typ(at))->o; |
| new->code=COMPARE; |
| new->typf=LIBCALL_CMPTYPE; |
| new->q2.flags=KONST; |
| gval.vmax=Z0; |
| eval_const(&gval,MAXINT); |
| insert_const(&new->q2.val,LIBCALL_CMPTYPE); |
| }else{ |
| #endif |
| new->code=COMPARE; |
| tl=p->left->ntyp->flags&NU;tr=p->right->ntyp->flags&NU; |
| if(p->right->flags==CEXPR&&ISINT(tr)&&ISINT(tl)&&zm2l(sizetab[tl&NQ])<=zm2l(sizetab[tr&NQ])&&((tl&NQ)>=INT||shortcut(COMPARE,tl))){ |
| int negativ; |
| eval_constn(p->right); |
| if(zmleq(vmax,l2zm(0L))) negativ=1; else negativ=0; |
| if((tl&UNSIGNED)||(tr&UNSIGNED)) negativ=0; |
| if((!negativ||zmleq(t_min(tl),vmax))&&(negativ||zumleq(vumax,t_max(tl)))){ |
| if((tl&UNSIGNED)||!(tr&UNSIGNED)||p->flags==EQUAL||p->flags==INEQUAL){ |
| convert(p->right,tl); |
| tr=tl; |
| } |
| } |
| } |
| if(ISARITH(tl)&&(tl!=tr||!shortcut(COMPARE,tl))){ |
| type *t; |
| t=arith_typ(p->left->ntyp,p->right->ntyp); |
| new->typf=t->flags; |
| freetyp(t); |
| }else{ |
| new->typf=p->left->ntyp->flags; |
| } |
| 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; |
| if(p->flags==EQUAL||p->flags==INEQUAL){ |
| /* generate TEST, if possible */ |
| if(new->q2.flags&KONST){ |
| eval_const(&new->q2.val,new->typf); |
| if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){ |
| new->code=TEST; |
| new->q2.flags=0; |
| } |
| } |
| } |
| #if HAVE_LIBCALLS |
| } |
| #endif |
| freetyp(at); |
| add_IC(new); |
| new=new_IC(); |
| if(p->flags==EQUAL) new->code=BEQ; |
| if(p->flags==INEQUAL) new->code=BNE; |
| if(p->flags==LESS) new->code=BLT; |
| if(p->flags==LESSEQ) new->code=BLE; |
| if(p->flags==GREATER) new->code=BGT; |
| if(p->flags==GREATEREQ) new->code=BGE; |
| if(ltrue) new->typf=ltrue; else new->typf=l1; |
| add_IC(new); |
| if(ltrue){ |
| new=new_IC(); |
| new->code=BRA; |
| new->typf=lfalse; |
| add_IC(new); |
| p->o.flags=0; |
| }else{ |
| gen_label(l3); |
| gen_cond(&p->o,1,l1,l2); |
| } |
| return; |
| } |
| if(p->flags==CALL){ |
| int r=0,radrpush=0; |
| obj *op,cfunc,ret_obj; |
| zmax sz; |
| int mregs[MAXR+1]; |
| IC *callic; |
| #ifdef ORDERED_PUSH |
| IC *merk_fp,*lp; |
| unsigned int merk_opushed=opushed; |
| #endif |
| if(p->left->flags==ADDRESS&&p->left->left->flags==IDENTIFIER){ |
| Var *v; |
| gen_IC(p->left,0,0); r=1; |
| v=p->left->o.v; |
| if(v->fi&&v->fi->first_ic&&!cross_module&&(c_flags_val[0].l&4096)){ |
| /* function call inlining */ |
| argument_list *al; |
| Var *vp,**argl1,**argl2; |
| IC *ip;int lc; |
| int arg_cnt=0,i; |
| if(DEBUG&1024){ |
| printf("inlining call to <%s>\n",v->identifier); |
| for(vp=v->fi->vars;vp;vp=vp->next) |
| printf("%s(%ld)/%p\n",vp->identifier,zm2l(vp->offset),(void*)vp); |
| } |
| for(vp=v->fi->vars;vp;vp=vp->next){ |
| /*FIXME: zmeqto hier ok? siehe cross_module_inline */ |
| if((zmeqto(vp->offset,l2zm(0L))||vp->reg)&&*vp->identifier&&(vp->storage_class==AUTO||vp->storage_class==REGISTER)) arg_cnt++; |
| } |
| |
| /* Argumente in die ersten Parametervariablen kopieren */ |
| argl1=mymalloc(arg_cnt*sizeof(Var *)); |
| argl2=mymalloc(arg_cnt*sizeof(Var *)); |
| |
| al=p->alist;vp=v->fi->vars;i=0; |
| while(al){ |
| /*FIXME: zmeqto hier ok? siehe cross_module_inline */ |
| while(vp&&(!*vp->identifier||(!zmeqto(vp->offset,l2zm(0L))&&!vp->reg)||(vp->storage_class!=REGISTER&&vp->storage_class!=AUTO))) vp=vp->next; |
| if(!vp){ error(39); break; } |
| if(i>=arg_cnt) ierror(0); |
| if(DEBUG&1024) printf("arg: %s(%ld)\n",vp->identifier,zm2l(vp->offset)); |
| argl1[i]=vp; |
| argl2[i]=add_var(empty,clone_typ(vp->vtyp),vp->storage_class,0); |
| if(!al->arg) ierror(0); |
| gen_IC(al->arg,0,0); |
| convert(al->arg,vp->vtyp->flags); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->q1=al->arg->o; |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(vp->vtyp); |
| new->z.flags=VAR; |
| new->z.val.vmax=l2zm(0L); |
| new->z.v=argl2[i]; |
| new->typf=vp->vtyp->flags; |
| new->typf2=falign(vp->vtyp); |
| add_IC(new); |
| i++; |
| al=al->next; |
| vp=vp->next; |
| } |
| if(i<arg_cnt){ error(83); arg_cnt=i;} |
| |
| /* Kopien der Variablen erzeugen */ |
| for(vp=v->fi->vars;vp;vp=vp->next){ |
| vp->inline_copy=0; |
| } |
| for(i=0;i<arg_cnt;i++){ |
| if(argl1[i]){ |
| if(!argl2[i]) ierror(0); |
| argl1[i]->inline_copy=argl2[i]; |
| } |
| } |
| |
| /* Rueckgabewert */ |
| if((p->ntyp->flags&NQ)!=VOID){ |
| p->o.flags=SCRATCH|VAR; |
| p->o.reg=0;p->o.val.vmax=l2zm(0L); |
| p->o.v=add_var(empty,clone_typ(p->ntyp),AUTO,0); |
| }else{ |
| p->o.flags=0; |
| } |
| |
| free(argl1); |
| free(argl2); |
| |
| /* Code einfuegen und Labels umschreiben */ |
| ip=v->fi->first_ic;lc=0; |
| while(ip){ |
| Var *iv; |
| int c; |
| new=new_IC(); |
| *new=*ip; |
| ip->copy=new; |
| c=ip->code; |
| /* evtl. ist ein IC praktisch ein SETRETURN, falls das */ |
| /* Rueckgabeziel ueber Parameterzeiger angespr. wird */ |
| if(ip->z.flags&VAR){ |
| iv=ip->z.v; |
| if(iv->storage_class==AUTO||iv->storage_class==REGISTER){ |
| if(!*iv->identifier&&zmeqto(iv->offset,l2zm(0L))){ |
| new->z=p->o; |
| }else{ |
| if(!iv->inline_copy){ |
| iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0); |
| iv->inline_copy->reg=iv->reg; |
| } |
| new->z.v=iv->inline_copy; |
| }/*else if(iv->inline_copy) ierror(0);*/ |
| } |
| } |
| /* Kopien aller auto/register Variablen erzeugen */ |
| if(ip->q1.flags&VAR){ |
| iv=ip->q1.v; |
| if(iv->storage_class==AUTO||iv->storage_class==REGISTER){ |
| if(!iv->inline_copy){ |
| iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0); |
| iv->inline_copy->reg=iv->reg; |
| } |
| new->q1.v=iv->inline_copy; |
| }/*else if(iv->inline_copy) ierror(0);*/ |
| } |
| if(ip->q2.flags&VAR){ |
| iv=ip->q2.v; |
| if(iv->storage_class==AUTO||iv->storage_class==REGISTER){ |
| if(!iv->inline_copy){ |
| iv->inline_copy=add_var(empty,clone_typ(iv->vtyp),iv->storage_class,0); |
| iv->inline_copy->reg=iv->reg; |
| } |
| new->q2.v=iv->inline_copy; |
| }/*else if(iv->inline_copy) ierror(0);*/ |
| } |
| if(c==CALL){ |
| int i; |
| function_calls+=currentpri; |
| new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt); |
| for(i=0;i<new->arg_cnt;i++) new->arg_list[i]=ip->arg_list[i]->copy; |
| } |
| if(c==LABEL||(c>=BEQ&&c<=BRA)){ |
| if(new->typf>lc) lc=new->typf; |
| new->typf+=label; |
| } |
| if(c==SETRETURN){ |
| new->code=ASSIGN; |
| new->z=p->o; |
| } |
| add_IC(new); |
| ip=ip->next; |
| } |
| label+=lc; |
| return; |
| } |
| /* einige spezielle Inline-Funktionen; das setzt voraus, dass */ |
| /* diese in den Headerfiles passend deklariert werden */ |
| if(v->storage_class==EXTERN){ |
| if((optflags&2)&&(!strcmp(v->identifier,"strlen")||!strcmp(v->identifier,"__asm_strlen"))&&p->alist&&p->alist->arg){ |
| np n=p->alist->arg; |
| if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){ |
| const_list *cl;zumax len=ul2zum(0UL); |
| cl=n->left->cl; |
| while(cl){ |
| if(zmeqto(l2zm(0L),zc2zm(cl->other->val.vchar))) break; |
| len=zumadd(len,ul2zum(1UL)); |
| cl=cl->next; |
| } |
| p->o.val.vumax=len; |
| eval_const(&p->o.val,UNSIGNED|MAXINT); |
| insert_constn(p); |
| insert_const(&p->o.val,p->ntyp->flags); |
| p->flags=CEXPR; |
| p->o.flags=KONST; |
| return; |
| } |
| } |
| |
| if(inline_memcpy_sz>0&&(optflags&2)){ |
| if((!strcmp(v->identifier,"strcpy")||!strcmp(v->identifier,"__asm_strcpy"))&&p->alist&&p->alist->next&&p->alist->next->arg){ |
| np n=p->alist->next->arg; |
| if(n->flags==ADDRESSA&&n->left->flags==STRING&&zmeqto(n->left->val.vmax,l2zm(0L))){ |
| const_list *cl;zmax len=l2zm(0L); |
| cl=n->left->cl; |
| while(cl){ |
| len=zmadd(len,l2zm(1L)); |
| if(zmeqto(zc2zm(cl->other->val.vchar),l2zm(0L))) break; |
| cl=cl->next; |
| } |
| if(zmleq(len,l2zm((long)inline_memcpy_sz))){ |
| inline_memcpy(p->alist->arg,n,len); |
| p->o=p->alist->arg->o; |
| return; |
| } |
| } |
| } |
| if(!strcmp(v->identifier,"memcpy")||!strcmp(v->identifier,"__asm_memcpy")){ |
| if(p->alist&&p->alist->next&&p->alist->next->next |
| &&p->alist->next->next->arg |
| &&p->alist->next->next->arg->flags==CEXPR){ |
| eval_constn(p->alist->next->next->arg); |
| if(zmleq(vmax,l2zm((long)inline_memcpy_sz))){ |
| inline_memcpy(p->alist->arg,p->alist->next->arg,vmax); |
| p->o=p->alist->arg->o; |
| return; |
| } |
| } |
| } |
| } |
| } |
| } |
| rl=0; |
| if(!(optflags&2)){ |
| int r; |
| for(r=1;r<=MAXR;r++){mregs[r]=regs[r];regs[r]&=~(RNOSAVE|RHALF);} |
| }else{ |
| gen_IC(p->left,0,0); |
| } |
| #ifdef ORDERED_PUSH |
| merk_fp=first_pushed; |
| first_pushed=0; |
| lp=last_ic; |
| #endif |
| #ifdef HAVE_REGPARMS |
| if(!ffreturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID){ |
| IC *new2;static type ptyp={0}; |
| treg_handle reg_handle=empty_reg_handle; |
| int reg; |
| ptyp.next=p->ntyp; |
| ptyp.flags=POINTER_TYPE(p->ntyp); |
| reg=reg_parm(®_handle,&ptyp,0,p->left->ntyp->next); |
| if(reg){ |
| new2=new_IC(); |
| new2->code=ADDRESS; |
| new2->typf=p->ntyp->flags; |
| new2->typf2=POINTER_TYPE(p->ntyp); |
| new2->q1.flags=VAR; |
| new2->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0); |
| new2->q1.val.vmax=l2zm(0L); |
| op=&new2->q1; |
| new2->q2.flags=0; |
| get_scratch(&new2->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0); |
| ret_obj=new2->z; |
| add_IC(new2); |
| sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,&ret_obj,p->ntyp,reg,p->left->ntyp); |
| if(optflags&2) |
| handle_reglist(rl,&ret_obj); |
| }else{ |
| sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,0,p->ntyp,reg,p->left->ntyp); |
| radrpush=1; |
| if(optflags&2) |
| handle_reglist(rl,0); |
| } |
| }else{ |
| treg_handle reg_handle=empty_reg_handle; |
| sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl,®_handle,0,0,-1,p->left->ntyp); |
| if(optflags&2) |
| handle_reglist(rl,0); |
| } |
| #else |
| sz=push_args(p->alist,p->left->ntyp->next->exact,0,&rl); |
| if(optflags&2) |
| handle_reglist(rl,0); |
| #endif |
| if(!r&&!(optflags&2)) 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; |
| p->o.dtyp=p->left->ntyp->flags; |
| } |
| }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)&&p->ntyp->flags==p->left->ntyp->flags){ |
| new->z=p->left->o; |
| new->z.flags&=~DREFOBJ; |
| }else{ |
| get_scratch(&new->z,p->left->ntyp->flags,FUNKT,p->left->ntyp); |
| } |
| new->code=ASSIGN; |
| new->typf=p->left->ntyp->flags; |
| new->q1=p->left->o; |
| new->q2.val.vmax=sizetab[new->typf&NQ]; |
| new->q2.flags=0; |
| p->o=new->z; |
| add_IC(new); |
| p->o.flags|=DREFOBJ; |
| p->o.dtyp=p->left->ntyp->flags; |
| } |
| } |
| /* p->left->o.flags-=DREFOBJ|VARADR; Was sollte das?? */ |
| |
| #if 0 |
| if(optflags&2){ |
| while(rl){ |
| regargs_list *m; |
| new=new_IC(); |
| new->code=NOP; |
| new->q1.flags=VAR; |
| new->q1.v=rl->v; |
| new->q1.val.vmax=l2zm(0L); |
| new->typf=0; |
| new->q2.flags=new->z.flags=0; |
| add_IC(new); |
| m=rl->next;free(rl);rl=m; |
| } |
| } |
| #endif |
| |
| /* gegebenenfalls Adresse des Ziels auf den Stack */ |
| #ifdef HAVE_REGPARMS |
| if(radrpush) |
| #else |
| if(!ffreturn(p->ntyp)&&(p->ntyp->flags&NQ)!=VOID) |
| #endif |
| { |
| #if defined(ORDERED_PUSH) && defined(HAVE_REGPARMS) |
| ierror(0); |
| #endif |
| new=new_IC(); |
| new->code=ADDRESS; |
| new->typf=p->ntyp->flags; |
| new->typf2=POINTER_TYPE(p->ntyp); |
| new->q1.flags=VAR; |
| new->q1.v=add_var(empty,clone_typ(p->ntyp),AUTO,0); |
| new->q1.val.vmax=l2zm(0L); |
| op=&new->q1; |
| new->q2.flags=0; |
| get_scratch(&new->z,POINTER_TYPE(p->ntyp),p->ntyp->flags,0); |
| ret_obj=new->z; |
| add_IC(new); |
| new=new_IC(); |
| new->code=PUSH; |
| new->typf=POINTER_TYPE(p->ntyp); |
| new->q1=ret_obj; |
| new->q2.flags=new->z.flags=0; |
| new->q2.val.vmax=sizetab[new->typf&NQ]; |
| new->z.val.vmax=new->q2.val.vmax; |
| add_IC(new); |
| sz=zmadd(sz,sizetab[new->typf&NQ]); |
| } |
| |
| /* Scratchregister evtl. sichern */ |
| cfunc=p->o; |
| if(!nocode) |
| savescratch(MOVEFROMREG,last_ic,0,&cfunc); |
| function_calls+=currentpri; |
| new=new_IC(); |
| new->code=CALL; |
| callic=new; |
| if(p->alist){ |
| /* insert list of argument ICs */ |
| int i=0; |
| argument_list *a=p->alist; |
| while(a){i++;a=a->next;} |
| new->arg_cnt=i; |
| new->arg_list=mymalloc(sizeof(*new->arg_list)*i); |
| for(a=p->alist,i=0;a;a=a->next,i++) new->arg_list[i]=a->pushic; |
| }else{ |
| new->arg_cnt=0; |
| new->arg_list=0; |
| } |
| new->typf=FUNKT; |
| new->q1=p->o; |
| new->q2.flags=new->z.flags=0; |
| new->q2.val.vmax=sz; /* Groesse der Parameter auf dem Stack */ |
| add_IC(new); |
| |
| //pric2(stdout,new); |
| |
| if(optflags&2){ |
| while(rl){ |
| regargs_list *m; |
| new=new_IC(); |
| new->code=NOP; |
| new->q1.flags=VAR; |
| new->q1.v=rl->v; |
| new->q1.val.vmax=l2zm(0L); |
| new->typf=0; |
| new->q2.flags=new->z.flags=0; |
| add_IC(new); |
| m=rl->next;free(rl);rl=m; |
| } |
| } |
| |
| r=0; |
| if((p->ntyp->flags&NQ)!=VOID){ |
| new=new_IC(); |
| new->code=GETRETURN; |
| new->q1.flags=new->q2.flags=0; |
| new->q1.reg=ffreturn(p->ntyp); |
| new->q2.val.vmax=szof(p->ntyp); |
| new->typf=p->ntyp->flags; |
| if(ffreturn(p->ntyp)){ |
| int t=p->ntyp->flags&NQ; |
| if(ISSTRUCT(t)||ISUNION(t)){ |
| new->z.v=add_var(empty,clone_typ(p->ntyp),AUTO,0); |
| new->z.flags=VAR; |
| new->z.val.vmax=l2zm(0L); |
| }else{ |
| if(optflags&2){ |
| get_scratch(&new->z,p->ntyp->flags,0,p->ntyp); |
| }else{ |
| /* Suche geeignetes Register, um Rueckgabewert zu speichern. */ |
| regargs_list *l2; |
| int r; |
| r=new->q1.reg; |
| if(regs[r]||!regok(r,p->ntyp->flags,0)||(reg_pair(r,&rp)&&(regs[rp.r1]||regs[rp.r2]))){ |
| r=0; |
| }else{ |
| for(l2=rl;l2;l2=l2->next){ |
| if(l2->v&&abs(l2->reg)==r) {r=0;break;} |
| } |
| } |
| if(r==0){ |
| for(r=1;r<=MAXR;r++){ |
| if(!regs[r]&®ok(r,p->ntyp->flags,0)&&(!reg_pair(r,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){ |
| for(l2=rl;l2;l2=l2->next){ |
| if(l2->v&&abs(l2->reg)==r) break; |
| } |
| if(l2) continue; |
| break; |
| } |
| } |
| } |
| if(r>=1&&r<=MAXR){ |
| alloc_hardreg(r); |
| new->z.flags=(REG|SCRATCH); |
| new->z.reg=r; |
| }else{ |
| get_scratch(&new->z,p->ntyp->flags,0,p->ntyp); |
| } |
| } |
| } |
| } else |
| new->z=*op; |
| if((new->z.flags&(REG|DREFOBJ))==REG) r=new->z.reg; |
| p->o=new->z; |
| add_IC(new); |
| }else{ |
| p->o.flags=0; |
| } |
| /* Scratchregister evtl. wiederherstellen */ |
| if(!nocode) |
| savescratch(MOVETOREG,last_ic,r,&cfunc); |
| if(!(optflags&2)){ |
| int r; |
| for(r=1;r<=MAXR;r++){ |
| if(regs[r]) |
| regs[r]|=(mregs[r]&RNOSAVE); |
| } |
| } |
| /* Evtl. gespeicherte Registerargumente wiederherstellen. */ |
| while(rl){ |
| regargs_list *m; |
| if(rl->v){ |
| int r; |
| for(r=MAXR;r>=1;r--){ |
| if(regs[r]&®_pair(r,&rp)&&(rp.r1==abs(rl->reg)||rp.r2==abs(rl->reg))) |
| break; |
| } |
| if(r<=1) r=abs(rl->reg); |
| new=new_IC(); |
| new->code=MOVETOREG; |
| new->typf=0; |
| new->q1.flags=VAR|DONTREGISTERIZE; |
| new->q1.v=rl->v; |
| new->q1.val.vmax=l2zm(0L); |
| new->z.flags=REG; |
| if(rl->rsaved) |
| new->z.reg=rl->rsaved; |
| else |
| new->z.reg=abs(r); |
| new->q2.flags=0; |
| new->q2.val.vmax=regsize[r]; |
| add_IC(new); |
| if(rl->rsaved) |
| free_reg(abs(rl->reg)); |
| }else{ |
| free_reg(abs(rl->reg)); |
| } |
| m=rl->next;free(rl);rl=m; |
| } |
| #ifdef ORDERED_PUSH |
| /* If arguments have been pushed nested we have to copy them and */ |
| /* push them later. */ |
| if(merk_fp&&opushed!=merk_opushed){ |
| IC *p,*m=0,*np; |
| if(!lp) ierror(0); |
| for(p=merk_fp;p;){ |
| np=p->next; |
| if(p->code==PUSH){ |
| new=new_IC(); |
| *new=*p; |
| /* be careful about the address because of arg_list! */ |
| if(p->prev) p->prev->next=new; |
| new->prev=p->prev; |
| if(p->next) p->next->prev=new; |
| new->next=p->next; |
| if(p==last_ic) last_ic=new; |
| if(p==first_ic) first_ic=new; |
| if(new->q1.flags&&!(p->flags&ORDERED_PUSH_COPY)){ |
| new->code=ASSIGN; |
| new->z.flags=VAR; |
| new->z.val.vmax=l2zm(0L); |
| /* typ allocated in push_args and not used there */ |
| /* if(!p->ityp) ierror(0);*/ |
| new->z.v=add_tmp_var(clone_typ(p->ityp)); /*FIXME??*/ |
| p->q1=new->z; |
| /* p->ityp=0;*/ |
| }else{ |
| remove_IC(new); |
| } |
| p->next=p->prev=0; |
| p->flags|=ORDERED_PUSH_COPY; |
| add_IC(p); |
| if(!m&&!nocode) m=p; |
| } |
| if(p==lp) break; |
| p=np; |
| } |
| if(!m) ierror(0); |
| first_pushed=m; |
| }else |
| first_pushed=merk_fp; |
| #endif |
| return; |
| } |
| if(p->flags>=PREINC&&p->flags<=POSTDEC){ |
| obj o; |
| #if HAVE_LIBCALLS |
| char *libname; |
| node tn={ADD},one={CEXPR}; |
| #endif |
| gen_IC(p->left,0,0); |
| if((p->flags==POSTINC||p->flags==POSTDEC)){ |
| /*new=new_IC();*/ |
| new->code=ASSIGN; |
| new->typf=p->ntyp->flags; |
| new->q2.val.vmax=sizetab[p->ntyp->flags&NQ]; |
| new->q1=p->left->o; |
| postop_obj=&new->q1; |
| postop_type=new->typf; |
| new->q1.flags&=~SCRATCH; |
| get_scratch(&new->z,p->left->ntyp->flags,0,p->left->ntyp); |
| new->q2.flags=0; |
| o=new->z; |
| add_IC(new); |
| new=new_IC(); |
| }else |
| o=p->left->o; |
| #if HAVE_LIBCALLS |
| if(p->flags==PREDEC||p->flags==POSTDEC) |
| tn.flags=SUB; |
| tn.left=p->left; |
| tn.right=&one; |
| tn.ntyp=p->ntyp; |
| one.flags=CEXPR; |
| one.ntyp=p->ntyp; |
| gval.vmax=l2zm(1L); |
| eval_const(&gval,MAXINT); |
| insert_const(&one.val,p->ntyp->flags&NU); |
| if(libname=use_libcall_wrap(tn.flags,tn.ntyp->flags,0)){ |
| np lc; |
| lc=gen_libcall(libname,p->left,0,&one,0); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=p->ntyp->flags; |
| new->q2.val.vmax=sizetab[p->ntyp->flags&NQ]; |
| new->q1=lc->o; |
| new->q1.flags&=~SCRATCH; |
| new->z=p->left->o; |
| add_IC(new); |
| new=new_IC(); |
| free(lc); |
| }else |
| #endif |
| if(ISPOINTER(p->left->ntyp->flags)){ |
| if(p->flags==PREINC||p->flags==POSTINC) |
| new->code=ADDI2P; |
| else |
| new->code=SUBIFP; |
| vmax=szof(p->left->ntyp->next); |
| new->q2.val.vint=zm2zi(vmax); |
| new->typf=INT; |
| new->typf2=p->left->ntyp->flags; |
| 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; |
| new->q1=p->left->o; |
| new->z=p->left->o; |
| new->q2.flags=KONST; |
| gval.vint=zm2zi(l2zm(1L)); |
| eval_const(&gval,INT); |
| insert_const(&new->q2.val,new->typf); |
| add_IC(new); |
| } |
| if(p->left->flags==BITFIELD){ |
| insert_bitfield(&p->left->left->o,&new->z,&p->o,p->left->bfs,p->left->bfo,p->ntyp->flags,0); |
| if(p->flags!=POSTINC&&p->flags!=POSTDEC){ |
| o=p->o; |
| }else{ |
| if((p->o.flags&(REG|SCRATCH))==(REG|SCRATCH)) |
| free_reg(p->o.reg); |
| } |
| } |
| if(p->flags==POSTINC||p->flags==POSTDEC||p->left->flags==BITFIELD){ |
| if((p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)) |
| free_reg(p->left->o.reg); |
| } |
| |
| postop_obj=0; |
| 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){ |
| gen_test(&p->left->o,p->left->ntyp->flags,BEQ,lfalse); |
| }else{ |
| eval_constn(p->left); |
| if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))){ |
| 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); |
| if((p->ntyp->flags&NQ)!=VOID){ |
| convert(p->right->left,p->ntyp->flags); |
| if((p->right->left->o.flags&(SCRATCH|DREFOBJ))==SCRATCH){ |
| p->o=p->right->left->o; |
| }else{ |
| get_scratch(&p->o,p->ntyp->flags,0,p->ntyp); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->q1=p->right->left->o; |
| new->z=p->o; |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(p->ntyp); |
| new->typf=p->ntyp->flags; |
| p->o=new->z; |
| add_IC(new); |
| } |
| }else |
| p->o.flags=0; |
| new=new_IC(); |
| new->code=BRA; |
| new->typf=lout; |
| add_IC(new); |
| gen_label(lfalse); |
| gen_IC(p->right->right,0,0); |
| if((p->ntyp->flags&NQ)!=VOID){ |
| convert(p->right->right,p->ntyp->flags); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->q1=p->right->right->o; |
| new->z=p->o; |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(p->ntyp); |
| new->typf=p->ntyp->flags; |
| add_IC(new); |
| } |
| gen_label(lout); |
| return; |
| } |
| if(p->flags==BITFIELD){ |
| int lsc,rsc,bfo; |
| obj tmp; |
| bfo=bflayout(p->bfo,p->bfs,p->ntyp->flags); |
| lsc=zm2l(zmmult(sizetab[p->ntyp->flags&NQ],char_bit))-p->bfs-bfo; |
| rsc=lsc+bfo; |
| gen_IC(p->left,0,0); |
| new->code=LSHIFT; |
| new->typf=p->ntyp->flags; |
| new->typf2=INT; |
| new->q1=p->left->o; |
| new->q2.flags=KONST; |
| new->q2.val.vint=zm2zi(l2zm((long)lsc)); |
| get_scratch(&new->z,new->typf,0,0); |
| tmp=new->z; |
| add_IC(new); |
| new=new_IC(); |
| new->code=RSHIFT; |
| new->typf=p->ntyp->flags; |
| new->typf2=INT; |
| new->q1=tmp; |
| new->q2.flags=KONST; |
| new->q2.val.vint=zm2zi(l2zm((long)rsc)); |
| new->z=tmp; |
| p->o=new->z; |
| add_IC(new); |
| return; |
| } |
| printf("Operation: %d=%s\n",p->flags,ename[p->flags]); |
| ierror(0); |
| free(new); |
| p->o.flags=0; |
| } |
| |
| static void handle_reglist(regargs_list *nrl,obj *radr) |
| { |
| IC *new; |
| /* Letztes Argument; jetzt in Register laden. */ |
| #ifdef HAVE_REGPARMS |
| int didradr=0; |
| #endif |
| while(nrl){ |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=nrl->v->vtyp->flags/*|VOLATILE*/; |
| new->q1.flags=VAR; |
| new->q1.v=nrl->v; |
| new->q1.val.vmax=l2zm(0L); |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(nrl->v->vtyp); |
| new->z.flags=VAR; |
| new->z.val.vmax=l2zm(0L); |
| new->z.v=add_var(empty,clone_typ(nrl->v->vtyp),AUTO,0); |
| new->z.v->reg=nrl->reg; |
| new->z.v->vtyp->flags|=VOLATILE; |
| nrl->v=new->z.v; |
| add_IC(new); |
| |
| #ifdef HAVE_REGPARMS |
| if(radr&&!didradr){ |
| didradr=1; |
| }else{ |
| #endif |
| nrl->al->pushic=new; |
| fix_pushic(&nrl->al->pushic,new); |
| #ifdef HAVE_REGPARMS |
| } |
| #endif |
| nrl=nrl->next; |
| } |
| } |
| |
| #ifdef HAVE_REGPARMS |
| zmax push_args(argument_list *al,struct_declaration *sd,int n,regargs_list **rl,treg_handle *reg_handle,obj *radr,type *rtype,int rreg,type *fkt) |
| #else |
| zmax push_args(argument_list *al,struct_declaration *sd,int n,regargs_list **rl) |
| #endif |
| /* 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. */ |
| { |
| int t,reg,regpush,evaluated=0;type *ft; |
| IC *new;regargs_list *nrl;zmax sz,rsz,of;obj *arg; |
| #ifdef HAVE_REGPARMS |
| int stdreg; |
| if(!al&&!radr) return(0); |
| if(radr){ |
| stdreg=rreg; |
| }else{ |
| if(n<sd->count){ |
| stdreg=reg_parm(reg_handle,(*sd->sl)[n].styp,0,fkt->next); |
| }else{ |
| if(sd->count) |
| stdreg=reg_parm(reg_handle,al->arg->ntyp,1,fkt->next); |
| else{ |
| if(short_push&&ISINT(al->arg->ntyp->flags)){ |
| static type t; |
| t.flags=int_erw(al->arg->ntyp->flags); |
| stdreg=reg_parm(reg_handle,&t,0,fkt->next); |
| }else{ |
| stdreg=reg_parm(reg_handle,al->arg->ntyp,0,fkt->next); |
| } |
| } |
| } |
| } |
| reg=stdreg; |
| #else |
| if(!al) return(0); |
| reg=0; |
| #endif |
| #ifdef HAVE_REGPARMS |
| if(!radr){ |
| #endif |
| if(!al->arg) ierror(0); |
| if(!sd) ierror(0); |
| if(n<sd->count){ |
| ft=clone_typ((*sd->sl)[n].styp);sz=szof(ft); |
| t=ft->flags; |
| reg=(*sd->sl)[n].reg; |
| }else{ |
| ft=clone_typ(al->arg->ntyp);sz=szof(ft); |
| t=ft->flags; |
| } |
| if(ISINT(t)){ |
| if(n>=sd->count||!short_push) |
| t=int_erw(t); |
| ft->flags=t; |
| sz=sizetab[t&NQ]; |
| } |
| if((t&NQ)==FLOAT&&n>=sd->count) {t=DOUBLE;ft->flags=t;sz=sizetab[t&NQ];} |
| #ifdef HAVE_REGPARMS |
| }else{ |
| ft=new_typ(); |
| ft->flags=t=POINTER_TYPE(rtype); |
| ft->next=clone_typ(rtype); |
| sz=sizetab[t&NQ]; |
| } |
| #endif |
| if(reg<0) {reg=-reg;regpush=1;} else regpush=0; |
| rsz=sz; |
| sz=zmmult(zmdiv(zmadd(sz,zmsub(stackalign,l2zm(1L))),stackalign),stackalign); |
| #ifdef ORDERED_PUSH |
| if(reg==0||regpush){ |
| new=new_IC(); |
| #ifdef HAVE_REGPARMS |
| if(!radr&&!evaluated){ |
| #endif |
| gen_IC(al->arg,0,0); |
| convert(al->arg,t); |
| evaluated=1; |
| new->q1=al->arg->o; |
| al->pushic=new; |
| #ifdef HAVE_REGPARMS |
| }else |
| new->q1=*radr; |
| #endif |
| /* Parameteruebergabe ueber Stack. */ |
| new->code=PUSH; |
| new->typf=t; |
| new->ityp=ft; |
| new->q2.flags=new->z.flags=0; |
| new->q2.val.vmax=sz; |
| new->z.val.vmax=rsz; |
| if(regpush){ |
| if(c_flags[26]&USEDFLAG){ |
| new->q1.am=new->q2.am=new->z.am=0; |
| new->line=line; new->file=filename; |
| insert_IC(last_ic,new); |
| }else{ |
| new->q1.flags=0; |
| add_IC(new); |
| if(al) fix_pushic(&al->pushic,new); |
| } |
| }else{ |
| add_IC(new); |
| if(al) fix_pushic(&al->pushic,new); |
| } |
| opushed++; |
| if(!first_pushed&&!nocode) first_pushed=new; |
| if(al&&!al->next&&!regpush) return sz; |
| } |
| #endif |
| #ifdef HAVE_REGPARMS |
| if(radr){ |
| if(al) of=push_args(al,sd,0,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L); |
| }else{ |
| if(al->next) of=push_args(al->next,sd,n+1,rl,reg_handle,0,0,0,fkt); else of=l2zm(0L); |
| } |
| #else |
| if(al->next) of=push_args(al->next,sd,n+1,rl); else of=l2zm(0L); |
| #endif |
| #ifdef ORDERED_PUSH |
| if(reg==0) return zmadd(of,sz); |
| #endif |
| |
| if(regpush) of=zmadd(of,sz); |
| |
| #ifdef HAVE_REGPARMS |
| if(radr){ |
| arg=radr; |
| }else{ |
| if(!evaluated){ |
| gen_IC(al->arg,0,0); |
| convert(al->arg,t); |
| evaluated=1; |
| } |
| arg=&al->arg->o; |
| } |
| #else |
| if(!evaluated){ |
| gen_IC(al->arg,0,0); |
| convert(al->arg,t); |
| evaluated=1; |
| } |
| arg=&al->arg->o; |
| #endif |
| #ifndef ORDERED_PUSH |
| if(reg==0||regpush){ |
| /* Parameteruebergabe ueber Stack. */ |
| new=new_IC(); |
| new->code=PUSH; |
| new->typf=t; |
| new->q1=*arg; |
| if(regpush&&!(c_flags[26]&USEDFLAG)) new->q1.flags=0; |
| new->q2.flags=new->z.flags=0; |
| new->q2.val.vmax=sz; |
| new->z.val.vmax=rsz; |
| add_IC(new); |
| al->pushic=new; |
| fix_pushic(&al->pushic,new); |
| if(!regpush) return(zmadd(of,sz)); |
| } |
| #endif |
| if(reg){ |
| /* Parameteruebergabe in Register. */ |
| Var *v=0; type *t2; |
| int rsaved=0; |
| if(optflags&2){ |
| /* Version fuer Optimizer. */ |
| t2=new_typ(); |
| t2->flags=t; |
| if(ISPOINTER(t)){ |
| t2->next=new_typ(); |
| t2->next->flags=VOID; |
| } |
| v=add_var(empty,t2,AUTO,0); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=t; |
| new->q1=*arg; |
| new->q2.flags=0; |
| new->q2.val.vmax=sizetab[t&NQ]; |
| new->z.flags=VAR; |
| new->z.v=v; |
| new->z.val.vmax=l2zm(0L); |
| add_IC(new); |
| nrl=mymalloc(sizeof(*nrl)); |
| nrl->next=*rl; |
| nrl->reg=reg; |
| nrl->v=v; |
| nrl->al=al; |
| *rl=nrl; |
| return of; |
| }else{ |
| /* Nicht-optimierende Version. */ |
| |
| if(DEBUG&16){ |
| printf("reg[%s]=%d ",regnames[reg],regs[reg]); |
| if(reg_pair(reg,&rp)) |
| printf("reg[%s]=%d reg[%s]=%d ",regnames[rp.r1],regs[rp.r1],regnames[rp.r2],regs[rp.r2]); |
| printf("\n"); |
| } |
| if(reg_pair(reg,&rp)&&(arg->flags&(REG|SCRATCH))==(REG|SCRATCH)&&(arg->reg==rp.r1||arg->reg==rp.r2)){ |
| /* rx->reg_pair(rx,ry): make a copy */ |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=t; |
| new->q1=*arg; |
| new->q2.flags=0; |
| new->q2.val.vmax=sizetab[t&NQ]; |
| scratch_var(&new->z,t,0); |
| add_IC(new); |
| *arg=new->z; |
| free_reg(arg->reg); |
| } |
| if(!regs[reg]&&(!reg_pair(reg,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))&&!nocode){ |
| new=new_IC(); |
| new->code=ALLOCREG; |
| new->typf=0; |
| new->q1.flags=REG; |
| new->q1.reg=reg; |
| new->q2.flags=new->z.flags=0; |
| add_IC(new); |
| regs[reg]=(1|RNOSAVE);regused[reg]++; |
| if(DEBUG&16) printf("allocated %s (1)\n",regnames[reg]); |
| if(reg_pair(reg,&rp)){ |
| regs[rp.r1]=1|RNOSAVE;regused[rp.r1]++; |
| regs[rp.r2]=1|RNOSAVE;regused[rp.r2]++; |
| } |
| }else if(!regs[reg]&®_pair(reg,&rp)&&(regs[rp.r1]||regs[rp.r2])&&!nocode){ |
| int r=0; |
| regargs_list *p; |
| |
| new=new_IC(); |
| new->code=ALLOCREG; |
| new->typf=0; |
| new->q1.flags=REG; |
| new->q2.flags=new->z.flags=0; |
| if(regs[rp.r1]){ |
| new->q1.reg=rp.r2; |
| r=rp.r1; |
| regs[r]|=RHALF; |
| }else{ |
| new->q1.reg=rp.r1; |
| r=rp.r2; |
| regs[r]|=RHALF; |
| } |
| regs[new->q1.reg]=(1|RNOSAVE);regused[new->q1.reg]++; |
| regs[reg]=(1|RNOSAVE);regused[reg]++; |
| add_IC(new); |
| if(DEBUG&16) printf("allocated %s (half)\n",regnames[new->q1.reg]); |
| rsaved=r; |
| /* Testen, ob Quellregister gesichert wurde. Unschoen. */ |
| for(p=*rl;p;p=p->next){ |
| int ri; |
| if(p->v&&(ri=abs(p->reg))){ |
| if(ri==r) break; |
| if(reg_pair(ri,&rp)&&(rp.r1==r||rp.r2==r)) break; |
| } |
| } |
| |
| if(r&&!p){ |
| t2=clone_typ(regtype[r]); |
| v=add_var(empty,t2,AUTO,0); |
| v->flags|=USEDASADR; |
| new=new_IC(); |
| new->code=MOVEFROMREG; |
| new->typf=0; |
| new->q1.flags=REG; |
| new->q1.reg=r; |
| new->q2.flags=0; |
| new->q2.val.vmax=regsize[r]; |
| new->z.flags=VAR|DONTREGISTERIZE; |
| new->z.v=v; |
| new->z.val.vmax=l2zm(0L); |
| add_IC(new); |
| } |
| }else{ |
| if((arg->flags&(REG|SCRATCH))!=(REG|SCRATCH)||arg->reg!=reg){ |
| int r=0; |
| regargs_list *p; |
| |
| /* register pairs */ |
| if(reg_pair(reg,&rp)){ |
| if(regs[reg]||regs[rp.r1]||regs[rp.r2]) |
| r=reg; |
| }else{ |
| for(r=MAXR;r>=1;r--){ |
| if(regs[r]&®_pair(r,&rp)&&(rp.r1==reg||rp.r2==reg)) |
| break; |
| } |
| if(r<1) r=reg; |
| } |
| |
| |
| /* Testen, ob Quellregister gesichert wurde. Unschoen. */ |
| for(p=*rl;p;p=p->next){ |
| int ri; |
| if(p->v&&(ri=abs(p->reg))){ |
| if(ri==r||(reg_pair(r,&rp)&&(rp.r1==ri||rp.r2==ri))) {break;} |
| if(reg_pair(ri,&rp)&&(rp.r1==r||rp.r2==r)) {break;} |
| } |
| } |
| |
| if(r&&!p){ |
| t2=clone_typ(regtype[r]); |
| v=add_var(empty,t2,AUTO,0); |
| v->flags|=USEDASADR; |
| new=new_IC(); |
| new->code=MOVEFROMREG; |
| new->typf=0; |
| new->q1.flags=REG; |
| new->q1.reg=r; |
| new->q2.flags=0; |
| new->q2.val.vmax=regsize[r]; |
| new->z.flags=VAR|DONTREGISTERIZE; |
| new->z.v=v; |
| new->z.val.vmax=l2zm(0L); |
| add_IC(new); |
| } |
| }else{ |
| regs[reg]|=RNOSAVE; |
| } |
| } |
| new=new_IC(); |
| #ifdef HAVE_REGPARMS |
| if(!radr){ |
| al->pushic=new; |
| } |
| #else |
| al->pushic=new; |
| #endif |
| new->code=ASSIGN; |
| new->typf=t; |
| new->q1=*arg; |
| /* Testen, ob Quellregister gesichert wurde. Unschoen. */ |
| if((new->q1.flags®)){ |
| regargs_list *p; |
| for(p=*rl;p;p=p->next){ |
| int r; |
| if(p->v&&(r=abs(p->reg))){ |
| if(new->q1.reg==r||(reg_pair(new->q1.reg,&rp)&&(rp.r1==r||rp.r2==r))) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;} |
| /*FIXME: andersrum bei LITTLEENDIAN?? */ |
| if(reg_pair(r,&rp)&&rp.r1==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=l2zm(0L);break;} |
| if(reg_pair(r,&rp)&&rp.r2==new->q1.reg) {new->q1.v=p->v;new->q1.val.vmax=regsize[rp.r1];break;} |
| |
| } |
| } |
| if(p&&new->q1.v){ |
| if(!(new->q1.flags&DREFOBJ)&&must_convert(new->typf,regtype[new->q1.reg]->flags,0)){ |
| new->code=CONVERT; |
| new->typf2=regtype[new->q1.reg]->flags; |
| } |
| new->q1.flags&=~REG; |
| new->q1.flags|=VAR; |
| /*new->q1.val.vmax=l2zm(0L);*/ |
| } |
| } |
| new->q2.flags=new->z.flags=0; |
| new->q2.val.vmax=sizetab[t&NQ]; |
| new->z.flags=REG; |
| new->z.reg=reg; |
| add_IC(new); |
| if(al) fix_pushic(&al->pushic,new); |
| nrl=mymalloc(sizeof(*nrl)); |
| nrl->next=*rl; |
| nrl->reg=reg; |
| nrl->v=v; |
| nrl->rsaved=rsaved; /* if only part of a pair was saved */ |
| rsaved=0; |
| *rl=nrl; |
| return of; |
| } |
| } |
| } |
| |
| void convert(np p,int f) |
| /* konvertiert das Objekt in p->o in bestimmten Typ */ |
| /* wenn volatile_convert gesetzt ist, wird immer IC erzeugt */ |
| { |
| IC *new; |
| int o=p->ntyp->flags; |
| int to,tn,mc,dr; |
| static node n,nn; |
| static type nt; |
| char *libname; |
| if((f&NQ)==VOID) return; |
| |
| if(p->flags==CEXPR||p->flags==PCEXPR){ |
| #ifdef HAVE_MISRA |
| /* removed */ |
| /* removed */ |
| #endif |
| eval_constn(p); |
| p->ntyp->flags=f; |
| insert_constn(p); |
| p->o.val=p->val; |
| return; |
| } |
| if((AVOID_FLOAT_TO_UNSIGNED&&ISFLOAT(o)&&(f&UNSIGNED))|| |
| (AVOID_UNSIGNED_TO_FLOAT&&ISFLOAT(f)&&(o&UNSIGNED))){ |
| union atyps val; |
| int l1,l2,it; |
| Var *tmp; |
| np t; |
| type *ttyp; |
| if(f&UNSIGNED) |
| it=f&NQ; |
| else |
| it=o&NQ; |
| ttyp=clone_typ(p->ntyp); |
| ttyp->flags=f; |
| tmp=add_tmp_var(ttyp); |
| new=new_IC(); |
| new->code=COMPARE; |
| new->typf=o; |
| new->q1=p->o; |
| new->q1.flags&=~SCRATCH; |
| new->q2.flags=KONST; |
| new->q2.val.vumax=t_max[it]; |
| eval_const(&new->q2.val,MAXINT|UNSIGNED); |
| insert_const(&new->q2.val,o); |
| val=new->q2.val; |
| add_IC(new); |
| new=new_IC(); |
| new->code=BLE; |
| l1=++label; |
| new->typf=l1; |
| add_IC(new); |
| new=new_IC(); |
| new->code=SUB; |
| new->typf=o; |
| new->q1=p->o; |
| new->q1.flags&=~SCRATCH; |
| new->q2.flags=KONST; |
| new->q2.val=val; |
| new->z.flags=VAR; |
| get_scratch(&new->z,o,0,0); |
| t=new_node(); |
| t->ntyp=clone_typ(p->ntyp); |
| t->ntyp->flags&=~UNSIGNED; |
| t->o=new->z; |
| add_IC(new); |
| convert(t,f&NQ); |
| new=new_IC(); |
| new->code=ADD; |
| new->typf=f; |
| new->q1=t->o; |
| new->q1.flags&=~SCRATCH; |
| freetyp(t->ntyp); |
| free(t); |
| new->q2.flags=KONST; |
| new->q2.val.vumax=t_max[it]; |
| eval_const(&new->q2.val,MAXINT|UNSIGNED); |
| insert_const(&new->q2.val,f); |
| new->z.flags=VAR; |
| new->z.v=tmp; |
| new->z.val.vmax=l2zm(0L); |
| add_IC(new); |
| new=new_IC(); |
| new->code=BRA; |
| l2=++label; |
| new->typf=l2; |
| add_IC(new); |
| new=new_IC(); |
| new->code=LABEL; |
| new->typf=l1; |
| add_IC(new); |
| p->ntyp->flags&=~UNSIGNED; |
| convert(p,f&NQ); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=f; |
| new->q1=p->o; |
| new->z.flags=VAR; |
| new->z.v=tmp; |
| new->z.val.vmax=l2zm(0L); |
| new->q2.val.vmax=sizetab[f&NQ]; |
| p->o=new->z; |
| p->ntyp->flags=f; |
| add_IC(new); |
| new=new_IC(); |
| new->code=LABEL; |
| new->typf=l2; |
| add_IC(new); |
| return; |
| } |
| if(ISVECTOR(f)&&ISSCALAR(o)){ |
| o=VECTYPE(f); |
| convert(p,o); |
| } |
| if(!volatile_convert&&((o&(NU&~UNSIGNED))==(f&(NU&~UNSIGNED))||(!(mc=must_convert(o,f,const_expr))&&(const_expr||!(optflags&2))))){ |
| p->ntyp->flags=f; |
| if(!ISPOINTER(f)&&!ISARRAY(f)){freetyp(p->ntyp->next);p->ntyp->next=0;} |
| return; |
| } |
| /* do not create direct converts between float and small types |
| if the backend does not like that */ |
| if(ISFLOAT(o)&&ISINT(f)&&(f&NQ)<MIN_FLOAT_TO_INT_TYPE) |
| tn=MIN_FLOAT_TO_INT_TYPE|(f&UNSIGNED); |
| else |
| tn=f; |
| libname=0; |
| if(ISFLOAT(f)&&ISINT(o)&&(o&NQ)<MIN_INT_TO_FLOAT_TYPE){ |
| #if HAVE_LIBCALLS |
| if((libname=use_libcall_wrap(CONVERT,tn,o))&&mc){ |
| to=o; |
| libname=use_libcall_wrap(CONVERT,tn,MIN_INT_TO_FLOAT_TYPE|(o&UNSIGNED)); |
| if(!libname) ierror(0); |
| }else |
| #endif |
| { |
| to=MIN_INT_TO_FLOAT_TYPE|(o&UNSIGNED); |
| convert(p,to); |
| } |
| }else{ |
| to=o; |
| } |
| #if HAVE_LIBCALLS |
| n.flags=CONVERT; |
| n.ntyp=&nt; |
| nt.flags=f; |
| n.left=&nn; |
| nn.ntyp=p->ntyp; |
| if((libname||(libname=use_libcall_wrap(CONVERT,tn,to)))&&mc){ |
| node *n=new_node(); |
| n->flags=REINTERPRET; |
| n->o=p->o; |
| n->ntyp=p->ntyp; |
| p->o=gen_libcall(libname,n,p->ntyp,0,0)->o; |
| }else{ |
| #endif |
| new=new_IC(); |
| new->q1=p->o; |
| new->q2.flags=0; |
| new->code=CONVERT; |
| new->typf2=to; |
| new->typf=tn; |
| if((p->o.flags&(SCRATCH|REG))!=(SCRATCH|REG)||!regok(p->o.reg,tn,0)){ |
| get_scratch(&new->z,tn,0,0); |
| }else{ |
| new->z=p->o;new->z.flags&=~DREFOBJ; |
| } |
| p->o=new->z; |
| /* hmm... */ |
| if(!mc&&libname){ |
| new->code=ASSIGN; |
| new->q2.val.vmax=sizetab[tn&NQ]; |
| } |
| add_IC(new); |
| #if HAVE_LIBCALLS |
| } |
| #endif |
| if(f!=tn){ |
| p->ntyp->flags=tn; |
| convert(p,f); |
| } |
| } |
| |
| void alloc_hardreg(int r) |
| /* Belegt Register r. */ |
| { |
| IC *new; |
| if(nocode) return; |
| if(DEBUG&16) printf("allocated %s\n",regnames[r]); |
| regs[r]=1;regused[r]++; |
| new=new_IC(); |
| new->code=ALLOCREG; |
| new->typf=0; |
| new->q1.flags=REG; |
| new->q1.reg=r; |
| new->q2.flags=new->z.flags=0; |
| add_IC(new); |
| if(reg_pair(r,&rp)){ |
| regs[rp.r1]=1;regused[rp.r1]++; |
| regs[rp.r2]=1;regused[rp.r2]++; |
| } |
| } |
| |
| int allocreg(int f,int mode) |
| /* Fordert Register fuer Typ f an. */ |
| { |
| int i,r=0,prio=-1; |
| if(nocode) return(1); |
| for(i=1;i<=MAXR;i++){ |
| if(!regs[i]&®_prio[i]>prio&®ok(i,f,mode)&&(!reg_pair(i,&rp)||(!regs[rp.r1]&&!regs[rp.r2]))){ |
| r=i; |
| prio=reg_prio[i]; |
| } |
| } |
| if(r){ |
| if(DEBUG&16) printf("alloc %s\n",regnames[r]); |
| alloc_hardreg(r); |
| return r; |
| } |
| if(DEBUG&1) printf("Couldn't allocate register for type %d\n",f); |
| return 0; |
| } |
| void free_reg(int r) |
| /* Gibt Register r frei */ |
| { |
| IC *new; |
| if(!r||nocode) return; |
| if(regs[r]==0&&!cross_module) |
| {printf("Register %d(%s):\n",r,regnames[r]);ierror(0);} |
| if(DEBUG&16) printf("freed %s\n",regnames[r]); |
| new=new_IC(); |
| new->code=FREEREG; |
| new->typf=0; |
| new->q1.flags=REG; |
| new->q1.reg=r; |
| new->q2.flags=new->z.flags=0; |
| regs[r]=0; |
| if(reg_pair(r,&rp)){ |
| if(regs[rp.r1]&RHALF){ |
| if(DEBUG&16) printf("keep %s\n",regnames[rp.r1]); |
| regs[rp.r1]&=~RHALF; |
| new->q1.reg=rp.r2; |
| }else |
| regs[rp.r1]=0; |
| if(regs[rp.r2]&RHALF){ |
| if(DEBUG&16) printf("keep %s\n",regnames[rp.r2]); |
| regs[rp.r2]&=~RHALF; |
| new->q1.reg=rp.r1; |
| }else |
| regs[rp.r2]=0; |
| } |
| add_IC(new); |
| } |
| void gen_label(int l) |
| /* Erzeugt ein Label */ |
| { |
| IC *new; |
| new=new_IC(); |
| new->code=LABEL; |
| new->typf=l; |
| new->q1.flags=new->q2.flags=new->z.flags=0; |
| add_IC(new); |
| } |
| void gen_cond(obj *p,int m,int l1,int l2) |
| /* Generiert code, der 0 oder 1 in Register schreibt. Schreibt obj nach p. */ |
| { |
| IC *new; |
| obj omerk; |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=INT; |
| new->q1.flags=KONST; |
| new->q2.flags=0; |
| new->q2.val.vmax=sizetab[INT]; |
| if(!m) vmax=l2zm(1L); else vmax=l2zm(0L); |
| new->q1.val.vint=zm2zi(vmax); |
| get_scratch(&new->z,INT,0,0); |
| omerk=new->z; |
| add_IC(new); |
| new=new_IC(); |
| new->code=BRA; |
| new->typf=l2; |
| add_IC(new); |
| gen_label(l1); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=INT; |
| new->q1.flags=KONST; |
| new->q2.flags=0; |
| new->q2.val.vmax=sizetab[INT]; |
| if(!m) vmax=l2zm(0L); else vmax=l2zm(1L); |
| new->q1.val.vint=zm2zi(vmax); |
| new->z=omerk; |
| /* new->z.reg=r; |
| new->z.flags=SCRATCH|REG;*/ |
| add_IC(new); |
| gen_label(l2); |
| *p=omerk; |
| } |
| void scratch_var(obj *o,int t,type *typ) |
| /* liefert eine temporaere Variable */ |
| /* nicht effizient, aber wer hat schon so wenig Register... */ |
| { |
| type *nt; |
| if(!ISSCALAR(t)&&!ISVECTOR(t)){ |
| if(!typ) ierror(0); |
| nt=clone_typ(typ); |
| }else{ |
| nt=new_typ(); |
| nt->flags=t; |
| if(ISPOINTER(t)){ |
| nt->next=new_typ(); |
| nt->next->flags=VOID; |
| } |
| } |
| o->flags=SCRATCH|VAR;o->reg=0; |
| o->v=add_var(empty,nt,AUTO,0); |
| o->val.vmax=l2zm(0L); |
| } |
| void get_scratch(obj *o,int t1,int t2,type *typ) |
| /* liefert ein Scratchregister oder eine Scratchvariable */ |
| { |
| if(!(optflags&2)&&(o->reg=allocreg(t1,t2))){ |
| o->flags=SCRATCH|REG; |
| }else{ |
| scratch_var(o,t1,typ); |
| } |
| } |
| int do_arith(np p,IC *new,np dest,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,mflags; |
| 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++; |
| if(p->left->flags==BITFIELD){ |
| *o=p->left->left->o; |
| if((o->flags&(REG|SCRATCH))==(REG|SCRATCH)) |
| keep_reg(o->reg); |
| } |
| } |
| gen_IC(p->right,0,0); |
| if(dest&&p->right==dest) {*o=p->right->o;f++;} |
| if(dest){ |
| mflags=dest->o.flags; |
| if(p->left->flags!=BITFIELD) |
| dest->o.flags&=(~SCRATCH); |
| } |
| |
| if(ISPOINTER(p->left->ntyp->flags)&&ISPOINTER(p->right->ntyp->flags)){ |
| /* Subtrahieren zweier Pointer */ |
| int dt=PTRDIFF_T(p->left->ntyp->flags); |
| if(p->flags!=SUB) ierror(0); |
| new->typf=dt; |
| new->typf2=p->left->ntyp->flags; |
| new->code=SUBPFP; |
| new->q1=p->left->o; |
| new->q2=p->right->o; |
| if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->left->o.reg,dt,0)){ |
| new->z=p->left->o; |
| new->z.flags&=~DREFOBJ; |
| }else{ |
| if(USEQ2ASZ&&(p->right->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(p->right->o.reg,dt,0)){ |
| new->z=p->right->o; |
| new->z.flags&=(~DREFOBJ); |
| }else{ |
| get_scratch(&new->z,dt,0,0); |
| } |
| } |
| p->o=new->z; |
| add_IC(new); |
| if(!zmleq(szof(p->left->ntyp->next),l2zm(1L))){ |
| long ln; |
| new=new_IC(); |
| new->q1=p->o; |
| new->q2.flags=KONST; |
| gval.vmax=szof(p->left->ntyp->next); |
| eval_const(&gval,MAXINT); |
| if(ln=get_pof2(vumax)){ |
| /* Division immer ohne Rest, daher shift möglich */ |
| /* TODO: Haben wir Targets ohne arith. shift right? */ |
| gval.vmax=l2zm(ln-1); |
| eval_const(&gval,MAXINT); |
| insert_const(&new->q2.val,INT); |
| new->typf2=INT; |
| new->code=RSHIFT; |
| }else{ |
| insert_const(&new->q2.val,dt); |
| new->code=DIV; |
| } |
| new->z=p->o; |
| new->typf=dt; |
| add_IC(new); |
| } |
| if(dest) dest->o.flags=mflags; |
| return f; |
| } |
| if((p->flags==ADD||p->flags==SUB)&&(ISPOINTER(p->left->ntyp->flags)||ISPOINTER(p->right->ntyp->flags))){ |
| /* Addieren und Subtrahieren eines Integers zu einem Pointer */ |
| if(p->flags==ADD){ |
| new->code=ADDI2P; |
| if(!ISPOINTER(p->left->ntyp->flags)){ |
| np tmp=p->left; |
| p->left=p->right; |
| p->right=tmp; |
| } |
| }else |
| new->code=SUBIFP; |
| new->typf=p->right->ntyp->flags; |
| new->typf2=p->ntyp->flags; |
| new->q1=p->left->o; |
| /* kleinere Typen als MINADDI2P erst in diesen wandeln */ |
| if(new->typf&UNSIGNED){ |
| if((new->typf&NQ)<(MINADDUI2P&NQ)){convert(p->right,MINADDUI2P);new->typf=MINADDUI2P;} |
| }else{ |
| if((new->typf&NQ)<MINADDI2P){convert(p->right,MINADDI2P);new->typf=MINADDI2P;} |
| } |
| /* groessere Typen als MAXADDI2P erst in diesen wandeln */ |
| if(new->typf&UNSIGNED){ |
| if((new->typf&NQ)>(MAXADDI2P&NQ)){convert(p->right,MAXADDUI2P);new->typf=MAXADDUI2P;} |
| }else{ |
| if((new->typf&NQ)>MAXADDI2P){convert(p->right,MAXADDI2P);new->typf=MAXADDI2P;} |
| } |
| if((p->left->o.flags&VARADR)&&(p->right->o.flags&KONST)){ |
| eval_const(&p->right->o.val,p->right->ntyp->flags); |
| p->o=p->left->o; |
| p->o.val.vmax=zmadd(vmax,p->left->o.val.vmax); |
| free(new); |
| return f; |
| } |
| new->q2=p->right->o; |
| if(!dest&&(p->left->o.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(new->q1.reg,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags)){ |
| new->z=p->left->o; |
| new->z.flags&=(~DREFOBJ); |
| }else{ |
| /*get_scratch(&new->z,POINTER_TYPE(p->left->ntyp->next),p->left->ntyp->next->flags,0);*/ |
| get_scratch(&new->z,p->ntyp->flags,p->ntyp->next->flags,0); |
| } |
| p->o=new->z; |
| add_IC(new); |
| if(dest) dest->o.flags=mflags; |
| return f; |
| } |
| if(!ISVECTOR(p->ntyp->flags)||!ISVECTOR(p->left->ntyp->flags)) |
| convert(p->left,p->ntyp->flags); |
| if(p->flags==LSHIFT||p->flags==RSHIFT){ |
| if(shortcut(p->flags,p->left->ntyp->flags&NU)){ |
| convert(p->right,p->right->ntyp->flags); |
| new->typf2=p->right->ntyp->flags; |
| }else{ |
| convert(p->right,INT); |
| new->typf2=INT; |
| } |
| #if 0 |
| type *st; |
| st=clone_typ(p->right->ntyp); |
| /*st->flags=int_erw(st->flags);*/ |
| st->flags=INT; |
| convert(p->right,st->flags); |
| new->typf2=st->flags; |
| freetyp(st); |
| #endif |
| }else{ |
| if(!ISVECTOR(p->ntyp->flags)||!ISVECTOR(p->right->ntyp->flags)) |
| convert(p->right,p->ntyp->flags); |
| } |
| new->q1=p->left->o; |
| new->q2=p->right->o; |
| if(ISVECTOR(p->ntyp->flags)){ |
| new->typf=p->left->ntyp->flags; |
| new->typf2=p->ntyp->flags; |
| }else |
| new->typf=p->ntyp->flags; |
| /* Bei dest!=0, d.h. ASSIGNOP, darf q1 nicht als Ziel benuzt werden! */ |
| if(!dest&&(new->q1.flags&(SCRATCH|REG))==(SCRATCH|REG)&®ok(new->q1.reg,p->ntyp->flags,0)){ |
| new->z=new->q1; |
| new->z.flags&=~DREFOBJ; |
| }else{ |
| if((new->q2.flags&SCRATCH)&®ok(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,0); |
| } |
| } |
| }else{ |
| get_scratch(&new->z,new->typf,0,0); |
| } |
| } |
| p->o=new->z; |
| add_IC(new); |
| if(dest){ |
| dest->o.flags=mflags; |
| /* |
| if((dest->o.flags®)&&!regs[dest->o.reg]) |
| keep_reg(dest->o.reg); |
| */ |
| } |
| |
| return f; |
| } |
| void savescratch(int code,IC *p,int dontsave,obj *o) |
| /* speichert Scratchregister bzw. stellt sie wieder her (je nach code */ |
| /* entweder MOVEFROMREG oder MOVETOREG) */ |
| { |
| int i,s,e,b,ds1,ds2;IC *new; |
| if(code==MOVETOREG){ s=1;e=MAXR+1;b=1;} else {s=MAXR;e=0;b=-1;} |
| if(reg_pair(dontsave,&rp)){ |
| ds1=rp.r1; |
| ds2=rp.r2; |
| }else |
| ds1=ds2=0; |
| for(i=s;i!=e;i+=b){ |
| int mustsave=0; |
| if((o->flags&(VAR|DREFOBJ))==VAR&&o->v->fi&&(o->v->fi->flags&ALL_REGS)) |
| mustsave=BTST(o->v->fi->regs_modified,i); |
| else |
| mustsave=regscratch[i]; |
| if(regsa[i]) mustsave=0; |
| if(mustsave) simple_scratch[i]=1; |
| if(regs[i]&&!(regs[i]&RNOSAVE)&&mustsave&&i!=dontsave&&i!=ds1&&i!=ds2&&!reg_pair(i,&rp)){ |
| if(!regsbuf[i]){ |
| type *t; |
| if(code!=MOVEFROMREG) continue; |
| t=clone_typ(regtype[i]); |
| regsbuf[i]=add_var(empty,t,AUTO,0); |
| regsbuf[i]->flags|=USEDASADR; |
| regbnesting[i]=nesting; |
| } |
| new=new_IC(); |
| new->typf=new->q2.flags=0; |
| new->line=0;new->file=0; |
| new->code=code; |
| if(code==MOVEFROMREG){ |
| new->q1.flags=REG;new->q1.reg=i; |
| new->z.flags=VAR|DONTREGISTERIZE;new->z.v=regsbuf[i]; |
| new->z.val.vmax=l2zm(0L); |
| }else{ |
| new->z.flags=REG;new->z.reg=i; |
| new->q1.flags=VAR|DONTREGISTERIZE;new->q1.v=regsbuf[i]; |
| new->q1.val.vmax=l2zm(0L); |
| } |
| new->use_cnt=new->change_cnt=0; |
| new->use_list=new->change_list=0; |
| insert_IC(p,new); |
| } |
| } |
| } |
| |