URL
https://opencores.org/ocsvn/rf6809/rf6809/trunk
Subversion Repositories rf6809
[/] [rf6809/] [trunk/] [software/] [vbcc/] [machines/] [hc12/] [machine.c] - Rev 18
Compare with Previous | Blame | View Log
/* Code generator for Motorola 68hc12 microcontrollers. */ /*TODO: regs_modified bei struct-copy savings verfeinern 4-Byte Copy [static] testen peephole-Pass um ALLOCREGs zu entfernen ACC_IND (Achtung?) struct-copy Problemfälle banked bit long long, float, double, long double */ #include "supp.h" #include "vbc.h" /* nicht schoen, aber ... */ static char FILE_[]=__FILE__; #include "dwarf2.c" /* Public data that MUST be there. */ /* Name and copyright. */ char cg_copyright[]="vbcc code-generator for 6809/6803/68hc12 V0.2 (c) in 2000-2022 by Volker Barthelmann"; /* Commandline-flags the code-generator accepts */ int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0, 0,0,0,0, 0,0}; char *g_flags_name[MAXGF]={"cpu","fpu","no-delayed-popping","const-in-data", "merge-constants","no-peephole","mem-cse","acc-glob", "pcrel","drel","no-char-addi2p","nodx","nou"}; union ppi g_flags_val[MAXGF]; /* Typenames (needed because of HAVE_EXT_TYPES). */ char *typname[]={"strange","bit","char","short","int","long","long long", "float","double","long double","void", "near-pointer","far-pointer","huge-pointer", "array","struct","union","enum","function"}; int bitsperbyte = 8; int bytemask = 0xff; int dbl_bytemask = 0xffff; /* Alignment-requirements for all types in bytes. */ zmax align[MAX_TYPE+1]; /* Alignment that is sufficient for every object. */ zmax maxalign; /* CHAR_BIT of the target machine. */ zmax char_bit; /* Sizes of all elementary types in bytes. */ zmax sizetab[MAX_TYPE+1]; /* Minimum and Maximum values each type can have. */ /* Must be initialized in init_cg(). */ zmax t_min[MAX_TYPE+1]; zumax t_max[MAX_TYPE+1]; zumax tu_max[MAX_TYPE+1]; /* Names of all registers. */ char *regnames[]={"noreg","d","x","y","sp","u","d/x"}; /* The Size of each register in bytes. */ zmax regsize[MAXR+1]; /* Type which can store each register. */ struct Typ *regtype[MAXR+1]; /* regsa[reg]!=0 if a certain register is allocated and should */ /* not be used by the compiler pass. */ int regsa[MAXR+1]; /* Specifies which registers may be scratched by functions. */ int regscratch[MAXR+1]={0,1,1,0,1,0}; int reg_prio[MAXR+1]={0,0,1,1,0,0}; struct reg_handle empty_reg_handle={0}; /* Names of target-specific variable attributes. */ char *g_attr_name[]={"__interrupt","__dpage","__far",0}; #define INTERRUPT 1 #define DPAGE 2 #define FAR 4 int MINADDI2P=CHAR; /****************************************/ /* Some private data and functions. */ /****************************************/ static long malign[MAX_TYPE+1]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; static long msizetab[MAX_TYPE+1]={0,1,1,2,2,4,4,4,4,4,0,2,4,4,0,0,0,2,0}; struct Typ ityp={SHORT},ltyp={LONG}; #define DATA 0 #define BSS 1 #define CODE 2 #define RODATA 3 #define SPECIAL 4 static int section=-1,newobj,scnt,pushed_acc; static char *codename="\t.text\n", *dataname="\t.data\n", *bssname="\t.section\t.bss\n", *rodataname="\t.section\t.rodata\n"; #define IMM_IND 1 #define VAR_IND 2 #define POST_INC 3 #define POST_DEC 4 #define PRE_INC 5 #define PRE_DEC 6 #define ACC_IND 7 #define KONSTINC 8 /* (user)stack-pointer, pointer-tmp, int-tmp; reserved for compiler */ static int acc=1,ix=2,iy=3,sp=4,iu=5,dx=6; static void pr(FILE *,struct IC *); static void function_top(FILE *,struct Var *,long); static void function_bottom(FILE *f,struct Var *,long); static char *marray[]={"__section(x,y)=__vattr(\"section(\"#x\",\"#y\")\")", "__HC12__", "__SIZE_T_INT=1", "__direct=__vattr(\"section(\\\"dpage\\\")\")", 0}; #define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG) #define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST) static long loff,roff,stackoffset,notpopped,dontpop,maxpushed,stack; static char *x_t[]={"?","","b","","","","","","","","","","","","","",""}; static char *ccs[]={"eq","ne","lt","ge","le","gt"}; static char *uccs[]={"eq","ne","lo","hs","ls","hi"}; static char *logicals[]={"ora","eor","and"}; static char *dct[]={"",".bit",".byte",".2byte",".2byte",".4byte",".8byte",".4byte",".8byte",".8byte", "(void)",".2byte",".34byte",".34byte"}; static char *idprefix="",*labprefix=".l"; static int exit_label,have_frame; static char *ret; static int stackchecklabel; static int frame_used,stack_valid; static int CPU=6812; static int pcrel,drel; static int skip_rel; static char *jsrinst="jsr"; static char *jmpinst="jmp"; static int nodx,nou; int switchsubs; static int cc_t; static struct obj *cc; static struct obj mobj; #define STR_NEAR "near" #define STR_FAR "far" #define STR_HUGE "huge" #define STR_BADDR "baddr" #define ISNULL() (zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))) #define ISLWORD(t) ((t&NQ)==LONG||(t&NQ)==FPOINTER||(t&NQ)==HPOINTER||(t&NQ)==FLOAT) #define ISHWORD(t) ((t&NQ)==INT||(t&NQ)==SHORT||(t&NQ)==NPOINTER) #define ISCHWORD(t) ((t&NQ)==CHAR||ISHWORD(t)) #define ISSTATIC(v) ((v)->storage_class==EXTERN||(v)->storage_class==STATIC) #define ISBADDR(v) ((v)->vtyp->attr&&strstr(STR_BADDR,(v)->vtyp->attr)) /*FIXME*/ #define ISFAR(v) ((v)->vtyp->attr&&(strstr(STR_FAR,(v)->vtyp->attr)||strstr(STR_HUGE,(v)->vtyp->attr))) #define ISACC(x) ((x)==acc) #define ISX(x) ((x)==ix) #define ISY(x) ((x)==iy) #define ISU(x) ((x)==iu) #define ISIDX(x) (ISX(x)||ISY(x)||(ISU(x)&&CPU!=6812)) #define ISRACC(x) (isreg(x)&&ISACC(p->x.reg)) #define ISRX(x) (isreg(x)&&ISX(p->x.reg)) #define ISRY(x) (isreg(x)&&ISY(p->x.reg)) #define ISRU(x) (isreg(x)&&ISU(p->x.reg)) #define ISRIDX(x) (isreg(x)&&ISIDX(p->x.reg)) #define CPUOPT ((g_flags[0]&USEDFLAG)?g_flags_val[0].l:6812) #define SPUSH(x) (CPU==6812?"\tpsh" x "\n":"\tpshs\t" x "\n") #define SPUSHD (CPU==6812?"\tpshd\n":"\tpshs\tb,a\n") #define SPULL(x) (CPU==6812?"\tpul" x "\n":"\tpuls\t" x "\n") #define SPULLD (CPU==6812?"\tpuld\n":"\tpuls\ta,b\n") #define SCMP(x) (CPU==6812?"\tcp" x "\t":"\tcmp" x "\t") #define SEX (CPU==6812?"\tsex\tb,d\n":"\tsex\n") #define SGN16(x) (zm2l(zi2zm(zm2zi(l2zm((long)(x)))))) enum peepf { NEEDSAME = 1, REMOVE1ST = 2, ALLOWSFX = 4}; struct peeps {char *s1,*s2,*r;enum peepf flags;}; static int check_sfx(char *s) { if(!*s) return 0; s+=strlen(s)-1; if(*s=='+'||*s=='-') return 1; if(*s!='s'&&*s!='x'&&*s!='y'&&*s!='u') return 0; s--; if(*s!=',') return 0; s--; if(*s=='+'||*s=='-') return 1; return 0; } static int setszflag(char *op,char r) { static char *zb[]={"adcb","addb","andb","aslb","asrb","clrb","comb","decb","eorb","incb", "ldab","ldb","lslb","lsrb","negb","orb","orab","rolb","rorb","sbcb", "stb","stab","subb","tstb"}; static char *zd[]={"addd","ldd","sex","std","subd"}; int i; if(r=='b'){ for(i=0;i<sizeof(zb)/sizeof(*zb);i++) if(!strcmp(op,zb[i])) return 1; } if(r=='d'){ for(i=0;i<sizeof(zd)/sizeof(*zd);i++) if(!strcmp(op,zd[i])) return 1; } if(r=='x'&&(!strcmp(op,"leax")||!strcmp(op,"ldx"))) return 1; if(r=='y'&&(!strcmp(op,"leay")||!strcmp(op,"ldy"))) return 1; if(CPU==6812){ if(r=='x'&&(!strcmp(op,"dex")||!strcmp(op,"inx"))) return 1; if(r=='y'&&(!strcmp(op,"dey")||!strcmp(op,"iny"))) return 1; } return 0; } int emit_peephole(void) { int entries,i,j,v1,v2; char *asmline[EMIT_BUF_DEPTH]; char buf1[1024],buf2[1024]; char op1[8],op2[8]; /* TODO: adapt better */ static struct peeps elim[]={ "lda","sta",0,NEEDSAME, "ldb","stb",0,NEEDSAME, "ldaa","staa",0,NEEDSAME, "ldab","stab",0,NEEDSAME, "ldd","std",0,NEEDSAME, "ldx","stx",0,NEEDSAME, "ldy","sty",0,NEEDSAME, "ldu","stu",0,NEEDSAME, "sta","sta",0,NEEDSAME, "stb","stb",0,NEEDSAME, "staa","staa",0,NEEDSAME, "stab","stab",0,NEEDSAME, "std","std",0,NEEDSAME, "stx","stx",0,NEEDSAME, "sty","sty",0,NEEDSAME, "stu","stu",0,NEEDSAME, "sta","lda",0,NEEDSAME, "stb","ldb",0,NEEDSAME, "staa","ldaa",0,NEEDSAME, "stab","ldab",0,NEEDSAME, "std","ldd",0,NEEDSAME, "stx","ldx",0,NEEDSAME, "sty","ldy",0,NEEDSAME, "stu","ldu",0,NEEDSAME, #if 0 "lda","lda",0,REMOVE1ST, "ldaa","ldaa",0,REMOVE1ST, "ldab","ldab",0,REMOVE1ST, "ldb","ldb",0,REMOVE1ST, "ldd","ldd",0,REMOVE1ST, "ldx","ldx",0,REMOVE1ST, "ldy","ldy",0,REMOVE1ST, "ldu","ldu",0,REMOVE1ST, "lda","pla",0,REMOVE1ST, "lda","txa",0,REMOVE1ST, "lda","tya",0,REMOVE1ST, "ldx","tax",0,REMOVE1ST, "ldy","tay",0,REMOVE1ST, "tay","ldy",0,REMOVE1ST, "tax","ldx",0,REMOVE1ST, "txa","lda",0,REMOVE1ST, "tya","lda",0,REMOVE1ST, #endif }; i=emit_l; if(emit_f==0) entries=i-emit_f+1; else entries=EMIT_BUF_DEPTH; asmline[0]=emit_buffer[i]; if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpb")&&!strcmp(buf1,"#0")) strcpy(asmline[0],"\ttstb\n"); if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"cmpd")&&!strcmp(buf1,"#0")) strcpy(asmline[0],"\tsubd\t#0\n"); if(entries>=2){ i--; if(i<0) i=EMIT_BUF_DEPTH-1; asmline[1]=emit_buffer[i]; for(j=0;j<sizeof(elim)/sizeof(elim[0]);j++){ if(elim[j].flags&NEEDSAME){ if(sscanf(asmline[0]," %6s %999s",op2,buf2)==2&& sscanf(asmline[1]," %6s %999s",op1,buf1)==2&& !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)&& !strcmp(buf1,buf2)){ if(!check_sfx(buf1)&&!check_sfx(buf2)){ if(elim[j].r){ strcpy(asmline[0],elim[j].r); }else{ if(elim[j].flags&REMOVE1ST) strcpy(asmline[1],asmline[0]); remove_asm(); } return 1; } } }else{ *buf1=0;*buf2=0; if(sscanf(asmline[1]," %6s %999s",op1,buf1)>=1&& sscanf(asmline[0]," %6s %999s",op2,buf2)>=1&& !strcmp(op1,elim[j].s1)&&!strcmp(op2,elim[j].s2)){ if((elim[j].flags&ALLOWSFX)||(!check_sfx(buf1)&&!check_sfx(buf2))){ if(elim[j].flags&REMOVE1ST) strcpy(asmline[1],asmline[0]); remove_asm(); return 1; } } } } if(!strcmp(asmline[0],"\trts\n")&&sscanf(asmline[1]," %6s %999s",op1,buf1)==2&&!strcmp(op1,"puls")){ sprintf(asmline[1]+strlen(asmline[1])-1,",pc\n"); remove_asm(); return 1; } if(!strcmp(asmline[0],"\tstb\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-1,s\n")){ strcpy(asmline[1],"\tpshs\tb\n"); remove_asm(); return 1; } if(!strcmp(asmline[0],"\tstd\t0,s\n")&&!strcmp(asmline[1],"\tleas\t-2,s\n")){ strcpy(asmline[1],"\tpshs\tb,a\n"); remove_asm(); return 1; } if(!strcmp(asmline[0],"\tldb\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb\n")){ remove_asm(); return 1; } if(!strcmp(asmline[0],"\tldd\t0,s\n")&&!strcmp(asmline[1],"\tpshs\tb,a\n")){ remove_asm(); return 1; } if(!strcmp(asmline[0],"\tpshs\tb,a\n")&&!strcmp(asmline[1],"\tpuls\ta,b\n")){ strcpy(asmline[1],"\tldd\t0,s\n"); remove_asm(); return 1; } if(sscanf(asmline[1]," ldd %999s",op1)>=1&&sscanf(asmline[0]," ldd %999s",op2)>=1){ if(!((op2[0]=='a'||op2[0]=='b'||op2[0]=='d')&&op2[1]==',')){ strcpy(asmline[1],asmline[0]); remove_asm(); return 1; } } if(!strcmp(asmline[0],"\ttfr\tx,d\n")&&!strcmp(asmline[1],"\ttfr\td,x\n")){ remove_asm(); return 1; } if(!strcmp(asmline[0],"\ttfr\ty,d\n")&&!strcmp(asmline[1],"\ttfr\td,y\n")){ remove_asm(); return 1; } if(!strcmp(asmline[0],"\tstd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){ remove_asm(); return 1; } if(!strcmp(asmline[0],"\tldd\t0,sp\n")&&!strcmp(asmline[1],"\tpshd\n")){ remove_asm(); return 1; } if(sscanf(asmline[0]," leas %d,s",&v1)==1&&sscanf(asmline[1]," leas %d,s",&v2)==1){ sprintf(asmline[1],"\tleas\t%ld,s\n",SGN16(v1+v2)); remove_asm(); return 1; } if(CPU!=6812&&sscanf(asmline[0]," tfr %c,%c",buf1,buf2)==2){ if((*buf1=='x'||*buf1=='y'||*buf1=='u'||*buf1=='s')&& (*buf2=='x'||*buf2=='y'||*buf2=='u'||*buf2=='s')){ sprintf(asmline[0],"\tlea%c\t,%c\n",*buf2,*buf1); } } if(CPU==6812&&(!strcmp(asmline[1],"\tdex\n")||!strcmp(asmline[1],"\tdey\n")||!strcmp(asmline[1],"\tsubd\t#1\n"))&& (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){ char r=asmline[1][3]; if(r=='b') r='d'; strcpy(asmline[1],"\td"); strncpy(asmline[1]+2,asmline[0]+1,4); asmline[1][6]=r;asmline[1][7]=','; strcpy(asmline[1]+8,asmline[0]+5); remove_asm(); return 1; } if(CPU==6812&&(!strcmp(asmline[1],"\tinx\n")||!strcmp(asmline[1],"\tiny\n")||!strcmp(asmline[1],"\taddd\t#1\n"))&& (!strncmp(asmline[0],"\tbne\t",5)||!strncmp(asmline[0],"\tbeq\t",5))){ char r=asmline[1][3]; strcpy(asmline[1],"\ti"); strncpy(asmline[1]+2,asmline[0]+1,4); asmline[1][6]=r;asmline[1][7]=','; strcpy(asmline[1]+8,asmline[0]+5); remove_asm(); return 1; } } if(entries>=3){ i--; if(i<0) i=EMIT_BUF_DEPTH-1; asmline[2]=emit_buffer[i]; if(sscanf(asmline[0]," %6s %999s",op1,buf1)==2){ if(!strcmp(op1,"beq")||!strcmp(op1,"bne")){ if(!strcmp(asmline[1],"\ttstb\n")||!strcmp(asmline[1],"\tcpb\t#0\n")){ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&& setszflag(op2,'b')){ strcpy(asmline[1],asmline[0]); remove_asm(); return 1; } } if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&& (!strcmp(op2,"subd")||!strcmp(op2,"cpd"))&&!strcmp(buf2,"#0")){ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&& setszflag(op2,'d')){ strcpy(asmline[1],asmline[0]); remove_asm(); return 1; } } if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&& !strcmp(op2,(CPU==6812)?"cpx":"cmpx")&&!strcmp(buf2,"#0")){ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&& setszflag(op2,'x')){ strcpy(asmline[1],asmline[0]); remove_asm(); return 1; } } if(sscanf(asmline[1]," %6s %999s",op2,buf2)==2&& !strcmp(op2,(CPU==6812)?"cpy":"cmpy")&&!strcmp(buf2,"#0")){ if(sscanf(asmline[2]," %6s %999s",op2,buf2)>=1&& setszflag(op2,'y')){ strcpy(asmline[1],asmline[0]); remove_asm(); return 1; } } } } } return 0; } static int special_section(FILE *f,struct Var *v) { char *sec; if(v->tattr&DPAGE){ emit(f,"\t.section\t.dpage\n"); }else{ if(!v->vattr) return 0; sec=strstr(v->vattr,"section("); if(!sec) return 0; sec+=strlen("section("); emit(f,"\t.section\t"); while(*sec&&*sec!=')') emit_char(f,*sec++); emit(f,"\n"); } if(f) section=SPECIAL; return 1; } static struct fpconstlist { struct fpconstlist *next; int label,typ; union atyps val; } *firstfpc; static int addfpconst(struct obj *o,int t) { struct fpconstlist *p=firstfpc; t&=NQ; if(g_flags[4]&USEDFLAG){ for(p=firstfpc;p;p=p->next){ if(t==p->typ){ eval_const(&p->val,t); if(t==FLOAT&&zldeqto(vldouble,zf2zld(o->val.vfloat))) return p->label; if(t==DOUBLE&&zldeqto(vldouble,zd2zld(o->val.vdouble))) return p->label; if(t==LDOUBLE&&zldeqto(vldouble,o->val.vldouble)) return p->label; } } } p=mymalloc(sizeof(struct fpconstlist)); p->next=firstfpc; p->label=++label; p->typ=t; p->val=o->val; firstfpc=p; return p->label; } int pointer_type(struct Typ *p) { if(!p) ierror(0); while((p->flags&NQ)==ARRAY) p=p->next; if((p->flags&NQ)==FUNKT) { if(p->attr) if(strstr(p->attr,STR_FAR)) return FPOINTER; if (p->flags&FAR) return FPOINTER; return NPOINTER; /*FIXME: banked*/ } if(p->attr){ if(strstr(p->attr,STR_HUGE)) return HPOINTER; if(strstr(p->attr,STR_FAR)) return FPOINTER; if(strstr(p->attr,STR_NEAR)) return NPOINTER; } /*FIXME*/ return NPOINTER; } static long voff(struct obj *p) { if(zm2l(p->v->offset)<0) return loff-zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset+1; else return zm2l(p->v->offset)+zm2l(p->val.vmax)-stackoffset; } static void emit_obj(FILE *f,struct obj *p,int t) /* Gibt Objekt auf Bildschirm aus */ { if(p->am){ int flags=p->am->flags; if(flags==ACC_IND){ emit(f,"%s,%s",regnames[acc],regnames[p->am->base]); return; } if(flags==KONSTINC){ eval_const(&p->val,p->am->base); if((t&NQ)==CHAR){ vumax=zumrshift(vumax,bitsperbyte*3-bitsperbyte*p->am->offset); vumax=zumand(vumax,ul2zum(tu_max[CHAR])); }else{ vumax=zumrshift(vumax,bitsperbyte*2-bitsperbyte*p->am->offset); vumax=zumand(vumax,ul2zum(tu_max[SHORT])); } emit(f,"#%lu",zum2ul(vumax)); return; } if(flags<POST_INC||flags>PRE_DEC||CPU==6812) emit(f,"%ld",p->am->offset&tu_max[SHORT]); if(p->am->v){ if(p->am->v->storage_class==STATIC) emit(f,"+%s%ld",labprefix,zm2l(p->am->v->offset)); else emit(f,"+(%s%s)",idprefix,p->am->v->identifier); } emit(f,","); if(flags==PRE_INC){ emit(f,"+"); if(p->am->offset==2&&CPU!=6812) emit(f,"+"); }else if(flags==PRE_DEC){ emit(f,"-"); if(p->am->offset==2&&CPU!=6812) emit(f,"-"); } emit(f,"%s",regnames[p->am->base]); if(flags==POST_INC){ emit(f,"+"); if(p->am->offset==2&&CPU!=6812) emit(f,"+"); }else if(flags==POST_DEC){ emit(f,"-"); if(p->am->offset==2&&CPU!=6812) emit(f,"-"); } return; } if((p->flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){ emitval(f,&p->val,p->dtyp&NU); return; } if(p->flags&VARADR) emit(f,"#"); if((p->flags&(DREFOBJ|REG))==(DREFOBJ|REG)) emit(f,"0,"); if((p->flags&(DREFOBJ|REG))==DREFOBJ) emit(f,"["); if((p->flags&(VAR|REG))==VAR){ if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){ emit(f,"%ld,%s",voff(p),regnames[sp]); }else{ if(!zmeqto(l2zm(0L),p->val.vmax)){ emit(f,"%ld",zm2l(zi2zm(zm2zi(p->val.vmax)))); emit(f,"+"); } if(p->v->storage_class==STATIC){ emit(f,"%s%ld",labprefix,zm2l(p->v->offset)); }else{ emit(f,"(%s%s)",idprefix,p->v->identifier); } if(pcrel&&!(p->flags&VARADR)&&ISFUNC(p->v->vtyp->flags)) emit(f,",pc"); if(drel&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags)){ if(CPU==6812) ierror(0); emit(f,",%s",regnames[iu]); } } } if(p->flags®){ if(ISACC(p->reg)&&(t&NQ)==CHAR) emit(f,"b"); else emit(f,"%s",regnames[p->reg]); } if(p->flags&KONST){ if(ISFLOAT(t)){ emit(f,"%s%d",labprefix,addfpconst(p,t)); }else{ emit(f,"#");emitval(f,&p->val,t&NU); } } if((p->flags&(DREFOBJ|REG))==DREFOBJ){ if(p->v->storage_class==EXTERN||p->v->storage_class==STATIC){ if(is_const(p->v->vtyp)){ if(!pcrel&&CPU==6812) emit(f,",pc"); }else{ if(!drel&&CPU==6812) emit(f,",pc"); } } emit(f,"]"); } } static void dwarf2_print_frame_location(FILE *f,struct Var *v) { /*FIXME: needs a location list and correct register translation */ struct obj o; o.flags=REG; o.reg=sp; o.val.vmax=l2zm(0L); o.v=0; dwarf2_print_location(f,&o); } static int dwarf2_regnumber(int r) { /*FIXME: always returns D as accumulator, even if byte size */ static int dwarf_regs[MAXR+1]={-1,3,7,8,15}; return dwarf_regs[r]; } static zmax dwarf2_fboffset(struct Var *v) { /*FIXME*/ if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0); if(!zmleq(l2zm(0L),v->offset)) return l2zm((long)(loff-zm2l(v->offset))); else return v->offset; } /* test operand for mov instruction */ static int mov_op(struct obj *o) { long off; if(CPU!=6812) return 0; if(o->am){ int f=o->am->flags; if(f==POST_INC||f==PRE_INC||f==POST_DEC||f==PRE_DEC||f==ACC_IND) return 1; if(f==IMM_IND){ if(o->am->v) return 0; off=o->am->offset; if(off>=-256&&off<=255) return 1; else return 0; } ierror(0); } if(o->flags&(KONST|VARADR)) return 1; if((o->flags&(REG|DREFOBJ))==(REG|DREFOBJ)) return 1; if((o->flags&(VAR|REG|DREFOBJ))==VAR){ if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN) return 1; off=voff(o); if(off>=-256&&off<=255) return 1; else return 0; } return 0; } /* add an offset to an object describing a memory address */ static void inc_addr(struct obj *o,long val,int t) { if(o->am){ int f=o->am->flags; if(f==IMM_IND||f==KONSTINC) o->am->offset+=val; else if(f==POST_INC||f==POST_DEC||f==PRE_INC||f==PRE_DEC){ struct AddressingMode *old=o->am; o->am=mymalloc(sizeof(*o->am)); o->am->flags=IMM_IND; o->am->base=old->base; o->am->v=0; if(f==POST_DEC) o->am->offset=old->offset-val; else if(f==POST_INC) o->am->offset=-old->offset+val; else if(f==PRE_DEC) o->am->offset=val; else o->am->offset=-val; }else ierror(0); }else if(o->flags&DREFOBJ){ struct AddressingMode *am; o->am=am=mymalloc(sizeof(*am)); am->flags=IMM_IND; if(!o->reg) ierror(0); am->base=o->reg; am->offset=zm2l(val); am->v=0; }else if(o->flags&KONST){ struct AddressingMode *am; if(o->am) ierror(0); o->am=am=mymalloc(sizeof(*am)); am->flags=KONSTINC; am->offset=zm2l(val); am->base=t; }else{ o->val.vmax=zmadd(o->val.vmax,val); } } /* pushed on the stack by a callee, no pop needed */ static void callee_push(long l) { if(l-stackoffset>stack) stack=l-stackoffset; } static void push(long l) { stackoffset-=l; if(stackoffset<maxpushed) maxpushed=stackoffset; if(-maxpushed>stack) stack=-maxpushed; } static void pop(long l) { stackoffset+=l; } static void gen_pop(FILE *f,long l) { if(l==0) return; if(l==1&&CPU==6812){ emit(f,"\tins\n"); #if 0 /* might clobber return register */ }else if(l==2&&!regs[acc]){ emit(f,SPULLD); BSET(regs_modified,acc); }else if(l==2&&!regs[ix]){ emit(f,SPULL("x")); BSET(regs_modified,ix); }else if(l==2&&!regs[iy]){ emit(f,SPULL("y")); BSET(regs_modified,iy); #endif }else{ emit(f,"\tleas\t%u,%s\n",SGN16(l),regnames[sp]); } pop(l); } static void pr(FILE *f,struct IC *p) { int r; if(pushed_acc){ emit(f,SPULLD); pop(2); pushed_acc=0; } for(r=MAXR;r>=1;r--){ if(regs[r]&8){ emit(f,"\t%s%s\n",CPU==6812?"pul":"puls\t",regnames[r]); pop(2); } regs[r]&=~12; } } static void function_top(FILE *f,struct Var *v,long offset) /* erzeugt Funktionskopf */ { int i; emit(f,"# offset=%ld\n",offset); have_frame=0;stack_valid=1;stack=0; if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;} if(v->storage_class==EXTERN){ if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC) emit(f,"\t.global\t%s%s\n",idprefix,v->identifier); emit(f,"%s%s:\n",idprefix,v->identifier); }else{ emit(f,"%s%ld:\n",labprefix,zm2l(v->offset)); } roff=0; for(i=MAXR;i>0;i--){ if(regused[i]&&!regscratch[i]&&!regsa[i]){ have_frame=1; loff+=2; roff+=2; if(i==iy) emit(f,SPUSH("y")); else if(i==iu){ if(CPU!=6812&®used[iy]){ emit(f,"\tpshs\tu,y\n"); loff+=2;roff+=2;i=iy; }else emit(f,SPUSH("u")); }else ierror(0); } } if(stack_check){ stackchecklabel=++label; emit(f,"\tldy\t#%s%d\n",labprefix,stackchecklabel); /* FIXME: banked */ emit(f,"\t%s\t%s__stack_check\n",jsrinst,idprefix); } if(offset){ if(CPU==6812&&offset==1) emit(f,SPUSH("b")); else if(CPU==6812&&offset==2) emit(f,SPUSHD); else emit(f,"\tleas\t%ld,%s\n",SGN16(-offset),regnames[sp]); have_frame=1; } } static void function_bottom(FILE *f,struct Var *v,long offset) /* erzeugt Funktionsende */ { int i; offset-=roff; if(offset){ if(offset==1&&CPU==6812) emit(f,"\tins\n"); else if(offset==2&&CPU==6812&&!zmeqto(szof(v->vtyp->next),l2zm(4L))) emit(f,SPULL("x")); else if(offset==2&&CPU==6812&®used[iy]) emit(f,SPULL("y")); else emit(f,"\tleas\t%ld,%s\n",SGN16(offset),regnames[sp]); } for(i=1;i<=MAXR;i++){ if(regused[i]&&!regscratch[i]&&!regsa[i]){ have_frame=1; if(i==iy){ if(CPU!=6812&®used[iu]&&!regscratch[iu]&&!regsa[iu]){ emit(f,"\tpuls\tu,y\n"); i=iu; }else emit(f,SPULL("y")); }else if(i==iu) emit(f,SPULL("u")); else ierror(0); } } if(ret) emit(f,"\t%s\n",ret); if(v->storage_class==EXTERN){ emit(f,"\t.type\t%s%s,@function\n",idprefix,v->identifier); emit(f,"\t.size\t%s%s,$-%s%s\n",idprefix,v->identifier,idprefix,v->identifier); }else{ emit(f,"\t.type\t%s%ld,@function\n",labprefix,zm2l(v->offset)); emit(f,"\t.size\t%s%ld,$-%s%ld\n",labprefix,zm2l(v->offset),labprefix,zm2l(v->offset)); } if(stack_check) emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stackchecklabel,offset-maxpushed); if(stack_valid){ if(!v->fi) v->fi=new_fi(); v->fi->flags|=ALL_STACK; v->fi->stack1=l2zm(stack+offset); emit(f,"# stacksize=%ld\n",stack+offset); emit(f,"\t.equ\t%s__stack_%s,%ld\n",idprefix,v->identifier,stack+offset); } } static int compare_objects(struct obj *o1,struct obj *o2) { if(o1->flags==o2->flags&&o1->am==o2->am){ if(!(o1->flags&VAR)||(o1->v==o2->v&&zmeqto(o1->val.vmax,o2->val.vmax))){ if(!(o1->flags®)||o1->reg==o2->reg){ return 1; } } } return 0; } /*FIXME*/ static void clear_ext_ic(struct ext_ic *p) { p->flags=0; p->r=0; p->offset=0; } static long pof2(zumax x) /* Yields log2(x)+1 oder 0. */ { zumax p;int ln=1; p=ul2zum(1L); while(ln<=32&&zumleq(p,x)){ if(zumeqto(x,p)) return ln; ln++;p=zumadd(p,p); } return 0; } static void peephole(struct IC *p) { int c,c2,r,t;struct IC *p2; struct AddressingMode *am; zmax incmin,incmax; if(CPU==6812){ incmin=l2zm(-8L); incmax=l2zm(8L); }else{ incmin=l2zm(-2L); incmax=l2zm(2L); } frame_used=0; for(;p;p=p->next){ c=p->code; if(!frame_used){ if((p->q1.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q1.v)) frame_used=1; if((p->q2.flags&(REG|VAR))==VAR&&!ISSTATIC(p->q2.v)) frame_used=1; if((p->z.flags&(REG|VAR))==VAR&&!ISSTATIC(p->z.v)) frame_used=1; } /* letztes Label merken */ if(c!=FREEREG&&c!=ALLOCREG&&(c!=SETRETURN||!isreg(q1)||p->q1.reg!=p->z.reg)) exit_label=0; if(c==LABEL) exit_label=p->typf; #if 0 /* and x,#const;bne/beq, FIXME */ if(c==AND&&isconst(q2)&&isreg(z)){ long bit; eval_const(&p->q2.val,p->typf); if(bit=pof2(vumax)){ struct IC *cmp=0;int fr=0; for(p2=p->next;p2;p2=p2->next){ c2=p2->code; if(c2==TEST){ if((p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg){ cmp=p2;continue; } } if(c2==COMPARE&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==p->z.reg&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){ eval_const(&p2->q2.val,p2->typf); if(ISNULL()){ cmp=p2;continue; } break; } if(c2==FREEREG&&p2->q1.reg==p->z.reg) {fr++;continue;} if((c2==BNE||c2==BEQ)&&cmp&&fr==1){ p->ext.flags=EXT_IC_BTST; p2->ext.flags=EXT_IC_BTST; p2->ext.offset=bit-1; cmp->code=NOP; cmp->q1.flags=cmp->q2.flags=cmp->z.flags=0; break; } if(((p2->q1.flags®)&&p2->q1.reg==p->z.reg)||((p2->q2.flags®)&&p2->q2.reg==p->z.reg)||((p2->z.flags®)&&p2->z.reg==p->z.reg)) break; if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; } } } #endif /* Try d,idx */ if(c==ADDI2P&&ISRACC(q2)&&ISRIDX(z)&&(ISRIDX(q1)||p->q2.reg!=p->z.reg)){ int base,idx;struct obj *o; r=p->z.reg;idx=p->q2.reg; if(isreg(q1)) base=p->q1.reg; else base=r; o=0; for(p2=p->next;p2;p2=p2->next){ c2=p2->code; if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break; if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break; if((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==idx&&idx!=r) break; if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){ if(o||!ISCHWORD(q1typ(p2))) break; o=&p2->q1; } if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){ break; /*TODO: check what is possible */ if(o||!ISCHWORD(q2typ(p2))) break; o=&p2->q2; } if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){ break; /*TODO: check what is possible */ if(o||!ISCHWORD(ztyp(p2))) break; o=&p2->z; } } if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){ int m; if(c2==FREEREG) m=p2->q1.reg; else m=p2->z.reg; if(m==r){ if(o){ o->am=am=mymalloc(sizeof(*am)); am->flags=ACC_IND; am->base=base; if(idx!=acc) ierror(0); am->offset=idx; if(isreg(q1)){ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0; }else{ p->code=c=ASSIGN;p->q2.flags=0; p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ]; } } break; } if(c2!=FREEREG&&m==base) break; continue; } /* better no instructions between, accu used too much */ if(c2!=FREEREG&&c2!=ALLOCREG&&!o) break; } } /* POST_INC/DEC in q1 */ if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){ r=p->q1.reg; t=q1typ(p); if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){ for(p2=p->next;p2;p2=p2->next){ c2=p2->code; if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){ eval_const(&p2->q2.val,p2->typf2); if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax); if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){ p2->code=NOP; p2->q1.flags=p2->q2.flags=p2->z.flags=0; p->q1.am=mymalloc(sizeof(*am)); p->q1.am->base=r; p->q1.am->v=0; if(zmleq(vmax,l2zm(0L))){ p->q1.am->flags=POST_DEC; p->q1.am->offset=-zm2l(vmax); }else{ p->q1.am->flags=POST_INC; p->q1.am->offset=zm2l(vmax); } }else break; } if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break; } } } /* POST_INC/DEC in q2 */ if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){ r=p->q2.reg; t=q2typ(p); if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)){ for(p2=p->next;p2;p2=p2->next){ c2=p2->code; if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){ eval_const(&p2->q2.val,p2->typf2); if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax); if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){ p2->code=NOP; p2->q1.flags=p2->q2.flags=p2->z.flags=0; p->q2.am=mymalloc(sizeof(*am)); p->q2.am->base=r; p->q2.am->v=0; if(zmleq(vmax,l2zm(0L))){ p->q2.am->flags=POST_DEC; p->q2.am->offset=-zm2l(vmax); }else{ p->q2.am->flags=POST_INC; p->q2.am->offset=zm2l(vmax); } }else break; } if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break; } } } /* POST_INC/DEC in z */ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)){ r=p->z.reg; t=ztyp(p); if(ISCHWORD(t)&&ISIDX(r)&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->q2.flags®)||p->q2.reg!=r)){ for(p2=p->next;p2;p2=p2->next){ c2=p2->code; if((c2==ADD||c2==ADDI2P||(CPU==6812&&(c2==SUB||c2==SUBIFP)))&&(p2->q1.flags&(REG|DREFOBJ))==REG&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){ eval_const(&p2->q2.val,p2->typf2); if(c2==SUB||c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax); if(zmleq(vmax,incmax)&&zmleq(incmin,vmax)){ p2->code=NOP; p2->q1.flags=p2->q2.flags=p2->z.flags=0; p->z.am=mymalloc(sizeof(*am)); p->z.am->base=r; p->z.am->v=0; if(zmleq(vmax,l2zm(0L))){ p->z.am->flags=POST_DEC; p->z.am->offset=-zm2l(vmax); }else{ p->z.am->flags=POST_INC; p->z.am->offset=zm2l(vmax); } }else break; } if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; if(((p2->q1.flags®)&&p2->q1.reg==r)||((p2->q2.flags®)&&p2->q2.reg==r)||((p2->z.flags®)&&p2->z.reg==r)) break; } } } /* R,#c */ if((c==ADDI2P||c==SUBIFP)&&ISHWORD(p->typf)&&((p->typf2&NQ)==NPOINTER||(p->typf2&NQ)==FPOINTER)&&isreg(z)&&((p->q2.flags&(KONST|DREFOBJ))==KONST||(!drel&&(p->q1.flags&VARADR)))){ int base;zmax of;struct obj *o;struct Var *v; if(p->q1.flags&VARADR){ v=p->q1.v; of=p->q1.val.vmax; r=p->z.reg; if(isreg(q2)&&ISIDX(p->q2.reg)) base=p->q2.reg; else base=r; }else{ eval_const(&p->q2.val,p->typf); if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax; v=0; r=p->z.reg; if(isreg(q1)&&ISIDX(p->q1.reg)) base=p->q1.reg; else base=r; } o=0; for(p2=p->next;p2;p2=p2->next){ c2=p2->code; if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; if(c2!=FREEREG&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r) break; if(c2!=FREEREG&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==r) break; if(c2!=CALL&&(c2<LABEL||c2>BRA)/*&&c2!=ADDRESS*/){ if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r){ if(o||!ISHWORD(q1typ(p2))) break; o=&p2->q1; } if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){ if(o||!ISHWORD(q2typ(p2))) break; o=&p2->q2; } if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){ if(o||!ISHWORD(ztyp(p2))) break; o=&p2->z; } } if(c2==FREEREG||(p2->z.flags&(REG|DREFOBJ))==REG){ int m; if(c2==FREEREG) m=p2->q1.reg; else m=p2->z.reg; if(m==r){ if(o){ o->am=am=mymalloc(sizeof(*am)); am->flags=IMM_IND; am->base=base; am->offset=zm2l(of); am->v=v; if(!v){ if(isreg(q1)&&ISIDX(p->q1.reg)){ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0; }else{ p->code=c=ASSIGN;p->q2.flags=0; p->typf=p->typf2;p->q2.val.vmax=sizetab[p->typf2&NQ]; } }else{ if(isreg(q2)&&ISIDX(p->q2.reg)){ p->code=c=NOP;p->q1.flags=p->q2.flags=p->z.flags=0; }else{ p->code=c=ASSIGN;p->q1=p->q2;p->q2.flags=0; p->q2.val.vmax=sizetab[p->typf&NQ]; } } } break; } if(/*get_reg!! c2!=FREEREG&&*/m==base) break; continue; } } } } } static struct obj *cam(int flags,int base,long offset,struct Var *v) /* Initializes an addressing-mode structure and returns a pointer to */ /* that object. Will not survive a second call! */ { static struct obj obj; static struct AddressingMode am; obj.am=&am; am.flags=flags; am.base=base; am.offset=offset; am.v=v; return &obj; } static void get_acc(FILE *f,struct IC *p) { if(regs[acc]){ if(p->q2.am) if(p->q2.am->flags==ACC_IND) ierror(0); else if((p->q2.flags®)&&ISACC(p->q2.reg)) ierror(0); if(p->z.am) if(p->z.am->flags==ACC_IND) ierror(0); else if((p->z.flags®)&&ISACC(p->z.reg)) ierror(0); if(regs[acc]){ emit(f,SPUSHD); push(2); pushed_acc=1; } } } static int get_idx(FILE *f,IC *p) { int r; for(r=1;r<=MAXR;r++){ if(ISIDX(r)){ if(!regs[r]){ regs[r]|=4; return r; } } } for(r=1;r<=MAXR;r++){ if(ISIDX(r)){ if((!(p->q1.flags®)||p->q1.reg!=r)&& (!(p->q2.flags®)||p->q2.reg!=r)&& (!(p->z.flags®)||p->z.reg!=r)){ emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[r]); regs[r]|=8; push(2); return r; } } } ierror(0); } static int get_reg(FILE *f,struct IC *p,int t) { int reg; if(!regs[acc]) reg=acc; else if(ISHWORD(t)&&!regs[ix]) reg=ix; #if 0 else if(ISHWORD(t)&&!regs[iy]) reg=iy; #endif else{ get_acc(f,p); reg=acc; } BSET(regs_modified,reg); return reg; } static void load_reg(FILE *f,int r,struct obj *o,int t) { if(!o->am){ if((o->flags&(REG|DREFOBJ))==REG){ if(o->reg==r) return; emit(f,"\ttfr\t%s,%s\n",regnames[o->reg],regnames[r]); return; } if(r==acc&&(o->flags&(KONST|DREFOBJ))==KONST){ eval_const(&o->val,t); if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))){ if(CPU!=6812&&!optsize) emit(f,"\tldd\t#0\n"); else emit(f,"\tclra\n\tclrb\n"); cc=o;cc_t=t; return; } } } if(o->flags&VARADR){ char *base=0; if(pcrel&&ISFUNC(o->v->vtyp->flags)) base="pc"; if(drel&&!ISFUNC(o->v->vtyp->flags)) base=regnames[iu]; if(base&&!skip_rel){ if(ISACC(r)) emit(f,"\ttfr\t%s,d\n",base); if(ISIDX(r)) emit(f,"\tlea%s\t",regnames[r]); else{ if(*base=='p') emit(f,"%s%d:\n",labprefix,++label); emit(f,"\taddd\t#"); } emitzm(f,o->val.vmax); emit(f,"+"); if(o->v->storage_class==EXTERN) emit(f,"%s%s",idprefix,o->v->identifier); else emit(f,"%s%ld",labprefix,zm2l(o->v->offset)); if(ISIDX(r)) emit(f,",%s",base); else if(*base=='p') emit(f,"-%s%d",labprefix,label); emit(f,"\n"); cc=o;cc_t=t; return; } skip_rel=0; } emit(f,"\tld%s\t",(r==acc&&(t&NQ)==CHAR)?(CPU==6812?"ab":"b"):regnames[r]); emit_obj(f,o,t);emit(f,"\n"); cc=o;cc_t=t; } static void store_reg(FILE *f,int r,struct obj *o,int t) { if((o->flags&(REG|DREFOBJ))==REG){ if(o->reg==r) return; emit(f,"\ttfr\t%s,%s\n",regnames[r],regnames[o->reg]); }else{ if(r==acc&&(t&NQ)==CHAR) emit(f,"\tst%s\t",(CPU==6812)?"ab":"b"); else emit(f,"\tst%s\t",regnames[r]); emit_obj(f,o,t);emit(f,"\n"); cc=o;cc_t=t; } } static void load_addr(FILE *f,int r,struct obj *o) { if(o->am){ if(o->am->flags==IMM_IND){ if(o->am->base==r&&o->am->offset==0&&!o->am->v) return; if(ISIDX(r)){ emit(f,"\tlea%s\t",regnames[r]); emit_obj(f,o,0); emit(f,"\n"); }else{ if(r!=acc) ierror(0); emit(f,"\ttfr\t%s,%s\n",regnames[o->am->base],regnames[r]); emit(f,"\taddd\t#%ld\n",o->am->offset); if(o->am->v){ if(o->am->v->storage_class==STATIC) emit(f,"+%s%ld",labprefix,zm2l(o->am->v->offset)); else emit(f,"+%s%s",idprefix,o->am->v->identifier); } emit(f,"\n"); cc=0; } return; } ierror(0); } if(o->flags&DREFOBJ){ o->flags&=~DREFOBJ; load_reg(f,r,o,o->dtyp); o->flags|=DREFOBJ; return; } if((o->flags&(VAR|VARADR))==VAR){ if(o->v->storage_class==STATIC||o->v->storage_class==EXTERN){ o->flags|=VARADR; load_reg(f,r,o,POINTER_TYPE(o->v->vtyp)); o->flags&=~VARADR; return; } if(voff(o)==0){ emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]); return; } if(ISIDX(r)){ emit(f,"\tlea%s\t",regnames[r]); emit_obj(f,o,0); emit(f,"\n"); }else{ if(r!=acc) ierror(0); emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[r]); emit(f,"\taddd\t#%ld\n",voff(o)); cc=0; } return; } ierror(0); } static int scratchreg(int r,struct IC *p) { int c; while(1){ p=p->next; if(!p||((c=p->code)==FREEREG&&p->q1.reg==r)) return 1; if(c==CALL||(c>=BEQ&&c<=BRA)) return 0; if((p->q1.flags®)&&p->q1.reg==r) return 0; if((p->q2.flags®)&&p->q2.reg==r) return 0; if((p->z.flags®)&&p->z.reg==r) return 0; } } /****************************************/ /* End of private fata and functions. */ /****************************************/ int init_cg(void) /* Does necessary initializations for the code-generator. Gets called */ /* once at the beginning and should return 0 in case of problems. */ { int i; CPU=CPUOPT; if (CPU==680912) { bitsperbyte = 12; bytemask = 0xfff; dbl_bytemask = 0xffffff; } /* Initialize some values which cannot be statically initialized */ /* because they are stored in the target's arithmetic. */ maxalign=l2zm(1L); char_bit=l2zm((long)bitsperbyte); for(i=0;i<=MAX_TYPE;i++){ sizetab[i]=l2zm(msizetab[i]); align[i]=l2zm(malign[i]); } for(i=1;i<=iu;i++){ regsize[i]=l2zm(2L);regtype[i]=&ityp; } regsize[dx]=l2zm(4L);regtype[i]=<yp; /* Initialize the min/max-settings. Note that the types of the */ /* host system may be different from the target system and you may */ /* only use the smallest maximum values ANSI guarantees if you */ /* want to be portable. */ /* That's the reason for the subtraction in t_min[INT]. Long could */ /* be unable to represent -2147483648 on the host system. */ if (CPU==680912) { t_min[CHAR]=l2zm(-2048L); t_min[SHORT]=l2zm(-8388608L); t_min[INT]=t_min[SHORT]; t_min[LONG]=zmsub(l2zm(0x800000000000LL),l2zm(1L)); t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L)); t_min[MAXINT]=t_min(LLONG); t_max[CHAR]=ul2zum(2047L); t_max[SHORT]=ul2zum(8388607UL); t_max[INT]=t_max[SHORT]; t_max[LONG]=ul2zum(0x7fffffffffffULL); t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL)); t_max[MAXINT]=t_max(LLONG); tu_max[CHAR]=ul2zum(4095UL); tu_max[SHORT]=ul2zum(16777215UL); tu_max[INT]=tu_max[SHORT]; tu_max[LONG]=ul2zum(0xffffffffffffULL); tu_max[LLONG]=zumkompl(ul2zum(0UL)); tu_max[MAXINT]=t_max(UNSIGNED|LLONG); } else { t_min[CHAR]=l2zm(-128L); t_min[SHORT]=l2zm(-32768L); t_min[INT]=t_min[SHORT]; t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L)); t_min[LLONG]=zmlshift(l2zm(1L),l2zm(63L)); t_min[MAXINT]=t_min(LLONG); t_max[CHAR]=ul2zum(127L); t_max[SHORT]=ul2zum(32767UL); t_max[INT]=t_max[SHORT]; t_max[LONG]=ul2zum(2147483647UL); t_max[LLONG]=zumrshift(zumkompl(ul2zum(0UL)),ul2zum(1UL)); t_max[MAXINT]=t_max(LLONG); tu_max[CHAR]=ul2zum(255UL); tu_max[SHORT]=ul2zum(65535UL); tu_max[INT]=tu_max[SHORT]; tu_max[LONG]=ul2zum(4294967295UL); tu_max[LLONG]=zumkompl(ul2zum(0UL)); tu_max[MAXINT]=t_max(UNSIGNED|LLONG); } if(g_flags[9]&USEDFLAG) drel=1; if(g_flags[10]&USEDFLAG) MINADDI2P=SHORT; if(g_flags[11]&USEDFLAG) nodx=1; if(g_flags[12]&USEDFLAG) nou=1; if(CPU==6812) switchsubs=1; /* Reserve a few registers for use by the code-generator. */ regsa[sp]=REGSA_NEVER; regscratch[sp]=0; if(CPU==6812||drel||nou){ regsa[iu]=REGSA_NEVER; regscratch[iu]=0; } if(CPU!=6812){ regnames[sp]="s"; logicals[0]="or"; } if(!(g_flags[6]&USEDFLAG)){ extern int static_cse,dref_cse; static_cse=0; dref_cse=0; } if(!(g_flags[7]&USEDFLAG)){ regsa[acc]=REGSA_TEMPS; regsa[dx]=REGSA_TEMPS; } if(g_flags[8]&USEDFLAG){ pcrel=1; jsrinst="lbsr"; jmpinst="lbra"; rodataname="\t.data\n"; } if(CPU==6809) marray[1]="__6809__"; if(CPU==6309) marray[1]="__6309__"; if(CPU==680912) marray[1]="__680912__"; target_macros=marray; declare_builtin("__mulint16",INT,INT,acc,INT,0,1,0); declare_builtin("__divint16",INT,INT,ix,INT,acc,1,0); declare_builtin("__divuint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0); declare_builtin("__modint16",INT,INT,ix,INT,acc,1,0); declare_builtin("__moduint16",UNSIGNED|INT,UNSIGNED|INT,ix,UNSIGNED|INT,acc,1,0); /* TODO: set argument registers */ declare_builtin("__mulint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__addint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__subint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__andint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__orint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__eorint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__negint32",LONG,LONG,0,0,0,1,0); declare_builtin("__lslint32",LONG,LONG,0,INT,0,1,0); declare_builtin("__divint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__divuint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0); declare_builtin("__modint32",LONG,LONG,0,LONG,0,1,0); declare_builtin("__moduint32",UNSIGNED|LONG,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0); declare_builtin("__lsrsint32",LONG,LONG,0,INT,0,1,0); declare_builtin("__lsruint32",UNSIGNED|LONG,UNSIGNED|LONG,0,INT,0,1,0); declare_builtin("__cmpsint32",INT,LONG,0,LONG,0,1,0); declare_builtin("__cmpuint32",INT,UNSIGNED|LONG,0,UNSIGNED|LONG,0,1,0); declare_builtin("__sint32toflt32",FLOAT,LONG,0,0,0,1,0); declare_builtin("__uint32toflt32",FLOAT,UNSIGNED|LONG,0,0,0,1,0); declare_builtin("__sint32toflt64",DOUBLE,LONG,0,0,0,1,0); declare_builtin("__uint32toflt64",DOUBLE,UNSIGNED|LONG,0,0,0,1,0); declare_builtin("__flt32tosint32",LONG,FLOAT,0,0,0,1,0); declare_builtin("__flt32touint32",UNSIGNED|LONG,FLOAT,0,0,0,1,0); declare_builtin("__flt64tosint32",LONG,DOUBLE,0,0,0,1,0); declare_builtin("__flt64touint32",UNSIGNED|LONG,DOUBLE,0,0,0,1,0); declare_builtin("__mulint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__addint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__subint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__andint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__orint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__eorint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__negint64",LLONG,LLONG,0,0,0,1,0); declare_builtin("__lslint64",LLONG,LLONG,0,INT,0,1,0); declare_builtin("__divsint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__divuint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0); declare_builtin("__modsint64",LLONG,LLONG,0,LLONG,0,1,0); declare_builtin("__moduint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0); declare_builtin("__lsrsint64",LLONG,LLONG,0,INT,0,1,0); declare_builtin("__lsruint64",UNSIGNED|LLONG,UNSIGNED|LLONG,0,INT,0,1,0); declare_builtin("__cmpsint64",INT,LLONG,0,LLONG,0,1,0); declare_builtin("__cmpuint64",INT,UNSIGNED|LLONG,0,UNSIGNED|LLONG,0,1,0); declare_builtin("__sint64toflt32",FLOAT,LLONG,0,0,0,1,0); declare_builtin("__uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0); declare_builtin("__sint64toflt64",DOUBLE,LLONG,0,0,0,1,0); declare_builtin("__uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0); declare_builtin("__flt32tosint64",LLONG,FLOAT,0,0,0,1,0); declare_builtin("__flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0); declare_builtin("__flt64tosint64",LLONG,DOUBLE,0,0,0,1,0); declare_builtin("__flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0); declare_builtin("__flt32toflt64",DOUBLE,FLOAT,0,0,0,1,0); declare_builtin("__flt64toflt32",FLOAT,DOUBLE,0,0,0,1,0); declare_builtin("__addflt32",FLOAT,FLOAT,0,FLOAT,0,1,0); declare_builtin("__subflt32",FLOAT,FLOAT,0,FLOAT,0,1,0); declare_builtin("__mulflt32",FLOAT,FLOAT,0,FLOAT,0,1,0); declare_builtin("__divflt32",FLOAT,FLOAT,0,FLOAT,0,1,0); declare_builtin("__negflt32",FLOAT,FLOAT,0,FLOAT,0,1,0); declare_builtin("__cmpflt32",INT,FLOAT,0,FLOAT,0,1,0); declare_builtin("__addflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0); declare_builtin("__subflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0); declare_builtin("__mulflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0); declare_builtin("__divflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0); declare_builtin("__negflt64",DOUBLE,DOUBLE,0,DOUBLE,0,1,0); declare_builtin("__cmpflt64",INT,DOUBLE,0,DOUBLE,0,1,0); return 1; } int freturn(struct Typ *t) /* Returns the register in which variables of type t are returned. */ /* If the value cannot be returned in a register returns 0. */ { int f=t->flags&NQ; if(ISSCALAR(f)){ if(ISHWORD(f)||f==CHAR) return acc; else if(ISLWORD(f)) return dx; } return 0; } int regok(int r,int t,int mode) /* Returns 0 if register r cannot store variables of */ /* type t. If t==POINTER and mode!=0 then it returns */ /* non-zero only if the register can store a pointer */ /* and dereference a pointer to mode. */ { if(!ISSCALAR(t)) return 0; if(r==dx){ if(ISLWORD(t)&&(optflags&2)&&!nodx) return 1; return 0; } if(mode==-1){ if(ISHWORD(t)) return 1; if((t&NQ)==CHAR&&ISACC(r)) return 1; }else{ if(ISIDX(r)){ if(ISPOINTER(t)&&ISHWORD(t)) return 1; } if(ISACC(r)){ if((t&NQ)==CHAR) return 1; if(ISINT(t)&&ISHWORD(t)) return 1; } } return 0; } int reg_pair(int r,struct rpair *p) /* Returns 0 if the register is no register pair. If r */ /* is a register pair non-zero will be returned and the */ /* structure pointed to p will be filled with the two */ /* elements. */ { if(r==dx){ p->r1=acc; p->r2=ix; return 1; } return 0; } int cost_savings(struct IC *p,int r,struct obj *o) { /*FIXME*/ int c=p->code; if(r==dx){ if(c==GETRETURN||c==SETRETURN||c==PUSH||c==ASSIGN) return 8; return INT_MIN; } if(o->flags&VKONST){ struct obj *co=&o->v->cobj; if(o->flags&DREFOBJ) return 0; if(o==&p->q1&&p->code==ASSIGN&&((p->z.flags&DREFOBJ)||p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN)){ return 2; } return 0; } if((o->flags&DREFOBJ)){ if(!ISIDX(r)) return INT_MIN; if(p->q2.flags&&o!=&p->z) return 6; else return 6; }else if(c==GETRETURN&&p->q1.reg==r){ return 4; }else if(c==SETRETURN&&p->z.reg==r){ return 4; }else if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR)&®ok(r,CHAR,0)){ return 3; } if(o==&p->z&&r==acc){ if(c==SUB||c==SUBIFP||c==SUBPFP||c==AND||c==OR||c==XOR) return 6; if((c==ADD||c==ADDI2P)&&!(p->q1.flags&(KONST|VKONST))&&!(p->q2.flags&(KONST|VKONST))) return 4; if(c==MULT) return 5; if(c==ASSIGN&&(p->q1.flags&KONST)){ eval_const(&p->q1.val,p->typf); if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))) return 3; } } #if 1 if((o==&p->q2/*||o==&p->z*/)&&!(o->flags&DREFOBJ)&&!ISACC(o->reg)&&(c==MULT||c==DIV||c==MOD)) return INT_MIN; #endif if(c==COMPARE||c==TEST){ if(r==ix) return 3; if(r==iy) return 2; if(r==iu) return 1; } return 2; } int dangerous_IC(struct IC *p) /* Returns zero if the IC p can be safely executed */ /* without danger of exceptions or similar things. */ /* vbcc may generate code in which non-dangerous ICs */ /* are sometimes executed although control-flow may */ /* never reach them (mainly when moving computations */ /* out of loops). */ /* Typical ICs that generate exceptions on some */ /* machines are: */ /* - accesses via pointers */ /* - division/modulo */ /* - overflow on signed integer/floats */ { int c=p->code; if((p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ)||(p->z.flags&DREFOBJ)) return 1; if((c==DIV||c==MOD)&&!isconst(q2)) return 1; return 0; } /* Return name of library function, if this node should be implemented via libcall. */ char *use_libcall(int c,int t,int t2) { static char fname[16]; char *ret=0; if(c==COMPARE){ if((t&NQ)==LLONG||ISFLOAT(t)){ sprintf(fname,"__cmp%s%s%ld",(t&UNSIGNED)?"u":"s",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8); ret=fname; } }else{ t&=NU; t2&=NU; if(t==LDOUBLE) t=DOUBLE; if(t2==LDOUBLE) t2=DOUBLE; if(c==CONVERT){ if(t==t2) return 0; if(t==FLOAT&&t2==DOUBLE) return "__flt64toflt32"; if(t==DOUBLE&&t2==FLOAT) return "__flt32toflt64"; if(ISFLOAT(t)){ sprintf(fname,"__%cint%ldtoflt%d",(t2&UNSIGNED)?'u':'s',zm2l(sizetab[t2&NQ])*8,(t==FLOAT)?32:64); ret=fname; } if(ISFLOAT(t2)){ sprintf(fname,"__flt%dto%cint%ld",((t2&NU)==FLOAT)?32:64,(t&UNSIGNED)?'u':'s',zm2l(sizetab[t&NQ])*8); ret=fname; } } if((t&NQ)==LLONG||ISFLOAT(t)){ if((c>=LSHIFT&&c<=MOD)||(c>=OR&&c<=AND)||c==KOMPLEMENT||c==MINUS){ if(t==(UNSIGNED|LLONG)&&(c==DIV||c==MOD||c==RSHIFT)){ sprintf(fname,"__%suint64",ename[c]); ret=fname; }else if((t&NQ)==LLONG){ sprintf(fname,"__%sint64",ename[c]); ret=fname; }else if(t==(UNSIGNED|LONG)&&(c==DIV||c==MOD||c==RSHIFT)){ sprintf(fname,"__%suint32",ename[c]); ret=fname; }else if((t&NQ)==LONG){ sprintf(fname,"__%sint32",ename[c]); ret=fname; }else{ sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8); ret=fname; } } } if((c==MULT&&(CPU==6809||(t&NQ)==LONG))||c==DIV||c==MOD){ sprintf(fname,"__%s%s%s%ld",ename[c],(c!=MULT&&(t&UNSIGNED))?"u":"",ISFLOAT(t)?"flt":"int",zm2l(sizetab[t&NQ])*8); ret=fname; } } return ret; } int must_convert(int o,int t,int const_expr) /* Returns zero if code for converting np to type t */ /* can be omitted. */ { int op=o&NQ,tp=t&NQ; if(op==tp) return 0; if(ISHWORD(op)&&ISHWORD(tp)) return 0; if(ISFLOAT(op)||ISFLOAT(tp)) return 1; if(ISLWORD(op)&&ISLWORD(tp)) return 0; return 1; } void gen_ds(FILE *f,zmax size,struct Typ *t) /* This function has to create <size> bytes of storage */ /* initialized with zero. */ { if(newobj&§ion!=SPECIAL) emit(f,"%ld\n",zm2l(size)); else emit(f,"\t.space\t%ld\n",zm2l(size)); newobj=0; } void gen_align(FILE *f,zmax align) /* This function has to make sure the next data is */ /* aligned to multiples of <align> bytes. */ { /* nothing to do */ } void gen_var_head(FILE *f,struct Var *v) /* This function has to create the head of a variable */ /* definition, i.e. the label and information for */ /* linkage etc. */ { int constflag; if(v->clist) constflag=is_const(v->vtyp); if(v->storage_class==STATIC){ if(ISFUNC(v->vtyp->flags)) return; if(v->tattr&DPAGE) emit(f,"\t.direct\t%s%ld\n",labprefix,zm2l(v->offset)); if(!special_section(f,v)){ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){ emit(f,dataname);if(f) section=DATA; } if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=RODATA){ emit(f,rodataname);if(f) section=RODATA; } if(!v->clist&§ion!=BSS){ emit(f,bssname);if(f) section=BSS; } } emit(f,"\t.type\t%s%ld,@object\n",labprefix,zm2l(v->offset)); emit(f,"\t.size\t%s%ld,%ld\n",labprefix,zm2l(v->offset),zm2l(szof(v->vtyp))); if(v->clist||section==SPECIAL) emit(f,"%s%ld:\n",labprefix,zm2l(v->offset)); else emit(f,"\t.lcomm\t%s%ld,",labprefix,zm2l(v->offset)); newobj=1; } if(v->storage_class==EXTERN){ if(v->flags&(DEFINED|TENTATIVE)){ emit(f,"\t.global\t%s%s\n",idprefix,v->identifier); if(v->tattr&DPAGE) emit(f,"\t.direct\t%s%s\n",idprefix,v->identifier); if(!special_section(f,v)){ if(v->clist&&(!constflag||(g_flags[3]&USEDFLAG))&§ion!=DATA){ emit(f,dataname);if(f) section=DATA; } if(v->clist&&constflag&&!(g_flags[3]&USEDFLAG)&§ion!=RODATA){ emit(f,rodataname);if(f) section=RODATA; } if(!v->clist&§ion!=BSS){ emit(f,bssname);if(f) section=BSS; } } emit(f,"\t.type\t%s%s,@object\n",idprefix,v->identifier); emit(f,"\t.size\t%s%s,%ld\n",idprefix,v->identifier,zm2l(szof(v->vtyp))); if(v->clist||section==SPECIAL) emit(f,"%s%s:\n",idprefix,v->identifier); else emit(f,"\t.global\t%s%s\n\t.lcomm\t%s%s,",idprefix,v->identifier,idprefix,v->identifier); newobj=1; } } } void gen_dc(FILE *f,int t,struct const_list *p) /* This function has to create static storage */ /* initialized with const-list p. */ { emit(f,"\t%s\t",dct[t&NQ]); if(!p->tree){ if(ISFLOAT(t)){ /* auch wieder nicht sehr schoen und IEEE noetig */ unsigned char *ip; ip=(unsigned char *)&p->val.vdouble; emit(f,"0x%02x%02x%02x%02x",ip[3],ip[2],ip[1],ip[0]); if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE){ emit(f,",0x%02x%02x%02x%02x",ip[7],ip[6],ip[5],ip[4]); } }else{ emitval(f,&p->val,(t&NU)|UNSIGNED); } }else{ int m=p->tree->o.flags,md=drel,mp=pcrel; p->tree->o.flags&=~VARADR; drel=0;pcrel=0; emit_obj(f,&p->tree->o,t&NU); p->tree->o.flags=m; drel=md;pcrel=mp; } emit(f,"\n");newobj=0; } static void preload(FILE *f,IC *p) { int t,r; if((p->typf&VOLATILE)||(p->typf2&VOLATILE)|| ((p->q1.flags&DREFOBJ)&&(p->q1.dtyp&(VOLATILE|PVOLATILE)))|| ((p->q2.flags&DREFOBJ)&&(p->q2.dtyp&(VOLATILE|PVOLATILE)))|| ((p->z.flags&DREFOBJ)&&(p->z.dtyp&(VOLATILE|PVOLATILE)))) emit(f,"; volatile barrier\n"); t=q1typ(p); if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){ r=get_idx(f,p); p->q1.flags&=~DREFOBJ; load_reg(f,r,&p->q1,INT); p->q1.flags|=(REG|DREFOBJ); p->q1.reg=r; } t=q2typ(p); if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){ r=get_idx(f,p); p->q2.flags&=~DREFOBJ; load_reg(f,r,&p->q2,INT); p->q2.flags|=(REG|DREFOBJ); p->q2.reg=r; }else if(isreg(z)&&(((p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg==p->z.reg)||(p->q2.am&&p->q2.am->base==p->z.reg))){ r=get_idx(f,p); p->q2.flags&=~DREFOBJ; load_reg(f,r,&p->q2,INT); p->q2.flags|=(REG|DREFOBJ); p->q2.reg=r; } t=ztyp(p); if(!p->z.am&&(p->z.flags&(REG|DREFOBJ|KONST))==DREFOBJ&&ISLWORD(t)){ r=get_idx(f,p); p->z .flags&=~DREFOBJ; load_reg(f,r,&p->z ,INT); p->z .flags|=(REG|DREFOBJ); p->z .reg=r; } } /* The main code-generation routine. */ /* f is the stream the code should be written to. */ /* p is a pointer to a doubly linked list of ICs */ /* containing the function body to generate code for. */ /* v is a pointer to the function. */ /* offset is the size of the stackframe the function */ /* needs for local variables. */ void gen_code(FILE *f,struct IC *fp,struct Var *v,zmax offset) { int c,t,lastcomp=0,reg,short_add,bit_reverse,need_return=0; struct obj *bit_obj;char *bit_reg; static int idone; struct obj o; IC *p,*p2; if(v->tattr&INTERRUPT) ret="rti"; else if (v->tattr&FAR) ret="rtf"; else ret="rts"; /*FIXME: banked */ if(DEBUG&1) printf("gen_code()\n"); for(p=fp;p;p=p->next) clear_ext_ic(&p->ext); emit(f,"#off1=%ld\n",zm2l(offset)); if(!(g_flags[5]&USEDFLAG)){ peephole(fp); if(!frame_used) offset=l2zm(0L); } for(c=1;c<=MAXR;c++) regs[c]=(regsa[c]==REGSA_NEVER)?1:0; for(c=1;c<=MAXR;c++){ if(regscratch[c]&&(regsa[c]||regused[c])){ BSET(regs_modified,c); } } t=0; for(p=fp;p;p=p->next){ c=p->code; if(c==ALLOCREG){ regs[p->q1.reg]=1; if(p->q1.reg==dx) regs[acc]=regs[ix]=1;} if(c==FREEREG){ regs[p->q1.reg]=0; if(p->q1.reg==dx) regs[acc]=regs[ix]=0;} if((c==LSHIFT||c==RSHIFT)&&(p->typf&NQ)>=LONG) regused[iy]=1; if(c==PUSH&&(p->q1.flags&(REG|DREFOBJ))!=REG){ if(zmeqto(p->q2.val.vmax,Z1)){ if(regs[acc]) t=(t>2)?t:2; }else if(zmeqto(p->q2.val.vmax,l2zm(2L))){ if(regs[acc]&®s[ix]&®s[iy]&&(CPU==6812||regs[iu])) t=(t>2)?t:2; }else if(zmeqto(p->q2.val.vmax,l2zm(4L))){ if(regs[acc]) t=(t>2)?t:2; }else{ /* TODO: finer check */ if(drel||!regsa[iu]) t=(t>8)?t:8; else t=(t>6)?t:6; } } } emit(f,"#toff=%d\n",t); loff=zm2l(offset)+t; function_top(f,v,loff); stackoffset=notpopped=dontpop=maxpushed=0; for(p=fp;p;pr(f,p),p=p->next){ c=p->code;t=p->typf; if(debug_info) dwarf2_line_info(f,p); short_add=0; if(c==NOP) continue; if(c==ALLOCREG){ regs[p->q1.reg]=1; if(p->q1.reg==dx) regs[acc]=regs[ix]=1; continue; } if(c==FREEREG){ regs[p->q1.reg]=0; if(p->q1.reg==dx) regs[acc]=regs[ix]=0; continue; } if(notpopped&&!dontpop){ int flag=0; if(c==LABEL||c==COMPARE||c==TEST||c==BRA){ gen_pop(f,notpopped); notpopped=0; } } if(c==LABEL) {cc=0;emit(f,"%s%d:\n",labprefix,t);continue;} if(c>=BEQ&&c<=BGT&&t==exit_label) need_return=1; if(c==BRA){ if(p->typf==exit_label&&!have_frame){ emit(f,"\t%s\n",ret); }else{ if(t==exit_label) need_return=1; emit(f,"\tbra\t%s%d\n",labprefix,t); } cc=0;continue; } if(c>=BEQ&&c<BRA){ if((lastcomp&UNSIGNED)||ISPOINTER(lastcomp)) emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,t); else emit(f,"\tb%s\t%s%d\n",ccs[c-BEQ],labprefix,t); continue; } if(c==MOVETOREG){ load_reg(f,p->z.reg,&p->q1,SHORT); continue; } if(c==MOVEFROMREG){ store_reg(f,p->q1.reg,&p->z,SHORT); continue; } /*if(ISFLOAT(t)) {pric2(stdout,p);ierror(0);}*/ if((t&NQ)==BIT){ ierror(0); } if(c==CONVERT&&ISLWORD(t)&&ISLWORD(p->typf2)){ p->code=c=ASSIGN; p->q2.val.vmax=l2zm(4L); } if((p->q2.flags®)&&ISACC(p->q2.reg)&&(c==ADD||c==MULT||c==AND||c==OR||c==XOR)){ obj o=p->q1; p->q1=p->q2; p->q2=o; } if(c==TEST){ lastcomp=t; p->code=c=COMPARE; gval.vmax=l2zm(0L); p->q2.flags=KONST; eval_const(&gval,MAXINT); insert_const(&p->q2.val,t); } if(c==SUBPFP){ p->code=c=SUB; p->typf=t=(UNSIGNED|INT); } if((c==ASSIGN||c==PUSH)&&zmeqto(p->q2.val.vmax,l2zm(4L))) p->typf=t=LONG; preload(f,p); if(c==ADDI2P||c==SUBIFP){ if((p->typf2&NQ)!=HPOINTER){ if(p->q2.flags&KONST){ eval_const(&p->q2.val,p->typf); insert_const(&p->q2.val,p->typf2); p->typf=t=(UNSIGNED|SHORT); }else{ if(ISLWORD(t)) inc_addr(&p->q2,2,t); if((t&NQ)==CHAR) short_add=t; p->typf=t=(UNSIGNED|SHORT); } }else if(ISHWORD(t)){ if((t&NQ)==LLONG) inc_addr(&p->q2,4,t); else if((t&NQ)!=LONG) short_add=t; p->typf=t=(UNSIGNED|LONG); } p->code=c=(c==ADDI2P)?ADD:SUB; } if(c==COMPARE&&ISLWORD(t)){ IC *branch=p->next; int r; while(branch&&branch->code==FREEREG) branch=branch->next; if(!branch) ierror(0); c=branch->code; if(c<BEQ||c>BGT) ierror(0); if(!regs[ix]) r=ix; else r=get_reg(f,p,INT); if(c==BEQ||c==BNE){ inc_addr(&p->q1,0,t); inc_addr(&p->q2,0,t); load_reg(f,r,&p->q1,INT); emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]); emit_obj(f,&p->q2,INT); emit(f,"\n"); if(pushed_acc) emit(f,SPULLD); emit(f,"\tbne\t%s%d\n",labprefix,c==BEQ?++label:branch->typf); if(pushed_acc) emit(f,SPUSHD); inc_addr(&p->q1,2,t); inc_addr(&p->q2,2,t); load_reg(f,r,&p->q1,INT); emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]); emit_obj(f,&p->q2,INT); emit(f,"\n"); pr(f,p); if(c==BEQ){ emit(f,"\tbeq\t%s%d\n",labprefix,branch->typf); emit(f,"%s%d:\n",labprefix,label); }else emit(f,"\tbne\t%s%d\n",labprefix,branch->typf); }else{ inc_addr(&p->q1,0,t); inc_addr(&p->q2,0,t); load_reg(f,r,&p->q1,INT); emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]); emit_obj(f,&p->q2,INT); emit(f,"\n"); label++; if(pushed_acc) emit(f,SPULLD); if(t&UNSIGNED){ if(c==BLT||c==BGT) emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lo":"hi",labprefix,branch->typf); else emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lo":"hi",labprefix,label); }else{ if(c==BLT||c==BGT) emit(f,"\tb%s\t%s%d\n",(c==BLT)?"lt":"gt",labprefix,branch->typf); else emit(f,"\tb%s\t%s%d\n",(c==BGE)?"lt":"gt",labprefix,label); } emit(f,"\tbne\t%s%d\n",labprefix,(c==BLT||c==BGT)?label:branch->typf); if(pushed_acc) emit(f,SPUSHD); inc_addr(&p->q1,2,t); inc_addr(&p->q2,2,t); load_reg(f,r,&p->q1,INT); emit(f,"\t%s%s\t",CPU==6812?"cp":"cmp",regnames[r]); emit_obj(f,&p->q2,INT); emit(f,"\n"); pr(f,p); emit(f,"\tb%s\t%s%d\n",uccs[c-BEQ],labprefix,branch->typf); emit(f,"%s%d:\n",labprefix,label); } branch->code=NOP; continue; } if(ISLWORD(t)&&(c==LSHIFT||c==RSHIFT)){ int cnt=-1000,i,r=0; int px=0,py=0,pa=0; if(isconst(q2)){ eval_const(&p->q2.val,p->typf2); cnt=(int)zm2l(vmax); if(cnt==1&&compare_objects(&p->q1,&p->z)){ if(c==LSHIFT) emit(f,"\tlsl\t"); else emit(f,"\t%s\t",(t&UNSIGNED)?"lsr":"asr"); inc_addr(&p->z,c==LSHIFT?3:0,t); emit_obj(f,&p->z,t); emit(f,"\n"); emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror"); inc_addr(&p->z,c==LSHIFT?-1:1,t); emit_obj(f,&p->z,t); emit(f,"\n"); emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror"); inc_addr(&p->z,c==LSHIFT?-1:1,t); emit_obj(f,&p->z,t); emit(f,"\n"); emit(f,"\t%s\t",(c==LSHIFT)?"rol":"ror"); inc_addr(&p->z,c==LSHIFT?-1:1,t); emit_obj(f,&p->z,t); emit(f,"\n"); continue; } } inc_addr(&p->q1,2,t); inc_addr(&p->z,2,t); if(ISRACC(q2)||(regs[acc]&&!scratchreg(acc,p))){ emit(f,SPUSHD); push(2); pa=1; } if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){ if(regs[ix]&&!scratchreg(ix,p)) {px=1;emit(f,SPUSH("x"));push(2);} if(regs[iy]&&!scratchreg(iy,p)) {py=1;emit(f,SPUSH("y"));push(2);} } if(!compare_objects(&p->q1,&p->z)){ load_reg(f,acc,&p->q1,INT); store_reg(f,acc,&p->z,INT); } inc_addr(&p->q1,-2,t); inc_addr(&p->z,-2,t); load_reg(f,acc,&p->q1,INT); if(cnt<0||(optsize&&cnt>1)||(cnt>3&&!optspeed)){ if((p->q2.flags®)&&p->q2.reg==ix){ if((p->z.flags®)&&p->z.reg==iy) ierror(0); }else load_addr(f,ix,&p->z); if(ISRACC(q2)){ if(scratchreg(acc,p)&&(px+py==0)){ emit(f,SPULL("y")); pop(2);pa=0; }else emit(f,"\tldy\t%d,%s\n",(px+py)*2,regnames[sp]); }else load_reg(f,iy,&p->q2,p->typf2); /*TODO: types!=INT?? */ if((p->q2.flags®)&&p->q2.reg==ix) load_addr(f,ix,&p->z); if(c==LSHIFT) emit(f,"\t%s\t%s__lsll\n",jsrinst,idprefix); else emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,(t&UNSIGNED)?"lsrl":"asrl"); if(py) {emit(f,SPULL("y"));pop(2);} if(px) {emit(f,SPULL("x"));pop(2);} }else{ inc_addr(&p->z,c==LSHIFT?3:2,t); for(i=0;i<cnt;i++){ if(c==LSHIFT){ emit(f,"\tlsl\t"); emit_obj(f,&p->z,CHAR); emit(f,"\n"); inc_addr(&p->z,-1,t); emit(f,"\trol\t"); emit_obj(f,&p->z,CHAR); emit(f,"\n"); inc_addr(&p->z,1,t); emit(f,"\trolb\n"); emit(f,"\trola\n"); }else{ emit(f,"\t%s\n",(t&UNSIGNED)?"lsra":"asra"); emit(f,"\trorb\n"); emit(f,"\tror\t"); emit_obj(f,&p->z,CHAR); emit(f,"\n"); inc_addr(&p->z,1,t); emit(f,"\tror\t"); emit_obj(f,&p->z,CHAR); emit(f,"\n"); inc_addr(&p->z,-1,t); } } inc_addr(&p->z,c==LSHIFT?-3:-2,t); store_reg(f,acc,&p->z,INT); } if(pa) {emit(f,SPULLD);pop(2);} continue; } if(ISLWORD(t)&&c!=GETRETURN&&c!=SETRETURN&&c!=COMPARE&&c!=CONVERT&&c!=ADDRESS){ if(c==PUSH&&isreg(q1)&&p->q1.reg==dx){ if(CPU==6812){ emit(f,"\tpshd\n"); emit(f,"\tpshx\n"); }else{ //emit(f,"\tpshs\ta,b,x\n"); emit(f,"\tpshs\tb,a\n"); emit(f,"\tpshs\tx\n"); } push(4); continue; } if(c==ASSIGN&&isreg(q1)&&p->q1.reg==dx){ inc_addr(&p->z,2,t); store_reg(f,ix,&p->z,INT); inc_addr(&p->z,-2,t); store_reg(f,acc,&p->z,INT); continue; } if(c==ASSIGN&&isreg(z)&&p->z.reg==dx){ inc_addr(&p->q1,2,t); load_reg(f,ix,&p->q1,INT); inc_addr(&p->q1,-2,t); load_reg(f,acc,&p->q1,INT); continue; } if(c==PUSH){ if(regs[acc]) emit(f,"\tstd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]); }else get_acc(f,p); /*TODO: acc in IC, constants */ inc_addr(&p->q1,2,t); if(c==MINUS){ if(CPU!=6812&&!optsize) emit(f,"\tldd\t#0\n"); else emit(f,"\tclra\n\tclrb\n"); }else load_reg(f,acc,&p->q1,INT); if(c==ADD||c==SUB){ inc_addr(&p->q2,2,t); emit(f,"\t%s\t",c==ADD?"addd":"subd"); emit_obj(f,&p->q2,INT); emit(f,"\n"); }else if(c==ASSIGN||c==PUSH){ }else if(c==MINUS){ emit(f,"\tsubd\t"); emit_obj(f,&p->q1,INT); emit(f,"\n"); }else if(c==KOMPLEMENT){ emit(f,"\tcoma\n"); emit(f,"\tcomb\n"); }else{ if(c==AND) emit(f,"\tandb\t"); else if(c==OR) emit(f,"\tor%sb\t",CPU==6812?"a":""); else if(c==XOR) emit(f,"\teorb\t"); inc_addr(&p->q2,3,t); emit_obj(f,&p->q2,CHAR); emit(f,"\n"); if(c==AND) emit(f,"\tanda\t"); else if(c==OR) emit(f,"\tor%sa\t",CPU==6812?"a":""); else if(c==XOR) emit(f,"\teora\t"); inc_addr(&p->q2,-1,t); emit_obj(f,&p->q2,CHAR); emit(f,"\n"); } if(c==PUSH){ if(CPU==6812) emit(f,"\tpshd\n"); else emit(f,"\tpshs\tb,a\n"); push(2);dontpop+=2; }else{ inc_addr(&p->z,2,t); store_reg(f,acc,&p->z,INT); } inc_addr(&p->q1,-2,t); if(c==MINUS) emit(f,"\tldd\t#0\n"); else load_reg(f,acc,&p->q1,INT); if(c==ADD) emit(f,"\tadcb\t"); else if(c==SUB) emit(f,"\tsbcb\t"); else if(c==AND) emit(f,"\tandb\t"); else if(c==OR) emit(f,"\tor%sb\t",CPU==6812?"a":""); else if(c==XOR) emit(f,"\teorb\t"); else if(c==KOMPLEMENT) emit(f,"\tcomb\n"); else if(c==MINUS){ inc_addr(&p->q1,1,t); emit(f,"\tsbcb\t"); emit_obj(f,&p->q1,CHAR); emit(f,"\n"); } if(p->q2.flags){ inc_addr(&p->q2,-1,t); emit_obj(f,&p->q2,CHAR); emit(f,"\n"); } if(c==ADD) emit(f,"\tadca\t"); else if(c==SUB) emit(f,"\tsbca\t"); else if(c==AND) emit(f,"\tanda\t"); else if(c==OR) emit(f,"\tor%sa\t",CPU==6812?"a":""); else if(c==XOR) emit(f,"\teora\t"); else if(c==KOMPLEMENT) emit(f,"\tcoma\n"); else if(c==MINUS){ inc_addr(&p->q1,-1,t); emit(f,"\tsbca\t"); emit_obj(f,&p->q1,CHAR); emit(f,"\n"); } if(p->q2.flags){ inc_addr(&p->q2,-1,t); emit_obj(f,&p->q2,CHAR); emit(f,"\n"); } if(c==PUSH){ if(CPU==6812) emit(f,"\tpshd\n"); else emit(f,"\tpshs\tb,a\n"); push(2);dontpop+=2; if(regs[acc]) emit(f,"\tldd\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]); }else{ inc_addr(&p->z,-2,t); store_reg(f,acc,&p->z,INT); } continue; } if(c==COMPARE){ int vadr; if(drel&&(p->q1.flags&VARADR)&&!ISFUNC(p->q1.v->vtyp->flags)) vadr=1; else if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) vadr=2; else if(pcrel&&(p->q1.flags&VARADR)&&ISFUNC(p->q1.v->vtyp->flags)) vadr=1; else if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) vadr=2; else vadr=0; if(vadr!=1&&(vadr==2||isconst(q1)||ISRACC(q2))){ struct IC *p2; o=p->q1;p->q1=p->q2;p->q2=o; p2=p->next; while(p2&&p2->code==FREEREG) p2=p2->next; if(!p2||p2->code<BEQ||p2->code>BGT) ierror(0); if(p2->code==BLT) p2->code=BGT; else if(p2->code==BGT) p2->code=BLT; else if(p2->code==BLE) p2->code=BGE; else if(p2->code==BGE) p2->code=BLE; } /* case with two relative addresses */ if(drel&&(p->q2.flags&VARADR)&&!ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1; if(pcrel&&(p->q2.flags&VARADR)&&ISFUNC(p->q2.v->vtyp->flags)) skip_rel=1; } #if 0 /* TODO: fix cc */ if(c==COMPARE&&isconst(q2)){ eval_const(&p->q2.val,t); if(ISNULL()){ if(cc&&(cc_t&NU)==(t&NU)&&compare_objects(cc,&p->q1)){ lastcomp=t;continue; } } } #endif if(!short_add) switch_IC(p); if(c==CONVERT){ int to=p->typf2&NU; if(to==INT) to=SHORT; if(to==(UNSIGNED|INT)||to==NPOINTER) to=(UNSIGNED|SHORT); if(to==FPOINTER||to==HPOINTER) to=(UNSIGNED|LONG); if((t&NU)==INT) t=SHORT; if((t&NU)==(UNSIGNED|INT)||(t&NU)==NPOINTER) t=(UNSIGNED|SHORT); if((t&NQ)==FPOINTER||(t&NQ)==HPOINTER) t=(UNSIGNED|LONG); /*if((t&NQ)>=LONG||(to&NQ)>=LONG) ierror(0);*/ if((to&NQ)<=LONG&&(t&NQ)<=LONG){ if((to&NQ)<(t&NQ)){ if(ISLWORD(t)){ get_acc(f,p); load_reg(f,acc,&p->q1,to); if((to&NU)==CHAR) emit(f,SEX); else if((to&NU)==(UNSIGNED|CHAR)) emit(f,"\tclra\n"); inc_addr(&p->z,2,t); store_reg(f,acc,&p->z,INT); inc_addr(&p->z,-2,t); if(to&UNSIGNED){ emit(f,"\tclra\n\tclrb\n"); }else{ if(CPU==6812) emit(f,"\texg\ta,b\n"); else emit(f,"\ttfr\ta,b\n"); emit(f,SEX); emit(f,"\ttfr\ta,b\n"); } store_reg(f,acc,&p->z,INT); continue; } /*emit(f,"#conv RACC=%d, regs=%d scratch=%d\n",(int)ISRACC(z),regs[acc],scratchreg(acc,p));*/ if(!ISRACC(z)) get_acc(f,p); load_reg(f,acc,&p->q1,to); if(to&UNSIGNED) emit(f,"\tclra\n"); else emit(f,SEX); store_reg(f,acc,&p->z,t); cc=&p->z;cc_t=t; continue; }else if((to&NQ)>(t&NQ)){ if(!ISRACC(z)&&!ISRACC(q1)) get_acc(f,p); if(ISLWORD(to)) inc_addr(&p->q1,2,to); load_reg(f,acc,&p->q1,to); store_reg(f,acc,&p->z,t); continue; }else{ c=ASSIGN; p->q2.val.vmax=sizetab[t&NQ]; } } } if(c==KOMPLEMENT){ cc=0; if(compare_objects(&p->q1,&p->z)&&!isreg(q1)&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&(!p->q1.am||p->q1.am->flags!=ACC_IND)){ emit(f,"\tcom\t"); emit_obj(f,&p->z,t); emit(f,"\n"); if(ISHWORD(t)){ mobj=p->z; inc_addr(&mobj,1,t); emit(f,"\tcom\t"); emit_obj(f,&mobj,INT); emit(f,"\n"); } continue; } if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p)) get_acc(f,p); load_reg(f,acc,&p->q1,t); emit(f,"\tcoma\n\tcomb\n"); store_reg(f,acc,&p->z,t); continue; } if(c==MINUS){ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p)) get_acc(f,p); if(isreg(q1)){ load_reg(f,acc,&p->q1,t); emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n"); }else{ if(CPU!=6812&&!optsize) emit(f,"\tldd\t#0\n"); else emit(f,"\tclra\n\tclrb\n"); emit(f,"\tsubd\t"); emit_obj(f,&p->q1,t); emit(f,"\n"); } cc=&p->z;cc_t=t; store_reg(f,acc,&p->z,t); continue; } if(c==SETRETURN){ if(isreg(q1)&&p->q1.reg==p->z.reg) continue; if(p->z.reg){ if(ISLWORD(t)){ inc_addr(&p->q1,0,t); load_reg(f,ix,&p->q1,INT); BSET(regs_modified,ix); inc_addr(&p->q1,2,t); } load_reg(f,acc,&p->q1,t); BSET(regs_modified,acc); } continue; } if(c==GETRETURN){ if(isreg(z)&&p->z.reg==p->q1.reg) continue; if(p->q1.reg){ if(ISLWORD(t)){ store_reg(f,ix,&p->z,INT); BSET(regs_modified,ix); inc_addr(&p->z,2,t); } store_reg(f,acc,&p->z,(t&NQ)==CHAR?t:INT); } continue; } if(c==CALL){ int reg,jmp=0; cc=0; if(!calc_regs(p,f!=0)&&v->fi) v->fi->flags&=~ALL_REGS; if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){ long of=va_offset(v)+loff+2; emit(f,"\ttfr\t%s,d\n",regnames[sp]); if(of) emit(f,"\taddd\t#%ld\n",of); continue; } if((p->q1.flags&VAR)&&p->q1.v->fi&&p->q1.v->fi->inline_asm){ emit_inline_asm(f,p->q1.v->fi->inline_asm); jmp=1; }else{ if(stackoffset==0&&!have_frame&&!strcmp(ret,"rts")){ struct IC *p2; jmp=1; for(p2=p->next;p2;p2=p2->next){ if(p2->code!=FREEREG&&p2->code!=ALLOCREG&&p2->code!=LABEL){ jmp=0;break; } } } if(p->q1.flags&DREFOBJ){ /*FIXME: test this*/ if(jmp) emit(f,"\tjmp\t"); else emit(f,"\tjsr\t"); if (p->q1.v->tattr&FAR) emit(f,"\tfar\t"); emit_obj(f,&p->q1,t); emit(f,"\n"); }else{ if(jmp){ emit(f,"\t%s\t",jmpinst); /*emit(f,"\tbra\t");*/ /*if(!need_return) ret=0;*/ /*TODO: works with optimizer? */ }else{ emit(f,"\t%s\t",jsrinst); /*emit(f,"\tbsr\t");*/ } if (p->q1.v->tattr&FAR) emit(f,"\tfar\t"); if(pcrel){ pcrel=0; emit_obj(f,&p->q1,t); pcrel=1; }else emit_obj(f,&p->q1,t); emit(f,"\n"); } } if(stack_valid){ int i; if(p->call_cnt<=0){ err_ic=p;if(f) error(320); stack_valid=0; } for(i=0;stack_valid&&i<p->call_cnt;i++){ if(p->call_list[i].v->fi&&(p->call_list[i].v->fi->flags&ALL_STACK)){ /*FIXME: size of return addr depends on mode */ if(!jmp) push(2); callee_push(zm2l(p->call_list[i].v->fi->stack1)); if(!jmp) pop(2); }else{ err_ic=p;if(f) error(317,p->call_list[i].v->identifier); stack_valid=0; } } } if(!zmeqto(l2zm(0L),p->q2.val.vmax)){ notpopped+=zm2l(p->q2.val.vmax); dontpop-=zm2l(p->q2.val.vmax); if(!(g_flags[2]&USEDFLAG)&&stackoffset==-notpopped){ /* Entfernen der Parameter verzoegern */ }else{ gen_pop(f,zm2l(p->q2.val.vmax)); notpopped-=zm2l(p->q2.val.vmax); } } continue; } if(c==ASSIGN||c==PUSH){ if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax); if(!zmleq(p->q2.val.vmax,l2zm(2L))){ unsigned long size;int qr=0,zr=0,cr=0,px=0,py=0,pu=0,pd=0,lq=0,lz=0; size=zm2l(p->q2.val.vmax); if(c==ASSIGN){ if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->z.reg)){ zr=p->z.reg;lz=1; } } if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&ISIDX(p->q1.reg)&&p->q1.reg!=zr){ qr=p->q1.reg;lq=1; } if(!qr){ if(zr==ix) qr=iy; else if(zr==iy||zr==iu) qr=ix; else{qr=ix;zr=iy;} }else if(!zr){ if(qr==ix) zr=iy; else zr=ix; } if(CPU!=6812){ if(qr!=iu&&zr!=iu) cr=iu; if(qr!=ix&&zr!=ix) cr=ix; if(qr!=iy&&zr!=iy) cr=iy; if(!cr) ierror(0); } if(c==PUSH){ emit(f,"\tleas\t%ld,%s\n",SGN16(-size),regnames[sp]); push(size); } if(CPU!=6812&&(drel||!regused[iu]||(regs[iu]&&!scratchreg(iu,p)))){ if(c==PUSH) emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]); else{ emit(f,SPUSH("u")); push(2); } pu=1; } if(!regused[iy]||(regs[iy]&&!scratchreg(iy,p))){ if(c==PUSH) emit(f,"\tsty\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]); else{ emit(f,SPUSH("y")); push(2); } py=1; } if(regs[ix]&&!scratchreg(ix,p)){ if(c==PUSH) emit(f,"\tstx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]); else{ emit(f,SPUSH("x")); push(2); } px=1; } if(!lq) load_addr(f,qr,&p->q1); if(c==PUSH) emit(f,"\ttfr\t%s,%s\n",regnames[sp],regnames[zr]); else if(!lz) load_addr(f,zr,&p->z); if(size<=6||(size<=16&&!optsize)){ if(CPU!=6812){ if(!scratchreg(acc,p)){ if(c==PUSH) emit(f,"\tstd\t%ld,%s\n",loff-roff-6-stackoffset,regnames[sp]); else{ emit(f,SPUSHD); push(2); } pd=2; } } while(size>2){ if(CPU==6812) emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]); else emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]); size-=2; } if(CPU==6812) emit(f,"\tmov%c\t0,%s,0,%s\n",size==2?'w':'b',regnames[qr],regnames[zr]); else emit(f,"\tld%c\t,%s\n\tst%c\t,%s\n",size==2?'d':'b',regnames[qr],size==2?'d':'b',regnames[zr]); }else{ int l=++label,cnt=(int)(optsize?size:size/8); if(regs[acc]&&!scratchreg(acc,p)){ if(c==PUSH) emit(f,"\tst%c\t%ld,%s\n",(CPU!=6812&&cnt<=bytemask)?'b':'d',loff-roff-6-stackoffset,regnames[sp]); else{ if(CPU!=6812&&cnt<=bytemask){ emit(f,SPUSH("b")); push(1); }else{ emit(f,SPUSHD); push(2); } } pd=(CPU!=6812&&cnt<=bytemask)?1:2; } if(CPU!=6812&&cnt<=bytemask) emit(f,"\tldb\t#%lu\n",cnt); else emit(f,"\tldd\t#%lu\n",cnt); cc=0; #if 0 if(CPU!=6812&&((!regsa[iu]&®s[iu])||drel)){ if(c==PUSH){ emit(f,"\tstu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]); }else{ emit(f,SPUSH("u"));push(2); } } #endif emit(f,"%s%d:\n",labprefix,l); if(CPU==6812){ if(optsize){ emit(f,"\tmovb\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]); }else{ emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]); emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]); emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]); emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]); size=size&7; } emit(f,"\tdbne\td,%s%d\n",labprefix,l); }else{ if(optsize){ emit(f,"\tld%s\t,%s+\n\tst%s\t,%s+\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]); size&=1; }else{ emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]); emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]); emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]); emit(f,"\tld%s\t,%s++\n\tst%s\t,%s++\n",regnames[cr],regnames[qr],regnames[cr],regnames[zr]); size&=7; } if(cnt<=bytemask) emit(f,"\tdecb\n"); else emit(f,"\tsubd\t#1\n"); emit(f,"\tbne\t%s%d\n",labprefix,l); } #if 0 if(CPU!=6812&&((!regsa[iu]&®s[iu])||drel)){ if(c==PUSH){ emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]); }else{ emit(f,SPULL("u"));pop(2); } } #endif while(size>=2){ if(CPU==6812) emit(f,"\tmovw\t2,%s+,2,%s+\n",regnames[qr],regnames[zr]); else emit(f,"\tldd\t,%s++\n\tstd\t,%s++\n",regnames[qr],regnames[zr]); size-=2; } if(size){ if(CPU==6812) emit(f,"\tmovb\t0,%s,0,%s\n",regnames[qr],regnames[zr]); else emit(f,"\tldb\t,%s\n\tstb\t,%s\n",regnames[qr],regnames[zr]); } } if(pd){ if(c==PUSH) emit(f,"\tld%c\t%ld,%s\n",(pd==1)?'b':'d',loff-roff-6-stackoffset,regnames[sp]); else{ if(pd==1){ emit(f,SPULL("b")); pop(1); }else{ emit(f,SPULLD); pop(2); } } } if(px){ if(c==PUSH) emit(f,"\tldx\t%ld,%s\n",loff-roff-2-stackoffset,regnames[sp]); else{ emit(f,SPULL("x")); pop(2); } } if(py){ if(c==PUSH) emit(f,"\tldy\t%ld,%s\n",loff-roff-4-stackoffset,regnames[sp]); else{ emit(f,SPULL("y")); pop(2); } } if(pu){ if(c==PUSH) emit(f,"\tldu\t%ld,%s\n",loff-roff-8-stackoffset,regnames[sp]); else{ emit(f,SPULL("u")); pop(2); } } continue; } if(!ISSCALAR(t)) t=zmeqto(p->q2.val.vmax,l2zm(1L))?CHAR:INT; if((t&NQ)==CHAR&&!zmeqto(p->q2.val.vmax,l2zm(1L))) t=INT; if(mov_op(&p->q1)&&(c==PUSH||mov_op(&p->z))){ emit(f,"\tmov%c\t",ISHWORD(t)?'w':'b'); emit_obj(f,&p->q1,t); if(c==ASSIGN){ emit(f,","); emit_obj(f,&p->z,t); emit(f,"\n"); }else{ emit(f,",%d,-%s\n",ISHWORD(t)?2:1,regnames[sp]); push(ISHWORD(t)?2:1); } continue; } if(((regs[acc]&®s[ix])||(t&NQ)==CHAR)&&(p->q1.flags&KONST)&&!isreg(z)){ eval_const(&p->q1.val,t); if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&((p->z.flags&(REG|DREFOBJ))!=DREFOBJ||(t&NQ)==CHAR)&&(!p->z.am||p->z.am->flags!=ACC_IND||(t&NQ)==CHAR)){ emit(f,"\tclr\t"); if(c==ASSIGN){ emit_obj(f,&p->z,t);emit(f,"\n"); }else{ emit(f,CPU==6812?"1,-sp\n":",-s\n"); push(1); } if(!ISHWORD(t)) continue; emit(f,"\tclr\t"); if(c==ASSIGN){ mobj=p->z; inc_addr(&mobj,1,t); emit_obj(f,&mobj,t);emit(f,"\n"); }else{ emit(f,CPU==6812?"1,-sp\n":",-s\n"); push(1); } continue; } } if(c==PUSH){ int st=0; if(isreg(q1)){ reg=p->q1.reg; }else{ if((t&NQ)==CHAR||!regs[acc]||scratchreg(acc,p)) reg=acc; else if(!regs[ix]||scratchreg(ix,p)) reg=ix; else if(regused[iy]&&(!regs[iy]||scratchreg(iy,p))) reg=iy; else if(regused[iu]&&!drel&&CPU!=6812&&(!regs[iu]||scratchreg(iu,p))) reg=iu; else reg=acc; if(regs[reg]&&!scratchreg(reg,p)){ st=1; emit(f,"\tst%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]); } load_reg(f,reg,&p->q1,t); } if((t&NQ)==CHAR) emit(f,SPUSH("b")); else if(reg==ix) emit(f,SPUSH("x")); else if(reg==iy) emit(f,SPUSH("y")); else if(reg==iu) emit(f,SPUSH("u")); else emit(f,SPUSHD); push(zm2l(p->q2.val.vmax)); if(st) emit(f,"\tld%s\t%ld,%s\n",regnames[reg],(long)loff-roff-2-stackoffset,regnames[sp]); continue; } if(c==ASSIGN){ if(isreg(q1)&&isreg(z)){ if(p->q1.reg!=p->z.reg) emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[p->z.reg]); }else if(isreg(q1)){ store_reg(f,p->q1.reg,&p->z,t); }else if(isreg(z)){ load_reg(f,p->z.reg,&p->q1,t); }else{ reg=get_reg(f,p,t); load_reg(f,reg,&p->q1,t); store_reg(f,reg,&p->z,t); } continue; } ierror(0); } if(c==ADDRESS){ int px=0; if(isreg(z)){ reg=p->z.reg; }else if(!regs[ix]){ reg=ix; }else if(!regs[iy]){ reg=iy; }else{ /*FIXME: test if x used in q1 */ px=1; emit(f,SPUSH("x")); reg=ix; push(2); } load_addr(f,reg,&p->q1); if(!(p->z.flags®)||p->z.reg!=reg) store_reg(f,reg,&p->z,p->typf2); if(px){ emit(f,SPULL("x")); pop(2); } continue; } if((c==MULT||c==DIV||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){ long ln; eval_const(&p->q2.val,t); if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){ if((ln=pof2(vumax))&&ln<5){ if(c==MOD){ vmax=zmsub(vmax,l2zm(1L)); c=p->code=c=AND; }else{ vmax=l2zm(ln-1); if(c==DIV) p->code=c=RSHIFT; else p->code=c=LSHIFT; } c=p->code; gval.vmax=vmax; eval_const(&gval,MAXINT); if(c==AND){ insert_const(&p->q2.val,t); }else{ insert_const(&p->q2.val,t); p->typf2=INT; } } } } if(c==MOD||c==DIV){ ierror(0); continue; } if((c==ADD||c==SUB)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&(p->q1.flags&(REG|DREFOBJ))!=REG&&(p->q1.flags&(REG|DREFOBJ))!=DREFOBJ&&!p->q1.am&&!p->z.am&&compare_objects(&p->q1,&p->z)){ eval_const(&p->q2.val,t); if(c==SUB) vmax=zmsub(Z0,vmax); if((t&NQ)==CHAR&&zmeqto(vmax,Z1)){ emit(f,"\tinc\t"); emit_obj(f,&p->z,t); emit(f,"\n"); continue; }else if((t&NQ)==CHAR&&zmeqto(vmax,l2zm(-1L))){ emit(f,"\tdec\t"); emit_obj(f,&p->z,t); emit(f,"\n"); continue; }else if(((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(1L))){ inc_addr(&p->z,1,t); emit(f,"\tinc\t"); emit_obj(f,&p->z,t); emit(f,"\n"); emit(f,"\tbne\t%s%d\n",labprefix,++label); inc_addr(&p->z,-1,t); emit(f,"\tinc\t"); emit_obj(f,&p->z,t); emit(f,"\n"); emit(f,"%s%d:\n",labprefix,label); continue; }else if(regs[acc]&&((t&NQ)==SHORT||(t&NQ)==INT)&&zmeqto(vmax,l2zm(-1L))){ inc_addr(&p->z,1,t); emit(f,"\ttst\t"); emit_obj(f,&p->z,t); emit(f,"\n"); emit(f,"\tbne\t%s%d\n",labprefix,++label); inc_addr(&p->z,-1,t); emit(f,"\tdec\t"); emit_obj(f,&p->z,t); emit(f,"\n"); emit(f,"%s%d:\n",labprefix,label); inc_addr(&p->z,1,t); emit(f,"\tdec\t"); emit_obj(f,&p->z,t); emit(f,"\n"); continue; } } if((c>=LSHIFT&&c<=MOD)||c==ADDI2P||c==SUBIFP||c==SUBPFP||(c>=OR&&c<=AND)||c==COMPARE){ char *s; /*FIXME: nicht immer besser*/ if(ISLWORD(t)&&c==LSHIFT&&isconst(q2)){ eval_const(&p->q2.val,t); if(zm2l(vmax)==1){ p->code=c=ADD; p->q2=p->q1; } } if((c==ADD||c==ADDI2P||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&!isreg(q1)&&!short_add){ o=p->q1;p->q1=p->q2;p->q2=o; } if((c==ADD||c==MULT||(c>=OR&&c<=AND))&&isreg(q2)&&p->q2.reg==acc&&!short_add){ o=p->q1;p->q1=p->q2;p->q2=o; } if(c==MULT||c==MOD){ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p)) get_acc(f,p); reg=acc; /*FIXME: y bzw. x-Register*/ }else if(c==LSHIFT||c==RSHIFT||c==AND||c==OR||c==XOR){ if((!isreg(z)||p->z.reg!=acc)&®s[acc]&&!scratchreg(acc,p)) get_acc(f,p); reg=acc; }else if(c==DIV){ reg=ix; ierror(0); }else if(isreg(z)){ reg=p->z.reg; }else if(isreg(q1)&&(c==COMPARE||scratchreg(p->q1.reg,p))){ reg=p->q1.reg; }else{ if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==COMPARE){ if(ISRACC(q2)) reg=acc; else reg=get_reg(f,p,t); }else{ get_acc(f,p); reg=acc; } } if(c==ADD||c==ADDI2P||c==SUB||c==SUBIFP){ int opdone=0; if(isreg(q1)){ if(ISIDX(reg)&&ISIDX(p->q1.reg)&&isconst(q2)){ eval_const(&p->q2.val,short_add?short_add:q2typ(p)); if(CPU==6812&&p->q1.reg==reg&&zmeqto(vmax,l2zm(1L))&&zumeqto(vumax,ul2zum(1UL))){ emit(f,"\t%s%s\n",c==SUB?"de":"in",regnames[reg]); /*FIXME: condition-codes for bne/beq could be used */ }else{ emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],c==SUB?SGN16(-zm2l(vmax)):SGN16(zm2l(vmax)),regnames[p->q1.reg]); } opdone=1; }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISIDX(p->q1.reg)&&ISRACC(q2)){ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NQ)==CHAR||(short_add&NQ)==CHAR)?"b":"d",regnames[p->q1.reg]); opdone=1; }else if((c==ADD||c==ADDI2P)&&ISIDX(reg)&&ISACC(p->q1.reg)&&ISRIDX(q2)){ emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[p->q2.reg]); opdone=1; }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&!short_add){ load_reg(f,reg,&p->q2,t); emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]); opdone=1; }else if((c==ADD||c==ADDI2P)&&p->q1.reg==acc&&ISIDX(reg)&&(short_add&NU)==(UNSIGNED|CHAR)&&scratchreg(acc,p)){ emit(f,"\taddb\t"); emit_obj(f,&p->q2,short_add); emit(f,"\n"); emit(f,"\tadca\t#0\n"); emit(f,"\ttfr\td,y\n"); opdone=1; }else if((c==ADD||c==ADDI2P)&&ISACC(p->q1.reg)&&ISRACC(z)&&isreg(q2)&&ISIDX(p->q2.reg)){ if(!scratchreg(p->q2.reg,p)) emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]); emit(f,"\tlea%s\t%s,%s\n",regnames[p->q2.reg],regnames[acc],regnames[p->q2.reg]); emit(f,"\texg\t%s,%s\n",regnames[acc],regnames[p->q2.reg]); opdone=1; }else if(p->q1.reg!=reg){ if(c==ADD||c==ADDI2P||!ISRACC(q2)) emit(f,"\ttfr\t%s,%s\n",regnames[p->q1.reg],regnames[reg]); } }else if(short_add&&c==SUB&®==acc&&!(short_add&UNSIGNED)){ load_reg(f,reg,&p->q2,short_add); emit(f,"\tclra\n"); emit(f,"\tnegb\n"); emit(f,"\tsbca\t#0\n"); emit(f,"\taddd\t"); emit_obj(f,&p->q1,t); emit(f,"\n"); store_reg(f,reg,&p->z,ztyp(p)); continue; }else if(short_add&&c==ADD&®==acc){ load_reg(f,reg,&p->q2,short_add); if(short_add&UNSIGNED) emit(f,"\tclra\n"); else emit(f,SEX); emit(f,"\taddd\t"); emit_obj(f,&p->q1,t); emit(f,"\n"); store_reg(f,reg,&p->z,ztyp(p)); continue; }else{ if(!ISRACC(q2)) load_reg(f,reg,&p->q1,q1typ(p)); } if(!opdone){ if(reg==acc){ if(ISRACC(q2)){ if(!ISRACC(z)) get_acc(f,p); if(c==ADD||c==ADDI2P){ if(short_add){ if(short_add&UNSIGNED) emit(f,"\tclra\n"); else emit(f,SEX); emit(f,"\taddd\t"); emit_obj(f,&p->q1,t); emit(f,"\n"); }else{ if(CPU==6812) emit(f,"\tasld\n"); /* only cases with q1=q2=acc should remain */ else{ emit(f,"\taslb\n"); if((t&NQ)!=CHAR) emit(f,"\trola\n"); } } }else{ if(short_add){ if(short_add&UNSIGNED) emit(f,"\tld%sa\t#255\n",(CPU==6812)?"a":""); else{ emit(f,SEX); emit(f,"\tnega\n"); } emit(f,"\tnegb\n\tsbca\t#0\n"); }else if((t&NQ)!=CHAR){ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n"); }else{ emit(f,"\tnegb\n"); } if(ISRIDX(q1)){ emit(f,"\t%s%s\n",CPU==6812?"psh":"pshs\t",regnames[p->q1.reg]); emit(f,"\taddd\t%s\n",CPU==6812?"1,s+":",s++"); }else{ emit(f,"\taddd\t"); emit_obj(f,&p->q1,t); emit(f,"\n"); } } }else{ if(ISRIDX(q2)){ if(CPU==6812) emit(f,"\tpsh%s\n",regnames[p->q2.reg]); else emit(f,"\tpshs\t%s\n",regnames[p->q2.reg]); push(2);pop(2); if(CPU==6812) emit(f,"\t%sd\t2,%s+\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]); else emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]); }else{ emit(f,"\t%s%s\t",(c==ADD||c==ADDI2P)?"add":"sub",(short_add||(t&NQ)==CHAR)?"b":"d"); emit_obj(f,&p->q2,short_add?short_add:t);emit(f,"\n"); if(short_add){ if(short_add&UNSIGNED) emit(f,"\t%s\t#0\n",c==ADD?"adca":"sbca"); else ierror(0); } if(drel&&(p->q2.flags&VARADR)){ if(CPU==6812) ierror(0); emit(f,"\tpshs\t%s\n",regnames[iu]);push(2); emit(f,"\t%sd\t,%s++\n",(c==ADD||c==ADDI2P)?"add":"sub",regnames[sp]); pop(2); } } } cc=&p->z;cc_t=t; }else{ if(isconst(q2)){ long l; eval_const(&p->q2.val,short_add?short_add:t); l=zm2l(vmax); if(c==SUB) l=-l; /*FIXME: condition-codes for bne/beq could be used */ if(l==1&®==ix&&CPU==6812){ emit(f,"\tinx\n"); }else if(l==1&®==iy&&CPU==6812){ emit(f,"\tiny\n"); }else if(l==-1&®==ix&&CPU==6812){ emit(f,"\tdex\n"); }else if(l==-1&®==iy&&CPU==6812){ emit(f,"\tdey\n"); }else{ emit(f,"\tlea%s\t%ld,%s\n",regnames[reg],SGN16(l),regnames[reg]); } }else{ if(c!=ADD&&c!=ADDI2P){ if(!ISRACC(q2)){ if(!scratchreg(acc,p)) get_acc(f,p); load_reg(f,acc,&p->q2,t); if((t&NQ)!=CHAR){ emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n"); }else{ emit(f,"\tnegb\n"); } /*load_reg(f,reg,&p->q1,t);*/ }else{ get_acc(f,p); load_reg(f,reg,&p->q1,t); if((t&NQ)==CHAR) emit(f,"\tnegb\n"); else emit(f,"\tnega\n\tnegb\n\tsbca\t#0\n"); } }else if(!ISRACC(q2)){ get_acc(f,p); if(short_add){ load_reg(f,acc,&p->q2,short_add); if(short_add&UNSIGNED){ if(reg==ix){ emit(f,"\tabx\n"); store_reg(f,reg,&p->z,ztyp(p)); continue; }else{ emit(f,"\tclra\n"); } }else t=CHAR; }else load_reg(f,acc,&p->q2,t); }else{ load_reg(f,reg,&p->q1,t); if(short_add&UNSIGNED) emit(f,"\tclra\n"); emit(f,"\tlea%s\t%s,%s\n",regnames[reg],((t&NU)==CHAR||(short_add&NU)==CHAR)?"b":"d",regnames[reg]); store_reg(f,reg,&p->z,ztyp(p)); continue; } emit(f,"\tlea%s\t%s,%s\n",regnames[reg],(t&NQ)==CHAR?"b":"d",regnames[reg]); } } } store_reg(f,reg,&p->z,ztyp(p)); continue; } if(c!=LSHIFT&&c!=RSHIFT) load_reg(f,reg,&p->q1,t); if(c==MULT){ if(CPU==6812){ int py=0; if(reg!=acc) ierror(reg); if(!ISRY(q2)&®s[iy]){ emit(f,"\tpshy\n"); push(2); py=1; } load_reg(f,iy,&p->q2,t); emit(f,"\temul\n"); if(py){ emit(f,SPULL("y")); pop(2); } store_reg(f,acc,&p->z,t); continue; }else ierror(0); } if(c==LSHIFT||c==RSHIFT){ if(isconst(q2)){ int l,oldl; load_reg(f,acc,&p->q1,t); eval_const(&p->q2.val,t); oldl=l=zm2l(vmax); if(l>=24){ if(CPU!=6812&&!optsize) emit(f,"\tldd\t#0\n"); else emit(f,"\tclra\n\tclrb\n"); l=0; } if(l>=8){ if(c==LSHIFT) emit(f,"\t%s\n\tclrb\n",(CPU==6812)?"tba":"tfr\tb,a"); else{ if(t&UNSIGNED) emit(f,"\ttfr\ta,b\n\tclra\n"); else{ emit(f,"\ttfr\ta,b\n"); emit(f,SEX); } } l-=8; } while(l--){ if(c==RSHIFT){ if(t&UNSIGNED){ if((t&NQ)==CHAR) emit(f,"\tlsrb\n"); else emit(f,CPU==6809?"\tlsra\n\trorb\n":"\tlsrd\n"); }else{ if(oldl>12||(t&NQ)==CHAR) emit(f,"\tasrb\n"); else emit(f,"\tasra\n\trorb\n"); } }else{ if((t&NQ)==CHAR) emit(f,"\taslb\n"); else emit(f,CPU==6809?"\taslb\n\trola\n":"\tasld\n"); } } }else{ int px;char *s; if(regs[ix]&&!scratchreg(ix,p)&&(!isreg(z)||p->z.reg!=ix)){ emit(f,SPUSH("x")); push(2);px=1; }else px=0; if((p->typf2&NQ)==CHAR){ load_reg(f,acc,&p->q2,p->typf2); emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX); emit(f,"\ttfr\td,x\n"); }else load_reg(f,ix,&p->q2,t); load_reg(f,acc,&p->q1,p->typf); if((t&NQ)==CHAR) emit(f,(p->typf2&UNSIGNED)?"\tclra\n":SEX); if(c==LSHIFT) s="lsl"; else if(t&UNSIGNED) s="lsr"; else s="asr"; emit(f,"\t.global\t%s__%s\n",idprefix,s); emit(f,"\t%s\t%s__%s\n",jsrinst,idprefix,s); if(px){ emit(f,SPULL("x")); /*emit(f,"\tpul%s\n",regnames[ix]);*/ pop(2); } } cc=0; store_reg(f,acc,&p->z,t); continue; } if(c>=OR&&c<=AND){ s=logicals[c-OR]; if(p->q2.am&&p->q2.am->flags==ACC_IND){ mobj=p->q1;p->q1=p->q2;p->q2=mobj; } if(p->q2.flags&KONST){ unsigned long l,h; eval_const(&p->q2.val,t); l=zum2ul(vumax); if((t&NQ)!=CHAR){ h=(l>>bitsperbyte)&bytemask; if(c==AND&&h==0) emit(f,"\tclra\n"); else if(c==XOR&&h==bytemask) emit(f,"\tcoma\n"); else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0)) emit(f,"\t%sa\t#%lu\n",s,h); } h=l&bytemask; if(c==AND&&h==0) emit(f,"\tclrb\n"); else if(c==XOR&&h==bytemask) emit(f,"\tcomb\n"); else if((c==AND&&h!=bytemask)||(c==OR&&h!=0)||(c==XOR&&h!=0)) emit(f,"\t%sb\t#%lu\n",s,h); }else{ if(isreg(q2)){ if(p->q2.reg==acc){ if(c==XOR){ emit(f,"\tclrb\n"); if((t&NQ)!=CHAR) emit(f,"\tclra\n"); } }else{ if((t&NQ)==CHAR){ emit(f,SPUSH("a")); push(1); emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]); pop(1); }else{ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]); push(2); emit(f,"\t%sa\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]); emit(f,"\t%sb\t%s,%s+\n",s,CPU==6812?"1":"",regnames[sp]); pop(2); } } }else if((p->q2.flags&(REG|DREFOBJ))==DREFOBJ&&(t&NQ)!=CHAR){ int xr=0; if(!regs[ix]) xr=ix; else if(!regs[iy]) xr=iy; else{ xr=ix; emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[xr]); push(2); } BSET(regs_modified,xr); load_addr(f,xr,&p->q2); if((t&NQ)==CHAR) emit(f,"\t%sb\t0,%s\n",s,regnames[xr]); else{ emit(f,"\t%sa\t0,%s\n",s,regnames[xr]); emit(f,"\t%sb\t1,%s\n",s,regnames[xr]); } if(regs[ix]&&xr==ix){ emit(f,SPULL("x")); pop(2); } }else{ emit(f,"\t%sb\t",s); if((t&NQ)!=CHAR) inc_addr(&p->q2,1,t); emit_obj(f,&p->q2,t); emit(f,"\n"); if((t&NQ)!=CHAR){ inc_addr(&p->q2,-1,t); emit(f,"\t%sa\t",s); emit_obj(f,&p->q2,t); emit(f,"\n"); } } } cc=0; store_reg(f,reg,&p->z,t); continue; }else if(c==COMPARE){ lastcomp=t; if(isreg(q2)){ emit(f,"\t%s%s\n",(CPU==6812)?"psh":"pshs\t",regnames[p->q2.reg]); push(2); } if(reg==acc){ if((t&NQ)==CHAR) emit(f,"\tcmpb\t"); else emit(f,SCMP("d")); }else if(reg==ix){ emit(f,SCMP("x")); }else if(reg==iy){ emit(f,SCMP("y")); }else if(reg==iu){ emit(f,SCMP("u")); }else ierror(0); if(isreg(q2)){ if(CPU==6812) emit(f,"2,%s+\n",regnames[sp]); else emit(f,",%s++\n",regnames[sp]); pop(2); }else{ emit_obj(f,&p->q2,t);emit(f,"\n"); } continue; } ierror(0); } pric2(stdout,p); ierror(0); } if(notpopped){ gen_pop(f,notpopped); notpopped=0; } function_bottom(f,v,loff); if(debug_info){ emit(f,"%s%d:\n",labprefix,++label); dwarf2_function(f,v,label); if(f) section=-1; } } int shortcut(int c,int t) { if(c==COMPARE||c==ADD||c==SUB||c==AND||c==OR||c==XOR) return 1; if((c==LSHIFT||c==RSHIFT)&&ISCHWORD(t&NQ)) return 1; return 0; } void cleanup_cg(FILE *f) { struct fpconstlist *p; unsigned char *ip; if(f&&stack_check) emit(f,"\t.global\t%s__stack_check\n",idprefix); while(p=firstfpc){ if(f){ if(section!=RODATA){ emit(f,rodataname);if(f) section=RODATA; } emit(f,"%s%d\n\t%s\t",labprefix,p->label,dct[LONG]); ip=(unsigned char *)&p->val.vdouble; emit(f,"0x%02x%02x%02x%02x",ip[0],ip[1],ip[2],ip[3]); if((p->typ&NQ)==DOUBLE||(p->typ&NQ)==LDOUBLE){ emit(f,",0x%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]); } emit(f,"\n"); } firstfpc=p->next; free(p); } } int reg_parm(struct reg_handle *p,struct Typ *t,int mode,struct Typ *fkt) { if(p->gpr) return 0; if(ISSCALAR(t->flags)&&!ISFLOAT(t->flags)&&!ISLWORD(t->flags)){ p->gpr=1; return acc; } return 0; } void insert_const(union atyps *p,int t) /* Traegt Konstante in entprechendes Feld ein. */ { if(!p) ierror(0); t&=NU; if(t==BIT) {if(zmeqto(zc2zm(vchar),l2zm(0L))) p->vchar=zm2zc(l2zm(0L)); else p->vchar=zm2zc(l2zm(1L));return;} 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|BIT)) {if(zumeqto(zuc2zum(vuchar),ul2zum(0UL))) p->vuchar=zum2zuc(ul2zum(0UL)); else p->vuchar=zum2zuc(ul2zum(1UL));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==NPOINTER) {p->vuint=vuint;return;} if(t==FPOINTER||t==HPOINTER) {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>=BIT&&f<=LLONG)){ if(!(t&UNSIGNED)){ if(f==BIT){ if(zmeqto(zc2zm(p->vchar),l2zm(0L))) vmax=l2zm(0L); else vmax=l2zm(1L); }else 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==BIT){ if(zumeqto(zuc2zum(p->vuchar),ul2zum(0UL))) vumax=ul2zum(0UL); else vumax=ul2zum(1UL); }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)){ if(f==NPOINTER) vumax=zui2zum(p->vuint); else 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); } void printval(FILE *f,union atyps *p,int t) /* Gibt atyps aus. */ { t&=NU; if(t==BIT){vmax=zc2zm(p->vchar);fprintf(f,"B%d",!zmeqto(vmax,l2zm(0L)));} if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);fprintf(f,"UB%d",!zumeqto(vmax,ul2zum(0UL)));} if(t==CHAR){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)||t==NPOINTER){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)||t==FPOINTER||t==HPOINTER){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) printzm(f,p->vmax); if(t==(UNSIGNED|MAXINT)) printzum(f,p->vumax); } void emitval(FILE *f,union atyps *p,int t) { t&=NU; if((t&NQ)==NPOINTER) t=(UNSIGNED|INT); if(t==BIT){vmax=zc2zm(p->vchar);emit(f,"%d",!zmeqto(vmax,l2zm(0L)));} if(t==(UNSIGNED|BIT)){vumax=zuc2zum(p->vuchar);emit(f,"%d",!zumeqto(vmax,ul2zum(0UL)));} 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)||t==NPOINTER){vumax=zui2zum(p->vuint);emitzum(f,vumax);} if(t==LONG){vmax=zl2zm(p->vlong);emitzm(f,vmax);} if(t==(UNSIGNED|LONG)||t==FPOINTER||t==HPOINTER){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); } void conv_typ(struct Typ *p) /* Erzeugt extended types in einem Typ. */ { char *attr; while(p){ if(ISPOINTER(p->flags)){ p->flags=((p->flags&~NU)|POINTER_TYPE(p->next)); if(attr=p->next->attr){ if(strstr(attr,STR_NEAR)) p->flags=((p->flags&~NU)|NPOINTER); if(strstr(attr,STR_FAR)) p->flags=((p->flags&~NU)|FPOINTER); if(strstr(attr,STR_HUGE)) p->flags=((p->flags&~NU)|HPOINTER); } } if(ISINT(p->flags)&&(attr=p->attr)&&strstr(attr,"bit")) p->flags=((p->flags&~NU)|BIT); p=p->next; } } void init_db(FILE *f) { dwarf2_setup(sizetab[HPOINTER],".byte",".2byte",".4byte",".4byte",labprefix,idprefix,".section"); dwarf2_print_comp_unit_header(f); } void cleanup_db(FILE *f) { dwarf2_cleanup(f); if(f) section=-1; }