/* $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=⁢ 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&®scratch[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®)&&!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®)||!(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++; /* Merken, on Fliesskomma benutzt wurde */ if(code!=LABEL&&(codeBRA)){ 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®))) free_reg(new->q1.reg); if((new->q2.flags&(SCRATCH|REG))==(SCRATCH|REG)&&(new->q2.reg!=new->z.reg||!(new->z.flags®))) 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; } } 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)) 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 */ { struct IC *new; struct regargs_list *rl; if(!p) return; if(p->flags==STRING){ p->o.v=add_var(empty,clone_typ(p->ntyp),STATIC,p->cl); p->o.v->flags|=DEFINED; 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_LIBCALLS if(!(optflags&2)){ char *libname; if(libname=use_libcall_wrap(p->flags,p->ntyp->flags,0)){ np lc;struct Typ *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); } 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 */ struct obj o,q;struct 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==LSHIFT)?INT:0)){ struct Typ *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->left->ntyp->flags,0,p->left->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; struct Typ *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=TEST; new->typf=INT; }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)){ 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)))){ convert(p->right,tl); tr=tl; } } if(ISARITH(tl)&&(tl!=tr||!shortcut(COMPARE,tl))){ struct Typ *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; struct obj *op,cfunc,ret_obj; zmax sz; int mregs[MAXR+1]; struct IC *callic; #ifdef ORDERED_PUSH struct IC *merk_fp,*lp; unsigned int merk_opushed=opushed; #endif if(p->left->flags==ADDRESS&&p->left->left->flags==IDENTIFIER){ struct 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 */ struct argument_list *al; struct Var *vp,**argl1,**argl2; struct 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(struct Var *)); argl2=mymalloc(arg_cnt*sizeof(struct 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(ifi->vars;vp;vp=vp->next){ vp->inline_copy=0; } for(i=0;iinline_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){ struct 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;iarg_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")&&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))){ struct 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(INLINEMEMCPY>0&&(optflags&2)){ if(!strcmp(v->identifier,"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))){ struct 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)INLINEMEMCPY))){ inline_memcpy(p->alist->arg,n,len); p->o=p->alist->arg->o; return; } } } if(!strcmp(v->identifier,"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)INLINEMEMCPY))){ 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]&=~32;} }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){ struct IC *new2;static struct Typ ptyp={0}; struct reg_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); 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{ struct reg_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){ struct 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; struct 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); if(optflags&2){ while(rl){ struct 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. */ struct 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]&32); } } /* Evtl. gespeicherte Registerargumente wiederherstellen. */ while(rl){ struct 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; new->z.reg=abs(r); new->q2.flags=0; new->q2.val.vmax=regsize[r]; add_IC(new); }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){ struct 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){ struct obj o; #if HAVE_LIBCALLS char *libname; struct 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; 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); } 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; struct 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(struct regargs_list *nrl,struct obj *radr) { struct 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; #ifdef HAVE_REGPARMS } #endif nrl=nrl->next; } } #ifdef HAVE_REGPARMS zmax push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct regargs_list **rl,struct reg_handle *reg_handle,struct obj *radr,struct Typ *rtype,int rreg,struct Typ *fkt) #else zmax push_args(struct argument_list *al,struct struct_declaration *sd,int n,struct 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;struct Typ *ft; struct IC *new;struct regargs_list *nrl;zmax sz,rsz,of;struct obj *arg; #ifdef HAVE_REGPARMS int stdreg; if(!al&&!radr) return(0); if(radr){ stdreg=rreg; }else{ if(ncount){ stdreg=reg_parm(reg_handle,(*sd->sl)[n].styp,0,fkt); }else{ if(sd->count) stdreg=reg_parm(reg_handle,al->arg->ntyp,1,fkt); else stdreg=reg_parm(reg_handle,al->arg->ntyp,0,fkt); } } 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(ncount){ 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(!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(); if(!radr&&!evaluated){ gen_IC(al->arg,0,0); convert(al->arg,t); evaluated=1; new->q1=al->arg->o; al->pushic=new; }else new->q1=*radr; /* 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); } }else{ add_IC(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; if(!regpush) return(zmadd(of,sz)); } #endif if(reg){ /* Parameteruebergabe in Register. */ struct Var *v=0; struct Typ *t2; 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(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]=33;regused[reg]++; if(reg_pair(reg,&rp)){ regs[rp.r1]=33;regused[rp.r1]++; regs[rp.r2]=33;regused[rp.r2]++; } }else{ if((arg->flags&(REG|SCRATCH))!=(REG|SCRATCH)||arg->reg!=reg){ int r=0; struct 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]|=32; } } 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®)){ struct 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); nrl=mymalloc(sizeof(*nrl)); nrl->next=*rl; nrl->reg=reg; nrl->v=v; *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 */ { struct IC *new; int o=p->ntyp->flags; int to,tn,mc,dr; static struct node n,nn; static struct Typ 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; struct Var *tmp; np t; struct Typ *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)==(f&NU)||(!(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)ntyp; if((libname=use_libcall_wrap(CONVERT,tn,to))&&mc){ struct 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. */ { struct 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 */ { struct IC *new; if(!r||nocode) return; if(regs[r]==0) {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; add_IC(new); regs[r]=0; if(reg_pair(r,&rp)){ regs[rp.r1]=0; regs[rp.r2]=0; } } void gen_label(int l) /* Erzeugt ein Label */ { struct 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(struct obj *p,int m,int l1,int l2) /* Generiert code, der 0 oder 1 in Register schreibt. Schreibt obj nach p. */ { struct IC *new; struct 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(struct obj *o,int t,struct Typ *typ) /* liefert eine temporaere Variable */ /* nicht effizient, aber wer hat schon so wenig Register... */ { struct Typ *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(struct obj *o,int t1,int t2,struct Typ *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,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,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))){ new=new_IC(); new->code=DIV; new->q1=p->o; new->q2.flags=KONST; gval.vmax=szof(p->left->ntyp->next); eval_const(&gval,MAXINT); insert_const(&new->q2.val,dt); 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&NQ)right,MINADDI2P);new->typf=MINADDI2P;} /* groessere Typen als MAXADDI2P erst in diesen wandeln */ 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); } 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 struct Typ *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,struct IC *p,int dontsave,struct obj *o) /* speichert Scratchregister bzw. stellt sie wieder her (je nach code */ /* entweder MOVEFROMREG oder MOVETOREG) */ { int i,s,e,b,ds1,ds2;struct 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]&32)&&mustsave&&i!=dontsave&&i!=ds1&&i!=ds2&&!reg_pair(i,&rp)){ if(!regsbuf[i]){ struct Typ *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); } } }