| /* $VER: vbcc (supp.c) $Revision: 1.49 $ */ |
| |
| #include "supp.h" |
| #include "opt.h" |
| |
| static char FILE_[]=__FILE__; |
| |
| #ifndef HAVE_EXT_TYPES |
| char *typname[]={"strange","char","short","int","long","long long", |
| "float","double","long double","void", |
| "pointer","array","struct","union","enum","function", |
| "bool","vector"}; |
| #endif |
| |
| char *storage_class_name[]={"strange","auto","register","static","extern","typedef"}; |
| |
| char *ename[]={"strange","sequence","move","set+","set-","set*","set/","set%", |
| "set&","set^","set|","set<<","set>>","?:","lor","land","or", |
| "eor","and","eq","neq","lt","le","gt","ge","lsl", |
| "lsr","add","sub","mul","div","mod","negate", |
| "not","preinc","postinc","predec","postdec","neg", |
| "dref-pointer","address-of","cast","call","index", |
| "dref-struct-pointer","dref-struct","identifier","constant", |
| "string","member", |
| "convert","convert-short","convert-int","convert-long", |
| "convert-float","convert-double","convert-void","convert-pointer", |
| "convert-uchar","convert-ushort","convert-uint","convert-ulong", |
| "address-of-array","first-element-of-array","pmult", |
| "allocreg","freereg","pconstant","test","label","beq","bne", |
| "blt","bge","ble","bgt","bra","compare","push","pop", |
| "address-of-struct","add-int-to-pointer","sub-int-from-pointer", |
| "sub-pointer-from-pointer","push-reg","pop-reg","pop-args", |
| "save-regs","restore-regs","identifier-label","dc","align", |
| "colon","get-return","set-return","move-from-reg","move-to-reg", |
| "nop","bitfield"}; |
| |
| char *empty=""; |
| zchar vchar; zuchar vuchar; |
| zshort vshort; zushort vushort; |
| zint vint; zuint vuint; |
| zlong vlong; zulong vulong; |
| zllong vllong; zullong vullong; |
| zmax vmax; zumax vumax; |
| zfloat vfloat; zdouble vdouble; |
| zldouble vldouble; |
| |
| union atyps gval; |
| |
| #ifndef DEBUG |
| int DEBUG; |
| #endif |
| |
| int label; |
| |
| int regs[MAXR+1],regused[MAXR+1],simple_scratch[MAXR+1]; |
| Var *regsv[MAXR+1]; |
| int goto_used; |
| int ic_count; |
| zmax max_offset; |
| int function_calls,vlas; |
| int coloring; |
| int dmalloc; |
| int disable; |
| int multiple_ccs; |
| int lastlabel,return_label; |
| int only_inline; |
| IC *err_ic; |
| long maxoptpasses=30; |
| long optflags; |
| int optsize,optspeed,unroll_all,stack_check; |
| int cross_module,final,no_emit; |
| int debug_info; |
| long inline_size=100; |
| long inline_depth=1; |
| long unroll_size=200; |
| long clist_copy_stack=6; |
| long clist_copy_static=6; |
| long clist_copy_pointer=20; |
| long inline_memcpy_sz=INLINEMEMCPY; |
| int fp_assoc,noaliasopt,noitra; |
| char *filename; |
| IC *first_ic,*last_ic; |
| int float_used; |
| bvtype regs_modified[RSIZE/sizeof(bvtype)]; |
| /* Das haette ich gern woanders */ |
| Var *vl0,*vl1,*vl2,*vl3; |
| int align_arguments=1; |
| zmax stackalign; |
| int misracheck,misraversion,misracomma,misratok; |
| int pack_align; |
| int short_push; |
| int default_unsigned; |
| Var *add_attr_haddecl; |
| |
| char *emit_buffer[EMIT_BUF_DEPTH]; |
| char *emit_p; |
| int emit_f,emit_l; |
| int no_inline_peephole; |
| |
| static int get_scalar_byte(int f,union atyps *v,zmax n, zuchar *out) |
| /* Yields byte n of a constant */ |
| { |
| if(!zmleq(l2zm(0L),n)) ierror(0); |
| f&=NQ; |
| if(f>=CHAR&&f<=LLONG){ |
| int j; |
| eval_const(v,f); |
| if(LITTLEENDIAN) |
| j=zm2l(n); |
| else |
| j=(int)sizetab[f]-(int)zm2l(n)-1; |
| while(j){ |
| vumax=zumrshift(vumax,char_bit); |
| j--; |
| } |
| *out=zum2zuc(vumax); |
| return 1; |
| }else |
| return 0; |
| } |
| |
| zumax get_clist_int(type *t, const_list *cl, zmax n, int sz,int *state) |
| /* yields an integer of size sz from offset n */ |
| { |
| zuchar zuc; |
| zumax val = ZU0; |
| |
| if(LITTLEENDIAN) |
| n=zmadd(n,l2zm((long)(sz-1))); |
| |
| while(sz){ |
| val=zumlshift(val,char_bit); |
| if(!get_clist_byte(t,cl,n,&zuc)) {*state=0;return ZU0;} |
| val=zumadd(val,zuc2zum(zuc)); |
| sz--; |
| n=LITTLEENDIAN?zmsub(n,Z1):zmadd(n,Z1); |
| } |
| *state=1; |
| return val; |
| } |
| |
| int get_clist_byte(type *t,const_list *cl, zmax n, zuchar *out) |
| /* Yields byte n from a const list */ |
| { |
| if(!cl){ |
| *out=zum2zuc(ul2zum(0UL)); |
| return 1; |
| } |
| |
| if(ISARRAY(t->flags)){ |
| zmax i,j,x; |
| x=szof(t->next); |
| i=zmdiv(n,x); |
| while(1){ |
| if(!cl) break; |
| if(zmleq(i,cl->idx)) break; |
| cl=cl->next; |
| } |
| if(!cl||!zmeqto(cl->idx,i)){ |
| *out=zum2zuc(ul2zum(0UL)); |
| return 1; |
| } |
| return get_clist_byte(t->next,cl->other,zmmod(n,x),out); |
| } |
| if(ISUNION(t->flags)){ |
| int i=zm2l(cl->idx); |
| if(cl->tree) return 0; |
| return get_clist_byte((*t->exact->sl)[i].styp,cl->other,n,out); |
| } |
| if(ISSTRUCT(t->flags)){ |
| zmax al;int fl;type *st; |
| int i,bfo,bfs;zmax sz;zumax bfval=ul2zum(0UL); |
| |
| sz=l2zm(0L); |
| if(cl&&cl->tree){ |
| /* initialized by another */ |
| return 0; |
| }else{ |
| for(i=0;i<t->exact->count&&cl;i++){ |
| if(!cl->other){ierror(0);} |
| st=(*t->exact->sl)[i].styp; |
| al=(*t->exact->sl)[i].align; |
| if(!(*t->exact->sl)[i].identifier) ierror(0); |
| bfo=(*t->exact->sl)[i].bfoffset; |
| if(!zmeqto(zmmod(sz,al),l2zm(0L))){ |
| sz=zmadd(sz,zmsub(al,zmmod(sz,al))); |
| if(!zmleq(sz,n)){ |
| *out=zum2zuc(ul2zum(0L)); |
| return 1; |
| } |
| } |
| if(bfo>=0){ |
| /* bitfield */ |
| |
| if((*t->exact->sl)[i].identifier[0]){ |
| bfs=(*t->exact->sl)[i].bfsize; |
| if(zmeqto(l2zm((long)i),cl->idx)){ |
| eval_const(&cl->other->val,st->flags); |
| cl=cl->next; |
| }else{ |
| vumax=ul2zum(0UL); |
| } |
| vumax=zumand(vumax,zumsub(zumlshift(ul2zum(1UL),ul2zum((unsigned long)bfs)),ul2zum(1UL))); |
| bfval=zumor(bfval,zumlshift(vumax,ul2zum((unsigned long)bflayout(bfo,bfs,st->flags)))); |
| } |
| if(i+1>=t->exact->count||(*t->exact->sl)[i+1].bfoffset<=0||!cl){ |
| /* last bitfield in integer */ |
| gval.vumax=bfval; |
| eval_const(&gval,UNSIGNED|MAXINT); |
| insert_const(&gval,st->flags&NU); |
| bfval=ul2zum(0L); |
| sz=zmadd(sz,szof(st)); |
| if(!zmleq(sz,n)) |
| return get_scalar_byte(st->flags,&gval,zmsub(n,zmsub(sz,szof(st))),out); |
| } |
| }else{ |
| sz=zmadd(sz,szof(st)); |
| if(!zmleq(sz,n)){ |
| if(zmeqto(l2zm((long)i),cl->idx)){ |
| return get_clist_byte(st,cl->other,zmsub(n,zmsub(sz,szof(st))),out); |
| }else{ |
| *out=zum2zuc(ul2zum(0UL)); |
| return 1; |
| } |
| } |
| if(zmeqto(l2zm((long)i),cl->idx)) |
| cl=cl->next; |
| } |
| } |
| } |
| *out=zum2zuc(ul2zum(0UL)); |
| return 1; |
| } |
| |
| if(zmeqto(cl->idx,l2zm(-1L))) |
| return 0; |
| else{ |
| if(cl->tree) |
| return 0; |
| else |
| return get_scalar_byte(t->flags,&cl->val,n,out); |
| |
| } |
| ierror(0); |
| } |
| |
| type *new_typ(void) |
| /* Erzeigt neuen (leeren) Typ. */ |
| { |
| type *new=mymalloc(TYPS); |
| new->flags=0; |
| new->next=0; |
| new->exact=0; |
| new->attr=0; |
| new->dsize=0; |
| new->reg=0; |
| #ifdef HAVE_ECPP |
| /* removed */ |
| #endif |
| return new; |
| } |
| |
| type *clone_typ(type *old) |
| /* Erzeugt Kopie eines Typs und liefert Zeiger auf Kopie. */ |
| { |
| type *new; |
| if(!old) return 0; |
| new=new_typ(); |
| *new=*old; |
| if(old->attr){ |
| new->attr=mymalloc(strlen(old->attr)+1); |
| strcpy(new->attr,old->attr); |
| } |
| if(new->next) new->next=clone_typ(new->next); |
| return new; |
| } |
| Var *new_var(void) |
| { |
| Var *new=mymalloc(sizeof(*new)); |
| new->clist=0; |
| new->vtyp=0; |
| new->storage_class=0; |
| new->reg=0; |
| new->vattr=0; |
| new->next=0; |
| new->flags=0; |
| new->fi=0; |
| new->nesting=0; |
| new->filename=0; |
| new->line=0; |
| new->dfilename=0; |
| new->dline=0; |
| new->description=0; |
| new->tunit=0; |
| new->offset=l2zm(0L); |
| new->identifier=0; |
| #ifdef HAVE_TARGET_ATTRIBUTES |
| new->tattr=0; |
| #endif |
| #ifdef ALEX_REG |
| new->iRegCopyNr = -1; |
| new->iRegCopyNrHc12V = -1; |
| #endif |
| return new; |
| } |
| |
| IC *new_IC(void) |
| { |
| IC *p=mymalloc(ICS); |
| p->change_cnt=0; |
| p->use_cnt=0; |
| p->call_cnt=0; |
| p->arg_cnt=0; |
| p->use_list=0; |
| p->change_list=0; |
| p->call_list=0; |
| p->arg_list=0; |
| p->line=0; |
| p->file=0; |
| p->flags=0; |
| p->q1.flags=p->q2.flags=p->z.flags=0; |
| p->q1.am=p->q2.am=p->z.am=0; |
| p->q1.val.vmax=p->q2.val.vmax=p->z.val.vmax=l2zm(0L); |
| p->savedsp=0; |
| p->typf=p->typf2=0; |
| #ifdef ALEX_REG |
| p->iZWebIndex = -1; |
| p->iQ1WebIndex = -1; |
| p->iQ2WebIndex = -1; |
| p->pFlow = NULL; |
| #endif /* GC_RALLOC */ |
| |
| return p; |
| } |
| /* (partially) clones an IC list */ |
| IC *clone_ic(IC *p) |
| { |
| IC *new,*first,*last; |
| first=last=new=0; |
| while(p){ |
| new=mymalloc(sizeof(*new)); |
| *new=*p; |
| p->copy=new; |
| |
| if(p->q1.am||p->q2.am||p->z.am) ierror(0); |
| |
| if(new->code==CALL){ |
| int i; |
| new->arg_list=mymalloc(sizeof(*new->arg_list)*new->arg_cnt); |
| for(i=0;i<new->arg_cnt;i++){ |
| if(!p->arg_list[i]) |
| ierror(0); |
| if(!p->arg_list[i]->copy) |
| ierror(0); |
| new->arg_list[i]=p->arg_list[i]->copy; |
| } |
| } |
| new->prev=last; |
| new->next=0; |
| if(!first) first=new; |
| if(last) last->next=new; |
| last=new; |
| p=p->next; |
| } |
| return first; |
| } |
| void free_IC(IC *p) |
| /* Gibt IC-Liste inkl. Typen frei. */ |
| { |
| IC *merk; |
| if(DEBUG&1) printf("free_IC()\n"); |
| while(p){ |
| /*if(p->q1.am&&!p->q1.flags) ierror(0); |
| if(p->q2.am&&!p->q2.flags) ierror(0); |
| if(p->z.am&&!p->z.flags) ierror(0);*/ |
| |
| if(p->q1.am&&p->q1.am==p->q2.am) |
| ierror(0); |
| |
| if(p->q1.am) free(p->q1.am); |
| if(p->q2.am) free(p->q2.am); |
| if(p->z.am) free(p->z.am); |
| if(p->code==CALL) free(p->arg_list); |
| merk=p->next; |
| free(p); |
| p=merk; |
| } |
| } |
| void move_IC(IC *after,IC *p) |
| { |
| if(p->prev) |
| p->prev->next=p->next; |
| else |
| first_ic=p->next; |
| if(p->next) |
| p->next->prev=p->prev; |
| else |
| last_ic=p->prev; |
| insert_IC(after,p); |
| } |
| void remove_IC(IC *p) |
| /* Entfernt IC p aus Liste. */ |
| { |
| if(p->prev) p->prev->next=p->next; else first_ic=p->next; |
| if(p->next) p->next->prev=p->prev; else last_ic=p->prev; |
| if(p->q1.am) free(p->q1.am); |
| if(p->q2.am) free(p->q2.am); |
| if(p->z.am) free(p->z.am); |
| free(p); |
| } |
| void freetyp(type *p) |
| /* Gibt eine Typ-Liste frei, aber keine struct_declaration oder so. */ |
| { |
| int f;type *merk; |
| if(DEBUG&8){printf("freetyp: ");prd(stdout,p);printf("\n");} |
| while(p){ |
| merk=p->next; |
| f=p->flags&NQ; |
| if(merk&&!ISARRAY(f)&&!ISPOINTER(f)&&!ISFUNC(f)&&!ISVECTOR(f)) |
| ierror(0); |
| free(p->attr); |
| free(p); |
| p=merk; |
| } |
| } |
| |
| #ifndef HAVE_TGT_FALIGN |
| zmax falign(type *t) |
| /* Liefert Alignment eines Typs. Funktioniert im Gegensatz zum */ |
| /* align[]-Array auch mit zusammengesetzten Typen. */ |
| { |
| int i,f; zmax al,alt; |
| f=t->flags&NQ; |
| if(ISVECTOR(f)) return szof(t); |
| al=align[f]; |
| if(ISSCALAR(f)) return al; |
| if(ISARRAY(f)){ |
| do{ |
| t=t->next; |
| f=t->flags&NQ; |
| }while(ISARRAY(f)||ISVECTOR(f)); |
| alt=falign(t); |
| if(zmleq(al,alt)) return alt; else return al; |
| } |
| if(ISUNION(f)||ISSTRUCT(f)){ |
| if(!t->exact) ierror(0); |
| for(i=0;i<t->exact->count;i++){ |
| alt=(*t->exact->sl)[i].align; |
| if(!zmleq(alt,al)) al=alt; |
| } |
| } |
| return al; |
| } |
| #endif |
| |
| /* check, whether t is a variable length array */ |
| int is_vlength(type *t) |
| { |
| if(!ISARRAY(t->flags)) |
| return 0; |
| if(t->dsize) |
| return 1; |
| else |
| return is_vlength(t->next); |
| } |
| |
| /* calculate size of a variable length array */ |
| Var *vlength_szof(type *t) |
| { |
| IC *new;type *nt; |
| if(!ISARRAY(t->flags)) |
| ierror(0); |
| new=new_IC(); |
| new->code=MULT; |
| new->typf=HAVE_INT_SIZET?(UNSIGNED|INT):(UNSIGNED|LONG); |
| if(t->dsize){ |
| new->q1.flags=VAR; |
| new->q1.v=t->dsize; |
| new->q1.val.vmax=l2zm(0L); |
| }else{ |
| new->q1.flags=KONST; |
| #if HAVE_INT_SIZET |
| new->q1.val.vuint=zum2zui(zm2zum(t->size)); |
| #else |
| new->q1.val.vulong=zum2zul(zm2zum(t->size)); |
| #endif |
| } |
| new->z.flags=VAR; |
| nt=new_typ(); |
| nt->flags=new->typf; |
| new->z.v=add_tmp_var(nt); |
| new->z.val.vmax=l2zm(0L); |
| if(is_vlength(t->next)){ |
| new->q2.flags=VAR; |
| new->q2.v=vlength_szof(t->next); |
| new->q2.val.vmax=l2zm(0L); |
| }else{ |
| new->q2.flags=KONST; |
| #if HAVE_INT_SIZET |
| new->q2.val.vuint=zum2zui(zm2zum(szof(t->next))); |
| #else |
| new->q2.val.vulong=zum2zul(zm2zum(szof(t->next))); |
| #endif |
| } |
| add_IC(new); |
| return new->z.v; |
| } |
| |
| /* return the type of a d-dim vector of base type x */ |
| int mkvec(int x,int d) |
| { |
| int t=x&NQ,r; |
| if(d!=2&&d!=3&&d!=4&&d!=8&&d!=16) ierror(0); |
| switch(t){ |
| case BOOL: |
| r=VECBOOL;break; |
| case CHAR: |
| r=VECCHAR;break; |
| case SHORT: |
| r=VECSHORT;break; |
| case INT: |
| r=VECINT;break; |
| case LONG: |
| r=VECLONG;break; |
| case FLOAT: |
| r=VECFLOAT;break; |
| default: |
| ierror(0); |
| } |
| return (r+d-1)|(x&~NQ); |
| } |
| |
| /* return the base type of a vector */ |
| int VECTYPE(int x) |
| { |
| int t=x&NQ,r=0; |
| if(t>=VECBOOL&&t<=VECBOOL+MAXVECDIM) |
| r=BOOL; |
| if(t>=VECCHAR&&t<=VECCHAR+MAXVECDIM) |
| r=CHAR; |
| if(t>=VECSHORT&&t<=VECSHORT+MAXVECDIM) |
| r=SHORT; |
| if(t>=VECINT&&t<=VECINT+MAXVECDIM) |
| r=INT; |
| if(t>=VECLONG&&t<=VECLONG+MAXVECDIM) |
| r=LONG; |
| if(t>=VECFLOAT&&t<=VECFLOAT+MAXVECDIM) |
| r=FLOAT; |
| if(!r) ierror(0); |
| return r|(x&~NQ); |
| } |
| |
| |
| #ifndef HAVE_TGT_SZOF |
| zmax szof(type *t) |
| /* Liefert die benoetigte Groesse eines Typs in Bytes. */ |
| { |
| int i=t->flags&NQ,j;zmax size,m; |
| #ifdef HAVE_ECPP |
| /* removed */ |
| #endif |
| |
| if(ISSCALAR(i)) return sizetab[i]; |
| if(ISARRAY(i)){ |
| if(is_vlength(t)) |
| return sizetab[POINTER_TYPE(t->next)]; |
| size=zmmult((t->size),szof(t->next)); |
| m=align[ARRAY]; |
| return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */ |
| } |
| if(ISVECTOR(i)){ |
| zmax dim=VECDIM(i); |
| if(zmeqto(dim,l2zm(3L))) dim=l2zm(4L); |
| return zmmult(dim,sizetab[VECTYPE(i)&NQ]); |
| } |
| if(ISUNION(i)){ |
| for(j=0,size=l2zm(0L);j<t->exact->count;j++){ |
| m=szof((*t->exact->sl)[j].styp); |
| if(zmeqto(m,l2zm(0L))) return l2zm(0L); |
| if(!zmleq(m,size)) size=m; |
| } |
| m=falign(t); |
| return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */ |
| } |
| if(ISSTRUCT(i)){ |
| size=l2zm(0L); |
| #ifdef HAVE_ECPP |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| #endif |
| for(j=0;j<t->exact->count;j++){ |
| type *h=(*t->exact->sl)[j].styp; |
| if((*t->exact->sl)[j].bfoffset<=0){ |
| int n;size_t al; |
| al=(*t->exact->sl)[j].align; |
| #ifdef HAVE_ECPP |
| /* removed */ |
| #endif |
| if(zmeqto(al,l2zm(0L))) {prd(stdout,h);ierror(0);} |
| m=szof(h); |
| /* find the largest type in a bitfield */ |
| for(n=j+1;n<t->exact->count&&(*t->exact->sl)[n].bfoffset>0;n++){ |
| size_t tmp=szof((*t->exact->sl)[n].styp); |
| if(zmleq(m,tmp)) |
| m=tmp; |
| } |
| size=zmmult(zmdiv(zmadd(size,zmsub(al,l2zm(1L))),al),al); |
| /*if(zmeqto(m,l2zm(0L))) return l2zm(0L);*/ |
| size=zmadd(size,m); |
| } |
| } |
| m=falign(t); |
| return zmmult(zmdiv(zmadd(size,zmsub(m,l2zm(1L))),m),m); /* align */ |
| } |
| return sizetab[i]; |
| } |
| zmax struct_offset(struct_declaration *sd,const char *identifier) |
| { |
| int i=0,intbitfield=-1;zmax offset=l2zm(0),al; |
| while(i<sd->count&&strcmp((*sd->sl)[i].identifier,identifier)){ |
| if((*sd->sl)[i].bfoffset>=0){ |
| if(i+1<sd->count&&(*sd->sl)[i+1].bfoffset>0){ |
| i++; |
| continue; |
| } |
| } |
| al=(*sd->sl)[i].align; |
| offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al); |
| offset=zmadd(offset,szof((*sd->sl)[i].styp)); |
| i++; |
| } |
| if(i>=sd->count) {error(23,identifier);return l2zm(0L);} |
| al=(*sd->sl)[i].align; |
| offset=zmmult(zmdiv(zmadd(offset,zmsub(al,l2zm(1L))),al),al); |
| return offset; |
| } |
| #ifdef HAVE_ECPP |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| #endif |
| #endif |
| |
| #ifndef HAVE_TGT_PRINTVAL |
| void printval(FILE *f,union atyps *p,int t) |
| /* Gibt atyps aus. */ |
| { |
| t&=NU; |
| if(t==CHAR){fprintf(f,"C");vmax=zc2zm(p->vchar);printzm(f,vmax);} |
| if(t==(UNSIGNED|CHAR)){fprintf(f,"UC");vumax=zuc2zum(p->vuchar);printzum(f,vumax);} |
| if(t==SHORT){fprintf(f,"S");vmax=zs2zm(p->vshort);printzm(f,vmax);} |
| if(t==(UNSIGNED|SHORT)){fprintf(f,"US");vumax=zus2zum(p->vushort);printzum(f,vumax);} |
| if(t==FLOAT){fprintf(f,"F");vldouble=zf2zld(p->vfloat);printzld(f,vldouble);} |
| if(t==DOUBLE){fprintf(f,"D");vldouble=zd2zld(p->vdouble);printzld(f,vldouble);} |
| if(t==LDOUBLE){fprintf(f,"LD");printzld(f,p->vldouble);} |
| if(t==INT){fprintf(f,"I");vmax=zi2zm(p->vint);printzm(f,vmax);} |
| if(t==(UNSIGNED|INT)){fprintf(f,"UI");vumax=zui2zum(p->vuint);printzum(f,vumax);} |
| if(t==LONG){fprintf(f,"L");vmax=zl2zm(p->vlong);printzm(f,vmax);} |
| if(t==(UNSIGNED|LONG)){fprintf(f,"UL");vumax=zul2zum(p->vulong);printzum(f,vumax);} |
| if(t==LLONG){fprintf(f,"LL");vmax=zll2zm(p->vllong);printzm(f,vmax);} |
| if(t==(UNSIGNED|LLONG)){fprintf(f,"ULL");vumax=zull2zum(p->vullong);printzum(f,vumax);} |
| if(t==MAXINT){fprintf(f,"M");printzm(f,p->vmax);} |
| if(t==(UNSIGNED|MAXINT)){fprintf(f,"UM");printzum(f,p->vumax);} |
| /*FIXME*/ |
| if(t==POINTER){fprintf(f,"P");vumax=zul2zum(p->vulong);printzum(f,vumax);} |
| } |
| void emitval(FILE *f,union atyps *p,int t) |
| /* Gibt atyps aus. */ |
| { |
| t&=NU; |
| if(t==CHAR){vmax=zc2zm(p->vchar);emitzm(f,vmax);} |
| if(t==(UNSIGNED|CHAR)){vumax=zuc2zum(p->vuchar);emitzum(f,vumax);} |
| if(t==SHORT){vmax=zs2zm(p->vshort);emitzm(f,vmax);} |
| if(t==(UNSIGNED|SHORT)){vumax=zus2zum(p->vushort);emitzum(f,vumax);} |
| if(t==FLOAT){vldouble=zf2zld(p->vfloat);emitzld(f,vldouble);} |
| if(t==DOUBLE){vldouble=zd2zld(p->vdouble);emitzld(f,vldouble);} |
| if(t==LDOUBLE){emitzld(f,p->vldouble);} |
| if(t==INT){vmax=zi2zm(p->vint);emitzm(f,vmax);} |
| if(t==(UNSIGNED|INT)){vumax=zui2zum(p->vuint);emitzum(f,vumax);} |
| if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);} |
| if(t==(UNSIGNED|LONG)){vumax=zul2zum(p->vulong);emitzum(f,vumax);} |
| if(t==LLONG){vmax=zll2zm(p->vllong);emitzm(f,vmax);} |
| if(t==(UNSIGNED|LLONG)){vumax=zull2zum(p->vullong);emitzum(f,vumax);} |
| if(t==MAXINT){emitzm(f,p->vmax);} |
| if(t==(UNSIGNED|MAXINT)){emitzum(f,p->vumax);} |
| /*FIXME*/ |
| if(t==POINTER){vumax=zul2zum(p->vulong);emitzum(f,vumax);} |
| } |
| #endif |
| |
| void pric2(FILE *f,IC *p) |
| /* Gibt ein IC aus. */ |
| { |
| if(p->code>NOP) ierror(0); |
| if(p->next&&p->next->prev!=p) ierror(0); |
| if(p->code>=LABEL&&p->code<=BRA){ |
| if(p->code==LABEL) |
| fprintf(f,"L%d",p->typf); |
| else{ |
| fprintf(f,"\t%s L%d",ename[p->code],p->typf); |
| if(p->q1.flags){ fprintf(f,",");probj(f,&p->q1,0);} |
| } |
| if(p->code==LABEL&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (while-loop)"); |
| if(p->code==BRA&&(p->flags&LOOP_COND_TRUE)) fprintf(f," (to-loop-test)"); |
| }else{ |
| fprintf(f,"\t%s ",ename[p->code]); |
| if(p->typf&VOLATILE) fprintf(f,"volatile "); |
| if(p->typf&CONST) fprintf(f,"const "); |
| if(p->typf&UNSIGNED) fprintf(f,"unsigned "); |
| if(p->typf){ |
| if(ISVECTOR(p->typf)) |
| fprintf(f,"%s%d ",typname[VECTYPE(p->typf)&NQ],VECDIM(p->typf)); |
| else |
| fprintf(f,"%s ",typname[p->typf&NQ]); |
| } |
| probj(f,&p->q1,q1typ(p)); |
| if(p->q2.flags){fprintf(f,",");probj(f,&p->q2,q2typ(p));} |
| if(p->z.flags){fprintf(f,"->");probj(f,&p->z,ztyp(p));} |
| if(p->code==ASSIGN||p->code==PUSH||p->code==POP||p->code==CALL) |
| fprintf(f," size=%ld",zm2l(p->q2.val.vmax)); |
| if((p->code==SAVEREGS||p->code==RESTOREREGS)&&p->q1.reg) |
| fprintf(f," except %s",regnames[p->q1.reg]); |
| if(p->code==CONVERT) |
| fprintf(f," from %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]); |
| if(p->code==LSHIFT||p->code==RSHIFT) |
| fprintf(f," shift-type %s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]); |
| if(p->code==ADDI2P||p->code==SUBIFP||p->code==SUBPFP||p->code==ADDRESS) |
| fprintf(f," ptype=%s%s",(p->typf2&UNSIGNED)?"unsigned ":"",typname[p->typf2&NQ]); |
| if(p->code==ASSIGN||p->code==PUSH) |
| if(p->typf2) fprintf(f," align=%d\n",p->typf2); |
| } |
| if(p->code==CALL){ |
| fprintf(f," =>"); |
| if(p->call_cnt==0) |
| fprintf(f,"(unknown)"); |
| else{ |
| int i; |
| for(i=0;i<p->call_cnt;i++) |
| fprintf(f," %s",p->call_list[i].v->identifier); |
| } |
| |
| } |
| if(p->flags&EFF_IC) fprintf(f," (eff_ic)"); |
| fprintf(f,"\n"); |
| #if 0 |
| if(p->code==CALL){ |
| int i; |
| //fprintf(f,"c=%p\n",p); |
| for(i=0;i<p->arg_cnt;i++){ |
| //fprintf(f,"%p!\n",p->arg_list[i]); |
| fprintf(f,"%02d:",i); |
| pric2(f,p->arg_list[i]); |
| } |
| } |
| #endif |
| } |
| void pric(FILE *f,IC *p) |
| /* Gibt IC-Liste auf dem Bildschirm aus. */ |
| { |
| while(p){ |
| pric2(f,p); |
| /* if(p->q1.am||p->q2.am||p->z.am) ierror(0);*/ |
| p=p->next; |
| } |
| } |
| void printzm(FILE *f,zmax x) |
| /* Konvertiert zmax nach ASCII. */ |
| /* Basiert noch einigermassen auf */ |
| /* Zweierkomplementdarstellung (d.h. -MIN>MAX). */ |
| /* Ausserdem muss max(abs(max))<=max(unsigned max). */ |
| { |
| zmax zm;zumax zum; |
| zm=l2zm(0L); |
| if(zmleq(x,zm)&&!zmeqto(x,zm)){ |
| fprintf(f,"-");zm=zum2zm(t_max(MAXINT)); |
| if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){ |
| /* aufpassen, da -x evtl. >LONG_MAX */ |
| zum=t_max(MAXINT); |
| x=zmadd(x,zm); |
| }else |
| zum=ul2zum(0UL); |
| x=zmsub(l2zm(0L),x); |
| vumax=zm2zum(x); |
| zum=zumadd(zum,vumax); |
| }else |
| zum=zm2zum(x); |
| printzum(f,zum); |
| } |
| void printzum(FILE *f,zumax x) |
| /* Konvertiert zumax nach ASCII. */ |
| { |
| zumax zum;unsigned long l; |
| zum=ul2zum(10UL); |
| if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) printzum(f,zumdiv(x,zum)); |
| zum=zummod(x,zum);l=zum2ul(zum); |
| fprintf(f,"%c",(int)(l+'0')); |
| } |
| |
| void printzld(FILE *f,zldouble x) |
| /* Konvertiert zdouble nach ASCII, noch nicht fertig. */ |
| { |
| fprintf(f,"fp-constant"); |
| } |
| void emitzm(FILE *f,zmax x) |
| /* Konvertiert zmax nach ASCII. */ |
| /* Basiert noch einigermassen auf */ |
| /* Zweierkomplementdarstellung (d.h. -MIN>MAX). */ |
| /* Ausserdem muss max(abs(max))<=max(unsigned max). */ |
| { |
| zmax zm;zumax zum; |
| zm=l2zm(0L); |
| if(zmleq(x,zm)&&!zmeqto(x,zm)){ |
| emit(f,"-");zm=zum2zm(t_max(MAXINT)); |
| if(zmleq(x,zmsub(l2zm(0L),zm))&&!zmeqto(x,zmsub(l2zm(0L),zm))){ |
| /* aufpassen, da -x evtl. >LONG_MAX */ |
| zum=t_max(MAXINT); |
| x=zmadd(x,zm); |
| }else |
| zum=ul2zum(0UL); |
| x=zmsub(l2zm(0L),x); |
| vumax=zm2zum(x); |
| zum=zumadd(zum,vumax); |
| }else |
| zum=zm2zum(x); |
| emitzum(f,zum); |
| } |
| void emitzum(FILE *f,zumax x) |
| /* Konvertiert zumax nach ASCII. */ |
| { |
| zumax zum;unsigned long l; |
| zum=ul2zum(10UL); |
| if(!zumeqto(zumdiv(x,zum),ul2zum(0UL))) emitzum(f,zumdiv(x,zum)); |
| zum=zummod(x,zum);l=zum2ul(zum); |
| emit(f,"%c",(int)(l+'0')); |
| } |
| |
| void emitzld(FILE *f,zldouble x) |
| /* Konvertiert zdouble nach ASCII, noch nicht fertig. */ |
| { |
| emit(f,"fp-constant"); |
| } |
| |
| typedef struct memblock {struct memblock *next;void *p;} memblock; |
| static memblock *first_mb; |
| |
| static void add_mb(void *p) |
| { |
| memblock *mb_second=first_mb; |
| memblock *mb=malloc(sizeof(*mb)); |
| if(!mb){ |
| error(12); |
| raus(); |
| } |
| first_mb=mb; |
| mb->next=mb_second; |
| mb->p=p; |
| } |
| |
| static void remove_mb(void *p) |
| { |
| memblock *mb_prev=0; |
| memblock *mb=first_mb; |
| while(mb){ |
| if(mb->p==p){ |
| if(mb_prev==0) first_mb=mb->next; |
| else mb_prev->next=mb->next; |
| (free)(mb); |
| return; |
| } |
| mb_prev=mb; |
| mb=mb->next; |
| } |
| ierror(0); |
| } |
| |
| void *mymalloc(size_t size) |
| /* Allocate memory and quit on failure. */ |
| { |
| void *p; |
| if(dmalloc) |
| size+=sizeof(size); |
| else if(size==0) |
| /* Not very nice, but simplest way to avoid a failure when size==0. */ |
| size=1; |
| if(!(p=malloc(size))){ |
| error(12); |
| raus(); |
| } |
| if(DEBUG&32768){ |
| printf("malloc %p (s=%lu)\n",p,(unsigned long)size); |
| fflush(stdout); |
| } |
| if(DEBUG&65536) add_mb(p); |
| if(dmalloc){ |
| *(size_t *)p=size; |
| p=((char *)p)+sizeof(size); |
| memset(p,0xaa,size-sizeof(size)); |
| } |
| return p; |
| } |
| |
| void *myrealloc(void *p,size_t size) |
| /* Reallocate memory and quit on failure. */ |
| { |
| void *new; |
| if(!p) return mymalloc(size); |
| if(dmalloc){ |
| size+=sizeof(size); |
| new=realloc(((char *)p)-sizeof(size),size); |
| if(!new){ |
| error(12); |
| raus(); |
| } |
| if(DEBUG&32768){ |
| printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size); |
| fflush(stdout); |
| } |
| if(DEBUG&65536){ |
| remove_mb(p); |
| add_mb(new); |
| } |
| *(size_t *)new=size; |
| new=((char *)new)+sizeof(size); |
| return new; |
| }else{ |
| new=realloc(p,size); |
| if(!new){ |
| error(12); |
| raus(); |
| } |
| if(DEBUG&32768){ |
| printf("realloc %p to %p (s=%lu)\n",p,new,(unsigned long)size); |
| fflush(stdout); |
| } |
| if(DEBUG&65536){ |
| remove_mb(p); |
| add_mb(new); |
| } |
| return new; |
| } |
| } |
| |
| void myfree(void *p) |
| { |
| if(p&&dmalloc){ |
| p=((char*)p)-sizeof(size_t); |
| memset(p,0xbb,*(size_t *)(p)); |
| } |
| if(DEBUG&32768){ |
| printf("free %p\n",p); |
| fflush(stdout); |
| } |
| if((DEBUG&65536)&&p) remove_mb(p); |
| (free)(p); /* supp.h has #define free(x) myfree(x) */ |
| } |
| |
| char *mystrdup(char *p) |
| { |
| char *new=mymalloc(strlen(p)+1); |
| strcpy(new,p); |
| return new; |
| } |
| |
| /* Testet, ob zwei objs dieselben Register belegen. */ |
| int collides(obj *x,obj *y) |
| { |
| int x1,x2,y1,y2; |
| if(!(x->flags®)||!(y->flags®)) return 0; |
| if(reg_pair(x->reg,&rp)){ |
| x1=rp.r1;x2=rp.r2; |
| }else{ |
| x1=x->reg;x2=-1; |
| } |
| if(reg_pair(y->reg,&rp)){ |
| y1=rp.r1;y2=rp.r2; |
| }else{ |
| y1=y->reg;y2=-2; |
| } |
| if(x1==y1||x1==y2||x2==y1||x2==y2) |
| return 1; |
| else |
| return 0; |
| } |
| |
| /* Versucht, ein IC so zu drehen, dass q2 und z kein gemeinsames */ |
| /* Register belegen. Liefert Null, wenn das nicht moeglich ist. */ |
| int switch_IC(IC *p) |
| { |
| int c; |
| obj o; |
| if(!collides(&p->q2,&p->z)) return 1; |
| c=p->code; |
| if((c<OR||c>AND)&&c!=ADD&&c!=MULT&&c!=ADDI2P) return 0; |
| if(c==ADDI2P&&must_convert(q1typ(p),q2typ(p),0)) return 0; |
| if(collides(&p->q1,&p->z)) return 0; |
| o=p->q2;p->q2=p->q1;p->q1=o; |
| return 1; |
| } |
| |
| void probj(FILE *f,obj *p,int t) |
| /* Gibt Objekt auf Bildschirm aus. */ |
| { |
| if(p->am){ fprintf(f,"[tgt-addressing-mode]");return;} |
| if(p->flags&DREFOBJ){ |
| fprintf(f,"(["); |
| if(p->dtyp&CONST) fprintf(f,"const "); |
| if(p->dtyp&VOLATILE) fprintf(f,"volatile "); |
| if(p->dtyp&PVOLATILE) fprintf(f,"pvolatile "); |
| fprintf(f,"%s]",typname[p->dtyp&NQ]); |
| } |
| if(p->flags&VARADR) fprintf(f,"#"); |
| if(p->flags&VAR) { |
| if(!(p->flags®)) |
| printval(f,&p->val,MAXINT); |
| if(p->flags®){ |
| fprintf(f,"%s",regnames[p->reg]); |
| }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){ |
| fprintf(f,"+%ld(FP)", zm2l(p->v->offset)); |
| }else{ |
| if(p->v->storage_class==STATIC){ |
| fprintf(f,"+L%ld",zm2l(p->v->offset)); |
| }else{ |
| fprintf(f,"+_%s",p->v->identifier); |
| } |
| } |
| if(*p->v->identifier) |
| fprintf(f,"(%s)",p->v->identifier); |
| else if(p->v->description) |
| fprintf(f,"(%s)",p->v->description); |
| else |
| fprintf(f,"(%p)",(void *)p->v); |
| if(p->v->reg) fprintf(f,":%s",regnames[abs(p->v->reg)]); |
| } |
| if((p->flags®)&&!(p->flags&VAR)) fprintf(f,"%s",regnames[p->reg]); |
| if(p->flags&KONST){ |
| fprintf(f,"#"); |
| if(p->flags&DREFOBJ) |
| printval(f,&p->val,p->dtyp&NU); |
| else |
| printval(f,&p->val,t&NU); |
| } |
| if(p->flags&SCRATCH) fprintf(f,"[S]"); |
| if(p->flags&DREFOBJ) fprintf(f,")"); |
| } |
| void prl(FILE *o,struct_declaration *p) |
| /* Gibt eine struct_declaration auf dem Bildschirm aus. */ |
| { |
| int i; |
| static int recurse=2; |
| int merk_recurse=recurse; |
| --recurse; |
| #ifdef HAVE_ECPP |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| #endif |
| for(i=0;i<p->count;i++){ |
| fprintf(o," %d.:",i); |
| if(recurse>=0){ |
| if((*p->sl)[i].identifier)fprintf(o," ident: %s; ",(*p->sl)[i].identifier); |
| prd(o,(*p->sl)[i].styp); |
| } |
| } |
| recurse=merk_recurse; |
| } |
| void prd(FILE *o,type *p) |
| /* Gibt einen Typ auf dem Bildschirm aus. */ |
| { |
| int f; |
| if(!p) {fprintf(o,"empty type ");return;} |
| f=p->flags; |
| /* fprintf(o,"(Sizeof=%ld,flags=%d)",zl2l(szof(p)),f);*/ |
| /* if(type_uncomplete(p)) {fprintf(o,"incomplete ");}*/ |
| if(f&CONST) {fprintf(o,"const ");f&=~CONST;} |
| if(f&STRINGCONST) {fprintf(o,"string-const ");f&=~STRINGCONST;} |
| if(f&VOLATILE) {fprintf(o,"volatile ");f&=~VOLATILE;} |
| if(f&UNSIGNED) {fprintf(o,"unsigned ");f&=~UNSIGNED;} |
| if(p->attr) fprintf(o,"attr(%s) ",p->attr); |
| if(p->reg) fprintf(o,"reg(%s) ",regnames[p->reg]); |
| if(ISFUNC(f)){ |
| fprintf(o,"%s with parameters (",typname[f&NQ]); |
| prl(o,p->exact); |
| fprintf(o,") returning ");prd(o,p->next);return; |
| } |
| if(ISSTRUCT(f)||ISUNION(f)){ |
| fprintf(o,"%s with components {",typname[f&NQ]); |
| prl(o,p->exact); fprintf(o,"} "); |
| return; |
| } |
| if(ISPOINTER(f)) {fprintf(o,"%s to ",typname[f&NQ]);prd(o,p->next);return;} |
| if(ISARRAY(f)) {fprintf(o,"%s [size %ld] of ",typname[f&NQ],zm2l(p->size));prd(o,p->next);return;} |
| if(ISVECTOR(f)) {fprintf(o,"vector [size %ld] of %s",zm2l(p->size),typname[VECTYPE(f)&NQ]);return;} |
| |
| fprintf(o,"%s",typname[f&NQ]); |
| } |
| void print_var(FILE *o,Var *p) |
| /* Gibt eine Variable aus. */ |
| { |
| if(p->identifier&&*p->identifier){ |
| fprintf(o, "ident: %s: ", p->identifier); |
| } |
| prd(o, p->vtyp); |
| } |
| |
| /* returns the first base Type in an compound type */ |
| int get_first_base_type(type *t) |
| { |
| if (!t) return 0; |
| if (ISARRAY(t->flags)) { |
| return get_first_base_type(t->next); |
| } else if ((ISSTRUCT(t->flags)) || (ISUNION(t->flags))) { |
| return get_first_base_type((*t->exact->sl)[0].styp); |
| } else return t->flags; |
| } |
| |
| |
| #ifndef HAVE_EXT_TYPES |
| |
| void insert_const(union atyps *p,int t) |
| /* Traegt Konstante in entprechendes Feld ein. */ |
| { |
| if(!p) ierror(0); |
| t&=NU; |
| if(t==CHAR) {p->vchar=vchar;return;} |
| if(t==SHORT) {p->vshort=vshort;return;} |
| if(t==INT) {p->vint=vint;return;} |
| if(t==LONG) {p->vlong=vlong;return;} |
| if(t==LLONG) {p->vllong=vllong;return;} |
| if(t==MAXINT) {p->vmax=vmax;return;} |
| if(t==(UNSIGNED|CHAR)) {p->vuchar=vuchar;return;} |
| if(t==(UNSIGNED|SHORT)) {p->vushort=vushort;return;} |
| if(t==(UNSIGNED|INT)) {p->vuint=vuint;return;} |
| if(t==(UNSIGNED|LONG)) {p->vulong=vulong;return;} |
| if(t==(UNSIGNED|LLONG)) {p->vullong=vullong;return;} |
| if(t==(UNSIGNED|MAXINT)) {p->vumax=vumax;return;} |
| if(t==FLOAT) {p->vfloat=vfloat;return;} |
| if(t==DOUBLE) {p->vdouble=vdouble;return;} |
| if(t==LDOUBLE) {p->vldouble=vldouble;return;} |
| if(t==POINTER) {p->vulong=vulong;return;} |
| } |
| void eval_const(union atyps *p,int t) |
| /* Weist bestimmten globalen Variablen Wert einer CEXPR zu. */ |
| { |
| int f=t&NQ; |
| if(!p) ierror(0); |
| if(f==MAXINT||(f>=CHAR&&f<=LLONG)){ |
| if(!(t&UNSIGNED)){ |
| if(f==CHAR) vmax=zc2zm(p->vchar); |
| else if(f==SHORT)vmax=zs2zm(p->vshort); |
| else if(f==INT) vmax=zi2zm(p->vint); |
| else if(f==LONG) vmax=zl2zm(p->vlong); |
| else if(f==LLONG) vmax=zll2zm(p->vllong); |
| else if(f==MAXINT) vmax=p->vmax; |
| else ierror(0); |
| vumax=zm2zum(vmax); |
| vldouble=zm2zld(vmax); |
| }else{ |
| if(f==CHAR) vumax=zuc2zum(p->vuchar); |
| else if(f==SHORT)vumax=zus2zum(p->vushort); |
| else if(f==INT) vumax=zui2zum(p->vuint); |
| else if(f==LONG) vumax=zul2zum(p->vulong); |
| else if(f==LLONG) vumax=zull2zum(p->vullong); |
| else if(f==MAXINT) vumax=p->vumax; |
| else ierror(0); |
| vmax=zum2zm(vumax); |
| vldouble=zum2zld(vumax); |
| } |
| }else{ |
| if(ISPOINTER(f)){ |
| vumax=zul2zum(p->vulong); |
| vmax=zum2zm(vumax);vldouble=zum2zld(vumax); |
| }else{ |
| if(f==FLOAT) vldouble=zf2zld(p->vfloat); |
| else if(f==DOUBLE) vldouble=zd2zld(p->vdouble); |
| else vldouble=p->vldouble; |
| vmax=zld2zm(vldouble); |
| vumax=zld2zum(vldouble); |
| } |
| } |
| vfloat=zld2zf(vldouble); |
| vdouble=zld2zd(vldouble); |
| vuchar=zum2zuc(vumax); |
| vushort=zum2zus(vumax); |
| vuint=zum2zui(vumax); |
| vulong=zum2zul(vumax); |
| vullong=zum2zull(vumax); |
| vchar=zm2zc(vmax); |
| vshort=zm2zs(vmax); |
| vint=zm2zi(vmax); |
| vlong=zm2zl(vmax); |
| vllong=zm2zll(vmax); |
| } |
| #endif |
| |
| function_info *new_fi(void) |
| /* Belegt neue function_info-Struktur und initialisiert sie. */ |
| { |
| function_info *new; |
| new=mymalloc(sizeof(*new)); |
| new->first_ic=new->last_ic=new->opt_ic=0; |
| new->vars=0; |
| new->statics=0; |
| new->inline_asm=0; |
| new->flags=0; |
| new->call_cnt=new->use_cnt=new->change_cnt=0; |
| new->call_list=new->use_list=new->change_list=0; |
| memset(new->regs_modified,0,sizeof(new->regs_modified)); |
| #if HAVE_OSEK |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| #endif |
| new->stack1=ul2zum(0UL); |
| new->stack2=ul2zum(0UL); |
| new->inline_size=-1; |
| new->inline_depth=0; |
| return new; |
| } |
| void free_fi(function_info *p) |
| /* Gibt ein function_info mit Inhalt frei. */ |
| { |
| if(p->first_ic) free_IC(p->first_ic); |
| if(p->opt_ic) free_IC(p->opt_ic); |
| if(p->vars) free_var(p->vars); |
| /* do not free statics */ |
| free(p->call_list); |
| free(p->use_list); |
| free(p->change_list); |
| free(p->inline_asm); |
| free(p); |
| } |
| |
| void print_fi(FILE *f,function_info *p) |
| /* Gibt function_info aus. */ |
| { |
| int i; |
| fprintf(f,"function_info:\n"); |
| if(p->first_ic){ |
| IC *ic=p->first_ic; |
| fprintf(f," inline_code:\n"); |
| pric2(f,ic); |
| while(ic!=p->last_ic){ |
| ic=ic->next; |
| pric2(f,ic); |
| } |
| } |
| if(p->inline_asm) |
| fprintf(f," inline_asm:\n%s\n",p->inline_asm); |
| if(p->flags&ALL_CALLS) |
| fprintf(f," all calls have been evaluated\n"); |
| if(p->flags&ALL_USES) |
| fprintf(f," all uses have been evaluated\n"); |
| if(p->flags&ALL_MODS) |
| fprintf(f," all changes have been evaluated\n"); |
| if(p->flags&ALL_REGS){ |
| fprintf(f," all reg-changes have been evaluated\n"); |
| for(i=1;i<=MAXR;i++) |
| if(BTST(p->regs_modified,i)) fprintf(f," %s\n",regnames[i]); |
| } |
| fprintf(f," call_list:\n");print_varlist(f,p->call_list,p->call_cnt); |
| fprintf(f," use_list:\n");print_varlist(f,p->use_list,p->use_cnt); |
| fprintf(f," change_list:\n");print_varlist(f,p->change_list,p->change_cnt); |
| if(p->flags&ALL_STACK){ |
| fprintf(f,"stack1: ");printzum(f,p->stack1);fprintf(f,"\n"); |
| fprintf(f,"stack2: ");printzum(f,p->stack2);fprintf(f,"\n"); |
| } |
| if(p->flags&NEVER_RETURNS) |
| fprintf(f," never returns\n"); |
| if(p->flags&ALWAYS_RETURNS) |
| fprintf(f," always returns\n"); |
| if(p->flags&NOSIDEFX) |
| fprintf(f," no side effects\n"); |
| } |
| |
| void print_varlist(FILE *f,varlist *p,int n) |
| { |
| int i; |
| char *s; |
| for(i=0;i<n;i++){ |
| if(p[i].v) s=p[i].v->identifier; else s="<unknown>"; |
| fprintf(f," %s(%p), flags=%d\n",s,(void*)p[i].v,p[i].flags); |
| } |
| } |
| |
| int is_const(type *t) |
| /* tested, ob ein Typ konstant (und damit evtl. in der Code-Section) ist */ |
| { |
| if(!(t->flags&(CONST|STRINGCONST))){ |
| do{ |
| if(t->flags&(CONST|STRINGCONST)) return(1); |
| if((t->flags&NQ)!=ARRAY) return 0; |
| t=t->next; |
| }while(1); |
| }else return 1; |
| } |
| |
| /* is object volatile? */ |
| int is_volatile_obj(obj *o) |
| { |
| if(o->flags&DREFOBJ){ |
| if(o->dtyp&(VOLATILE|PVOLATILE)){ |
| return 1; |
| } |
| if((o->flags&VAR)&&ISPOINTER(o->v->vtyp->flags)&&(o->v->vtyp->next->flags&VOLATILE)){ |
| return 1; |
| } |
| } |
| if(o->flags&VAR){ |
| return o->v->vtyp->flags&VOLATILE; |
| }else{ |
| return 0; |
| } |
| } |
| |
| /* is IC volatile? */ |
| int is_volatile_ic(IC *p) |
| { |
| if(p->q1.flags){ |
| if(is_volatile_obj(&p->q1)||(q1typ(p)&VOLATILE)) return 1; |
| } |
| if(p->q2.flags){ |
| if(is_volatile_obj(&p->q2)||(q2typ(p)&VOLATILE)) return 1; |
| } |
| if(p->z.flags){ |
| if(is_volatile_obj(&p->z)||(ztyp(p)&VOLATILE)) return 1; |
| } |
| return 0; |
| } |
| |
| /* removes last asm-line from emit-buffer */ |
| void remove_asm(void) |
| { |
| emit_l--; |
| if(emit_l<0) emit_l=EMIT_BUF_DEPTH-1; |
| } |
| |
| /* flush the asm-output buffer */ |
| void emit_flush(FILE *f) |
| { |
| if(!f||no_emit) return; |
| while(emit_f!=emit_l){ |
| fputs(emit_buffer[emit_f],f); |
| emit_f++; |
| if(emit_f>=EMIT_BUF_DEPTH) emit_f=0; |
| } |
| emit_l=emit_f=0; |
| emit_p=emit_buffer[0]; |
| } |
| |
| /* emit inline-asm, depending on no_inline_peephole, feed it through |
| asm_peephole() or flush the buffer and print it directly to the file */ |
| void emit_inline_asm(FILE *f,char *p) |
| { |
| if(!f||no_emit) return; |
| if(no_inline_peephole){ |
| emit_flush(f); |
| fprintf(f,"%s\n",p); |
| }else{ |
| while(*p){ |
| emit(f,"%c",*p++); |
| } |
| emit(f,"\n"); |
| } |
| } |
| |
| /* print output; this is only to be used for assembly output! */ |
| void emit(FILE *f,const char *fmt,...) |
| { |
| static char tmp[EMIT_BUF_LEN]; |
| char *p; |
| va_list vl; |
| if(!f||no_emit) return; |
| va_start(vl,fmt); |
| vsprintf(tmp,fmt,vl); |
| p=tmp; |
| while(*p){ |
| *emit_p++=*p++; |
| if(p[-1]=='\n'){ |
| *emit_p=0; |
| #if HAVE_TARGET_PEEPHOLE |
| while(emit_peephole()); |
| #endif |
| emit_l++; |
| if(emit_l>=EMIT_BUF_DEPTH) emit_l=0; |
| emit_p=emit_buffer[emit_l]; |
| if(emit_l==emit_f){ |
| /* FIXME: error check */ |
| fputs(emit_buffer[emit_f],f); |
| emit_f++; |
| if(emit_f>=EMIT_BUF_DEPTH) emit_f=0; |
| } |
| } |
| } |
| *emit_p=0; |
| } |
| |
| void emit_char(FILE *f,int c) |
| { |
| static char tmp[2]; |
| tmp[0]=c; |
| emit(f,tmp); |
| } |
| |
| /* detect whether the following code resembles a switch-case-statement */ |
| /* will return the longest sequence which has at least min_density */ |
| case_table *calc_case_table(IC *p,double min_density) |
| { |
| static case_table ct; |
| obj *o,*ccr; |
| static union atyps *vals; |
| union atyps min,max; |
| zumax diff; |
| static int *labels,cur_size; |
| double cur_density; |
| int t,j,num; |
| if(p->code!=COMPARE||!(p->q2.flags&KONST)) |
| return 0; |
| o=&p->q1;t=p->typf; |
| if(!ISINT(t)||(t&VOLATILE)) return 0; |
| num=0; |
| ct.num=0; |
| if(t&UNSIGNED){ |
| max.vumax=t_min(UNSIGNED|MAXINT); |
| min.vumax=t_max(UNSIGNED|MAXINT); |
| }else{ |
| max.vmax=t_min(MAXINT); |
| min.vmax=t_max(MAXINT); |
| } |
| while(p&&p->code==COMPARE&&(p->q2.flags&KONST)&&p->typf==t&&objs_equal(o,&p->q1,t)){ |
| zumax zum;zmax zm; |
| if(multiple_ccs) ccr=&p->z; |
| if(num>=cur_size){ |
| cur_size+=64; |
| labels=myrealloc(labels,cur_size*sizeof(*labels)); |
| vals=myrealloc(vals,cur_size*sizeof(*vals)); |
| } |
| for(j=0;j<num;j++){ |
| if(!compare_const(&vals[j],&p->q2.val,t)){ |
| return 0; /* FIXME? Could simply ignore? */ |
| } |
| } |
| vals[num]=p->q2.val; |
| p=p->next; |
| while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next; |
| if(p->code!=BEQ||(multiple_ccs&&!objs_equal(ccr,&p->q1,0))) break; |
| labels[num]=p->typf; |
| p=p->next; |
| while(p&&(p->code==NOP||p->code==ALLOCREG||p->code==FREEREG)) p=p->next; |
| eval_const(&vals[num],t); |
| num++; |
| if(t&UNSIGNED){ |
| if(zumleq(vumax,min.vumax)) |
| insert_const(&min,UNSIGNED|MAXINT); |
| if(zumleq(max.vumax,vumax)) |
| insert_const(&max,UNSIGNED|MAXINT); |
| cur_density=num/(1+zld2d(zum2zld(zumsub(max.vumax,min.vumax)))); |
| if(cur_density>=min_density){ |
| ct.num=num; |
| ct.next_ic=p; |
| ct.min=min; |
| ct.max=max; |
| ct.diff=zumsub(max.vumax,min.vumax); |
| ct.density=cur_density; |
| } |
| }else{ |
| if(zmleq(vmax,min.vmax)) |
| insert_const(&min,MAXINT); |
| if(zmleq(max.vmax,vmax)) |
| insert_const(&max,MAXINT); |
| cur_density=num/zld2d(zum2zld((1+zumsub(zm2zum(max.vmax),zm2zum(min.vmax))))); |
| if(cur_density>=min_density){ |
| ct.num=num; |
| ct.next_ic=p; |
| ct.min=min; |
| ct.max=max; |
| ct.diff=zumsub(zm2zum(max.vmax),zm2zum(min.vmax)); |
| ct.density=cur_density; |
| } |
| } |
| } |
| ct.vals=vals; |
| ct.labels=labels; |
| ct.typf=t; |
| return &ct; |
| } |
| |
| /* emit a list of jump-table entries */ |
| void emit_jump_table(FILE *f,case_table *ct,char *da,char *labprefix,int defl) |
| { |
| unsigned long l,e; |
| int i; |
| zmax zm;zumax zum; |
| if(ct->typf&UNSIGNED){ |
| zum=ct->min.vumax; |
| zm=zum2zm(zum); |
| }else{ |
| zm=ct->min.vmax; |
| zum=zm2zum(zm); |
| } |
| e=zum2ul(ct->diff); |
| for(l=0;l<=e;l++){ |
| emit(f,"%s",da); |
| for(i=0;i<ct->num;i++){ |
| eval_const(&ct->vals[i],ct->typf); |
| if(zmeqto(vmax,zm)&&zumeqto(vumax,zum)){ |
| emit(f,"%s%d\n",labprefix,ct->labels[i]); |
| break; |
| } |
| } |
| if(i>=ct->num) |
| emit(f,"%s%d\n",labprefix,defl); |
| zm=zmadd(zm,l2zm(1L)); |
| zum=zumadd(zum,ul2zum(1UL)); |
| } |
| } |
| /* display warnings if specified stack-size cannot be guaranteed */ |
| void static_stack_check(Var *v) |
| { |
| /*FIXME*/ |
| } |
| |
| #ifdef HAVE_REGPARMS |
| /* return the offset of the first variable-argument-macro to the |
| beginning of the argument-area (i.e. the space occupied by |
| normal arguments on the stack */ |
| zmax va_offset(Var *v) |
| { |
| int i; |
| zmax offset=l2zm(0L); |
| static type rp={0}; |
| treg_handle rh=empty_reg_handle; |
| if((v->vtyp->next->flags&NQ)!=VOID&&!freturn(v->vtyp->next)){ |
| rp.next=v->vtyp->next; |
| rp.flags=POINTER_TYPE(v->vtyp->next); |
| if(!reg_parm(&rh,&rp,0,v->vtyp)){ |
| ierror(0); |
| } |
| } |
| for(i=0;i<v->vtyp->exact->count;i++){ |
| #if 0 |
| if((*v->vtyp->exact->sl)[i].reg!=0) |
| continue; |
| #endif |
| if(((*v->vtyp->exact->sl)[i].styp->flags&NQ)==VOID) |
| ierror(0); |
| if(reg_parm(&rh,(*v->vtyp->exact->sl)[i].styp,0,v->vtyp)!=0) |
| continue; |
| offset=zmadd(offset,szof((*v->vtyp->exact->sl)[i].styp)); |
| offset=zmmult(zmdiv(zmadd(offset,zmsub(stackalign,l2zm(1L))),stackalign),stackalign); |
| } |
| return offset; |
| } |
| #endif |
| |
| /* We provide an own qsort to get reproducable results. */ |
| void vqsort (void *base,size_t nmemb,size_t size,int (*compar)(const void *,const void *)) |
| { char *base2=(char *)base; |
| char tmp; |
| size_t i,a,b,c; |
| while(nmemb>1) |
| { a=0; |
| b=nmemb-1; |
| c=(a+b)/2; /* Middle element */ |
| for(;;) |
| { while((*compar)(&base2[size*c],&base2[size*a])>0) |
| a++; /* Look for one >= middle */ |
| while((*compar)(&base2[size*c],&base2[size*b])<0) |
| b--; /* Look for one <= middle */ |
| if(a>=b) |
| break; /* We found no pair */ |
| for(i=0;i<size;i++) /* swap them */ |
| { tmp=base2[size*a+i]; |
| base2[size*a+i]=base2[size*b+i]; |
| base2[size*b+i]=tmp; } |
| if(c==a) /* Keep track of middle element */ |
| c=b; |
| else if(c==b) |
| c=a; |
| a++; /* These two are already sorted */ |
| b--; |
| } /* a points to first element of right intervall now (b to last of left) */ |
| b++; |
| if(b<nmemb-b) /* do recursion on smaller intervall and iteration on larger one */ |
| { vqsort(base2,b,size,compar); |
| base2=&base2[size*b]; |
| nmemb=nmemb-b; |
| } |
| else |
| { vqsort(&base2[size*b],nmemb-b,size,compar); |
| nmemb=b; } |
| } |
| return; |
| } |
| |
| /* calculates registers used by this call IC |
| returns 0 if not possible */ |
| int calc_regs(IC *p,int showwarnings) |
| { |
| int i; |
| if(p->call_cnt){ |
| for(i=0;i<p->call_cnt;i++){ |
| if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_REGS)){ |
| bvunite(regs_modified,p->call_list[i].v->fi->regs_modified,RSIZE); |
| #if HAVE_OSEK |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| #endif |
| }else{ |
| int r; |
| for(r=1;r<=MAXR;r++) if(regscratch[r]) BSET(regs_modified,r); |
| err_ic=p; |
| if(!p->call_list[i].v->fi) p->call_list[i].v->fi=new_fi(); |
| if(!(p->call_list[i].v->fi->flags&WARNED_REGS)){ |
| error(318,p->call_list[i].v->identifier); |
| p->call_list[i].v->fi->flags|=WARNED_REGS; |
| } |
| return 0; |
| } |
| } |
| return 1; |
| } |
| err_ic=p;if(showwarnings) error(320); |
| return 0; |
| } |
| |
| |
| |
| #ifndef HAVE_TARGET_BFLAYOUT |
| int bflayout(int bfoffset,int bfsize,int t) |
| { |
| if(BIGENDIAN) |
| return (int)zm2l(zmmult(sizetab[t&NQ],char_bit))-bfoffset-bfsize; |
| else |
| return bfoffset; |
| } |
| #endif |
| |
| long get_pof2(zumax x) |
| /* Yields log2(x)+1 oder 0. */ |
| { |
| zumax p;int ln=1,max=(int)zm2l(zmmult(sizetab[LLONG],char_bit)); |
| p=ul2zum(1L); |
| while(ln<=max&&zumleq(p,x)){ |
| if(zumeqto(x,p)) return ln; |
| ln++;p=zumadd(p,p); |
| } |
| return 0; |
| } |
| |
| /* check if type is a varargs function */ |
| int is_varargs(type *t) |
| { |
| int c; |
| if(t->exact&&(c=t->exact->count)!=0&&(*t->exact->sl)[c-1].styp->flags!=VOID) |
| return 1; |
| else |
| return 0; |
| } |
| |
| /* add string to type- oder variable-aatribute */ |
| void add_attr(char **attr,char *new) |
| { |
| int ln,lo; |
| if(!new) return; |
| if(*attr&&strstr(*attr,new)) return; |
| if(add_attr_haddecl&&(!*attr||!strstr(*attr,new))) error(371,add_attr_haddecl->identifier,new); |
| ln=strlen(new); |
| if(*attr){ |
| lo=strlen(*attr); |
| *attr=myrealloc(*attr,lo+ln+2); |
| }else{ |
| lo=0; |
| *attr=mymalloc(ln+2); |
| } |
| (*attr)[lo]=';'; |
| strcpy(*attr+lo+1,new); |
| } |
| |
| |
| hashtable *new_hashtable(size_t size) |
| { |
| hashtable *new = mymalloc(sizeof(*new)); |
| |
| new->size = size; |
| new->collisions = 0; |
| new->entries = mymalloc(size*sizeof(*new->entries)); |
| memset(new->entries,0,size*sizeof(*new->entries)); |
| return new; |
| } |
| |
| size_t hashcode(char *name) |
| { |
| size_t h = 5381; |
| int c; |
| |
| while (c = (unsigned char)*name++) |
| h = ((h << 5) + h) + c; |
| return h; |
| } |
| |
| /* add to hashtable; name must be unique */ |
| void add_hashentry(hashtable *ht,char *name,hashdata data) |
| { |
| size_t i=(hashcode(name)%ht->size); |
| hashentry *new=mymalloc(sizeof(*new)); |
| new->name=name; |
| new->data=data; |
| if(DEBUG&1){ |
| if(ht->entries[i]) |
| ht->collisions++; |
| } |
| new->next=ht->entries[i]; |
| ht->entries[i]=new; |
| } |
| |
| /* finds unique entry in hashtable */ |
| hashdata find_name(hashtable *ht,char *name) |
| { |
| size_t i=hashcode(name)%ht->size; |
| hashentry *p; |
| for(p=ht->entries[i];p;p=p->next){ |
| if(!strcmp(name,p->name)){ |
| return p->data; |
| }else |
| ht->collisions++; |
| } |
| return 0; |
| } |
| |
| #ifndef CHARBACK |
| unsigned char CHARBACK(unsigned char x) |
| { |
| static unsigned char tab[256],init=0; |
| if(!init){ |
| int i,j; |
| for(i=0;i<256;i++) |
| for(j=0;j<256;j++) |
| if(tab[j]==0&&CHARCONV(i)==j){ |
| tab[j&255]=i; |
| break; |
| } |
| init=1; |
| } |
| return tab[x&255]; |
| } |
| |
| void STRBACK(unsigned char *p) |
| { |
| while(p&&*p){ |
| *p=CHARBACK(*p); |
| p++; |
| } |
| } |
| #endif |
| |
| int objs_equal(obj *o1,obj *o2,int t) |
| /* Vergleicht die beiden Objekte; liefert 1, wenn sie gleich sind, sonst 0 */ |
| { |
| int i1,i2; |
| i1=o1->flags&~SCRATCH;i2=o2->flags&~SCRATCH; |
| if(i1!=i2) return 0; |
| if(i1&DREFOBJ){ |
| if(o1->dtyp!=o2->dtyp) return 0; |
| } |
| if(i1&KONST) return(!compare_const(&o1->val,&o2->val,t)); |
| if(i1&VAR){ |
| if(o1->v!=o2->v) return 0; |
| if(!zmeqto(o1->val.vmax,o2->val.vmax)) return 0; |
| } |
| return 1; |
| } |
| |
| |
| #ifdef HAVE_MISRA |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| /* removed */ |
| #endif |