| /* $VER: vbcc (m68k/machine.c) $Revision: 1.139 $ */ |
| /* Code generator for Motorola 680x0 CPUs. Supports 68000-68060+68881/2 */ |
| /* and ColdFire. */ |
| /* vasm, PhxAss and the GNU assembler is supported. */ |
| |
| |
| #include "supp.h" |
| |
| #define NEW_RET 0 |
| |
| static char FILE_[]=__FILE__; |
| |
| #include "dwarf2.c" |
| |
| /* Public data that MUST be there. */ |
| |
| /* Name and copyright. */ |
| char cg_copyright[]="vbcc code-generator for m68k/ColdFire V1.15 (c) in 1995-2022 by Volker Barthelmann"; |
| |
| /* Commandline-flags the code-generator accepts */ |
| int g_flags[MAXGF]={VALFLAG,VALFLAG,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
| char *g_flags_name[MAXGF]={ |
| "cpu","fpu","d2scratch","noa4","sc","sd","prof","const-in-data", |
| "use-framepointer","no-peephole","no-delayed-popping", |
| "gas","branch-opt","no-fp-return","no-mreg-return","hunkdebug", |
| "no-intz","old-peephole","conservative-sr","elf","use-commons", |
| "a2scratch","old-softfloat","amiga-softfloat","fastcall","fp2scratch", |
| "no-reserve-regs","phxass","clean-fattr","old-libcalls","vbcccall", |
| "float64" |
| }; |
| |
| union ppi g_flags_val[MAXGF]; |
| |
| /* 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[MAXR+1]={"noreg","a0","a1","a2","a3","a4","a5","a6","a7", |
| "d0","d1","d2","d3","d4","d5","d6","d7", |
| "fp0","fp1","fp2","fp3","fp4","fp5","fp6","fp7", |
| "d0/d1","d2/d3","d4/d5","d6/d7"}; |
| |
| static char *elfregnames[MAXR+1]={"noreg","%a0","%a1","%a2","%a3","%a4","%a5","%a6","%a7", |
| "%d0","%d1","%d2","%d3","%d4","%d5","%d6","%d7", |
| "%fp0","%fp1","%fp2","%fp3","%fp4","%fp5","%fp6","%fp7", |
| "%d0/%d1","%d2/%d3","%d4/%d5","%d6/%d7"}; |
| |
| static char *mregnames[MAXR+1]; |
| |
| /* The Size of each register in bytes. */ |
| zmax regsize[MAXR+1]; |
| |
| /* Type which can store each register. */ |
| type *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]={0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
| |
| /* Specifies which registers may be scratched by functions. */ |
| int regscratch[MAXR+1]={0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0, |
| 1,0,0,0}; |
| |
| int reg_prio[MAXR+1]={0,4,4,3,3,3,3,3,0,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0}; |
| |
| treg_handle empty_reg_handle={0,0,0}; |
| |
| /* Names of target-specific variable attributes. */ |
| char *g_attr_name[]={"__far","__near","__chip","__saveds", |
| "__interrupt","__amigainterrupt",0}; |
| #define FAR 1 |
| #define NEAR 2 |
| #define CHIP 4 |
| #define SAVEDS 8 |
| #define INTERRUPT 16 |
| #define AMIINTERRUPT 32 |
| #define STDARGS 64 /* not used, just for compatibility */ |
| |
| int MINADDI2P=SHORT; |
| |
| /****************************************/ |
| /* Some private data and functions. */ |
| /****************************************/ |
| #define CPU (g_flags_val[0].l) |
| #define FPU (g_flags_val[1].l) |
| #define D2SCRATCH (g_flags[2]&USEDFLAG) |
| #define NOA4 (g_flags[3]&USEDFLAG) |
| #define SMALLCODE (g_flags[4]&USEDFLAG) |
| #define SMALLDATA (g_flags[5]&USEDFLAG) |
| #define PROFILER (g_flags[6]&USEDFLAG) |
| #define CONSTINDATA (g_flags[7]&USEDFLAG) |
| #define USEFRAMEPOINTER (g_flags[8]&USEDFLAG) |
| #define NOPEEPHOLE (g_flags[9]&USEDFLAG) |
| #define NODELAYEDPOP (g_flags[10]&USEDFLAG) |
| #define GAS (g_flags[11]&USEDFLAG) |
| #define BRANCHOPT (g_flags[12]&USEDFLAG) |
| #define NOFPRETURN (g_flags[13]&USEDFLAG) |
| #define NOMREGRETURN (g_flags[14]&USEDFLAG) |
| #define HUNKDEBUG (g_flags[15]&USEDFLAG) |
| #define NOINTZ (g_flags[16]&USEDFLAG) |
| #define OLDPEEPHOLE (g_flags[17]&USEDFLAG) |
| #define CONSERVATIVE_SR (g_flags[18]&USEDFLAG) |
| #define ELF (g_flags[19]&USEDFLAG) |
| #define USE_COMMONS (g_flags[20]&USEDFLAG) |
| #define A2SCRATCH (g_flags[21]&USEDFLAG) |
| #define OLD_SOFTFLOAT (g_flags[22]&USEDFLAG) |
| #define AMI_SOFTFLOAT (g_flags[23]&USEDFLAG) |
| #define FASTCALL (g_flags[24]&USEDFLAG) |
| #define FP2SCRATCH (g_flags[25]&USEDFLAG) |
| #define RESERVEREGS (g_flags[26]&USEDFLAG) |
| #define PHXASS (g_flags[27]&USEDFLAG) |
| #define CLEANFATTR (g_flags[28]&USEDFLAG) |
| #define OLDLIBCALLS (g_flags[29]&USEDFLAG) |
| #define VBCCCALL (g_flags[30]&USEDFLAG) |
| #define FLOAT64 (g_flags[31]&USEDFLAG) |
| |
| |
| static int use_sd; |
| |
| #ifdef M68K_16BIT_INT |
| static long malign[MAX_TYPE+1]= {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1}; |
| static long msizetab[MAX_TYPE+1]={0,1,2,2,4,8,4,8,8,0,4,0,0,0,4,0}; |
| #else |
| static long malign[MAX_TYPE+1]= {1,1,2,2,2,2,2,2,2,1,2,1,1,1,2,1}; |
| static long msizetab[MAX_TYPE+1]={0,1,2,4,4,8,4,8,8,0,4,0,0,0,4,0}; |
| #endif |
| |
| static type ltyp={LONG},larray={ARRAY,<yp},lltyp={LLONG}; |
| |
| static char cpu_macro[16],fpu_macro[16],*marray[16]; |
| |
| static char pushreglist[200],popreglist[200]; |
| |
| #define DATA 0 |
| #define BSS 1 |
| #define CODE 2 |
| #define SPECIAL 3 |
| |
| static char *labprefix,*idprefix; |
| |
| static int reglabel,freglabel,section=-1; |
| enum { |
| a0=1,a1,a2,a3,a4,a5,a6,a7, |
| d0,d1,d2,d3,d4,d5,d6,d7, |
| fp0,fp1,fp2,fp3,fp4,fp5,fp6,fp7, |
| d0d1,d2d3,d4d5,d6d7 |
| }; |
| static int sp=8,fbp=6,framesize; |
| static int stack_valid; |
| static char *codename,*bssname,*dataname; |
| static char *m_bssname,*m_dataname; |
| static char *rprefix; |
| |
| static void emit_obj(FILE *,obj *,int); |
| static IC *do_refs(FILE *,IC *); |
| static void pr(FILE *,IC *); |
| static int get_reg(FILE *,int,IC *,int); |
| static long pof2(zumax); |
| static void function_top(FILE *,Var *,long); |
| static void function_bottom(FILE *f,Var *,long); |
| |
| #define saveregs(x,y) saveregswfp(x,y,0) |
| static void saveregswfp(FILE *,IC *,int); |
| static void restoreregsa(FILE *,IC *); |
| static void restoreregsd(FILE *,IC *); |
| |
| static void assign(FILE *,IC *,obj *,obj *,int,long,int); |
| static int compare_objects(obj *o1,obj *o2); |
| |
| static char x_s[]={'0','b','w','3','l'}; |
| #ifdef M68K_16BIT_INT |
| static char x_t[]={'?','b','w','w','l','L','s','d','d','v','l','a','s','u','e','f'}; |
| #else |
| static char x_t[]={'?','b','w','l','l','L','s','d','d','v','l','a','s','u','e','f'}; |
| #endif |
| |
| static char *quick[2]={"","q"}; |
| static char *strshort[2]={"l","w"}; |
| |
| static char *ubranch[]={"eq","ne","cs","cc","ls","hi"}; |
| |
| static int pushedreg,stored_cc; /* pushedreg&2: aregsaved; 4: dreg; 8: freg */ |
| /* 16: durch RESTOREREGS gepushed */ |
| static int comptyp; |
| static int pushflag; |
| static int geta4; |
| static int dscratch=1,ascratch=1,fscratch=1; |
| |
| #define D16OFF 1024 |
| |
| static int newobj=0; /* um zu erkennen, ob neue section erlaubt ist */ |
| |
| static int cf; |
| static int add_stdargs; |
| |
| static int isquickkonst(union atyps *,int),isquickkonst2(union atyps *,int),regavailable(int); |
| static void move(FILE *,obj *,int,obj *,int,int); |
| static void loadext(FILE *,int,obj *,int); |
| static void add(FILE *,obj *,int,obj *,int,int); |
| static void sub(FILE *,obj *,int,obj *,int,int); |
| static void mult(FILE *,obj *,int,obj *,int,int,int,IC *); |
| |
| extern int static_cse; |
| |
| static void scratch_modified(void) |
| { |
| BSET(regs_modified,a0); |
| BSET(regs_modified,a1); |
| BSET(regs_modified,d0); |
| BSET(regs_modified,d1); |
| if(FPU>68000){ |
| BSET(regs_modified,fp0); |
| BSET(regs_modified,fp1); |
| } |
| if(D2SCRATCH) BSET(regs_modified,d2); |
| if(A2SCRATCH) BSET(regs_modified,a2); |
| if(FP2SCRATCH) BSET(regs_modified,fp2); |
| |
| } |
| |
| static long pof2(zumax x) |
| /* Yields log2(x)+1 oder 0. */ |
| { |
| zumax p;int ln=1; |
| p=ul2zum(1UL); |
| while(ln<=32&&zumleq(p,x)){ |
| if(zumeqto(x,p)) return ln; |
| ln++;p=zumadd(p,p); |
| } |
| return 0; |
| } |
| |
| #define isreg(x) ((p->x.flags&(REG|DREFOBJ))==REG) |
| #define isconst(x) ((p->x.flags&(KONST|DREFOBJ))==KONST) |
| |
| #ifdef M68K_16BIT_INT |
| #define ISHWORD(x) ((x&NQ)<=INT) |
| #else |
| #define ISHWORD(x) ((x&NQ)<INT) |
| #endif |
| |
| #define PEA -1 |
| #define LEA -2 |
| |
| #define FUNCPREFIX(t) ((stdargs(t)&&rparmtype!=PARMVBCC)?idprefix:(rparmtype==PARMVBCC?"@$":"@")) |
| |
| static void emit_lword(FILE *,obj *); |
| static void emit_hword(FILE *,obj *); |
| static int addressing(IC *); |
| static long notpopped,dontpop,stackoffset,loff,maxpushed,stack; |
| static int offlabel,regoffset; |
| /* For keeping track of condition codes. */ |
| static obj *cc_set,*cc_set_tst; |
| static int cc_typ,cc_typ_tst; |
| static int missing,savedemit,savedalloc; |
| static int lastpush,unorderedpush,pushoff[MAXR+1]; |
| |
| static int vsec(FILE *f,Var *v) |
| { |
| char *type="bss"; |
| if(!sec_per_obj||(v->tattr&CHIP)) return 0; |
| if(ISFUNC(v->vtyp->flags)||(v->clist&&is_const(v->vtyp))) type="code"; else if(v->clist) type="data"; |
| emit(f,"\t%ssection\t\"DONTMERGE_%s.%s.%ld\"%s%s\n",GAS?".":"",type,v->identifier,v->storage_class==STATIC/*&&!ISFUNC(v->vtyp->flags)*/?(long)zm2l(v->offset):0L,GAS?"":",",GAS?"":type); |
| if(f) section=SPECIAL; |
| return 1; |
| } |
| |
| static int special_section(FILE *f,Var *v) |
| { |
| char *sec; |
| if(!v->vattr) return vsec(f,v);; |
| sec=strstr(v->vattr,"section("); |
| if(!sec) return vsec(f,v);; |
| sec+=strlen("section("); |
| if(GAS) |
| emit(f,"\t.section\t"); |
| else |
| emit(f,"\tsection\t"); |
| while(*sec&&*sec!=')') emit_char(f,*sec++); |
| emit(f,"\n"); |
| if(f) section=SPECIAL; |
| return 1; |
| } |
| |
| static enum{ |
| PARMSTD, |
| PARMVBCC, |
| PARMSAS |
| } rparmtype; |
| |
| static int stdargs(type *t) |
| { |
| type *p; |
| |
| if(VBCCCALL) rparmtype=PARMVBCC; |
| else if(FASTCALL) rparmtype=PARMSAS; |
| else rparmtype=PARMSTD; |
| |
| for(p=t->next;p;p=p->next){ |
| if(p->attr&&strstr(p->attr,"__stdargs")) {rparmtype=PARMSTD;return 1;} |
| if(p->attr&&strstr(p->attr,"__vbccargs")) {rparmtype=PARMVBCC;return 0;} |
| if(p->attr&&strstr(p->attr,"__regargs")) {rparmtype=PARMSAS;return 0;} |
| if(CLEANFATTR) break; |
| } |
| if((!FASTCALL&&!VBCCCALL)||add_stdargs) return 1; |
| if(t->flags==FUNKT&&is_varargs(t)) return 1; |
| return 0; |
| } |
| |
| /* 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; |
| } |
| |
| void title(FILE *f) |
| { |
| static int done; |
| extern char *inname; /*grmpf*/ |
| if(!done&&f){ |
| done=1; |
| if(GAS) |
| emit(f,"\t.file\t\"%s\"\n",inname); |
| else |
| emit(f,"\tidnt\t\"%s\"\n",inname); |
| } |
| } |
| |
| static int is_arg_reg(IC *p,int r) |
| { |
| int i,u;IC *a; |
| for(i=0;i<p->arg_cnt;i++){ |
| a=p->arg_list[i]; |
| u=0; |
| if((a->z.flags&(REG|DREFOBJ))==REG) |
| u=a->z.reg; |
| else if((a->z.flags&VAR)&&a->z.v->reg) |
| u=a->z.v->reg; |
| if(u){ |
| if(r==u||(reg_pair(u,&rp)&&r==rp.r1||r==rp.r2)){ |
| return 1; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| static int am_uses_reg(IC *p,int i) |
| { |
| if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i)) |
| ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i)) |
| ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i))) |
| return 1; |
| return 0; |
| } |
| |
| /* check if register can be scratched */ |
| static int scratchreg(int r,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; |
| if(am_uses_reg(p,r)) return 0; |
| } |
| } |
| |
| |
| |
| static int pget_reg(FILE *f,int flag,IC *p,int useq1) |
| { |
| int i; |
| |
| flag=1+flag*8; |
| |
| if(useq1){ |
| if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p)) |
| return p->q1.reg; |
| } |
| |
| for(i=flag;i<flag+8;i++){ |
| if(regs[i]==1&&(!p||(i!=p->q1.reg&&i!=p->q2.reg&&i!=p->z.reg))){ |
| if(p){ |
| if(am_uses_reg(p,i)) |
| continue; |
| if(p->code==CALL&&is_arg_reg(p,i)) |
| continue; |
| } |
| regs[i]|=8; |
| pushflag=1; |
| emit(f,"\tmove.l\t%s,%ld(%s)\n",mregnames[i],-stackoffset,mregnames[sp]); |
| if(i<d0) |
| pushedreg|=2; |
| else if (i<fp0) |
| pushedreg|=4; |
| else |
| pushedreg|=8; |
| BSET(regs_modified,i); |
| return i; |
| } |
| } |
| ierror(0); |
| } |
| |
| static int get_reg(FILE *f,int flag,IC *p,int useq1) |
| /* Gets a register: flag=0=areg, 1=dreg, 2=fpreg */ |
| { |
| int i; |
| |
| flag=1+flag*8; |
| |
| if(useq1){ |
| if(isreg(q1)&&p->q1.reg>=flag&&p->q1.reg<=flag+7&&scratchreg(p->q1.reg,p)) |
| return p->q1.reg; |
| } |
| |
| for(i=flag;i<flag+8;i++){ |
| if(regs[i]==0){ |
| if(p){ |
| if(am_uses_reg(p,i)) |
| continue; |
| if(p->code==CALL&&is_arg_reg(p,i)) |
| continue; |
| } |
| regs[i]=2;pushedreg|=1; |
| if(!regused[i]&&!regscratch[i]){regused[i]=1; } |
| BSET(regs_modified,i); |
| return i; |
| } |
| } |
| for(i=flag;i<flag+8;i++){ |
| static rpair rp; |
| if(regs[i]==1){ |
| if(p){ |
| if((p->q1.am&&((p->q1.am->dreg&127)==i||p->q1.am->basereg==i)) |
| ||(p->q2.am&&((p->q2.am->dreg&127)==i||p->q2.am->basereg==i)) |
| ||(p->z.am&&((p->z.am->dreg&127)==i||p->z.am->basereg==i))){ |
| continue; |
| } |
| if(p->code==CALL&&is_arg_reg(p,i)) |
| continue; |
| if(p->q1.flags®){ |
| if(p->q1.reg==i) continue; |
| if(reg_pair(p->q1.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue; |
| } |
| if(p->q2.flags®){ |
| if(p->q2.reg==i) continue; |
| if(reg_pair(p->q2.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue; |
| } |
| if(p->z.flags®){ |
| if(p->z.reg==i) continue; |
| if(reg_pair(p->z.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue; |
| } |
| } |
| regs[i]+=4; |
| if(i<lastpush){ |
| unorderedpush=1; |
| /*printf("%s %s\n",mregnames[lastpush],mregnames[i]);*/ |
| } |
| if(i<fp0){ |
| emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[i],mregnames[sp]); |
| push(4); |
| pushoff[i]=pushoff[lastpush]+4; |
| }else{ |
| emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[i],mregnames[sp]); |
| push(12); |
| pushoff[i]=pushoff[lastpush]+12; |
| } |
| lastpush=i; |
| if(i<d0) |
| pushedreg|=2; |
| else if(i<fp0) |
| pushedreg|=4; |
| else |
| pushedreg|=8; |
| BSET(regs_modified,i); |
| return i; |
| } |
| } |
| ierror(0); |
| } |
| static int isquickkonst(union atyps *p,int t) |
| /* Returns 1 if constant is between -128 and 127. */ |
| { |
| zmax zm;zumax zum; |
| if(ISFLOAT(t)) return 0; |
| eval_const(p,t); |
| if(t&UNSIGNED){ |
| zum=ul2zum(127UL); |
| return zumleq(vumax,zum); |
| }else{ |
| zm=l2zm(-129L); |
| if(zmleq(vmax,zm)) return 0; |
| zm=l2zm(127L); |
| return zmleq(vmax,zm); |
| } |
| } |
| static int isquickkonst2(union atyps *p,int t) |
| /* Returns 1 if constant is between 1 and 8. */ |
| { |
| zmax zm;zumax zum; |
| if(ISFLOAT(t)) return 0; |
| eval_const(p,t); |
| if(t&UNSIGNED){ |
| if(zumeqto(ul2zum(0UL),vumax)) return 0; |
| zum=ul2zum(8UL); |
| return zumleq(vumax,zum); |
| }else{ |
| if(zmeqto(l2zm(0L),vmax)) return 0; |
| zm=l2zm(-1L); |
| if(zmleq(vmax,zm)) return 0; |
| zm=l2zm(8L); |
| return zmleq(vmax,zm); |
| } |
| } |
| |
| static int pregavailable(IC *p,int art) |
| /* Returns true if matching register is available. Handles arglist*/ |
| { |
| int i; |
| art=1+art*8; |
| for(i=art+1;i<art+8;i++) |
| if(regs[i]==0&&!is_arg_reg(p,i)) return(1); |
| return 0; |
| } |
| |
| static int regavailable(int art) |
| /* Returns true if matching register is available. */ |
| { |
| int i; |
| art=1+art*8; |
| for(i=art+1;i<art+8;i++) |
| if(regs[i]==0) return(1); |
| return 0; |
| } |
| static int compare_objects(obj *o1,obj *o2) |
| /* Tests if two objects are equal. */ |
| { |
| if((o1->flags&(REG|DREFOBJ))==REG&&(o2->flags&(REG|DREFOBJ))==REG&&o1->reg==o2->reg) |
| return 1; |
| if((o1->flags&(KONST|VAR|DREFOBJ|REG|VARADR))==(o2->flags&(KONST|VAR|DREFOBJ|REG|VARADR))&&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; |
| } |
| static IC *do_refs(FILE *f,IC *p) |
| /* Loads DREFOBJs into address registers, if necessary. */ |
| /* Small constants are loaded into data registers if this */ |
| /* improves code. */ |
| { |
| int reg,c=p->code,t=p->typf,equal; |
| if((p->q1.flags&DREFOBJ)&&!(p->q1.flags&KONST)&&(!(p->q1.flags®)||p->q1.reg<1||p->q1.reg>8)){ |
| equal=0; |
| if(compare_objects(&p->q1,&p->q2)) equal|=1; |
| if(compare_objects(&p->q1,&p->z)) equal|=2; |
| if(p->code==PUSH&&!pregavailable(p,0)) |
| reg=pget_reg(f,0,p,0); |
| else if(p->code==CALL&&!pregavailable(p,0)) |
| return p; |
| else |
| reg=get_reg(f,0,p,0); |
| p->q1.flags&=~DREFOBJ; |
| emit(f,"\tmove.l\t");emit_obj(f,&p->q1,POINTER); |
| p->q1.flags=REG|DREFOBJ; |
| p->q1.reg=reg; |
| emit(f,",%s\n",mregnames[p->q1.reg]); |
| if(equal&1) p->q2=p->q1; |
| if(equal&2) p->z=p->q1; |
| if(c==TEST) cc_set_tst=cc_set=0; |
| } |
| if((p->q2.flags&DREFOBJ)&&!(p->q2.flags&KONST)&&(!(p->q2.flags®)||p->q2.reg<1||p->q2.reg>8)){ |
| if(compare_objects(&p->q2,&p->z)) equal=1; else equal=0; |
| reg=get_reg(f,0,p,0); |
| p->q2.flags&=~DREFOBJ; |
| emit(f,"\tmove.l\t");emit_obj(f,&p->q2,POINTER); |
| p->q2.flags=REG|DREFOBJ; |
| p->q2.reg=reg; |
| emit(f,",%s\n",mregnames[p->q2.reg]); |
| if(equal) p->z=p->q2; |
| } |
| if((p->z.flags&DREFOBJ)&&!(p->z.flags&KONST)&&(!(p->z.flags®)||p->z.reg<1||p->z.reg>8)){ |
| reg=get_reg(f,0,p,0); |
| p->z.flags&=~DREFOBJ; |
| emit(f,"\tmove.l\t");emit_obj(f,&p->z,POINTER); |
| p->z.flags=REG|DREFOBJ; |
| p->z.reg=reg; |
| emit(f,",%s\n",mregnames[p->z.reg]); |
| } |
| if(CPU!=68040){ |
| /* Don't do it on 040 because it's slower. */ |
| if(x_t[t&NQ]=='l'&&(t&NQ)!=FLOAT&&(c!=ASSIGN||!isreg(z))&& |
| c!=MULT&&c!=DIV&&c!=MOD&&c!=LSHIFT&&c!=RSHIFT&&c!=SETRETURN&&c!=PUSH&&c!=ADDI2P&&c!=SUBIFP&& |
| (!(p->z.flags®)||p->z.reg<d0||p->z.reg>d7)){ |
| /* Constants into registers. */ |
| if(isconst(q1)&&isquickkonst(&p->q1.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q1.val,t))){ |
| eval_const(&p->q1.val,t); |
| if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&®available(1)){ |
| reg=get_reg(f,1,p,0); |
| move(f,&p->q1,0,0,reg,t); |
| p->q1.flags=REG;p->q1.reg=reg; |
| p->q1.val.vmax=l2zm(0L); |
| } |
| } |
| if(isconst(q2)&&isquickkonst(&p->q2.val,t)&&((c!=ADD&&c!=SUB&&c!=ADDI2P&&c!=SUBIFP)||!isquickkonst2(&p->q2.val,t))){ |
| eval_const(&p->q2.val,t); |
| if((!zldeqto(d2zld(0.0),vldouble)||!zmeqto(l2zm(0L),vmax)||!zumeqto(ul2zum(0UL),vumax))&®available(1)){ |
| reg=get_reg(f,1,p,0); |
| move(f,&p->q2,0,0,reg,t); |
| p->q2.flags=REG;p->q2.reg=reg; |
| p->q2.val.vmax=l2zm(0L); |
| } |
| } |
| } |
| } |
| return p; |
| } |
| static void pr(FILE *f,IC *p) |
| /* Release registers and pop them from stack if necessary. */ |
| { |
| int i,size=0;char *s=""; |
| /* To keep track of condition codes. */ |
| #if 0 |
| if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE)){ |
| char *fp;IC *branch; |
| if(FPU>68000&&ISFLOAT(p->typf)) fp="f"; else fp=""; |
| branch=p; |
| while(branch->code<BEQ||branch->code>=BRA) branch=branch->next; |
| /*FIXME*/ |
| if((p->typf&UNSIGNED)||ISPOINTER(p->typf)){ |
| emit(f,"\ts%s\t-2(%s)\n",ubranch[branch->code-BEQ],mregnames[sp]); |
| }else{ |
| emit(f,"\t%ss%s\t-2(%s)\n",fp,ename[branch->code]+1,mregnames[sp]); |
| } |
| stored_cc=1; |
| } |
| #endif |
| if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE||p->code==SETRETURN)){ |
| s="m"; |
| if(!GAS&&!PHXASS) emit(f,"\topt\tom-\n"); |
| } |
| for(i=MAXR;i>0;i--){ |
| if(regs[i]==2) regs[i]=0; |
| if(regs[i]&8){ |
| regs[i]&=~8; |
| |
| emit(f,"\tmove%s.l\t%ld(%s),%s\n",s,-stackoffset,mregnames[sp],mregnames[i]); |
| if(i>=d0) cc_set=0; |
| if(cc_set&&(cc_set->flags®)&&cc_set->reg==i) |
| cc_set=0; |
| missing++; |
| } |
| if(regs[i]&4){ |
| regs[i]&=~4; |
| if(i>=1&&i<=d7){ |
| if(unorderedpush) |
| emit(f,"\tmove%s.l\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]); |
| else{ |
| if(cf&&*s=='m'){ |
| emit(f,"\tmove%s.l\t(%s),%s\n\taddq.l\t#4,%s\n",s,mregnames[sp],mregnames[i],mregnames[sp]); |
| }else{ |
| emit(f,"\tmove%s.l\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]); |
| } |
| } |
| pop(4);size+=4; |
| }else if(i>=fp0&&i<=fp7){ |
| if(unorderedpush) |
| emit(f,"\tfmove%s.x\t%d(%s),%s\n",s,pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]); |
| else |
| emit(f,"\tfmove%s.x\t(%s)+,%s\n",s,mregnames[sp],mregnames[i]); |
| pop(12);size+=12; |
| }else if(i>=25&&i<=28){ |
| if(unorderedpush) |
| emit(f,"\tmovem.l\t%d(%s),%s\n",pushoff[lastpush]-pushoff[i],mregnames[sp],mregnames[i]); |
| else{ |
| if(cf) |
| emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#8,%s\n",mregnames[sp],mregnames[i],mregnames[sp]); |
| else |
| emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[i]); |
| } |
| pop(8);size+=8; |
| }else |
| ierror(0); |
| if(i>=d0) cc_set=0; |
| if(cc_set&&(cc_set->flags®)&&cc_set->reg==i) |
| cc_set=0; |
| missing++; |
| } |
| } |
| if(*s=='m'&&!GAS&&!PHXASS) emit(f,"\topt\tom+\n"); |
| #if 0 |
| if((pushedreg&12)&&(p->code==TEST||p->code==COMPARE)) |
| emit(f,"\ttst.b\t-%d(%s)\n",size+2,mregnames[sp]); |
| #endif |
| if(unorderedpush) |
| emit(f,"\tadd%s.%c\t#%d,%s\n",pushoff[lastpush]<=8?"q":"",cf?'l':'w',pushoff[lastpush],mregnames[sp]); |
| lastpush=0; |
| unorderedpush=0; |
| } |
| static void emit_obj(FILE *f,obj *p,int t) |
| /* Write object. */ |
| { |
| if(p->am){ |
| /* Addressing modes. */ |
| if(NOPEEPHOLE) {ierror(0);p->am=0;return;} |
| if(p->am->skal>=0){ |
| long l=0; |
| if(p->flags&D16OFF) l=zm2l(p->val.vmax); |
| emit(f,"(%ld",p->am->dist+l); |
| if(!GAS&&CPU>=68020&&((p->am->dist+l)>32767||(p->am->dist+l)<-32768)) |
| emit(f,".l"); |
| else if(!GAS&&CPU>=68020&&((p->am->dist+l)>127||(p->am->dist+l)<-128)) |
| emit(f,".w"); |
| emit(f,",%s",mregnames[p->am->basereg]); |
| if(p->am->dreg){ |
| emit(f,",%s",mregnames[p->am->dreg&127]); |
| if(p->am->dreg&128) emit(f,".w"); else emit(f,".l"); |
| if(p->am->skal) emit(f,"*%d",p->am->skal); |
| } |
| emit(f,")"); |
| return; |
| } |
| if((p->flags&D16OFF)&&p->am->skal<0&&!zmeqto(l2zm(0L),p->val.vmax)) ierror(0); |
| if(p->am->skal==-1){ |
| emit(f,"(%s)+",mregnames[p->am->basereg]); |
| return; |
| } |
| if(p->am->skal==-2){ /* Noch nicht implementiert */ |
| emit(f,"-(%s)",mregnames[p->am->basereg]); |
| return; |
| } |
| } |
| if(p->flags&DREFOBJ){ |
| if(p->flags&KONST){ |
| emitval(f,&p->val,p->dtyp&NU); |
| return; |
| } |
| emit(f,"("); |
| if((p->flags&D16OFF)&&!zmeqto(l2zm(0L),p->val.vmax)){ |
| emitval(f,&p->val,MAXINT); |
| if(!zmleq(p->val.vmax,l2zm(32767L))||!zmleq(l2zm(-32768L),p->val.vmax)) |
| emit(f,".l"); |
| else if(!zmleq(p->val.vmax,l2zm(127L))||!zmleq(l2zm(-128L),p->val.vmax)) |
| emit(f,".w"); |
| emit(f,","); |
| } |
| } |
| if(p->flags&VARADR) emit(f,"#"); |
| if(p->flags&VAR) { |
| if(p->flags®){ |
| emit(f,"%s",mregnames[p->reg]); |
| }else if(p->v->storage_class==AUTO||p->v->storage_class==REGISTER){ |
| long os; |
| os=zm2l(p->val.vmax); |
| if(!USEFRAMEPOINTER&&!vlas){ |
| if(!zmleq(l2zm(0L),p->v->offset)) |
| os=os+loff-zm2l(p->v->offset)+(PROFILER?16:0); |
| else |
| os=os+zm2l(p->v->offset); |
| if(!GAS&&CPU>=68020&&(os-stackoffset)>0x7c00) /* +l%d max.1024? */ |
| emit(f,"((%ld+%s%d).l,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]); |
| else |
| emit(f,"(%ld+%s%d,%s)",os-stackoffset,labprefix,offlabel,mregnames[sp]); |
| }else{ |
| if(!zmleq(l2zm(0L),p->v->offset)) |
| os=os-zm2l(p->v->offset)+4+(PROFILER?16:0); |
| else |
| os=os-(zm2l(p->v->offset)+zm2l(szof(p->v->vtyp))); |
| emit(f,"(%ld",os); |
| if(!GAS&&CPU>=68020&&os>0x7fff) |
| emit(f,".l"); |
| emit(f,",%s)",mregnames[fbp]); |
| } |
| }else{ |
| if(!zmeqto(l2zm(0L),p->val.vmax)){emitval(f,&p->val,MAXINT);emit(f,"+");} |
| if(p->v->storage_class==STATIC){ |
| emit(f,"%s%ld",labprefix,zm2l(p->v->offset)); |
| }else{ |
| if(ISFUNC(p->v->vtyp->flags)) |
| emit(f,"%s%s",FUNCPREFIX(p->v->vtyp),p->v->identifier); |
| else |
| emit(f,"%s%s",idprefix,p->v->identifier); |
| } |
| if(use_sd&&!(p->flags&VARADR)&&!ISFUNC(p->v->vtyp->flags) |
| &&!(p->v->tattr&(CHIP|FAR))&&(CONSTINDATA||!is_const(p->v->vtyp)) |
| &&zmleq(l2zm(0L),p->val.vmax)&&!zmleq(szof(p->v->vtyp),p->val.vmax)) |
| emit(f,"(a4)"); |
| } |
| } |
| if((p->flags®)&&!(p->flags&VAR)) emit(f,"%s",mregnames[p->reg]); |
| if(p->flags&KONST){ |
| /* This requires IEEE floats/doubles on the host compiler. */ |
| if(ISFLOAT(t)){ |
| unsigned char *ip=(unsigned char *)&p->val.vfloat; |
| char *s; |
| if(GAS) s="0x"; else s="$"; |
| emit(f,"#%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]); |
| if((t&NQ)!=FLOAT){ |
| if(DEBUG&1) printf("doubleconst=%f\n",zld2d(zd2zld(p->val.vdouble))); |
| emit(f,"%02x%02x%02x%02x",ip[4],ip[5],ip[6],ip[7]); |
| } |
| }else{ |
| emit(f,"#");emitval(f,&p->val,t&NU); |
| } |
| } |
| if(p->flags&DREFOBJ) emit(f,")"); |
| } |
| static void dwarf2_print_frame_location(FILE *f,Var *v) |
| { |
| /*FIXME: needs a location list and correct register trabslation */ |
| obj o; |
| o.flags=REG; |
| if(USEFRAMEPOINTER||vlas) |
| o.reg=fbp; |
| else |
| o.reg=sp; |
| o.val.vmax=l2zm(0L); |
| o.v=0; |
| dwarf2_print_location(f,&o); |
| } |
| static int dwarf2_regnumber(int r) |
| { |
| if(r<=8) |
| return r+7; |
| else if(r<=d7) |
| return r-8; |
| else if(r<=fp7) |
| return r+1; |
| else |
| ierror(0); |
| } |
| static zmax dwarf2_fboffset(Var *v) |
| { |
| long os; |
| if(!v||(v->storage_class!=AUTO&&v->storage_class!=REGISTER)) ierror(0); |
| if(!USEFRAMEPOINTER&&!vlas){ |
| if(!zmleq(l2zm(0L),v->offset)) |
| os=loff-zm2l(v->offset); |
| else |
| os=zm2l(v->offset); |
| return l2zm(os+framesize); |
| }else{ |
| if(!zmleq(l2zm(0L),v->offset)) |
| return l2zm(-zm2l(v->offset)+4); |
| else |
| return l2zm(-(zm2l(v->offset)+zm2l(szof(v->vtyp)))); |
| } |
| } |
| |
| static char tsh[]={'w','l'}; |
| static int proflabel,stacksizelabel; |
| static void function_top(FILE *f,Var *v,long offset) |
| /* Writes function header. */ |
| { |
| geta4=0; |
| if(GAS){ |
| }else{ |
| if(debug_info&&HUNKDEBUG) emit(f,"\tsymdebug\n"); |
| if(CPU!=68000) emit(f,"\tmachine\t%ld\n",CPU); |
| if(cf) strshort[1]="l"; |
| if(FPU>68000) emit(f,"\tfpu\t1\n"); |
| if(SMALLCODE) emit(f,"\tnear\tcode\n"); |
| if(use_sd) emit(f,"\tnear\ta4,-2\n"); |
| if(PHXASS){ |
| emit(f,"\topt\t0\n\topt\tNQLPSM"); |
| if(CPU!=68040) emit(f,"R"); |
| if(1/*BRANCHOPT||(optflags&2)*/) emit(f,"BT"); |
| emit(f,"\n"); |
| }else{ |
| emit(f,"\topt o+,ol+,op+,oc+,ot+,oj+,ob+,om+"); |
| if(CPU==68040) emit(f,",a-"); |
| emit(f,"\n"); |
| } |
| } |
| if(!special_section(f,v)&§ion!=CODE){emit(f,codename);if(f) section=CODE;} |
| if(PROFILER){ |
| proflabel=++label; |
| if(GAS){ |
| emit(f,"%s%d:\n\t.byte\t\"%s\",0\n",labprefix,proflabel,v->identifier); |
| }else{ |
| emit(f,"%s%d\n\tdc.b\t\"%s\",0\n",labprefix,proflabel,v->identifier); |
| } |
| } |
| if(v->storage_class==EXTERN){ |
| if((v->flags&(INLINEFUNC|INLINEEXT))!=INLINEFUNC){ |
| if(GAS){ |
| emit(f,"\t.global\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier); |
| }else{ |
| emit(f,"\tpublic\t%s%s\n",FUNCPREFIX(v->vtyp),v->identifier); |
| } |
| } |
| } |
| if(v->storage_class==EXTERN){ |
| if(GAS){ |
| emit(f,"\t.align\t4\n%s%s:\n",FUNCPREFIX(v->vtyp),v->identifier); |
| }else{ |
| emit(f,"\tcnop\t0,4\n%s%s\n",FUNCPREFIX(v->vtyp),v->identifier); |
| } |
| }else{ |
| if(GAS){ |
| emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset)); |
| }else{ |
| emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset)); |
| } |
| } |
| if(stack_check&&!(v->tattr&AMIINTERRUPT)){ |
| stacksizelabel=++label; |
| if(GAS){ |
| emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjbsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]); |
| }else{ |
| emit(f,"\tmove.l\t#%s%d,-(%s)\n\tjsr\t___stack_check\n\taddq.l\t#4,%s\n",labprefix,stacksizelabel,mregnames[sp],mregnames[sp]); |
| } |
| } |
| if(PROFILER){ |
| if(GAS){ |
| emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\t.global\t__startprof\n\tjbsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]); |
| }else{ |
| emit(f,"\tsub.l\t#16,%s\n\tmove.l\t%s,-(%s)\n\tpea\t%s%d\n\tpublic\t__startprof\n\tjsr\t__startprof\n\taddq.%s\t#8,%s\n",mregnames[sp],mregnames[sp],mregnames[sp],labprefix,proflabel,strshort[1],mregnames[sp]); |
| } |
| } |
| offset=-((offset+4-1)/4)*4; |
| loff=-offset;offlabel=++label; |
| if(!USEFRAMEPOINTER&&!vlas){ |
| if(offset<0) emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[offset>=-8],strshort[offset>=-32768],-offset,mregnames[sp]); |
| }else{ |
| if(offset>=-32768||CPU>=68020){ |
| emit(f,"\tlink.%c\t%s,#%ld\n",tsh[offset<-32768],mregnames[fbp],offset); |
| }else{ |
| emit(f,"\tlink.w\t%s,#-32768\n",mregnames[fbp]);offset+=32768; |
| emit(f,"\tsub.%c\t#%ld,%s\n",tsh[offset<-32768],offset,mregnames[fbp]); |
| } |
| } |
| if(FPU>68000&&float_used){ |
| if(GAS){ |
| emit(f,"\t.word\t0xf227,%s%d\n",labprefix,freglabel); |
| }else{ |
| emit(f,"\tfmovem.x\t%s%d,-(%s)\n",labprefix,freglabel,mregnames[sp]); |
| } |
| } |
| if(cf){ |
| emit(f,"\tsub.l\t#%s%d,%s\n",labprefix,offlabel,mregnames[sp]); |
| if(GAS){ |
| emit(f,"\tmovem.l\t#%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]); |
| }else{ |
| emit(f,"\tmovem.l\t%s%d,(%s)\n",labprefix,reglabel,mregnames[sp]); |
| } |
| }else{ |
| if(GAS){ |
| emit(f,"\tmovem.l\t#%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]); |
| }else{ |
| emit(f,"\tmovem.l\t%s%d,-(%s)\n",labprefix,reglabel,mregnames[sp]); |
| } |
| } |
| if((v->tattr&SAVEDS)&&use_sd) emit(f,"\txref\t_LinkerDB\n\tlea\t_LinkerDB,a4\n"); |
| stack_valid=1; |
| stack=0; |
| } |
| static void function_bottom(FILE *f,Var *v,long offset) |
| /* Writes function footer. */ |
| { |
| int i,size=0;unsigned int pushval,popval; |
| *pushreglist=0;*popreglist=0; |
| pushval=popval=0; |
| if((v->tattr&SAVEDS)&&use_sd) geta4=1; |
| for(i=1;i<=16;i++){ |
| if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])||(i==5&&geta4)||(i==d0&&pushflag)){ |
| if(*pushreglist) strcat(pushreglist,"/"); |
| strcat(pushreglist,mregnames[i]); |
| if(i!=d0||(v->tattr&INTERRUPT)){ |
| if(*popreglist) strcat(popreglist,"/"); |
| strcat(popreglist,mregnames[i]); |
| } |
| if(i<d0){ |
| pushval|=(256>>i);popval|=(128<<i); |
| }else{ |
| pushval|=(0x8000>>(i-9)); |
| if(i!=d0) popval|=(1<<(i-9)); |
| } |
| size+=4; |
| } |
| } |
| if(pushflag){ |
| emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]); |
| if(v->tattr&INTERRUPT) ierror(0); |
| } |
| if(cf){ |
| if(GAS){ |
| if(popval) |
| emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s),#%u\n\tadd.l\t#%s%d%s,%s\n",labprefix,reglabel,pushval,mregnames[sp],popval,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]); |
| else |
| emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel); |
| }else{ |
| if(*pushreglist) |
| emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist); |
| else |
| emit(f,"%s%d\treg\n",labprefix,reglabel); |
| if(*popreglist) |
| emit(f,"\tmovem.l\t(%s),%s\n\tadd.l\t#%s%d%s,%s\n",mregnames[sp],popreglist,labprefix,offlabel,pushflag?"-4":"",mregnames[sp]); |
| } |
| }else{ |
| if(GAS){ |
| if(popval) |
| emit(f,"\t.equ\t%s%d,%u\n\tmovem.l\t(%s)+,#%u\n",labprefix,reglabel,pushval,mregnames[sp],popval); |
| else |
| emit(f,"\t.equ\t%s%d,0\n",labprefix,reglabel); |
| }else{ |
| if(*pushreglist) |
| emit(f,"%s%d\treg\t%s\n",labprefix,reglabel,pushreglist); |
| else |
| emit(f,"%s%d\treg\n",labprefix,reglabel); |
| if(*popreglist) |
| emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],popreglist); |
| } |
| } |
| *pushreglist=0;*popreglist=0;pushval=0xe000;popval=0xd000; |
| for(i=fp0;i<=fp7;i++){ |
| if((((regused[i]&&!regscratch[i])||((v->tattr&INTERRUPT)&&BTST(regs_modified,i)))&&!regsa[i])){ |
| if(*popreglist) strcat(popreglist,"/"); |
| strcat(popreglist,mregnames[i]); |
| pushval|=(1<<(i-17));popval|=(0x80>>(i-17)); |
| size+=12; |
| } |
| } |
| if(FPU>68000&&(float_used||(v->tattr&INTERRUPT))){ |
| if(GAS){ |
| if(popval!=0xd000) |
| emit(f,"\t.equ\t%s%d,0x%x\n\t.word\t0xf21f,0x%x\n",labprefix,freglabel,(int)pushval,(int)popval); |
| else |
| emit(f,"\t.equ\t%s%d,0xe000\n",labprefix,freglabel); |
| }else{ |
| if(*popreglist) |
| emit(f,"%s%d\tfreg\t%s\n\tfmovem.x\t(%s)+,%s%d\n",labprefix,freglabel,popreglist,mregnames[sp],labprefix,freglabel); |
| else |
| emit(f,"%s%d\tfreg\n",labprefix,freglabel); |
| } |
| } |
| if(cf||(!USEFRAMEPOINTER&&!vlas)){ |
| if(GAS){ |
| emit(f,"\t.equ\t%s%d,%d\n",labprefix,offlabel,size); |
| }else{ |
| emit(f,"%s%d\tequ\t%d\n",labprefix,offlabel,size); |
| } |
| } |
| if(!USEFRAMEPOINTER&&!vlas){ |
| if(loff) emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[loff<=8],strshort[loff<32768],loff,mregnames[sp]); |
| framesize=size; |
| }else |
| emit(f,"\tunlk\t%s\n",mregnames[fbp]); |
| if(PROFILER){ |
| if(GAS){ |
| emit(f,"\tmove.l\t%s,-(%s)\n\t.global\t__endprof\n\tjbsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]); |
| }else{ |
| emit(f,"\tmove.l\t%s,-(%s)\n\tpublic\t__endprof\n\tjsr\t__endprof\n\tadd.%s\t#20,%s\n",mregnames[sp],mregnames[sp],strshort[1],mregnames[sp]); |
| } |
| } |
| if(v->tattr&INTERRUPT) |
| emit(f,"\trte\n"); |
| else |
| emit(f,"\trts\n"); |
| if(stack_check&&!(v->tattr&AMIINTERRUPT)){ |
| if(GAS) |
| emit(f,"\t.equ\t%s%d,%ld\n",labprefix,stacksizelabel,size+loff-maxpushed); |
| else |
| emit(f,"%s%d\tequ\t%ld\n",labprefix,stacksizelabel,size+loff-maxpushed); |
| } |
| if(stack_valid){ |
| if(!v->fi) v->fi=new_fi(); |
| v->fi->flags|=ALL_STACK; |
| v->fi->stack1=l2zm(size+loff+stack); |
| emit(f,"%c stacksize=%ld\n",GAS?'#':';',size+loff+stack); |
| } |
| } |
| static void move(FILE *f,obj *q,int qreg,obj *z,int zreg,int t) |
| /* erzeugt eine move Anweisung...Da sollen mal Optimierungen rein */ |
| { |
| if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg; |
| if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg; |
| if(zreg==qreg&&zreg) return; |
| if(q&&(q->flags&VARADR)&&zreg>=1&&zreg<=8){ |
| emit(f,"\tlea\t"); |
| q->flags&=~VARADR;emit_obj(f,q,t);q->flags|=VARADR; |
| emit(f,",%s\n",mregnames[zreg]); |
| BSET(regs_modified,zreg); |
| return; |
| } |
| if(zreg>=d0&&zreg<fp0&&q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst(&q->val,t)){ |
| emit(f,"\tmoveq\t"); |
| }else{ |
| if((zreg>=fp0&&zreg<=fp7)||(qreg>=fp0&&qreg<=fp7)){ |
| if(qreg>=fp0&&qreg<=fp7&&zreg>=fp0&&zreg<=fp7) emit(f,"\tfmove.x\t"); |
| else emit(f,"\tfmove.%c\t",x_t[t&NQ]); |
| }else{ |
| if(!cf||qreg||zreg) |
| emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]); |
| } |
| } |
| if(cf&&!qreg&&!zreg){ |
| static IC dummy; |
| dummy.code=ASSIGN; |
| dummy.typf=t; |
| dummy.q1=*q; |
| dummy.q2.flags=0; |
| dummy.z=*z; |
| qreg=get_reg(f,1,&dummy,0); |
| emit(f,"\tmove.%c\t",x_s[msizetab[t&NQ]]); |
| emit_obj(f,q,t); |
| emit(f,",%s\n\tmove.%c\t%s,",mregnames[qreg],x_s[msizetab[t&NQ]],mregnames[qreg]); |
| emit_obj(f,z,t); |
| emit(f,"\n"); |
| }else{ |
| if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t); |
| emit(f,","); |
| if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t); |
| emit(f,"\n"); |
| if(zreg) BSET(regs_modified,zreg); |
| } |
| } |
| static void loadext(FILE *f,int r,obj *q,int t) |
| /* laedt Objekt q vom Typ t in Register r und erweitert auf long */ |
| { |
| if(t&UNSIGNED){ |
| if((q->flags&(REG|DREFOBJ))==REG&&q->reg==r) |
| emit(f,"\tand.l\t#%u,%s\n",((t&NQ)==CHAR?0xffu:0xffffu),mregnames[r]); |
| else |
| emit(f,"\tmoveq\t#0,%s\n",mregnames[r]); |
| } |
| move(f,q,0,0,r,t); |
| #ifdef M68K_16BIT_INT |
| if((t&NU)==SHORT||(t&NU)==INT) emit(f,"\text.l\t%s\n",mregnames[r]); |
| #else |
| if((t&NU)==SHORT) emit(f,"\text.l\t%s\n",mregnames[r]); |
| #endif |
| if((t&NU)==CHAR){ |
| if(cf||CPU>=68020) |
| emit(f,"\textb.l\t%s\n",mregnames[r]); |
| else |
| emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[r],mregnames[r]); |
| } |
| } |
| |
| static void add(FILE *f,obj *q,int qreg,obj *z,int zreg,int t) |
| /* erzeugt eine add Anweisung...Da sollen mal Optimierungen rein */ |
| { |
| if(!qreg&&!q) ierror(0); |
| if(!zreg&&!z) ierror(0); |
| if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg; |
| if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0); |
| if(!qreg&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){ |
| emit(f,"\taddq.%c\t",cf?'l':x_t[t&NQ]); |
| }else{ |
| /* hier noch Abfrage, ob #c.w,ax */ |
| emit(f,"\tadd.%c\t",cf?'l':x_t[t&NQ]); |
| } |
| if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t); |
| emit(f,","); |
| if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t); |
| emit(f,"\n"); |
| } |
| static void sub(FILE *f,obj *q,int qreg,obj *z,int zreg,int t) |
| /* erzeugt eine sub Anweisung...Da sollen mal Optimierungen rein */ |
| { |
| if(cf&&x_t[t&NQ]!='l'&&(qreg||(q->flags&(KONST|DREFOBJ))!=KONST)) ierror(0); |
| if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg; |
| if(q&&(q->flags&(KONST|DREFOBJ))==KONST&&isquickkonst2(&q->val,t)){ |
| emit(f,"\tsubq.%c\t",cf?'l':x_t[t&NQ]); |
| }else{ |
| /* hier noch Abfrage, ob #c.w,ax */ |
| emit(f,"\tsub.%c\t",cf?'l':x_t[t&NQ]); |
| } |
| if(qreg) emit(f,"%s",mregnames[qreg]); else emit_obj(f,q,t); |
| emit(f,","); |
| if(zreg) emit(f,"%s",mregnames[zreg]); else emit_obj(f,z,t); |
| emit(f,"\n"); |
| } |
| static void mult(FILE *f,obj *q,int qreg,obj *z,int zreg, int t,int c,IC *p) |
| /* erzeugt eine mult Anweisung...Da sollen mal Optimierungen rein */ |
| /* erzeugt auch div/mod etc. */ |
| { |
| int modreg; |
| if(!qreg&&(q->flags&(REG|DREFOBJ))==REG) qreg=q->reg; |
| if(!zreg&&(z->flags&(REG|DREFOBJ))==REG) zreg=z->reg; |
| if(cf&&!qreg) {qreg=get_reg(f,1,p,0);move(f,q,0,0,qreg,t);} |
| if((c==MULT||c==DIV||c==MOD)&&CPU<68020&&!cf&&msizetab[t&NQ]==4){ |
| if(c==MULT){ |
| /* ist das mit get_reg(.,.,0) ok? nochmal ueberdenken... */ |
| /* ...die ganze Routine am besten... */ |
| /* ...es war nicht, deshalb ist es jetzt geaendert */ |
| int dx,dy,t1,t2; |
| if(zreg>=d0&&zreg<=d7){ |
| dx=zreg; |
| }else{ |
| dx=get_reg(f,1,p,0); |
| move(f,z,0,0,dx,t); |
| } |
| if(qreg>=d0&&qreg<=d7&&qreg!=dx){ |
| dy=qreg; |
| }else{ |
| dy=get_reg(f,1,p,0); |
| move(f,q,0,0,dy,t); |
| } |
| t1=get_reg(f,1,p,0);t2=get_reg(f,1,p,0); |
| if(t1==dx||t2==dx||t1==dy||t2==dy) ierror(0); |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[dx],mregnames[t1]); |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[dy],mregnames[t2]); |
| emit(f,"\tswap\t%s\n",mregnames[t1]); |
| emit(f,"\tswap\t%s\n",mregnames[t2]); |
| emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[t1]); |
| emit(f,"\tmulu.w\t%s,%s\n",mregnames[dx],mregnames[t2]); |
| emit(f,"\tmulu.w\t%s,%s\n",mregnames[dy],mregnames[dx]); |
| emit(f,"\tadd.w\t%s,%s\n",mregnames[t2],mregnames[t1]); |
| emit(f,"\tswap\t%s\n",mregnames[t1]); |
| emit(f,"\tclr.w\t%s\n",mregnames[t1]); |
| emit(f,"\tadd.l\t%s,%s\n",mregnames[t1],mregnames[dx]); |
| if(zreg!=dx) move(f,0,t1,z,0,t); |
| }else ierror(0); |
| return; |
| } |
| if(c==MULT){ |
| /* das duerfte nur der Aesthetik dienen... */ |
| if(t&UNSIGNED) |
| emit(f,"\tmulu.%c\t",x_t[t&NQ]); |
| else |
| emit(f,"\tmuls.%c\t",x_t[t&NQ]); |
| if((t&NQ)<=SHORT) cc_set=0; |
| } |
| if(c==DIV||(c==MOD&&ISHWORD(t))){ |
| if(t&UNSIGNED){ |
| if(ISHWORD(t)) emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]); |
| emit(f,"\tdivu.%c\t",x_t[t&NQ]); |
| }else{ |
| if(ISHWORD(t)) emit(f,"\text.l\t%s\n",mregnames[zreg]); |
| emit(f,"\tdivs.%c\t",x_t[t&NQ]); |
| } |
| } |
| if(qreg) |
| emit(f,"%s",mregnames[qreg]); |
| else |
| emit_obj(f,q,t); |
| emit(f,","); |
| /* eigentlich muss zreg!=0 sein... */ |
| if(zreg) |
| emit(f,"%s",mregnames[zreg]); |
| else |
| emit_obj(f,z,t); |
| emit(f,"\n"); |
| if(c==MOD){ |
| emit(f,"\tswap\t%s\n",mregnames[zreg]); |
| cc_set=0; |
| } |
| } |
| static IC *am_freedreg[9],*am_shiftdreg[9]; |
| static IC *am_dist_ic[9],*am_dreg_ic[9],*am_use[9]; |
| /* am_dist_ic und am_dreg_ic werden auch fuer (ax)+ benutzt */ |
| static long am_dist[9],am_dreg[9],am_base[9],am_inc[9],am_skal[9],am_dbase[9]; |
| #define AMS sizeof(AddressingMode) |
| |
| static int mopsize(IC *p,int reg) |
| /* Liefert die Groesse in Bytes, mit der im IC auf (reg) zugegriffen wird. */ |
| { |
| int c=p->code; |
| if(c==ADDI2P||c==SUBIFP){ |
| if((p->q2.flags®)&&p->q2.reg==reg) |
| return zm2l(sizetab[p->typf&NQ]); |
| return 4; |
| } |
| if(c==CONVERT){ |
| if((p->z.flags®)&&p->z.reg==reg) |
| return zm2l(sizetab[p->typf&NQ]); |
| else |
| return zm2l(sizetab[p->typf2&NQ]); |
| } |
| return zm2l(sizetab[p->typf&NQ]); |
| } |
| static void clear_am(int reg) |
| /* loescht Werte fuer erweiterte Adressierungsarten fuer Register reg */ |
| { |
| if(reg<0||reg>d7) ierror(0); |
| if(DEBUG&32) printf("clear_am(%s)\n",mregnames[reg]); |
| if(reg<=8){ |
| am_dist_ic[reg]=am_dreg_ic[reg]=am_use[reg]=0; |
| am_dist[reg]=am_dreg[reg]=am_base[reg]=am_inc[reg]=0; |
| }else{ |
| reg-=8; |
| am_freedreg[reg]=am_shiftdreg[reg]=0; |
| am_skal[reg]=am_dbase[reg]=0; |
| } |
| } |
| static void mod_reg(int r) |
| { |
| int i; |
| for(i=1;i<=8;i++){ |
| if((!am_use[i]&&am_base[i]==r)||(am_dreg[i]&127)==r) |
| clear_am(i); |
| } |
| #if 0 |
| if(r>=9&&r<=16){ |
| for(i=9;i<=16;i++){ |
| if(am_dbase[i-8]==r) |
| clear_am(i); |
| } |
| } |
| #endif |
| } |
| /* return non-zero if IC is implemented by a function call */ |
| static int islibcall(IC *p) |
| { |
| int c=p->code,t=p->typf/NQ; |
| if((c==DIV||c==MOD)&&CPU<68020) |
| return 1; |
| if(t==LLONG&&c!=ADD&&c!=SUB&&c!=OR&&c!=AND&&c!=XOR&&c!=COMPARE) |
| return 1; |
| if(ISFLOAT(t)&&FPU<=68000) |
| return 1; |
| if(c==CONVERT){ |
| if(t==LLONG||ISFLOAT(t)) |
| return 1; |
| t=p->typf2&NQ; |
| if(t==LLONG||ISFLOAT(t)) |
| return 1; |
| } |
| return 0; |
| } |
| |
| static int new_peephole(IC *first) |
| { |
| int localused=0,c,r,t,c2;long sz; |
| IC *p,*p2; |
| AddressingMode *am; |
| for(p=first;p;p=p->next){ |
| int c=p->code; |
| if(!localused){ |
| if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset)) |
| localused=1; |
| if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset)) |
| localused=1; |
| if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset)) |
| localused=1; |
| if(DEBUG&32&&localused==1) printf("localused=1\n"); |
| } |
| /* -(ax) */ |
| if(c==SUBIFP&&isreg(q1)&&isreg(z)&&p->q1.reg==p->z.reg&&p->q1.reg<=8&&isconst(q2)){ |
| r=p->q1.reg; |
| eval_const(&p->q2.val,q2typ(p)); |
| sz=zm2l(vmax); |
| if(sz==1||sz==2||sz==4||sz==8){ |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q1.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)&&(c2!=CONVERT||(q1typ(p2)&NQ)<=(ztyp(p2)&NQ))){ |
| t=(q1typ(p2)&NQ); |
| if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q1typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){ |
| p2->q1.am=am=mymalloc(sizeof(*am)); |
| p2->q1.val.vmax=l2zm(0L); |
| am->basereg=r; |
| am->dist=0; |
| am->skal=-2; |
| am->dreg=0; |
| p->code=NOP; |
| p->q1.flags=p->q2.flags=p->z.flags=0; |
| break; |
| } |
| } |
| if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r&&(!(p2->q1.flags®)||p2->q1.reg!=r)&&(!(p2->z.flags®)||p2->z.reg!=r)){ |
| t=(q2typ(p2)&NQ); |
| if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[q2typ(p2)&NQ],l2zm(sz))&&!islibcall(p2)){ |
| p2->q2.am=am=mymalloc(sizeof(*am)); |
| p2->q2.val.vmax=l2zm(0L); |
| am->basereg=r; |
| am->dist=0; |
| am->skal=-2; |
| am->dreg=0; |
| p->code=NOP; |
| p->q1.flags=p->q2.flags=p->z.flags=0; |
| break; |
| } |
| } |
| if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r&&(!(p2->q2.flags®)||p2->q2.reg!=r)&&(!(p2->q1.flags®)||p2->q1.reg!=r)){ |
| t=(ztyp(p2)&NQ); |
| if((ISINT(t)||ISPOINTER(t))&&t!=LLONG&&zmeqto(sizetab[ztyp(p2)&NQ],l2zm(sz))&&!islibcall(p2)){ |
| p2->z.am=am=mymalloc(sizeof(*am)); |
| p2->z.val.vmax=l2zm(0L); |
| am->basereg=r; |
| am->dist=0; |
| am->skal=-2; |
| am->dreg=0; |
| p->code=NOP; |
| p->q1.flags=p->q2.flags=p->z.flags=0; |
| break; |
| } |
| } |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| if((p2->q1.flags®)&&p2->q1.reg==r) break; |
| if((p2->q2.flags®)&&p2->q2.reg==r) break; |
| if((p2->z.flags®)&&p2->z.reg==r) break; |
| } |
| } |
| } |
| /* (ax)+ in q1 */ |
| if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q1.reg<=8&&(c!=CONVERT||(q1typ(p)&NQ)<=(ztyp(p)&NQ))){ |
| t=(q1typ(p)&NQ); |
| sz=zm2l(sizetab[t]); |
| r=p->q1.reg; |
| if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){ |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){ |
| eval_const(&p2->q2.val,q2typ(p2)); |
| if(zmeqto(vmax,l2zm(sz))){ |
| p->q1.am=am=mymalloc(sizeof(*am)); |
| p->q1.val.vmax=l2zm(0L); |
| am->basereg=r; |
| am->dist=0; |
| am->skal=-1; |
| am->dreg=0; |
| p2->code=NOP; |
| p2->q1.flags=p2->q2.flags=p2->z.flags=0; |
| break; |
| } |
| } |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| if((p2->q1.flags®)&&p2->q1.reg==r) break; |
| if((p2->q2.flags®)&&p2->q2.reg==r) break; |
| if((p2->z.flags®)&&p2->z.reg==r) break; |
| if(p2->q1.am&&p2->q1.am->basereg==r) break; |
| if(p2->q2.am&&p2->q2.am->basereg==r) break; |
| if(p2->z.am&&p2->z.am->basereg==r) break; |
| } |
| } |
| } |
| /* (ax)+ in q2 */ |
| if(!p->q2.am&&(p->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->q2.reg<=8){ |
| t=(q2typ(p)&NQ); |
| sz=zm2l(sizetab[t]); |
| r=p->q2.reg; |
| if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->z.flags®)||p->z.reg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)&&(!p->z.am||p->z.am->basereg!=r)){ |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){ |
| eval_const(&p2->q2.val,q2typ(p2)); |
| if(zmeqto(vmax,l2zm(sz))){ |
| p->q2.am=am=mymalloc(sizeof(*am)); |
| p->q2.val.vmax=l2zm(0L); |
| am->basereg=r; |
| am->dist=0; |
| am->skal=-1; |
| am->dreg=0; |
| p2->code=NOP; |
| p2->q1.flags=p2->q2.flags=p2->z.flags=0; |
| break; |
| } |
| } |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| if((p2->q1.flags®)&&p2->q1.reg==r) break; |
| if((p2->q2.flags®)&&p2->q2.reg==r) break; |
| if((p2->z.flags®)&&p2->z.reg==r) break; |
| if(p2->q1.am&&p2->q1.am->basereg==r) break; |
| if(p2->q2.am&&p2->q2.am->basereg==r) break; |
| if(p2->z.am&&p2->z.am->basereg==r) break; |
| } |
| } |
| } |
| /* (ax)+ in z */ |
| if(!p->z.am&&(p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p->z.reg<=8){ |
| t=(ztyp(p)&NQ); |
| sz=zm2l(sizetab[t]); |
| r=p->z.reg; |
| if((sz==1||sz==2||sz==4||sz==8)&&(ISINT(t)||ISPOINTER(t))&&t!=LLONG&&(!(p->q1.flags®)||p->q1.reg!=r)&&(!(p->q2.flags®)||p->q2.reg!=r)&&(!p->q2.am||p->q2.am->basereg!=r)&&(!p->q1.am||p->q1.am->basereg!=r)){ |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST&&!islibcall(p)){ |
| eval_const(&p2->q2.val,q2typ(p2)); |
| if(zmeqto(vmax,l2zm(sz))){ |
| p->z.am=am=mymalloc(sizeof(*am)); |
| p->z.val.vmax=l2zm(0L); |
| am->basereg=r; |
| am->dist=0; |
| am->skal=-1; |
| am->dreg=0; |
| p2->code=NOP; |
| p2->q1.flags=p2->q2.flags=p2->z.flags=0; |
| break; |
| } |
| } |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| if((p2->q1.flags®)&&p2->q1.reg==r) break; |
| if((p2->q2.flags®)&&p2->q2.reg==r) break; |
| if((p2->z.flags®)&&p2->z.reg==r) break; |
| if(p2->q1.am&&p2->q1.am->basereg==r) break; |
| if(p2->q2.am&&p2->q2.am->basereg==r) break; |
| if(p2->z.am&&p2->z.am->basereg==r) break; |
| } |
| } |
| } |
| /* d(ax) (+d(ax,dy)) */ |
| if((c==ADDI2P||c==SUBIFP)&&isreg(z)&&p->z.reg<=8&&(p->q2.flags&(KONST|DREFOBJ))==KONST){ |
| int base,idx=-1;zmax of;obj *o; |
| IC *idx_ic=0,*free_idx=0,*free_base=0,*use=0; |
| eval_const(&p->q2.val,p->typf); |
| if(c==SUBIFP) of=zmsub(l2zm(0L),vmax); else of=vmax; |
| if(CPU>=68020||(zmleq(l2zm(-32768L),vmax)&&zmleq(vmax,l2zm(32767L)))){ |
| r=p->z.reg; |
| if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r; |
| o=0; |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(!idx_ic&&c2==ADDI2P&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg>=d0&&p2->q2.reg<fp0){ |
| if(CPU>=68020||(zmleq(of,l2zm(127L))&&zmleq(l2zm(-128L),of))){ |
| idx=p2->q2.reg; |
| idx_ic=p2; |
| continue; |
| } |
| } |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| if(!use&&idx_ic&&c2==FREEREG&&p2->q1.reg==idx){ |
| free_idx=p2; |
| continue; |
| } |
| if(!use&&c2==FREEREG&&p2->q1.reg==base){ |
| free_base=p2; |
| continue; |
| } |
| if(idx_ic){ |
| if((p2->q1.flags®)&&p2->q1.reg==idx) break; |
| if((p2->q2.flags®)&&p2->q2.reg==idx) break; |
| if((p2->z.flags®)&&p2->z.reg==idx) break; |
| if(p2->q1.am&&(p2->q1.am->dreg&127)==idx) break; |
| if(p2->q2.am&&(p2->q2.am->dreg&127)==idx) break; |
| if(p2->z.am&&(p2->z.am->dreg&127)==idx) break; |
| if(c2==ALLOCREG&&p2->q1.reg==idx) break; |
| } |
| |
| if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){ |
| if(o) break; |
| o=&p2->q1; |
| use=p2; |
| continue; |
| } |
| |
| 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) break; |
| o=&p2->q1; |
| use=p2; |
| } |
| if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){ |
| if(o) break; |
| o=&p2->q2; |
| use=p2; |
| } |
| if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){ |
| |
| if(o) break; |
| if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break; |
| o=&p2->z; |
| use=p2; |
| } |
| } |
| 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)); |
| o->val.vmax=l2zm(0L); |
| am->basereg=base; |
| am->dist=zm2l(of); |
| am->skal=0; |
| if(free_base) move_IC(use,free_base); |
| if(idx_ic){ |
| am->dreg=idx; |
| if(ISHWORD(idx_ic->typf)) am->dreg|=128; |
| if(free_idx) move_IC(use,free_idx); |
| idx_ic->code=NOP; |
| idx_ic->q1.flags=idx_ic->q2.flags=idx_ic->z.flags=0; |
| }else |
| am->dreg=0; |
| if(isreg(q1)&&p->q1.reg<=8){ |
| 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]; |
| } |
| if(!(o->flags&DREFOBJ)){ |
| o->flags|=DREFOBJ; |
| if(use->code==PUSH) |
| use->code=PEA; |
| else if(use->code==ASSIGN) |
| use->code=LEA; |
| else |
| ierror(0); |
| } |
| } |
| break; |
| } |
| if(c2!=FREEREG&&m==base) break; |
| continue; |
| } |
| } |
| } |
| } |
| /* (ax,dy) (+d(ax,dy)) */ |
| if(c==ADDI2P&&isreg(q2)&&p->q2.reg>=d0&&isreg(z)&&p->z.reg<=8&&(isreg(q1)||p->q2.reg!=p->z.reg)){ |
| int base,idx;obj *o; |
| long dist=0; |
| IC *free_idx=0,*free_base=0,*use=0,*off=0; |
| r=p->z.reg;idx=p->q2.reg; |
| if(isreg(q1)&&p->q1.reg<=8) base=p->q1.reg; else base=r; |
| o=0; |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(!off&&(c2==ADDI2P||c2==SUBIFP)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r&&(p2->q2.flags&(KONST|DREFOBJ))==KONST){ |
| eval_const(&p2->q2.val,p2->typf); |
| if(c2==SUBIFP) vmax=zmsub(l2zm(0L),vmax); |
| if(CPU>=68020||(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax))){ |
| dist=zm2l(vmax); |
| off=p2; |
| continue; |
| } |
| } |
| |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| |
| |
| |
| if(!p2->q1.am&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg==r&&c2==PUSH){ |
| if(o) break; |
| |
| o=&p2->q1; |
| use=p2; |
| continue; |
| } |
| |
| 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==ALLOCREG&&(p->q1.reg==idx||p->q1.reg==base)) break; |
| if(!use&&c2==FREEREG&&p2->q1.reg==base) free_base=p2; |
| if(!use&&c2==FREEREG&&p2->q1.reg==idx) free_idx=p2; |
| |
| |
| 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||(q1typ(p2)&NQ)==LLONG) break; |
| o=&p2->q1;use=p2; |
| } |
| if(!p2->q2.am&&(p2->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->q2.reg==r){ |
| if(o||(q2typ(p2)&NQ)==LLONG) break; |
| o=&p2->q2;use=p2; |
| } |
| if(!p2->z.am&&(p2->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&p2->z.reg==r){ |
| if(o||(ztyp(p2)&NQ)==LLONG) break; |
| if(p2->z.flags&&(idx==d0||idx==d1)&&FPU<=68000&&ISFLOAT(ztyp(p2))&&!(p2->q2.flags==0&&c2!=CONVERT)) break; |
| |
| o=&p2->z;use=p2; |
| } |
| } |
| 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){ |
| /* do not use addressing mode for libcalls */ |
| if(FPU<=68000&&o&&o==&use->z&&(ISFLOAT(use->typf)||ISFLOAT(use->typf2))&&use->code!=ASSIGN) |
| break; |
| if(o){ |
| o->am=am=mymalloc(sizeof(*am)); |
| o->val.vmax=l2zm(0L); |
| am->basereg=base; |
| am->dreg=idx; |
| am->dist=dist; |
| am->skal=0; |
| if(ISHWORD(q2typ(p))) am->dreg|=128; |
| if(isreg(q1)&&p->q1.reg<=8){ |
| 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]; |
| } |
| if(off){ |
| off->code=NOP; |
| off->q1.flags=off->q2.flags=off->z.flags=0; |
| } |
| if(!use) ierror(0); |
| if(free_idx) move_IC(use,free_idx); |
| if(free_base) move_IC(use,free_base); |
| if(free_idx&&use->next!=free_idx&&use->next->next!=free_idx) ierror(0); |
| if(free_base&&use->next!=free_base&&use->next->next!=free_base) ierror(0); |
| if(!(o->flags&DREFOBJ)){ |
| o->flags|=DREFOBJ; |
| if(use->code==PUSH) |
| use->code=PEA; |
| else if(use->code==ASSIGN) |
| use->code=LEA; |
| else |
| ierror(0); |
| } |
| } |
| |
| break; |
| } |
| if(c2!=FREEREG&&m==base) break; |
| continue; |
| } |
| } |
| } |
| |
| |
| } |
| |
| /* do an additional pass to search for scaled addressing-modes */ |
| if(CPU>=68020){ |
| for(p=first;p;p=p->next){ |
| c=p->code;t=p->typf; |
| if((c==MULT||c==LSHIFT)&&isconst(q2)&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(t)&&(t&NQ)<=LONG){ |
| unsigned long ul; |
| r=p->z.reg; |
| eval_const(&p->q2.val,q2typ(p)); |
| ul=zum2ul(vumax); |
| if(c==LSHIFT){ |
| if(ul<=3) |
| ul=1<<ul; |
| else |
| ul=0; |
| } |
| if(ul==2||ul==4||ul==8){ |
| AddressingMode *amuse=0; |
| IC *free_src=0,*free_rsrc=0,*use=0; |
| int src_mod=0; |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(!use&&p2->q1.am&&p2->q1.am->skal==0&&(p2->q1.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q2.flags®)||p2->q2.flags!=r)&&(!(p2->z.flags®)||p2->z.flags!=r)){ |
| amuse=p2->q1.am; |
| use=p2; |
| continue; |
| } |
| if(!use&&p2->q2.am&&p2->q2.am->skal==0&&(p2->q2.am->dreg&127)==r&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!p2->z.am||(p2->z.am->dreg&127)!=r)&&(!(p2->q1.flags®)||p2->q1.flags!=r)&&(!(p2->z.flags®)||p2->z.flags!=r)){ |
| amuse=p2->q2.am; |
| use=p2; |
| continue; |
| } |
| if(!use&&p2->z.am&&p2->z.am->skal==0&&(p2->z.am->dreg&127)==r&&(!p2->q2.am||(p2->q2.am->dreg&127)!=r)&&(!p2->q1.am||(p2->q1.am->dreg&127)!=r)&&(!(p2->q2.flags®)||p2->q2.flags!=r)&&(!(p2->z.flags®)||p2->z.flags!=r)){ |
| amuse=p2->z.am; |
| use=p2; |
| continue; |
| } |
| if(!use&&c2==FREEREG&&p2->q1.reg==r){ |
| free_src=p2; |
| continue; |
| } |
| if(!use&&c2==FREEREG&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7&&p2->q1.reg==p->q1.reg){ |
| free_rsrc=p2; |
| continue; |
| } |
| if(use&&((c2==FREEREG&&p2->q1.reg==r)||((p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg==r))){ |
| amuse->skal=ul; |
| if(!src_mod&&isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7){ |
| amuse->dreg=p->q1.reg; |
| p->code=NOP; |
| p->q1.flags=p->q2.flags=p->z.flags=0; |
| }else{ |
| p->code=ASSIGN; |
| p->q2.flags=0; |
| p->q2.val.vmax=sizetab[p->typf&NQ]; |
| } |
| if(free_src) move_IC(use,free_src); |
| if(free_rsrc) move_IC(use,free_rsrc); |
| break; |
| } |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| if((p2->q1.flags®)&&p2->q1.reg==r) break; |
| if((p2->q2.flags®)&&p2->q2.reg==r) break; |
| if((p2->z.flags®)&&p2->z.reg==r) break; |
| if(p2->q1.am&&(p2->q1.am->dreg&127)==r) break; |
| if(p2->q2.am&&(p2->q2.am->dreg&127)==r) break; |
| if(p2->z.am&&(p2->z.am->dreg&127)==r) break; |
| if((p2->z.flags&(REG|DREFOBJ))==REG&&(p->q1.flags&(REG|DREFOBJ))&&p2->z.reg==p->q1.reg) |
| src_mod=1; |
| } |
| } |
| } |
| } |
| } |
| |
| /* another pass to remove unnecessary ALLOCREGs */ |
| for(p=first;p;p=p->next){ |
| if(p->code==ALLOCREG){ |
| r=p->q1.reg; |
| for(p2=p->next;p2;p2=p2->next){ |
| c2=p2->code; |
| if(c2==ALLOCREG&&p2->q1.reg==r) ierror(0); |
| if(c2==FREEREG&&p2->q1.reg==r){ |
| p->code=NOP; |
| p->q1.flags=0; |
| p2->code=NOP; |
| p2->q1.flags=0; |
| savedalloc++; |
| break; |
| } |
| if(c2==CALL||c2==LABEL||(c2>=BEQ&&c2<=BRA)) break; |
| if((p2->q1.flags®)&&p2->q1.reg==r) break; |
| if((p2->q2.flags®)&&p2->q2.reg==r) break; |
| if((p2->z.flags®)&&p2->z.reg==r) break; |
| if((am=p2->q1.am)&&(am->basereg==r||(am->dreg&127)==r)) break; |
| if((am=p2->q2.am)&&(am->basereg==r||(am->dreg&127)==r)) break; |
| if((am=p2->z.am)&&(am->basereg==r||(am->dreg&127)==r)) break; |
| } |
| } |
| } |
| |
| return localused; |
| } |
| static int addressing(IC *p) |
| /* Untersucht ICs auf erweiterte Addresierungsarten */ |
| { |
| int count,localused=0; |
| if(!OLDPEEPHOLE) return new_peephole(p); |
| if(DEBUG&32) printf("addressing() started\n"); |
| for(count=1;count<=16;count++) clear_am(count); |
| for(count=0;p;p=p->next){ |
| int c=p->code,q1reg,q2reg,zreg; |
| if(p->q1.flags®) q1reg=p->q1.reg; else q1reg=0; |
| if(p->q2.flags®) q2reg=p->q2.reg; else q2reg=0; |
| if(p->z.flags®) zreg=p->z.reg; else zreg=0; |
| if(c==ADDI2P) c=ADD; |
| if(c==SUBIFP) c=SUB; |
| if(DEBUG&32) pric2(stdout,p); |
| if(!localused){ |
| if((p->q1.flags&(VAR|REG))==VAR&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q1.v->offset)) |
| localused=1; |
| if((p->q2.flags&(VAR|REG))==VAR&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->q2.v->offset)) |
| localused=1; |
| if((p->z.flags&(VAR|REG))==VAR&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)&&zmleq(l2zm(0L),p->z.v->offset)) |
| localused=1; |
| if(DEBUG&32&&localused==1) printf("localused=1\n"); |
| } |
| if(c==ASSIGN&&isreg(q1)&&isreg(z)&&q1reg>=1&&q1reg<=8&&zreg>=1&&zreg<=8){ |
| /* fuer (ax)+ */ |
| int i; |
| clear_am(q1reg); |
| for(i=1;i<=8;i++) |
| if(am_base[i]==zreg||am_base[i]==q1reg) clear_am(i); |
| mod_reg(zreg); |
| clear_am(zreg);am_base[zreg]=q1reg;am_dreg_ic[zreg]=p; |
| if(DEBUG&32) printf("move %s,%s found\n",mregnames[q1reg],mregnames[zreg]); |
| continue; |
| } |
| if(c==MULT&&CPU>=68020&&isconst(q2)&&isreg(z)&&zreg>=d0&&zreg<=d7){ |
| /* dx=a*const, fuer Skalierung */ |
| int dreg=zreg-8; |
| if(dreg<1||dreg>8) ierror(0); |
| if(q1reg>=1&&q1reg<=d7){ |
| if(isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg); |
| if((p->q1.flags&DREFOBJ)&&q1reg<=8&&am_use[q1reg]) clear_am(q1reg); |
| } |
| if(DEBUG&32) printf("mult x,const->dreg found\n"); |
| mod_reg(zreg); |
| if(am_skal[dreg]) {clear_am(zreg);continue;} |
| eval_const(&p->q2.val,p->typf); |
| am_skal[dreg]=zm2l(vmax); |
| if(am_skal[dreg]!=2&&am_skal[dreg]!=4&&am_skal[dreg]!=8) |
| {clear_am(zreg);continue;} |
| am_shiftdreg[dreg]=p; |
| if(isreg(q1)&&q1reg>=d0&&q1reg<=d7) am_dbase[dreg]=q1reg; else am_dbase[dreg]=zreg; |
| if((p->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)) clear_am(p->q1.reg); |
| if(DEBUG&32) printf("is usable\n"); |
| continue; |
| } |
| if((c==ADD||c==SUB)&&isconst(q2)&&zreg>=1&&zreg<=8&&isreg(z)){ |
| /* add ax,#const,ax->az Test auf d8/16 fehlt noch (nicht mehr) */ |
| long l; |
| if(zreg<1||zreg>8) ierror(0); |
| eval_const(&p->q2.val,p->typf); |
| l=zm2l(vmax); |
| if(c==SUB) l=-l; |
| mod_reg(zreg); |
| if(q1reg==zreg&&isreg(q1)&&am_use[zreg]&&(l==1||l==2||l==4)){ |
| if(l==mopsize(am_use[zreg],zreg)&&(am_use[zreg]->code!=CONVERT||zmleq(sizetab[am_use[zreg]->typf2&NQ],sizetab[am_use[zreg]->typf&NQ]))){ |
| IC *op=am_use[zreg]; |
| obj *o=0; |
| if(DEBUG&32){ printf("found postincrement:\n");pric2(stdout,op);pric2(stdout,p);} |
| if((op->q1.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q1.reg==zreg){ |
| if(DEBUG&32) printf("q1\n"); |
| o=&op->q1; |
| } |
| if((op->q2.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->q2.reg==zreg){ |
| if(DEBUG&32) printf("q2\n"); |
| if(o) continue; else o=&op->q2; |
| } |
| if((op->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&op->z.reg==zreg){ |
| if(DEBUG&32) printf("z\n"); |
| if(o) continue; else o=&op->z; |
| } |
| o->am=mymalloc(AMS); |
| o->am->basereg=zreg; |
| o->am->skal=-1; |
| o->am->dist=0; |
| o->am->dreg=0; |
| p=p->prev; |
| remove_IC(p->next); |
| clear_am(zreg);continue; |
| } |
| } |
| clear_am(q1reg); |
| if(am_dist[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Offset */ |
| if(isreg(q1)&&q1reg==zreg&&(l==1||l==2||l==4)){ |
| /* ax+=const, fuer (ax)+ */ |
| int i,f; |
| for(f=0,i=1;i<=8;i++){ |
| if(am_base[i]==zreg&&!am_dreg[i]&&!am_dist[i]){ |
| if(f) ierror(0); |
| am_inc[i]=l;am_dist_ic[i]=p;f=i; |
| if(DEBUG&32) printf("inc %s found\n",mregnames[i]); |
| } |
| } |
| if(f) continue; |
| } |
| am_dist[zreg]=l; |
| if(DEBUG&32) printf("dist=%ld\n",am_dist[zreg]); |
| if(CPU<68020){ |
| /* bei <68020 darf der Offset nur 16bit oder 8bit bei dreg sein */ |
| if((am_dreg[zreg]&&(am_dist[zreg]<-128||am_dist[zreg]>127))||am_dist[zreg]<-32768||am_dist[zreg]>32767) |
| {clear_am(zreg);continue;} |
| } |
| am_dist_ic[zreg]=p; |
| if(am_base[zreg]){ |
| if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;} |
| }else{ |
| if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg; |
| if(DEBUG&32) printf("%s potential base for %s\n",mregnames[am_base[zreg]],mregnames[zreg]); |
| } |
| if(DEBUG&32) printf("add #const,%s found\n",mregnames[zreg]); |
| continue; |
| } |
| if(c==ADD&&q2reg>=d0&&q2reg<=d7&&isreg(q2)&&zreg>=1&&zreg<=8&&isreg(z)&&(p->q1.flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){ |
| /* add ax,dy->az */ |
| int i; |
| if(zreg<1||zreg>8) ierror(0); |
| for(i=1;i<=8;i++) |
| if(am_dreg[i]==q2reg){ clear_am(q2reg);clear_am(i);} |
| clear_am(q1reg); |
| mod_reg(zreg); |
| if(am_dreg[zreg]||am_inc[zreg]||am_use[zreg]) {clear_am(zreg);continue;} /* nur ein Regoffset */ |
| if(CPU<68020&&(am_dist[zreg]<-128||am_dist[zreg]>127)) |
| {clear_am(zreg);continue;} /* bei <68020 nur 8bit Offset */ |
| am_dreg[zreg]=q2reg; |
| if(ISHWORD(p->typf)) am_dreg[zreg]|=128; /* dx.w statt dx.l */ |
| am_dreg_ic[zreg]=p; |
| if(am_base[zreg]){ |
| if(q1reg!=zreg||!isreg(q1)) {clear_am(zreg);continue;} |
| }else{ |
| if(q1reg>=1&&q1reg<=8&&isreg(q1)) am_base[zreg]=q1reg; else am_base[zreg]=zreg; |
| } |
| if(DEBUG&32) printf("add %s,%s found\n",mregnames[q2reg],mregnames[zreg]); |
| continue; |
| } |
| if(c==FREEREG){ |
| /* wir koennen den Modus tatsaechlich benutzen */ |
| AddressingMode *am;IC *p1,*p2;int dreg,i; |
| if(DEBUG&32) printf("freereg %s found\n",mregnames[p->q1.reg]); |
| if(q1reg>=d0&&q1reg<=d7) {am_freedreg[q1reg-8]=p;if(DEBUG&32) printf("freedreg[%d]=%lx\n",q1reg-8,(long)p);} |
| if(q1reg>8) continue; |
| if(DEBUG&32) printf("use=%p,base=%p,dist=%p,dreg=%p\n",(void*)am_use[q1reg],(void*)am_base[q1reg],(void*)am_dist[q1reg],(void*)am_dreg[q1reg]); |
| for(i=1;i<=8;i++) if(am_base[i]==q1reg) clear_am(i); |
| if(!am_use[q1reg]||!am_base[q1reg]) continue; |
| if(am_inc[q1reg]&&am_inc[q1reg]!=mopsize(am_use[q1reg],q1reg)) |
| {clear_am(q1reg);continue;} |
| if(!am_dist[q1reg]&&!am_dreg[q1reg]&&!am_inc[q1reg]) continue; |
| p1=am_dist_ic[q1reg];p2=am_dreg_ic[q1reg]; |
| if(DEBUG&32){ |
| printf("could really use %s\n",mregnames[q1reg]); |
| if(p1) pric2(stdout,p1); |
| if(p2) pric2(stdout,p2); |
| } |
| if(am_base[q1reg]==q1reg){ |
| if(p1) {p1->q2.flags=0;p1->code=ASSIGN;p1->q2.val.vmax=l2zm(4L);p1->typf=POINTER;} |
| if(p2) {p2->q2.flags=0;p2->code=ASSIGN;p2->q2.val.vmax=l2zm(4L);p2->typf=POINTER;} |
| }else{ |
| if(p1) remove_IC(p1); |
| if(p2) remove_IC(p2); |
| } |
| dreg=(am_dreg[q1reg]&127)-8; |
| am=mymalloc(AMS); |
| am->skal=0; |
| am->basereg=am_base[q1reg]; |
| am->dist=am_dist[q1reg]; |
| am->dreg=am_dreg[q1reg]; |
| if(am_inc[q1reg]) am->skal=-1; |
| if(dreg>0){ |
| /* bei (d,ax,dy) das freereg dy nach hinten verschieben */ |
| if(dreg<1||dreg>8) ierror(0); |
| if(p1=am_freedreg[dreg]){ |
| if(DEBUG&32){ |
| printf("freereg %s moved from %p to %p\n",mregnames[dreg+8],(void*)p1,(void*)p); |
| pric2(stdout,p1); |
| } |
| if(p1->code!=FREEREG){ierror(0);printf("freereg[%d]=%p\n",dreg,(void*)p1);continue;} |
| if(!p1->next) {ierror(0);continue;} |
| if(!p1->prev) {ierror(0);continue;} |
| p1->prev->next=p1->next; |
| p1->next->prev=p1->prev; |
| p1->next=p->next; |
| p1->prev=p; |
| if(p->next) p->next->prev=p1; |
| p->next=p1; |
| } |
| if(am_skal[dreg]){ |
| /* Skalierung bearbeiten */ |
| if(p1){ |
| am->skal=am_skal[dreg]; |
| am->dreg=am_dbase[dreg]; |
| p1=am_shiftdreg[dreg]; |
| if(DEBUG&32) pric2(stdout,p1); |
| if(am_dbase[dreg]==dreg+8){ |
| p1->code=ASSIGN;p1->q2.flags=0;p1->q2.val.vmax=sizetab[p1->typf&NQ]; |
| }else remove_IC(p1); |
| } |
| clear_am(dreg+8); |
| } |
| } |
| /* das hier duerfte unnoetig sein, da die Adressierungsart in */ |
| /* einem IC eigentlich hoechstens einmal vorkommen darf */ |
| if(q1reg<0||q1reg>8) ierror(0); |
| p1=am_use[q1reg]; |
| if(DEBUG&32) pric2(stdout,p1); |
| if(p1->code==PUSH&&p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(REG))){ |
| p1->q1.am=mymalloc(AMS); |
| memcpy(p1->q1.am,am,AMS); |
| p->q1.val.vmax=l2zm(0L); |
| p1->code=PEA; |
| if(DEBUG&32) printf("q1 patched\n"); |
| } |
| if(p1->q1.reg==q1reg&&((p1->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){ |
| p1->q1.am=mymalloc(AMS); |
| memcpy(p1->q1.am,am,AMS); |
| p1->q1.val.vmax=l2zm(0L); |
| if(DEBUG&32) printf("q1 patched\n"); |
| } |
| if(p1->q2.reg==q1reg&&((p1->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){ |
| p1->q2.am=mymalloc(AMS); |
| memcpy(p1->q2.am,am,AMS); |
| p1->q2.val.vmax=l2zm(0L); |
| if(DEBUG&32) printf("q2 patched\n"); |
| } |
| if(p1->z.reg==q1reg&&((p1->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG))){ |
| p1->z.am=mymalloc(AMS); |
| memcpy(p1->z.am,am,AMS); |
| p1->z.val.vmax=l2zm(0L); |
| if(DEBUG&32) printf("z patched\n"); |
| } |
| free(am);count++; |
| clear_am(q1reg); |
| continue; |
| } |
| if(c>=LABEL&&c<=BRA){ |
| int i; /* ueber basic blocks hinweg unsicher */ |
| for(i=1;i<=16;i++) clear_am(i); |
| continue; |
| } |
| /* Wenn Libraryaufrufe noetig sind (floating point ohne FPU oder */ |
| /* 32bit mul/div/mod ohne 020+) keine Addressierungsarten nutzen */ |
| if(FPU<=68000&&(ISFLOAT(p->typf)||(p->code==CONVERT&&ISFLOAT(p->typf2)))){ |
| int i; |
| for(i=1;i<=16;i++) clear_am(i); |
| continue; |
| } |
| if(CPU<68020&&(c==DIV||c==MOD)){ |
| int i; |
| for(i=1;i<=16;i++) clear_am(i); |
| continue; |
| } |
| if(c==PUSH&&((p->q1.flags&(DREFOBJ|REG))==REG&&q1reg<=8&&!am_use[q1reg]&&(am_inc[q1reg]||am_dist[q1reg]||am_dreg[q1reg]))){ |
| if(q1reg<1||q1reg>8) ierror(0); |
| if(am_inc[q1reg]&&am_inc[q1reg]!=msizetab[p->typf&NQ]) clear_am(q1reg); else am_use[q1reg]=p; |
| if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]); |
| continue; |
| } |
| if(((p->q1.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q1reg<=8)){ |
| if(q1reg<1||q1reg>8) ierror(0); |
| if(am_use[q1reg]&&(am_use[q1reg]!=p||am_inc[q1reg])) clear_am(q1reg); else am_use[q1reg]=p; |
| if(am_inc[q1reg]&&am_inc[q1reg]!=sizetab[p->typf&NQ]) clear_am(q1reg); |
| if(DEBUG&32) printf("use of %s found\n",mregnames[q1reg]); |
| } |
| if(((p->q2.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&q2reg<=8)){ |
| if(q2reg<1||q2reg>8) ierror(0); |
| if(am_use[q2reg]&&(am_use[q2reg]!=p||am_inc[q2reg])) clear_am(q2reg); else am_use[q2reg]=p; |
| if(am_inc[q2reg]&&am_inc[q2reg]!=sizetab[p->typf&NQ]) clear_am(q2reg); |
| if(DEBUG&32) printf("use of %s found\n",mregnames[q2reg]); |
| } |
| if(((p->z.flags&(DREFOBJ|REG))==(DREFOBJ|REG)&&zreg<=8)){ |
| if(zreg<1||zreg>8) ierror(0); |
| if(am_use[zreg]&&(am_use[zreg]!=p||am_inc[zreg])) clear_am(zreg); else am_use[zreg]=p; |
| if(am_inc[zreg]&&am_inc[zreg]!=sizetab[p->typf&NQ]) clear_am(zreg); |
| if(DEBUG&32) printf("use of %s found\n",mregnames[zreg]); |
| } |
| if(c==ALLOCREG){ |
| /* allocreg zaehlt als zerstoerung von reg */ |
| p->z.flags=REG; |
| p->z.reg=zreg=q1reg=p->q1.reg; |
| } |
| if(q1reg>=1&&q1reg<=d7&&isreg(q1)&&(q1reg>8||am_use[q1reg]!=p)) clear_am(q1reg); |
| if(q2reg>=1&&q2reg<=d7&&isreg(q2)&&(q2reg>8||am_use[q2reg]!=p)) clear_am(q2reg); |
| if(zreg>=1&&zreg<=d7&&isreg(z)) clear_am(zreg); |
| if(isreg(z)&&zreg<=d7){ |
| /* schauen, ob eines der Register ueberschrieben wird */ |
| /* wohl noch sehr langsam */ |
| mod_reg(zreg); |
| } |
| if(c==ALLOCREG) p->z.flags=0; |
| } |
| if(DEBUG&1) printf("%d addressingmodes used, localused=%d\n",count,localused); |
| return localused; |
| } |
| static int alignment(obj *o) |
| /* versucht rauszufinden, wie ein Objekt alignet ist */ |
| { |
| /* wenn es keine Variable ist, kann man nichts aussagen */ |
| long os; |
| if(o->am||!(o->flags&VAR)) return -1; |
| if((o->flags&DREFOBJ)){ |
| if(!(o->v->flags&NOTTYPESAFE)||!ISPOINTER(o->v->vtyp->flags)||zmeqto(falign(o->v->vtyp->next),l2zm(1L))) |
| return -1; |
| else |
| return 0; |
| } |
| if(!o->v) ierror(0); |
| os=zm2l(o->val.vmax); |
| if(o->v->storage_class==AUTO||o->v->storage_class==REGISTER){ |
| if(!USEFRAMEPOINTER&&!vlas){ |
| if(!zmleq(l2zm(0L),o->v->offset)) os=os+loff-zm2l(o->v->offset); |
| else os=os+zm2l(o->v->offset); |
| }else{ |
| if(!zmleq(l2zm(0L),o->v->offset)) os=os-zm2l(o->v->offset); |
| else os=os-(zm2l(o->v->offset)+zm2l(szof(o->v->vtyp))); |
| } |
| }else{ |
| if(!(o->v->flags&(TENTATIVE|DEFINED))&&zmeqto(falign(o->v->vtyp),l2zm(1L))) |
| return -1; |
| } |
| |
| return os&3; |
| } |
| static void stored0d1(FILE *f,obj *o,int t) |
| { |
| if((o->flags&(REG|DREFOBJ))==REG){ |
| if(!reg_pair(o->reg,&rp)) ierror(0); |
| if(o->reg==25) return; |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[rp.r1]); |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[10],mregnames[rp.r2]); |
| }else{ |
| if(cf&&(o->flags&(REG|DREFOBJ))!=(REG|DREFOBJ)){ |
| emit(f,"\tmove.l\t%s,",mregnames[d0]); |
| emit_obj(f,o,t); |
| emit(f,"\n"); |
| emit(f,"\tmove.l\t%s,",mregnames[d1]); |
| o->val.vmax=zmadd(o->val.vmax,l2zm(4L)); |
| emit_obj(f,o,t); |
| o->val.vmax=zmsub(o->val.vmax,l2zm(4L)); |
| emit(f,"\n"); |
| }else{ |
| emit(f,"\tmovem.l\t%s,",mregnames[d0d1]); |
| emit_obj(f,o,t); |
| emit(f,"\n"); |
| } |
| } |
| } |
| static void loadd0d1(FILE *f,obj *o,int t) |
| { |
| if((o->flags&(REG|DREFOBJ))==REG){ |
| if(!reg_pair(o->reg,&rp)) |
| ierror(0); |
| if(o->reg==25) return; |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r1],mregnames[d0]); |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[rp.r2],mregnames[10]); |
| }else{ |
| if(cf){ |
| emit(f,"\tmove.l\t"); |
| emit_obj(f,o,t); |
| emit(f,",%s\n",mregnames[d0]); |
| emit(f,"\tmove.l\t"); |
| o->val.vmax=zmadd(o->val.vmax,l2zm(4L)); |
| emit_obj(f,o,t); |
| o->val.vmax=zmsub(o->val.vmax,l2zm(4L)); |
| emit(f,",%s\n",mregnames[d1]); |
| }else{ |
| emit(f,"\tmovem.l\t"); |
| emit_obj(f,o,t); |
| emit(f,",%s\n",mregnames[d0d1]); |
| } |
| } |
| } |
| static void assign(FILE *f,IC *p,obj *q,obj *z,int c,long size,int t) |
| /* Generiert Code fuer Zuweisungen und PUSH. */ |
| { |
| /* auch noch sehr fpu-spezifisch */ |
| if(FPU<=68000&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&!((q->flags&(KONST|DREFOBJ))==KONST)) |
| t=LLONG; |
| if(ISFLOAT(t)){ |
| if(q&&(q->flags&(KONST|DREFOBJ))==KONST){ |
| if(z&&(z->flags&(DREFOBJ|REG))==REG&&z->reg>=fp0&&z->reg<=fp7){ |
| /* FP-Konstante->Register (muss immer reinpassen) */ |
| if(z->reg>=fp0) emit(f,"\tfmove"); else emit(f,"\tmove"); |
| emit(f,".%c\t",x_t[t&NQ]);emit_obj(f,q,t); |
| emit(f,",%s\n",mregnames[z->reg]); |
| }else{ |
| /* FP-Konstante->Speicher (evtl. auf zweimal) */ |
| int m,r;unsigned char *ip=(unsigned char *)&q->val.vfloat; /* nicht sehr schoen */ |
| char *s; |
| if(cf&&c==ASSIGN) r=get_reg(f,1,p,0); |
| if(GAS) s="0x"; else s="$"; |
| if(c==PUSH&&(t&NQ)!=FLOAT){ |
| emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,-(%s)\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[sp]); |
| push(4); |
| } |
| emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[0],ip[1],ip[2],ip[3]); |
| if(c==ASSIGN){ |
| if(cf) |
| emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]); |
| if(isreg(z)&®_pair(p->z.reg,&rp)) |
| emit(f,"%s",mregnames[rp.r1]); |
| else |
| emit_obj(f,z,t); |
| }else{ |
| emit(f,"-(%s)",mregnames[sp]); |
| push(4); |
| } |
| emit(f,"\n"); |
| if((t&NQ)==FLOAT||c==PUSH) return; |
| m=0; |
| if(z&&(z->flags®)){ |
| m=1;z->flags|=D16OFF; |
| z->val.vmax=l2zm(0L); |
| } |
| vmax=l2zm(4L); |
| z->val.vmax=zmadd(z->val.vmax,vmax); |
| emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,",s,ip[4],ip[5],ip[6],ip[7]); |
| if(cf) |
| emit(f,"%s\n\tmove.l\t%s,",mregnames[r],mregnames[r]); |
| if(isreg(z)&®_pair(p->z.reg,&rp)) |
| emit(f,"%s",mregnames[rp.r2]); |
| else |
| emit_obj(f,z,t); |
| emit(f,"\n"); |
| if(m){ |
| z->flags&=~D16OFF;vmax=l2zm(4L); |
| z->val.vmax=zmsub(z->val.vmax,vmax); |
| } |
| } |
| return; |
| } |
| if((q&&(q->flags®)&&q->reg>=fp0)||(z&&(z->flags®)&&z->reg>=fp0)){ |
| if(c==ASSIGN&&(q->flags®)&&(z->flags®)&&q->reg==z->reg) return; |
| if(c==ASSIGN){ move(f,q,0,z,0,t);return;} |
| emit(f,"\tfmove.%c\t",x_t[t&NQ]); |
| emit_obj(f,q,t); |
| emit(f,","); |
| if(c==PUSH){ |
| emit(f,"-(%s)",mregnames[sp]); |
| push(size); |
| } else |
| emit_obj(f,z,t); |
| emit(f,"\n");return; |
| } |
| if(size==8) t=LLONG; |
| } |
| if((t&NQ)==LLONG){ |
| if(z&&compare_objects(q,z)) return; |
| if(((cf&&c==ASSIGN)||(q->flags&(REG|DREFOBJ))==REG)&&(!z||(z->flags&(REG|DREFOBJ))!=REG)){ |
| if(cf){ |
| if(c==ASSIGN){ |
| int r; |
| if((q->flags&(REG|DREFOBJ))==REG){ |
| if(!reg_pair(q->reg,&rp)) ierror(0); |
| r=rp.r2; |
| }else{ |
| r=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,q); |
| emit(f,",%s\n",mregnames[r]); |
| } |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_lword(f,z); |
| emit(f,"\n"); |
| if((q->flags&(REG|DREFOBJ))==REG){ |
| r=rp.r1; |
| }else{ |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,q); |
| emit(f,",%s\n",mregnames[r]); |
| } |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_hword(f,z); |
| emit(f,"\n"); |
| }else{ |
| emit(f,"\tsubq.l\t#8,%s\n",mregnames[sp]); |
| push(8); |
| emit(f,"\tmovem.l\t%s,(%s)\n",mregnames[q->reg],mregnames[sp]); |
| } |
| }else{ |
| emit(f,"\tmovem.l\t%s,",mregnames[q->reg]); |
| if(c==ASSIGN){ |
| emit_obj(f,z,t); |
| }else{ |
| emit(f,"-(%s)",mregnames[sp]); |
| push(8); |
| } |
| emit(f,"\n"); |
| } |
| return; |
| } |
| if(!cf&&(q->flags&(REG|DREFOBJ))!=REG&&!((q->flags&(KONST|DREFOBJ))==KONST)&&z&&(z->flags&(REG|DREFOBJ))==REG){ |
| emit(f,"\tmovem.l\t"); |
| emit_obj(f,q,t); |
| emit(f,",%s\n",mregnames[z->reg]); |
| return; |
| } |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,q); |
| emit(f,","); |
| if(c==ASSIGN){ |
| emit_lword(f,z); |
| }else{ |
| emit(f,"-(%s)",mregnames[sp]); |
| push(4); |
| } |
| emit(f,"\n"); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,q); |
| emit(f,","); |
| if(c==ASSIGN){ |
| emit_hword(f,z); |
| }else{ |
| emit(f,"-(%s)",mregnames[sp]); |
| push(4); |
| } |
| emit(f,"\n"); |
| return; |
| } |
| if((size==1||size==2||size==4)&&!ISARRAY(t)&&(p->code!=PUSH||zm2l(p->z.val.vmax)!=3)&&((t&NQ)!=CHAR||size==1)){ |
| if(ISSTRUCT(t)||ISUNION(t)){ |
| if(p->code==PUSH&&!zmeqto(p->q2.val.vmax,p->z.val.vmax)){ |
| if(size!=4&&size!=2) ierror(size); |
| emit(f,"\tsubq.%s\t#%d,%s\n",cf?"l":"w",size,mregnames[sp]); |
| push(size); |
| size=zm2l(p->z.val.vmax); |
| if(size!=1&&size!=2) ierror(0); |
| emit(f,"\tmove.%c\t",size==1?'b':'w'); |
| emit_obj(f,q,(size==1?CHAR:SHORT)); |
| emit(f,",(%s)\n",mregnames[sp]); |
| return; |
| }else{ |
| if(size==1) |
| t=CHAR; |
| else if(size==2) |
| t=SHORT; |
| else |
| t=LONG; |
| } |
| } |
| if(c==ASSIGN){move(f,q,0,z,0,t);return;} |
| /* Sonderfall pea */ |
| if((q->flags&VARADR)&&c==PUSH){ |
| emit(f,"\tpea\t"); |
| q->flags&=~VARADR; emit_obj(f,q,t); q->flags|=VARADR; |
| emit(f,"\n"); |
| push(size); |
| return; |
| } |
| emit(f,"\tmove.%c\t",x_s[size]); |
| emit_obj(f,q,t); |
| emit(f,","); |
| if(c==PUSH){ |
| emit(f,"-(%s)",mregnames[sp]); |
| push(size); |
| } else |
| emit_obj(f,z,t); |
| emit(f,"\n");return; |
| }else{ |
| int a1,a2,qreg,zreg,dreg,loops,scratch=0,down=0;char *cpstr; |
| long s=size,osize=size; |
| IC *m; |
| for(m=p->next;m&&m->code==FREEREG;m=m->next){ |
| if(q&&m->q1.reg==q->reg) scratch|=1; |
| if(z&&m->q1.reg==z->reg) scratch|=2; |
| } |
| a1=alignment(q); |
| if(c!=PUSH) a2=alignment(z); else a2=0; |
| if(a1<0||a2<0) {a1=1;a2=2;} |
| if(p->typf2==2||p->typf2==4) {a1=a2=0;} |
| if((c==PUSH||(scratch&1))&&(q->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&q->reg>=1&&q->reg<=8&&!q->am){ |
| qreg=q->reg; |
| if(c==PUSH&&(a1&1)==0&&(a2&1)==0) |
| emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[q->reg]); |
| }else{ |
| if(c!=ASSIGN&&!regavailable(0)) |
| qreg=pget_reg(f,0,p,0); |
| else |
| qreg=get_reg(f,0,p,0); |
| if(c==PUSH&&(a1&1)==0&&(a2&1)==0){ |
| q->flags|=D16OFF; |
| q->val.vmax=zmadd(q->val.vmax,l2zm((long)s)); |
| emit(f,"\tlea\t");emit_obj(f,q,POINTER); |
| q->val.vmax=zmsub(q->val.vmax,l2zm((long)s)); |
| emit(f,",%s\n",mregnames[qreg]); |
| }else{ |
| emit(f,"\tlea\t");emit_obj(f,q,POINTER); |
| emit(f,",%s\n",mregnames[qreg]); |
| } |
| } |
| if(c==PUSH){ |
| if((a1&1)==0&&(a2&1)==0){ |
| zreg=8; |
| }else{ |
| emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[s<=8],strshort[s<=32767],(long)s,mregnames[sp]); |
| push(size); |
| size=0; |
| if(!regavailable(0)) |
| zreg=pget_reg(f,0,p,0); |
| else |
| zreg=get_reg(f,0,p,0); |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[zreg]); |
| } |
| }else{ |
| if((scratch&2)&&(z->flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&z->reg>=1&&z->reg<=8&&!z->am){ |
| zreg=z->reg; |
| }else{ |
| zreg=get_reg(f,0,p,0); |
| emit(f,"\tlea\t");emit_obj(f,z,POINTER); |
| emit(f,",%s\n",mregnames[zreg]); |
| } |
| } |
| /* wenn Typ==CHAR, dann ist das ein inline_memcpy und wir nehmen */ |
| /* das unguenstigste Alignment an */ |
| /*if((t&NQ)==CHAR){ a1=1;a2=2;}*/ |
| |
| if(c==PUSH&&(a1&1)==0&&(a2&1)==0){ |
| cpstr="\tmove.%c\t-(%s),-(%s)\n"; |
| down=1; |
| }else |
| cpstr="\tmove.%c\t(%s)+,(%s)+\n"; |
| |
| if((a1&1)&&(a2&1)){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;a1&=~1;a2&=~1;} |
| if((a1&2)&&(a2&2)){emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]);s-=2;a1&=~2;a2&=~2;} |
| if(!(a1&1)&&!(a2&1)) loops=s/16-1; else loops=s/4-1; |
| if(loops>0){ |
| if(c!=ASSIGN&&!regavailable(1)) dreg=pget_reg(f,1,p,0); |
| else dreg=get_reg(f,1,p,0); |
| emit(f,"\tmove%s.l\t#%d,%s\n%s%d:\n",quick[loops>=-128&&loops<=127],loops,mregnames[dreg],labprefix,++label); |
| } |
| if(loops>=0){ |
| int t; |
| if(!(a1&1)&&!(a2&1)) t='l'; else t='b'; |
| emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]); |
| emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]); |
| emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]); |
| emit(f,cpstr,t,mregnames[qreg],mregnames[zreg]); |
| } |
| if(loops>0){ |
| if(!cf&&loops<=32767&&loops>=-32768){ |
| emit(f,"\tdbra\t%s,%s%d\n",mregnames[dreg],labprefix,label); |
| }else{ |
| emit(f,"\tsubq.l\t#1,%s\n\tbge\t%s%d\n",mregnames[dreg],labprefix,label); |
| } |
| } |
| if(!(a1&1)&&!(a2&1)){ |
| if(s&8){ |
| emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]); |
| emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]); |
| } |
| if(s&4) emit(f,cpstr,'l',mregnames[qreg],mregnames[zreg]); |
| if(s&2) emit(f,cpstr,'w',mregnames[qreg],mregnames[zreg]); |
| if(s&1) emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]); |
| }else{ |
| s&=3; |
| while(s){emit(f,cpstr,'b',mregnames[qreg],mregnames[zreg]);s--;} |
| } |
| if(c==PUSH&&qreg==q->reg&&(!(scratch&1))&&!down) |
| emit(f,"\tsub%s.%s\t#%ld,%s\n",quick[osize<=8],strshort[osize<=32767],osize,regnames[qreg]); |
| if(c==PUSH) push(size); |
| } |
| return; |
| } |
| static int muststore(IC *p,int r) |
| { |
| if(!regs[r]) |
| return 0; |
| #if 0 |
| /* mal bei Gelegenheit testen */ |
| while(p){ |
| if(p->code==FREEREG&&p->q1.reg==r) |
| return 0; |
| if((p->q1.flags®)&&p->q1.reg==r) |
| return 1; |
| if(p->q1.am&&(p->q1.am->basereg==r||(p->q1.am->dreg&127)==r)) |
| return 1; |
| if((p->q2.flags®)&&p->q2.reg==r) |
| return 1; |
| if(p->q2.am&&(p->q2.am->basereg==r||(p->q2.am->dreg&127)==r)) |
| return 1; |
| if(p->z.am&&(p->z.am->basereg==r||(p->z.am->dreg&127)==r)) |
| return 1; |
| if((p->z.flags®)&&p->z.reg==r) |
| return (p->z.flags&DREFOBJ)!=0; |
| if(p->code>=LABEL&&p->code<=BRA) |
| return 1; |
| p=p->next; |
| } |
| return 0; |
| #else |
| return 1; |
| #endif |
| } |
| |
| static int store_saveregs; |
| static void saveregswfp(FILE *f,IC *p,int storefp) |
| { |
| int dontsave; |
| store_saveregs=0; |
| if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0; |
| if(dontsave!= d0&&dontsave!=25&&(muststore(p,d0)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d0],mregnames[sp]);push(4);store_saveregs|=1;} |
| if(dontsave!=10&&dontsave!=25&&(muststore(p,d1)||muststore(p,d0d1))) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[d1],mregnames[sp]);push(4);store_saveregs|=2;} |
| if(dontsave!= fp0&&muststore(p,fp0)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp0],mregnames[sp]);push(12);store_saveregs|=16;} |
| if(dontsave!= fp1&&muststore(p,fp1)) {emit(f,"\tfmove.x\t%s,-(%s)\n",mregnames[fp1],mregnames[sp]);push(12);store_saveregs|=32;} |
| if(dontsave!= a0&&muststore(p,a0)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a0],mregnames[sp]);push(4);store_saveregs|=4;} |
| if(dontsave!= a1&&muststore(p,a1)) {emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[a1],mregnames[sp]);push(4);store_saveregs|=8;} |
| |
| } |
| static void restoreregsa(FILE *f,IC *p) |
| { |
| if(store_saveregs&8) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a1]);pop(4);} |
| if(store_saveregs&4) {emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[a0]);pop(4);} |
| } |
| static void restoreregsd(FILE *f,IC *p) |
| { |
| int dontsave; |
| if((p->z.flags&(REG|DREFOBJ))==REG) dontsave=p->z.reg; else dontsave=0; |
| if(dontsave!=fp1&&(store_saveregs&32)){ |
| emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp1]); |
| pop(12); |
| } |
| if(dontsave!=fp0&&(store_saveregs&16)){ |
| emit(f,"\tfmove.x\t(%s)+,%s\n",mregnames[sp],mregnames[fp0]); |
| pop(12); |
| } |
| if(dontsave!=10&&(store_saveregs&2)){ |
| if(!GAS&&!PHXASS) |
| emit(f,"\topt\tom-\n"); |
| if(cf) |
| emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d1],mregnames[sp]); |
| else |
| emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d1]); |
| pop(4); |
| if(!GAS&&!PHXASS) |
| emit(f,"\topt\tom+\n"); |
| } |
| if(dontsave!=d0 &&(store_saveregs&1)){ |
| if(!GAS&&!PHXASS) |
| emit(f,"\topt\tom-\n"); |
| if(cf) |
| emit(f,"\tmovem.l\t(%s),%s\n\taddq.l\t#4,%s\n",mregnames[sp],mregnames[d0],mregnames[sp]); |
| else |
| emit(f,"\tmovem.l\t(%s)+,%s\n",mregnames[sp],mregnames[d0]); |
| pop(4); |
| if(!GAS&&!PHXASS) |
| emit(f,"\topt\tom+\n"); |
| } |
| } |
| |
| /* emits the low word of a long long object */ |
| static void emit_lword(FILE *f,obj *o) |
| { |
| if((o->flags&(REG|DREFOBJ))==REG){ |
| if(!reg_pair(o->reg,&rp)) |
| ierror(0); |
| emit(f,"%s",mregnames[rp.r2]); |
| }else if((o->flags&(KONST|DREFOBJ))==KONST){ |
| eval_const(&o->val,UNSIGNED|LLONG); |
| vumax=zumand(vumax,ul2zum(0xffffffff)); |
| insert_const(&gval,UNSIGNED|MAXINT); |
| emit(f,"#"); |
| emitval(f,&gval,UNSIGNED|MAXINT); |
| }else{ |
| if(o->am||(o->flags®)){ |
| o->flags|=D16OFF; |
| o->val.vmax=l2zm(0L); |
| } |
| o->val.vmax=zmadd(o->val.vmax,l2zm(4L)); |
| emit_obj(f,o,LLONG); |
| o->flags&=~D16OFF; |
| o->val.vmax=zmsub(o->val.vmax,l2zm(4L)); |
| } |
| } |
| /* emits the high word of a long long object */ |
| static void emit_hword(FILE *f,obj *o) |
| { |
| if((o->flags&(REG|DREFOBJ))==REG){ |
| if(!reg_pair(o->reg,&rp)) |
| ierror(0); |
| emit(f,"%s",mregnames[rp.r1]); |
| }else if((o->flags&(KONST|DREFOBJ))==KONST){ |
| eval_const(&o->val,UNSIGNED|MAXINT); |
| vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff)); |
| insert_const(&gval,UNSIGNED|MAXINT); |
| emit(f,"#"); |
| emitval(f,&gval,UNSIGNED|MAXINT); |
| }else{ |
| emit_obj(f,o,LONG); |
| } |
| } |
| /* process ICs with long long; return 1 if IC has been handled */ |
| static int handle_llong(FILE *f,IC *p) |
| { |
| int c=p->code,r=0,t=p->typf&NU; |
| char *libfuncname; |
| |
| if(c==ADDRESS) return 0; |
| |
| cc_set=0; |
| if(c==GETRETURN){ |
| if(isreg(z)&&p->z.reg==25) |
| return 1; |
| emit(f,"\tmove.l\t%s,",mregnames[d1]); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| emit(f,"\tmove.l\t%s,",mregnames[d0]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| return 1; |
| } |
| if(c==SETRETURN){ |
| if(isreg(q1)&&p->q1.reg==25) |
| return 1; |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q1); |
| emit(f,",%s\n",mregnames[d1]); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q1); |
| emit(f,",%s\n",mregnames[d0]); |
| return 1; |
| } |
| if(c==CONVERT){ |
| int told=q1typ(p),tnew=ztyp(p); |
| if(ISPOINTER(told)) told=UNSIGNED|LONG; |
| if(ISPOINTER(tnew)) tnew=UNSIGNED|LONG; |
| if(ISFLOAT(told)){ |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told); |
| scratch_modified(); |
| if(GAS) |
| emit(f,"\t.global\t__flt%ldto%cint64\n\tjbsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]); |
| else |
| emit(f,"\tpublic\t__flt%ldto%cint64\n\tjsr\t__flt%ldto%cint64\n\taddq.%s\t#%ld,%s\n",msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',msizetab[told&NQ]*8,(tnew&UNSIGNED)?'u':'s',strshort[1],msizetab[told&NQ],mregnames[sp]); |
| pop(msizetab[told]); |
| restoreregsa(f,p); |
| if(!isreg(z)||p->z.reg!=25){ /* d0/d1 */ |
| emit(f,"\tmove.l\t%s,",mregnames[d1]); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| emit(f,"\tmove.l\t%s,",mregnames[d0]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| } |
| restoreregsd(f,p); |
| return 1; |
| } |
| if(ISFLOAT(tnew)){ |
| saveregswfp(f,p,1); |
| assign(f,p,&p->q1,0,PUSH,msizetab[told&NQ],told); |
| scratch_modified(); |
| if(GAS) |
| emit(f,"\t.global\t__%cint64toflt%ld\n\tjbsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]); |
| else |
| emit(f,"\tpublic\t__%cint64toflt%ld\n\tjsr\t__%cint64toflt%ld\n\taddq.%s\t#%ld,%s\n",(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,(told&UNSIGNED)?'u':'s',msizetab[tnew&NQ]*8,strshort[1],msizetab[told&NQ],mregnames[sp]); |
| pop(msizetab[told&NQ]); |
| restoreregsa(f,p); |
| if(FPU>68000){ |
| emit(f,"\tfmove.x\tfp0,"); |
| emit_obj(f,&p->z,tnew); |
| emit(f,"\n"); |
| }else if((tnew&NQ)==FLOAT){ |
| emit(f,"\tmove.l\t%s,",mregnames[d0]); |
| emit_obj(f,&p->z,tnew); |
| emit(f,"\n"); |
| }else{ |
| emit(f,"\tmove.l\td1,"); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| emit(f,"\tmove.l\t%s,",mregnames[d0]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| } |
| restoreregsd(f,p); |
| return 1; |
| } |
| if((told&NQ)<LLONG){ |
| int destreg=0; |
| if(ISHWORD(told)||!(told&UNSIGNED)){ |
| if(isreg(z)){ |
| if(!reg_pair(p->z.reg,&rp)) ierror(0); |
| r=rp.r2; |
| destreg=1; |
| }else{ |
| r=get_reg(f,1,p,0); |
| } |
| loadext(f,r,&p->q1,told); |
| p->q1.flags=REG; |
| p->q1.reg=r; |
| p->q1.am=0; |
| } |
| if(!destreg){ |
| emit(f,"\tmove.l\t"); |
| emit_obj(f,&p->q1,told); |
| emit(f,","); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| } |
| if(told&UNSIGNED){ |
| emit(f,"\tmove.l\t#0,"); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| }else{ |
| int tmp; |
| if(r==0) |
| ierror(0); |
| if(destreg){ |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[r],mregnames[rp.r1]); |
| r=rp.r1; |
| } |
| tmp=get_reg(f,1,p,0); |
| emit(f,"\tmoveq\t#31,%s\n",mregnames[tmp]); |
| emit(f,"\tasr.l\t%s,%s\n",mregnames[tmp],mregnames[r]); |
| if(!destreg){ |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| } |
| } |
| return 1; |
| } |
| if((tnew&NQ)<LLONG){ |
| if((tnew&NQ)<INT&&!isreg(z)){ |
| r=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q1); |
| emit(f,",%s\n",mregnames[r]); |
| emit(f,"\tmove.%c\t%s,",x_t[tnew&NQ],mregnames[r]); |
| emit_obj(f,&p->z,tnew); |
| emit(f,"\n"); |
| }else{ |
| emit(f,"\tmove.%c\t",x_t[tnew&NQ]); |
| p->q1.val.vmax=zmadd(p->q1.val.vmax,zmsub(sizetab[LONG],sizetab[tnew&NQ])); |
| emit_lword(f,&p->q1); |
| emit(f,","); |
| emit_obj(f,&p->z,tnew); |
| emit(f,"\n"); |
| } |
| return 1; |
| } |
| assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t); |
| return 1; |
| } |
| if(c==ASSIGN){ |
| assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t); |
| return 1; |
| } |
| if(c==PUSH){ |
| dontpop+=zm2l(p->q2.val.vmax); |
| assign(f,p,&p->q1,0,PUSH,msizetab[t],t); |
| return 1; |
| } |
| if(c==MINUS||c==KOMPLEMENT){ |
| char *sl,*sh; |
| if(c==MINUS){ |
| sl="neg.l"; |
| sh="negx.l"; |
| }else |
| sl=sh="not.l"; |
| if(!cf&&compare_objects(&p->q1,&p->z)){ |
| emit(f,"\t%s\t",sl); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| emit(f,"\t%s\t",sh); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| return 1; |
| } |
| if(isreg(z)){ |
| if(!reg_pair(p->z.reg,&rp)) ierror(0); |
| assign(f,p,&p->q1,&p->z,ASSIGN,msizetab[t],t); |
| emit(f,"\t%s\t%s\n",sl,mregnames[rp.r2]); |
| emit(f,"\t%s\t%s\n",sh,mregnames[rp.r1]); |
| return 1; |
| } |
| r=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q1); |
| emit(f,",%s\n",mregnames[r]); |
| emit(f,"\t%s\t%s\n",sl,mregnames[r]); |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q1); |
| emit(f,",%s\n",mregnames[r]); |
| emit(f,"\t%s\t%s\n",sh,mregnames[r]); |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| return 1; |
| } |
| if((c>=OR&&c<=AND)||c==ADD||c==SUB){ |
| char *sl,*sh;int t2=0; |
| switch_IC(p); |
| if(c==ADD){sl="add.l";sh="addx.l";} |
| else if(c==SUB){sl="sub.l";sh="subx.l";} |
| else if(c==AND){sl=sh="and.l";} |
| else if(c==OR){sl=sh="or.l";} |
| else if(c==XOR){sl=sh="eor.l";} |
| else |
| ierror(0); |
| if(isreg(q1)&&isreg(q2)&&isreg(z)&&p->q1.reg==p->q2.reg&&p->q1.reg==p->z.reg){ |
| if(!reg_pair(p->q1.reg,&rp)) ierror(0); |
| emit(f,"\t%s\t%s,%s\n",sl,mregnames[rp.r2],mregnames[rp.r2]); |
| emit(f,"\t%s\t%s,%s\n",sh,mregnames[rp.r1],mregnames[rp.r1]); |
| return 1; |
| } |
| if(!isreg(z)&&compare_objects(&p->q1,&p->z)){ |
| if(isreg(q2)||(isconst(q2)&&(c==ADD||c==SUB)&&!cf)){ |
| if(!r) r=get_reg(f,1,p,0); |
| emit(f,"\t%s\t",sl); |
| emit_lword(f,&p->q2); |
| }else{ |
| if(!r) r=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q2); |
| emit(f,",%s\n",mregnames[r]); |
| emit(f,"\t%s\t%s",sl,mregnames[r]); |
| } |
| emit(f,","); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| if(!isreg(q2)||c==ADD||c==SUB||c==XOR){ |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q1); |
| emit(f,",%s\n",mregnames[r]); |
| if(isreg(q2)){ |
| if(!reg_pair(p->q2.reg,&rp)) ierror(0); |
| t2=rp.r1; |
| }else{ |
| t2=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q2); |
| emit(f,",%s\n",mregnames[t2]); |
| } |
| emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]); |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| }else{ |
| if(isreg(q2)){ |
| emit(f,"\t%s\t",sh); |
| emit_hword(f,&p->q2); |
| }else{ |
| if(!r) r=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q2); |
| emit(f,",%s\n",mregnames[r]); |
| emit(f,"\t%s\t%s",sh,mregnames[r]); |
| } |
| emit(f,","); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| } |
| return 1; |
| } |
| if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){ |
| if(!reg_pair(p->z.reg,&rp)) ierror(0); |
| r=rp.r2; |
| }else{ |
| r=get_reg(f,1,p,0); |
| } |
| if(!compare_objects(&p->q1,&p->z)){ |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q1); |
| emit(f,",%s\n",mregnames[r]); |
| } |
| if(c==XOR){ |
| t2=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q2); |
| emit(f,",%s\n",mregnames[t2]); |
| emit(f,"\t%s\t%s,%s\n",sl,mregnames[t2],mregnames[r]); |
| }else{ |
| emit(f,"\t%s\t",sl); |
| emit_lword(f,&p->q2); |
| emit(f,",%s\n",mregnames[r]); |
| } |
| if(isreg(z)&&(!isreg(q2)||p->z.reg!=p->q2.reg)){ |
| if(!reg_pair(p->z.reg,&rp)) ierror(0); |
| r=rp.r1; |
| }else{ |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| } |
| if(!compare_objects(&p->q1,&p->z)){ |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q1); |
| emit(f,",%s\n",mregnames[r]); |
| } |
| if(c==XOR||c==ADD||c==SUB){ |
| if(isreg(q2)){ |
| if(!reg_pair(p->q2.reg,&rp)) ierror(0); |
| t2=rp.r1; |
| }else{ |
| if(!t2) t2=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q2); |
| emit(f,",%s\n",mregnames[t2]); |
| } |
| emit(f,"\t%s\t%s,%s\n",sh,mregnames[t2],mregnames[r]); |
| }else{ |
| emit(f,"\t%s\t",sh); |
| emit_hword(f,&p->q2); |
| emit(f,",%s\n",mregnames[r]); |
| } |
| if(!isreg(z)||(isreg(q2)&&p->z.reg==p->q2.reg)){ |
| emit(f,"\tmove.l\t%s,",mregnames[r]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| } |
| return 1; |
| } |
| if(c==TEST){ |
| p->code=c=COMPARE; |
| p->q2.flags=KONST; |
| if((t&NU)==LLONG) |
| p->q2.val.vllong=zm2zll(l2zm(0L)); |
| else if((t&NU)==(UNSIGNED|LLONG)) |
| p->q2.val.vullong=zum2zull(ul2zum(0UL)); |
| else |
| ierror(0); |
| } |
| if(c==COMPARE){ |
| int rl,rh,t2; |
| comptyp=p->typf; |
| rl=get_reg(f,1,p,0); |
| rh=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q1); |
| emit(f,",%s\n",mregnames[rl]); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q1); |
| emit(f,",%s\n",mregnames[rh]); |
| if(isreg(q2)){ |
| if(!reg_pair(p->q2.reg,&rp)) ierror(0); |
| t2=rp.r1; |
| }else{ |
| t2=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_hword(f,&p->q2); |
| emit(f,",%s\n",mregnames[t2]); |
| } |
| emit(f,"\tsub.l\t"); |
| emit_lword(f,&p->q2); |
| emit(f,",%s\n",mregnames[rl]); |
| emit(f,"\tsubx.l\t%s,%s\n",mregnames[t2],mregnames[rh]); |
| return 1; |
| } |
| saveregs(f,p); |
| if((c==LSHIFT||c==RSHIFT)&&(q2typ(p)&NQ)==LLONG){ |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q2); |
| emit(f,",-(%s)\n",mregnames[sp]); |
| push(4); |
| }else |
| assign(f,p,&p->q2,0,PUSH,msizetab[q2typ(p)&NQ],q2typ(p)); |
| assign(f,p,&p->q1,0,PUSH,msizetab[q1typ(p)&NQ],q1typ(p)); |
| scratch_modified(); |
| if(c==MULT){ |
| if(CPU==68060) |
| libfuncname="__mulint64_060"; |
| else if(CPU>=68020) |
| libfuncname="__mulint64_020"; |
| else |
| libfuncname="__mulint64"; |
| }else if(c==DIV){ |
| if(t&UNSIGNED){ |
| if(CPU==68060) |
| libfuncname="__divuint64_060"; |
| else if(CPU>=68020) |
| libfuncname="__divuint64_020"; |
| else |
| libfuncname="__divuint64"; |
| }else{ |
| if(CPU==68060) |
| libfuncname="__divsint64_060"; |
| else if(CPU>=68020) |
| libfuncname="__divsint64_020"; |
| else |
| libfuncname="__divsint64"; |
| } |
| }else if(c==MOD){ |
| if(t&UNSIGNED){ |
| if(CPU==68060) |
| libfuncname="__moduint64_060"; |
| else if(CPU>=68020) |
| libfuncname="__moduint64_020"; |
| else |
| libfuncname="__moduint64"; |
| }else{ |
| if(CPU==68060) |
| libfuncname="__modsint64_060"; |
| else if(CPU>=68020) |
| libfuncname="__modsint64_020"; |
| else |
| libfuncname="__modsint64"; |
| } |
| }else if(c==RSHIFT){ |
| if(t&UNSIGNED) |
| libfuncname="__rshuint64"; |
| else |
| libfuncname="__rshsint64"; |
| }else if(c==LSHIFT) |
| libfuncname="__lshint64"; |
| else{ |
| printf("c=%d\n",c); |
| ierror(0); |
| } |
| if(GAS) |
| emit(f,"\t.global\t%s\n\tjbsr\t%s\n",libfuncname,libfuncname); |
| else |
| emit(f,"\tpublic\t%s\n\tjsr\t%s\n",libfuncname,libfuncname); |
| if(c==LSHIFT||c==RSHIFT){ |
| #ifdef M68K_16BIT_INT |
| emit(f,"\tadd.%s\t#10,%s\n",strshort[1],mregnames[sp]); |
| pop(10); |
| #else |
| emit(f,"\tadd.%s\t#12,%s\n",strshort[1],mregnames[sp]); |
| pop(12); |
| #endif |
| }else{ |
| emit(f,"\tadd.%s\t#16,%s\n",strshort[1],mregnames[sp]); |
| pop(16); |
| } |
| restoreregsa(f,p); |
| if(!isreg(z)||p->z.reg!=25){ |
| emit(f,"\tmove.l\t%s,",mregnames[d0]); |
| emit_hword(f,&p->z); |
| emit(f,"\n"); |
| emit(f,"\tmove.l\t%s,",mregnames[10]); |
| emit_lword(f,&p->z); |
| emit(f,"\n"); |
| } |
| restoreregsd(f,p); |
| return 1; |
| } |
| |
| /* generate inlines for Amiga IEEE softcalls */ |
| static char *ami_ieee(char *base,int off) |
| { |
| char *s; |
| if(cf) ierror(0); |
| s=mymalloc(128); |
| sprintf(s,"\tmove.l\t%s,-(%s)\n\tmove.l\t%sMathIeee%sBase%s,%s\n\tjsr\t%d(%s)\n\tmove.l\t(%s)+,%s",mregnames[a6],mregnames[sp],idprefix,base,use_sd?"(a4)":"",mregnames[a6],off,mregnames[a6],mregnames[sp],mregnames[a6]); |
| return s; |
| } |
| |
| /****************************************/ |
| /* 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; |
| larray.size=l2zm(3L); |
| /* Initialize some values which cannot be statically initialized */ |
| /* because they are stored in the target's arithmetic. */ |
| maxalign=l2zm(4L); |
| char_bit=l2zm(8L); |
| for(i=0;i<=MAX_TYPE;i++){ |
| sizetab[i]=l2zm(msizetab[i]); |
| align[i]=l2zm(malign[i]); |
| } |
| for(i= 1;i<=16;i++) {regsize[i]=l2zm( 4L);regtype[i]=<yp;} |
| for(i=fp0;i<=fp7;i++) {regsize[i]=l2zm(12L);regtype[i]=&larray;} |
| for(i=25;i<=28;i++) {regsize[i]=l2zm( 8L);regtype[i]=&lltyp;} |
| |
| if(ELF){ |
| for(i=1;i<=MAXR;i++) |
| mregnames[i]=elfregnames[i]; |
| idprefix=""; |
| labprefix=".l"; |
| rprefix="%"; |
| }else{ |
| for(i=1;i<=MAXR;i++) |
| mregnames[i]=regnames[i]; |
| idprefix="_"; |
| labprefix="l"; |
| rprefix=""; |
| } |
| |
| if(SMALLDATA) use_sd=1; |
| |
| |
| /* default CPU is 68000 */ |
| if(!(g_flags[0]&USEDFLAG)) CPU=68000; |
| if(CPU==68040) static_cse=0; else static_cse=1; |
| if(CPU<68000) cf=1; |
| if(cf) MINADDI2P=INT; /* requires 32bit int! */ |
| /* no FPU by default */ |
| if(!(g_flags[1]&USEDFLAG)) FPU=0; |
| if(FPU<=68000) {x_t[FLOAT]='l';} |
| if(D2SCRATCH){regscratch[d2]=1;dscratch++;} |
| if(A2SCRATCH) {regscratch[a2]=1;ascratch++;} |
| if(FP2SCRATCH) {regscratch[fp2]=1;fscratch++;} |
| |
| if(NOA4) regsa[5]=1; |
| if(GAS){ |
| codename="\t.text\n"; |
| bssname=""; |
| dataname="\t.data\n"; |
| if(use_sd) regsa[5]=1; |
| }else{ |
| codename="\tsection\t\"CODE\",code\n"; |
| if(use_sd){ |
| /* preparing small data */ |
| regsa[5]=1; |
| bssname= "\tsection\t\"__MERGED\",bss\n"; |
| dataname="\tsection\t\"__MERGED\",data\n"; |
| }else{ |
| bssname= "\tsection\t\"BSS\",bss\n"; |
| dataname="\tsection\t\"DATA\",data\n"; |
| } |
| } |
| m_dataname=dataname; |
| m_bssname=bssname; |
| /* a5 can be used if no framepointer is used. */ |
| if(!USEFRAMEPOINTER){ regsa[fbp]=0;/*fbp=sp;*/} |
| if(DEBUG&1) printf("CPU=%ld FPU=%ld\n",CPU,FPU); |
| /* 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. */ |
| t_min[CHAR]=l2zm(-128L); |
| t_min[SHORT]=l2zm(-32768L); |
| t_min[LONG]=zmsub(l2zm(-2147483647L),l2zm(1L)); |
| #ifdef M68K_16BIT_INT |
| t_min[INT]=t_min(SHORT); |
| #else |
| t_min[INT]=t_min(LONG); |
| #endif |
| 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[LONG]=ul2zum(2147483647UL); |
| #ifdef M68K_16BIT_INT |
| t_max[INT]=t_max(SHORT); |
| #else |
| t_max[INT]=t_max(LONG); |
| #endif |
| 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[LONG]=ul2zum(4294967295UL); |
| #ifdef M68K_16BIT_INT |
| tu_max[INT]=t_max(UNSIGNED|SHORT); |
| #else |
| tu_max[INT]=t_max(UNSIGNED|LONG); |
| #endif |
| tu_max[LLONG]=zumkompl(ul2zum(0UL)); |
| tu_max[MAXINT]=t_max(UNSIGNED|LLONG); |
| |
| #ifdef M68K_16BIT_INT |
| stackalign=2; |
| #endif |
| |
| if(FLOAT64){ |
| sizetab[FLOAT]=sizetab[DOUBLE]; |
| align[FLOAT]=malign[DOUBLE]; |
| } |
| |
| marray[0]="__section(x)=__vattr(\"section(\"#x\")\")"; |
| marray[1]="__M68K__"; |
| |
| if(CPU>=68000&&CPU<69000) |
| sprintf(cpu_macro,"__M%ld=1",CPU); |
| else |
| sprintf(cpu_macro,"__COLDFIRE=1"); |
| marray[2]=cpu_macro; |
| |
| #ifdef M68K_16BIT_INT |
| marray[3]="__INTSIZE=16"; |
| #else |
| marray[3]="__INTSIZE=32"; |
| #endif |
| |
| marray[4]="__stdargs=__attr(\"__stdargs;\")"; |
| marray[5]="__regargs=__attr(\"__regargs;\")"; |
| marray[6]="__vbccargs=__attr(\"__vbccargs;\")"; |
| marray[7]="__fp0ret=__attr(\"__fp0ret;\")"; |
| if(SMALLDATA) |
| marray[8]="__SMALL_DATA__"; |
| else |
| marray[8]="__LARGE_DATA__"; |
| |
| if(FPU==68881){ |
| sprintf(fpu_macro,"__M68881=1"); |
| marray[9]=fpu_macro; |
| }else if(FPU>68000&&FPU<69000){ |
| sprintf(fpu_macro,"__M68882=1"); |
| marray[9]=fpu_macro; |
| }else |
| marray[9]=0; |
| marray[10]=0; |
| target_macros=marray; |
| |
| if(AMI_SOFTFLOAT&&!optsize){ |
| declare_builtin("_ieeeaddl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-66)); |
| declare_builtin("_ieeesubl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-72)); |
| declare_builtin("_ieeemull",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-78)); |
| declare_builtin("_ieeedivl",FLOAT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-84)); |
| declare_builtin("_ieeenegl",FLOAT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-60)); |
| declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-66)); |
| declare_builtin("_ieeesubd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-72)); |
| declare_builtin("_ieeemuld",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-78)); |
| declare_builtin("_ieeedivd",DOUBLE,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-84)); |
| declare_builtin("_ieeenegd",DOUBLE,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-60)); |
| declare_builtin("_ieees2d",DOUBLE,FLOAT,d0,0,0,1,ami_ieee("DoubTrans",-108)); |
| declare_builtin("_ieeed2s",FLOAT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubTrans",-102)); |
| declare_builtin("_ieeefltsl",FLOAT,LONG,d0,0,0,1,ami_ieee("SingBas",-36)); |
| declare_builtin("_ieeefltsd",DOUBLE,LONG,d0,0,0,1,ami_ieee("DoubBas",-36)); |
| declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,0,0,0,1,0); |
| declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,0,0,0,1,0); |
| declare_builtin("_ieeefixlsl",LONG,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30)); |
| declare_builtin("_ieeefixlsw",SHORT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30)); |
| declare_builtin("_ieeefixlsb",CHAR,FLOAT,d0,0,0,1,ami_ieee("SingBas",-30)); |
| declare_builtin("_ieeefixdsl",LONG,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30)); |
| declare_builtin("_ieeefixdsw",SHORT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30)); |
| declare_builtin("_ieeefixdsb",CHAR,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-30)); |
| declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,0,0,0,1,0); |
| declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,0,0,0,1,0); |
| declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,0,0,0,1,0); |
| declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,0,0,0,1,0); |
| declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,0,0,0,1,0); |
| declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,0,0,0,1,0); |
| declare_builtin("_ieeecmpl",INT,FLOAT,d0,FLOAT,d1,1,ami_ieee("SingBas",-42)); |
| declare_builtin("_ieeecmpd",INT,DOUBLE,d0d1,DOUBLE,d2d3,1,ami_ieee("DoubBas",-42)); |
| #if 0 |
| declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0); |
| #endif |
| declare_builtin("_ieeetstl",INT,FLOAT,d0,0,0,1,ami_ieee("SingBas",-48)); |
| declare_builtin("_ieeetstd",INT,DOUBLE,d0d1,0,0,1,ami_ieee("DoubBas",-48)); |
| declare_builtin("_flt32tosint64",LLONG,FLOAT,0,0,0,1,0); |
| declare_builtin("_flt64tosint64",LLONG,DOUBLE,0,0,0,1,0); |
| declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,0,0,0,1,0); |
| declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,0,0,0,1,0); |
| declare_builtin("_sint64toflt32",FLOAT,LLONG,0,0,0,1,0); |
| declare_builtin("_sint64toflt64",DOUBLE,LLONG,0,0,0,1,0); |
| declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,0,0,0,1,0); |
| declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,0,0,0,1,0); |
| }else{ |
| int pd0,pd1,pd0d1; |
| if(VBCCCALL){ |
| pd0=d0;pd1=d1;pd0d1=d0d1; |
| }else{ |
| pd0=pd1=pd0d1=0; |
| } |
| |
| declare_builtin("_ieeeaddl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0); |
| declare_builtin("_ieeesubl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0); |
| declare_builtin("_ieeemull",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0); |
| declare_builtin("_ieeedivl",FLOAT,FLOAT,pd0,FLOAT,pd1,1,0); |
| declare_builtin("_ieeenegl",FLOAT,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeeaddd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0); |
| declare_builtin("_ieeesubd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0); |
| declare_builtin("_ieeemuld",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0); |
| declare_builtin("_ieeedivd",DOUBLE,DOUBLE,pd0d1,DOUBLE,0,1,0); |
| declare_builtin("_ieeenegd",DOUBLE,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieees2d",DOUBLE,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeed2s",FLOAT,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeefltsl",FLOAT,LONG,pd0,0,0,1,0); |
| declare_builtin("_ieeefltsd",DOUBLE,LONG,pd0,0,0,1,0); |
| declare_builtin("_ieeefltul",FLOAT,UNSIGNED|LONG,pd0,0,0,1,0); |
| declare_builtin("_ieeefltud",DOUBLE,UNSIGNED|LONG,pd0,0,0,1,0); |
| declare_builtin("_ieeefixlsl",LONG,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeefixlsw",SHORT,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeefixlsb",CHAR,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeefixdsl",LONG,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeefixdsw",SHORT,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeefixdsb",CHAR,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeefixlul",UNSIGNED|LONG,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeefixluw",UNSIGNED|SHORT,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeefixlub",UNSIGNED|CHAR,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeefixdul",UNSIGNED|LONG,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeefixduw",UNSIGNED|SHORT,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeefixdub",UNSIGNED|CHAR,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_ieeecmpl",INT,FLOAT,pd0,FLOAT,pd1,1,0); |
| declare_builtin("_ieeecmpd",INT,DOUBLE,pd0d1,DOUBLE,0,1,0); |
| #if 0 |
| declare_builtin("_ieeecmpllt",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplle",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplgt",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplge",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmpleq",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmplneq",INT,FLOAT,0,FLOAT,0,1,0); |
| declare_builtin("_ieeecmpdlt",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdle",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdgt",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdge",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdeq",INT,DOUBLE,0,DOUBLE,0,1,0); |
| declare_builtin("_ieeecmpdneq",INT,DOUBLE,0,DOUBLE,0,1,0); |
| #endif |
| declare_builtin("_ieeetstl",INT,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_ieeetstd",INT,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_flt32tosint64",LLONG,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_flt64tosint64",LLONG,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_flt32touint64",UNSIGNED|LLONG,FLOAT,pd0,0,0,1,0); |
| declare_builtin("_flt64touint64",UNSIGNED|LLONG,DOUBLE,pd0d1,0,0,1,0); |
| declare_builtin("_sint64toflt32",FLOAT,LLONG,pd0d1,0,0,1,0); |
| declare_builtin("_sint64toflt64",DOUBLE,LLONG,pd0d1,0,0,1,0); |
| declare_builtin("_uint64toflt32",FLOAT,UNSIGNED|LLONG,pd0d1,0,0,1,0); |
| declare_builtin("_uint64toflt64",DOUBLE,UNSIGNED|LLONG,pd0d1,0,0,1,0); |
| } |
| { |
| char *asm; |
| declare_builtin("_divs",LONG,LONG,d0,LONG,d1,1,0); |
| declare_builtin("_divu",LONG,LONG,d0,LONG,d1,1,0); |
| #define SMODS "\tjsr\t__divs\n\tmove.l\td1,d0" |
| #define SMODU "\tjsr\t__divu\n\tmove.l\td1,d0" |
| asm=mymalloc(strlen(SMODS)+1); |
| strcpy(asm,SMODS); |
| declare_builtin("_mods",LONG,LONG,d0,LONG,d1,1,asm); |
| asm=mymalloc(strlen(SMODU)+1); |
| strcpy(asm,SMODU); |
| declare_builtin("_modu",LONG,LONG,d0,LONG,d1,1,asm); |
| } |
| declare_builtin("_lshint64",LLONG,LLONG,0,INT,0,1,0); |
| declare_builtin("_rshsint64",LLONG,LLONG,0,INT,0,1,0); |
| declare_builtin("_rshuint64",(UNSIGNED|LLONG),(UNSIGNED|LLONG),0,INT,0,1,0); |
| |
| return 1; |
| } |
| |
| int freturn(type *t) |
| /* Returns the register in which variables of type t are returned. */ |
| /* If the value cannot be returned in a register returns 0. */ |
| { |
| long l;int tu=t->flags&NQ; |
| if(t->attr&&ISFLOAT(tu)&&FPU>68000&&strstr(t->attr,"__fp0ret;")) return fp0; |
| if(tu==FLOAT&&FLOAT64) tu+=DOUBLE-FLOAT; |
| if(tu==FLOAT){ |
| if(FPU>68000&&!NOFPRETURN) |
| return fp0; |
| else |
| return d0; |
| } |
| if(tu==DOUBLE||tu==LDOUBLE){ |
| if(FPU>68000&&!NOFPRETURN){ |
| return fp0; |
| }else{ |
| if(NOMREGRETURN) return 0; |
| #if NEW_RET |
| return d0d1; |
| #else |
| return d0; |
| #endif |
| } |
| } |
| if(tu==STRUCT||tu==UNION){ |
| if(!NOMREGRETURN){ |
| l=zm2l(szof(t)); |
| #if NEW_RET |
| if(l==4) return d0; |
| if(l==8) return d0d1; |
| /* alte Variante; unschoen */ |
| if(l==12) return d0; |
| if(l==16) return d0; |
| #else |
| if(l==4||l==8||l==12||l==16) return d0; |
| #endif |
| } |
| return 0; |
| } |
| if(tu==LLONG) |
| return d0d1; |
| if(zmleq(szof(t),l2zm(4L))) return d0; else return 0; |
| } |
| int cost_savings(IC *p,int r,obj *o) |
| { |
| int c=p->code; |
| if((r==a6||r==d7||r==d6d7||r==fp7)&&!RESERVEREGS) return -1; |
| if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3; |
| if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3; |
| if(o->flags&VKONST){ |
| int t; |
| if(CPU==68040) return 0; |
| t=o->v->ctyp&NQ; |
| if(ISFLOAT(t)) return 2; |
| if(t==CHAR&&r>=a0&&r<=a7) return 0/*INT_MIN*/; |
| if(t==LLONG) return 0; |
| if(cf&&(t<INT)&&p->q2.flags) return 0/*INT_MIN*/; |
| eval_const(&o->v->cobj.val,t); |
| if(zmeqto(vmax,Z0)) return 0; |
| if(o->flags&DREFOBJ) return 2; |
| if((p->code==ASSIGN&&o==&p->q1)||p->code==PUSH||p->code==SETRETURN){ |
| if(p->code==PUSH||(p->z.flags&DREFOBJ)|| |
| ((p->z.flags&VAR)&&(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN))){ |
| if(r>=d0&&r<=d7) |
| return 2; |
| else |
| return 1; |
| } |
| return 0; |
| } |
| if(c==ADDI2P||c==SUBIFP){ |
| if(zmleq(vmax,l2zm(32767L))&&zmleq(l2zm(-32768L),vmax)) return 0; |
| if(r>=d0&&r<=d7) |
| return 3; |
| return CPU<68020?1:0; |
| } |
| if(c==ADD||c==SUB||c==ADDI2P||c==SUBIFP||c==SUBPFP){ |
| if(zmleq(vmax,l2zm(8L))&&zmleq(l2zm(-8L),vmax)) return 0; |
| if(p->flags&EFF_IC) return 0; |
| if(r>=d0&&r<=d7) |
| return 2; |
| else |
| return 1; |
| } |
| if(c==COMPARE){ |
| if(r>=d0&&r<=d7) |
| return 2; |
| else |
| return 1; |
| } |
| if(r>=a0&&r<=a7) return INT_MIN; |
| /* TODO: which allocations are useful? */ |
| return 0; |
| } |
| if(o->flags&DREFOBJ){ |
| if(r>=a0&&r<=a7){ |
| return 4; |
| } |
| } |
| if((c==ADDI2P||c==SUBIFP||c==ADDRESS)&&(o==&p->q1||o==&p->z)&&r>=a0&&r<=a7){ |
| return 4; |
| } |
| if(r>=a0&&r<=a7){ |
| if(o->flags&DREFOBJ) ierror(0); |
| if(c!=GETRETURN&&c!=SETRETURN&&c!=ASSIGN&&c!=PUSH&&c!=TEST&&c!=COMPARE&&c!=CONVERT){ |
| if(c==ADDI2P||c==SUBIFP){ |
| if(o==&p->q2) |
| return INT_MIN; |
| }else if(c==SUBPFP){ |
| if(o==&p->z) |
| return INT_MIN; |
| }else{ |
| return INT_MIN; |
| } |
| } |
| if(c==CONVERT&&((p->typf&NQ)==CHAR||(p->typf2&NQ)==CHAR||ISFLOAT(p->typf)||ISFLOAT(p->typf2))) |
| return INT_MIN; |
| } |
| |
| if(c==TEST&&r>=d0&&r<=d7){ |
| return 3; |
| } |
| if(o==&p->z&&(p->q1.flags&VKONST)){ |
| eval_const(&p->q1.v->cobj.val,p->q1.v->ctyp&NQ); |
| if(zmleq(vmax,l2zm(127L))&&zmleq(l2zm(-128L),vmax)&&r>=d0&&r<=d7) |
| return 3; |
| } |
| return 2; |
| } |
| |
| 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(r==0) return 0; |
| t&=NQ; |
| if(ISFLOAT(t)){ |
| if(FPU>68000){ |
| if(r>=fp0&&r<=fp7) return(1); else return 0; |
| }else{ |
| if(t==FLOAT&&!FLOAT64) |
| return (r>=d0&&r<=d7); |
| else |
| return (r>=25&&r<=28); |
| } |
| } |
| if(t==POINTER&&mode<=0&&r>=d0&&r<=d7) return 1; |
| if(t==POINTER&&r>=1&&r<=8) return 1; |
| if(t>=CHAR&&t<=LONG){ |
| if((r>=d0&&r<=d7)||(mode==-1&&t>=SHORT&&r>=1&&r<=8)) return 1; |
| } |
| if(t==LLONG&&r>=25&&r<=28) return 1; |
| return 0; |
| } |
| |
| int dangerous_IC(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; |
| } |
| |
| 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; |
| /* All pointers have the same representation. */ |
| if(tp==POINTER&&op==POINTER) return 0; |
| /* Pointer and int/long as well */ |
| if(const_expr){ |
| #ifdef M68K_16BIT_INT |
| if(tp==POINTER&&(op==LONG)) return 0; |
| if(op==POINTER&&(tp==LONG)) return 0; |
| #else |
| if(tp==POINTER&&(op==INT||op==LONG)) return 0; |
| if(op==POINTER&&(tp==INT||tp==LONG)) return 0; |
| #endif |
| } |
| /* Signed und Unsigned integers with the same size, too. */ |
| if(op==tp) return 0; |
| #ifdef M68K_16BIT_INT |
| /* int==short */ |
| if((tp==INT&&op==SHORT)||(tp==SHORT&&op==INT)) return 0; |
| #else |
| /* int==long */ |
| if((tp==INT&&op==LONG)||(tp==LONG&&op==INT)) return 0; |
| #endif |
| if(FLOAT64&&ISFLOAT(op)&&ISFLOAT(tp)) return 0; |
| /* long double==double */ |
| if((op==DOUBLE||op==LDOUBLE)&&(tp==DOUBLE||tp==LDOUBLE)) return 0; |
| return 1; |
| } |
| |
| void gen_ds(FILE *f,zmax size,type *t) |
| /* This function has to create <size> bytes of storage */ |
| /* initialized with zero. */ |
| { |
| title(f); |
| if(GAS){ |
| if(newobj&§ion!=SPECIAL) |
| emit(f,"%ld\n",zm2l(size)); |
| else |
| emit(f,"\t.space\t%ld\n",zm2l(size)); |
| newobj=0; |
| }else{ |
| /*if(section!=BSS&§ion!=SPECIAL&&newobj){emit(f,bssname);if(f) section=BSS;}*/ |
| emit(f,"\tds.b\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. */ |
| { |
| title(f); |
| if(zm2l(align)>1){ |
| if(GAS){ |
| emit(f,"\t.align\t4\n"); |
| }else{ |
| emit(f,"\tcnop\t0,4\n"); |
| } |
| } |
| } |
| void gen_var_head(FILE *f,Var *v) |
| /* This function has to create the head of a variable */ |
| /* definition, i.e. the label and information for */ |
| /* linkage etc. */ |
| { |
| int constflag; |
| title(f); |
| if(v->clist) constflag=is_const(v->vtyp); |
| if(v->tattr&(FAR|CHIP)){ |
| if(v->tattr&CHIP){ |
| dataname="\tsection\t\"CHIP_DATA\",data,chip\n"; |
| bssname="\tsection\t\"CHIP_BSS\",bss,chip\n"; |
| }else{ |
| dataname="\tsection\t\"DATA\",data\n"; |
| bssname="\tsection\t\"BSS\",bss\n"; |
| } |
| if(f) section=-1; |
| }else{ |
| dataname=m_dataname; |
| bssname=m_bssname; |
| } |
| if(v->storage_class==STATIC){ |
| if(ISFUNC(v->vtyp->flags)) return; |
| if(!special_section(f,v)){ |
| if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&§ion!=DATA){emit(f,dataname);if(f) section=DATA;} |
| if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&§ion!=CODE){emit(f,codename);if(f) section=CODE;} |
| if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;} |
| } |
| if(GAS){ |
| if(section!=BSS) emit(f,"\t.align\t4\n%s%ld:\n",labprefix,zm2l(v->offset)); |
| else emit(f,"\t.comm\t%s%ld,",labprefix,zm2l(v->offset)); |
| }else{ |
| emit(f,"\tcnop\t0,4\n%s%ld\n",labprefix,zm2l(v->offset)); |
| } |
| newobj=1; |
| } |
| if(v->storage_class==EXTERN){ |
| if(GAS){ |
| emit(f,"\t.global\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier); |
| }else{ |
| emit(f,"\tpublic\t%s%s\n",ISFUNC(v->vtyp->flags)?FUNCPREFIX(v->vtyp):idprefix,v->identifier); |
| } |
| if(v->flags&(DEFINED|TENTATIVE)){ |
| if(!special_section(f,v)){ |
| if(v->clist&&(!constflag||CONSTINDATA/*||use_sd*/)&§ion!=DATA){emit(f,dataname);if(f) section=DATA;} |
| if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&§ion!=CODE){emit(f,codename);if(f) section=CODE;} |
| if(!v->clist&§ion!=BSS){emit(f,bssname);if(f) section=BSS;} |
| } |
| if(GAS){ |
| if(section!=BSS) |
| emit(f,"\t.align\t4\n%s%s:\n",idprefix,v->identifier); |
| else |
| emit(f,"\t.global\t%s%s\n\t.%scomm\t%s%s,",idprefix,v->identifier,(USE_COMMONS?"":"l"),idprefix,v->identifier); |
| }else{ |
| emit(f,"\tcnop\t0,4\n%s%s\n",idprefix,v->identifier); |
| } |
| newobj=1; |
| } |
| } |
| if(v->tattr&(FAR|CHIP)) {if(f) section=-1;newobj=0;} |
| } |
| void gen_dc(FILE *f,int t,const_list *p) |
| /* This function has to create static storage */ |
| /* initialized with const-list p. */ |
| { |
| char s; |
| title(f); |
| if(!p) ierror(0); |
| /* if(section!=DATA){emit(f,dataname);if(f) section=DATA;}*/ |
| if(ISFLOAT(t)||(t&NQ)==LLONG) s='l'; else s=x_t[t&NQ]; |
| if(GAS){ |
| char *str; |
| if(s=='b') str="\t.byte\t"; |
| else if(s=='w') str="\t.short\t"; |
| else if(s=='l') str="\t.long\t"; |
| else ierror(0); |
| emit(f,"%s",str); |
| }else{ |
| emit(f,"\tdc.%c\t",s); |
| } |
| if(!p->tree){ |
| if(ISFLOAT(t)){ |
| /* auch wieder nicht sehr schoen und IEEE noetig */ |
| unsigned char *ip;char *s; |
| ip=(unsigned char *)&p->val.vdouble; |
| if(GAS) s="0x"; else s="$"; |
| emit(f,"%s%02x%02x%02x%02x",s,ip[0],ip[1],ip[2],ip[3]); |
| if((t&NQ)!=FLOAT){ |
| emit(f,",%s%02x%02x%02x%02x",s,ip[4],ip[5],ip[6],ip[7]); |
| } |
| }else if((t&NQ)==LLONG){ |
| zumax tmp; |
| eval_const(&p->val,t); |
| tmp=vumax; |
| vumax=zumand(zumrshift(vumax,ul2zum(32UL)),ul2zum(0xffffffff)); |
| gval.vulong=zum2zul(vumax); |
| emitval(f,&gval,UNSIGNED|LONG); |
| emit(f,","); |
| vumax=zumand(tmp,ul2zum(0xffffffff)); |
| gval.vulong=zum2zul(vumax); |
| emitval(f,&gval,UNSIGNED|LONG); |
| }else{ |
| emitval(f,&p->val,t&NU); |
| } |
| }else{ |
| int m,m2,m3; |
| p->tree->o.am=0; |
| m=p->tree->o.flags; |
| p->tree->o.flags&=~VARADR; |
| m2=g_flags[5]; |
| g_flags[5]&=~USEDFLAG; |
| m3=use_sd; |
| use_sd=0; |
| emit_obj(f,&p->tree->o,t&NU); |
| p->tree->o.flags=m; |
| g_flags[5]=m2; |
| use_sd=m3; |
| } |
| emit(f,"\n");newobj=0; |
| } |
| |
| static void allocreg(int r) |
| { |
| if(reg_pair(r,&rp)){ |
| regs[rp.r1]=1; |
| regs[rp.r2]=1; |
| } |
| regs[r]=1; |
| } |
| |
| static void freereg(int r) |
| { |
| if(reg_pair(r,&rp)){ |
| regs[rp.r1]=0; |
| regs[rp.r2]=0; |
| } |
| regs[r]=0; |
| } |
| |
| /* 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,IC *p,Var *v,zmax offset) |
| { |
| int c,t;char fp[2]="\0\0"; |
| int act_line=0;char *act_file=0; |
| int shiftisdiv; |
| if(DEBUG&1) printf("gen_code()\n"); |
| for(c=1;c<=MAXR;c++) regs[c]=regsa[c]; |
| if(!NOPEEPHOLE){ |
| /* Adressierungsarten benutzen */ |
| if(!addressing(p)) offset=l2zm(0L); |
| } |
| title(f); |
| if(debug_info){ |
| if(HUNKDEBUG){ |
| if(!GAS){ |
| act_line=1; |
| emit(f,"\tdsource\t\"%s\"\n",filename); |
| emit(f,"\tdebug\t%d\n",act_line); |
| } |
| } |
| } |
| reglabel=++label;freglabel=++label; |
| function_top(f,v,zm2l(offset)); |
| cc_set=cc_set_tst=0; |
| stackoffset=notpopped=dontpop=maxpushed=0; |
| for(c=1;c<=MAXR;c++){ |
| if(regsa[c]||regused[c]){ |
| BSET(regs_modified,c); |
| } |
| } |
| for(;p;pr(f,p),p=p->next){ |
| if(debug_info){ |
| if(HUNKDEBUG){ |
| if(p->file&&p->file!=act_file){ |
| act_file=p->file; |
| if(!GAS) emit(f,"\tdsource\t\"%s\"\n",act_file); |
| } |
| if(p->line&&p->line!=act_line){ |
| act_line=p->line; |
| if(!GAS) emit(f,"\tdebug\t%d\n",act_line); |
| } |
| }else{ |
| dwarf2_line_info(f,p); |
| } |
| } |
| |
| if(FLOAT64){ |
| if(p->code==CONVERT) |
| if((q1typ(p)&NQ)==FLOAT) p->typf2+=DOUBLE-FLOAT; |
| if((ztyp(p)&NQ)==FLOAT) p->typf+=DOUBLE-FLOAT; |
| } |
| |
| c=p->code;t=p->typf; |
| if(c==NOP) continue; |
| cc_set_tst=cc_set; |
| cc_typ_tst=cc_typ; |
| shiftisdiv=0; |
| if(cc_set_tst&&(DEBUG&512)){emit(f,"; cc_set_tst=");emit_obj(f,cc_set_tst,t);emit(f,"\n");} |
| if(cc_set&&(DEBUG&512)){emit(f,"; cc_set=");emit_obj(f,cc_set,t);emit(f,"\n");} |
| pushedreg&=16;if(c==RESTOREREGS) pushedreg=0; |
| if(DEBUG&256){emit(f,"; "); pric2(f,p);} |
| if(DEBUG&512) emit(f,"; stackoffset=%ld, notpopped=%ld, pushedreg=%d, dontpop=%ld\n",stackoffset,notpopped,pushedreg,dontpop); |
| /* muessen wir Argumente poppen? */ |
| if(notpopped&&!dontpop){ |
| int flag=0; |
| if(c==LABEL||c==COMPARE||c==TEST||c==BRA){ |
| emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]); |
| pop(notpopped);notpopped=0;/*cc_set_tst=cc_set=0;*/ |
| } |
| } |
| /* na, ob das hier ok ist..? */ |
| if(c==SUBPFP) c=SUB; |
| if(c==PMULT) c=MULT; |
| if(c==ALLOCREG){ |
| allocreg(p->q1.reg); |
| continue; |
| } |
| if(c==FREEREG){ |
| freereg(p->q1.reg); |
| continue; |
| } |
| if(c==LABEL){ |
| if(debug_info&&HUNKDEBUG) act_line=0; |
| if(GAS){ |
| emit(f,"%s%d:\n",labprefix,t); |
| }else{ |
| emit(f,"%s%d\n",labprefix,t); |
| } |
| cc_set=0;continue; |
| } |
| if(c==BRA){emit(f,"\t%sbra\t%s%d\n",(GAS?"j":""),labprefix,t);continue;} |
| if(c>=BEQ&&c<BRA){ |
| if(GAS){ |
| if(stored_cc){emit(f,"\tjne\t%s%d\n",labprefix,t);stored_cc=0;continue;} |
| if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){ |
| emit(f,"\tj%s\t%s%d\n",ubranch[c-BEQ],labprefix,t); |
| }else{ |
| emit(f,"\t%sj%s\t%s%d\n",fp,ename[c]+1,labprefix,t); |
| } |
| }else{ |
| if(stored_cc){emit(f,"\tbne\t%s%d\n",labprefix,t);stored_cc=0;continue;} |
| if((comptyp&UNSIGNED)||(comptyp&NQ)==POINTER){ |
| emit(f,"\tb%s\t%s%d\n",ubranch[c-BEQ],labprefix,t); |
| }else{ |
| emit(f,"\t%s%s\t%s%d\n",fp,ename[c],labprefix,t); |
| } |
| } |
| continue; |
| } |
| #if 0 |
| if(CPU>=68020&&(c==LSHIFT||c==MULT)&&(p->q2.flags&(KONST|DREFOBJ))==KONST&&isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&ISINT(p->typf)){ |
| int l=0; |
| eval_const(&p->q2.val,q2typ(p)); |
| if(c==LSHIFT&&zmeqto(vmax,l2zm(1L))) l=2; |
| if(c==LSHIFT&&zmeqto(vmax,l2zm(2L))) l=4; |
| if(c==LSHIFT&&zmeqto(vmax,l2zm(3L))) l=8; |
| if(c==MULT&&zmeqto(vmax,l2zm(2L))) l=2; |
| if(c==MULT&&zmeqto(vmax,l2zm(4L))) l=4; |
| if(c==MULT&&zmeqto(vmax,l2zm(8L))) l=8; |
| if(l!=0){ |
| IC *p2=p->next; |
| while(p2&&(p2->code==ALLOCREG||p2->code==FREEREG)) p2=p2->next; |
| if((p2->code==ADD||p2->code==ADDI2P)&&(p2->q2.flags&(REG|DREFOBJ))==REG&&p2->q2.reg==p->z.reg&&(p2->typf&NU)==(p->typf&NU)&&(p2->q1.flags&(REG|DREFOBJ))==REG&&p2->q1.reg>=a0&&p2->q1.reg<=a7&&(p2->z.flags&(REG|DREFOBJ))==REG&&p2->z.reg>=a0&&p2->z.reg<=a7){ |
| IC *p3=p2->next; |
| while(p3&&p3->code==FREEREG) if(p3&&p3->q1.reg==p->z.reg) break; |
| if(p3&&p3->code==FREEREG&&p3->q1.reg==p->z.reg){ |
| int r; |
| if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7) |
| r=p->q1.reg; |
| else{ |
| move(f,&p->q1,0,0,p->z.reg,p->typf); |
| r=p->z.reg; |
| } |
| emit(f,"\tlea\t(%s,%s.%c*%d),%s\n",mregnames[p2->q1.reg],mregnames[r],sizetab[p->typf&NQ]==2?'w':'l',l,mregnames[p2->z.reg]); |
| p->code=NOP; |
| p->q1.flags=p->q2.flags=p->z.flags=0; |
| p2->code=NOP; |
| p2->q1.flags=p2->q2.flags=p2->z.flags=0; |
| continue; |
| } |
| } |
| } |
| } |
| #endif |
| if(c==COMPARE&&isconst(q2)&&!cf&&(t&NQ)!=LLONG){ |
| case_table *ct=calc_case_table(p,JUMP_TABLE_DENSITY); |
| IC *p2; |
| if(ct&&(ct->num>=JUMP_TABLE_LENGTH||(!isreg(q1)&&ct->num>=JUMP_TABLE_LENGTH/2))){ |
| int r,defl,tabl=++label,rts=0,i,ar=0; |
| if(ct->next_ic->code==BRA) |
| defl=ct->next_ic->typf; |
| else |
| defl=++label; |
| for(r=d0;r<=d7;r++) |
| if(!regs[r]) break; |
| if(r>d7){ |
| if((!(p->q1.flags®))||p->q1.reg!=d0) |
| r=d0; |
| else |
| r=d1; |
| emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]); |
| emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[r],mregnames[sp]); |
| push(8); |
| }else{ |
| regused[r]=1; |
| BSET(regs_modified,r); |
| } |
| if(!regs[r]||(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){ |
| for(ar=1;ar<sp;ar++) |
| if(!regs[ar]) break; |
| if(ar>=sp){ |
| ar=a0; |
| if(!regs[r]){ |
| emit(f,"\tsubq.%s\t#4,%s\n",cf?"l":"w",mregnames[sp]); |
| push(4); |
| } |
| emit(f,"\tmove.l\t%s,-(%s)\n",mregnames[ar],mregnames[sp]); |
| push(4); |
| }else{ |
| regused[ar]=1; |
| BSET(regs_modified,ar); |
| } |
| } |
| if(regs[r]||(ar&®s[ar])) defl=++label; |
| if(!p->q1.am&&(p->q1.flags&(REG|DREFOBJ))==DREFOBJ){ |
| p->q1.flags&=~DREFOBJ; |
| move(f,&p->q1,0,0,ar,POINTER); |
| p->q1.flags|=(REG|DREFOBJ); |
| p->q1.flags&=~VAR; |
| p->q1.reg=ar; |
| } |
| if((t&NU)==(UNSIGNED|CHAR)) |
| emit(f,"\tmoveq\t#0,%s\n",mregnames[r]); |
| move(f,&p->q1,0,0,r,t); |
| if((t&NU)==CHAR){ |
| emit(f,"\text.w\t%s\n",mregnames[r]); |
| t=SHORT; |
| } |
| if((t&NU)==(UNSIGNED|CHAR)) |
| t=(UNSIGNED|SHORT); |
| if(((t&UNSIGNED)&&!zumeqto(ct->min.vumax,ul2zum(0UL)))|| |
| (!(t&UNSIGNED)&&!zmeqto(ct->min.vmax,l2zm(0L)))){ |
| emit(f,"\tsub.%c\t#",x_t[t&NQ]); |
| if(t&UNSIGNED) |
| emitzum(f,ct->min.vumax); |
| else |
| emitzm(f,ct->min.vmax); |
| emit(f,",%s\n",mregnames[r]); |
| } |
| emit(f,"\tcmp.%c\t#",x_t[t&NQ]); |
| emitzum(f,ct->diff); |
| emit(f,",%s\n",mregnames[r]); |
| if(regs[r]||regs[ar]) |
| emit(f,"\tbhi\t%s%d\n",labprefix,++label); |
| else |
| emit(f,"\tbhi\t%s%d\n",labprefix,defl); |
| if(CPU<68020) |
| emit(f,"\tlsl.%c\t#2,%s\n",x_t[t&NQ],mregnames[r]); |
| for(i=MAXR;i>=1;i--) |
| if(regs[i]&4) rts=1; |
| if(regs[r]||regs[ar]){ |
| int off; |
| if(regs[r]) off=4; else off=0; |
| if(ar&®s[ar]) off+=4; |
| if(CPU>=68020) |
| emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]); |
| else |
| emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%d(%s)\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],off,mregnames[sp]); |
| if(ar&®s[ar]){ |
| emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]); |
| pop(4); |
| } |
| if(regs[r]){ |
| emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]); |
| pop(4); |
| } |
| emit(f,"\trts\n"); |
| pop(4); |
| }else{ |
| if(CPU>=68020) |
| emit(f,"\tmove.l\t%s%d(%spc,%s.%c*4),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]); |
| else |
| emit(f,"\tmove.l\t%s%d(%spc,%s.%c),%s\n",labprefix,tabl,rprefix,mregnames[r],x_t[t&NQ],mregnames[ar]); |
| emit(f,"\tjmp\t(%s)\n",mregnames[ar]); |
| } |
| if(GAS){ |
| emit(f,"\t.align\t2\n"); |
| emit(f,"%s%d:\n",labprefix,tabl); |
| emit_jump_table(f,ct,"\t.long\t","l",defl); |
| }else{ |
| emit(f,"\tcnop\t0,4\n"); |
| emit(f,"%s%d\n",labprefix,tabl); |
| emit_jump_table(f,ct,"\tdc.l\t","l",defl); |
| } |
| if(ct->next_ic->code!=BRA||regs[r]||(ar&®s[ar])){ |
| if(regs[r]||(ar&®s[ar])){ |
| emit(f,"%s%d%s\n",labprefix,label,GAS?":":""); |
| if(ar&®s[ar]) |
| emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[ar]); |
| if(regs[r]) |
| emit(f,"\tmove.l\t(%s)+,%s\n",mregnames[sp],mregnames[r]); |
| emit(f,"\taddq.%c\t#4,%s\n",cf?'l':'w',mregnames[sp]); |
| } |
| emit(f,"%s%d%s\n",labprefix,defl,GAS?":":""); |
| p2=ct->next_ic->prev; |
| }else |
| p2=ct->next_ic; |
| if(p->prev) p=p->prev; |
| do{ |
| p=p->next; |
| if(p->code==ALLOCREG) |
| allocreg(p->q1.reg); |
| if(p->code==FREEREG) |
| freereg(p->q1.reg); |
| }while(p!=p2); |
| continue; |
| } |
| } |
| if(p->q1.am){ |
| if(!regs[p->q1.am->basereg]){ |
| pric2(stdout,p);printf("%s\n",mregnames[p->q1.am->basereg]); ierror(0); |
| } |
| if(p->q1.am->dreg&&!regs[p->q1.am->dreg&127]){ |
| printf("Register %s:\n",mregnames[p->q1.am->dreg&127]); |
| ierror(0); |
| } |
| } |
| if(p->q2.am){ |
| if(!regs[p->q2.am->basereg]) {pric2(stdout,p);ierror(0);} |
| if(p->q2.am->dreg&&!regs[p->q2.am->dreg&127]) {printf("Register %s:\n",mregnames[p->q2.am->dreg&127]);ierror(0);} |
| } |
| if(p->z.am){ |
| if(!regs[p->z.am->basereg]) {pric2(stdout,p);printf("am=%p b=%s,i=%s,o=%ld,s=%d\n",(void*)p->z.am,mregnames[p->z.am->basereg],mregnames[p->z.am->dreg&127],p->z.am->dist,p->z.am->skal);ierror(0);} |
| if(p->z.am->dreg&&!regs[p->z.am->dreg&127]) {printf("Register %s:\n",mregnames[p->z.am->dreg&127]);ierror(0);} |
| } |
| if((p->q1.flags®)&&!regs[p->q1.reg]&&p->code!=MOVEFROMREG&&(!reg_pair(p->q1.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){ |
| printf("Register %s:\n",mregnames[p->q1.reg]);pric2(stdout,p);terror("illegal use of register");} |
| if((p->q2.flags®)&&!regs[p->q2.reg]&&(!reg_pair(p->q2.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->q2.reg]);pric2(stdout,p);terror("illegal use of register");} |
| if((p->z.flags®)&&!regs[p->z.reg]&&p->code!=MOVETOREG&&(!reg_pair(p->z.reg,&rp)||!regs[rp.r1]||!regs[rp.r2])){printf("Register %s:\n",mregnames[p->z.reg]);if(reg_pair(p->z.reg,&rp)) printf("%s=%d %s=%d\n",regnames[rp.r1],regs[rp.r1],regnames[rp.r2],regs[rp.r2]);pric2(stdout,p);terror("illegal use of register");} |
| /* if((p->q2.flags®)&&(p->z.flags®)&&p->q2.reg==p->z.reg){pric2(stdout,p);ierror(0);}*/ |
| /*if((p->q2.flags&VAR)&&(p->z.flags&VAR)&&p->q2.v==p->z.v&&compare_objects(&p->q2,&p->z)){pric2(stdout,p);ierror(0);}*/ |
| /* COMPARE #0 durch TEST ersetzen (erlaubt, da tst alle Flags setzt) */ |
| if(c==COMPARE&&isconst(q2)){ |
| eval_const(&p->q2.val,t); |
| if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){ |
| c=p->code=TEST;p->q2.flags=0; |
| } |
| } |
| if(c==COMPARE&&isconst(q1)){ |
| eval_const(&p->q1.val,t); |
| if(zmeqto(l2zm(0L),vmax)&&zumeqto(ul2zum(0UL),vumax)&&zldeqto(d2zld(0.0),vldouble)){ |
| IC *bp=p->next;int bc; |
| c=p->code=TEST;p->q1=p->q2;p->q2.flags=0;p->q2.am=0; |
| /* Nachfolgenden Branch umdrehen */ |
| while(bp&&bp->code==FREEREG) bp=bp->next; |
| bc=bp->code; |
| if(!bp||bc<BEQ||bc>BGT) ierror(0); |
| if(bc==BLT) bp->code=BGT; |
| if(bc==BGT) bp->code=BLT; |
| if(bc==BLE) bp->code=BGE; |
| if(bc==BGE) bp->code=BLE; |
| } |
| } |
| /* gesetzte ConditionCodes merken */ |
| if(p->z.flags&&(!isreg(z)||p->z.reg>=d0)&&(c!=CONVERT||!ISFLOAT(p->typf2))&&((!ISFLOAT(t))||FPU>68000)){ |
| cc_set=&p->z;cc_typ=p->typf; |
| }else{ |
| cc_set=0; |
| } |
| if(c==LEA){ |
| if(!isreg(z)||p->z.reg>8) ierror(0); |
| emit(f,"\tlea\t");emit_obj(f,&p->q1,t); |
| emit(f,",%s\n",mregnames[p->z.reg]); |
| continue; |
| } |
| if(c==PEA){ |
| emit(f,"\tpea\t");emit_obj(f,&p->q1,t);emit(f,"\n"); |
| push(zm2l(p->q2.val.vmax)); |
| dontpop+=zm2l(p->q2.val.vmax); |
| continue; |
| } |
| if(c==MOVEFROMREG){ |
| if(p->q1.reg<fp0) |
| emit(f,"\tmove.l\t%s,",mregnames[p->q1.reg]); |
| else if(p->q1.reg<25) |
| emit(f,"\tfmove.x\t%s,",mregnames[p->q1.reg]); |
| else |
| emit(f,"\tmovem.l\t%s,",mregnames[p->q1.reg]); |
| emit_obj(f,&p->z,t);emit(f,"\n"); |
| continue; |
| } |
| if(c==MOVETOREG){ |
| if(p->z.reg<fp0) |
| emit(f,"\tmove.l\t"); |
| else if(p->z.reg<25) |
| emit(f,"\tfmove.x\t"); |
| else |
| emit(f,"\tmovem.l\t"); |
| emit_obj(f,&p->q1,t);emit(f,",%s\n",mregnames[p->z.reg]); |
| continue; |
| } |
| if(NOPEEPHOLE){ |
| if(p->q1.am||p->q2.am||p->z.am){ |
| ierror(0); |
| p->q1.am=p->q2.am=p->z.am=0; |
| } |
| } |
| p=do_refs(f,p); |
| if((p->q1.flags&&(q1typ(p)&NQ)==LLONG)||(p->q2.flags&&(q2typ(p)&NQ)==LLONG&&p->code!=LSHIFT&&p->code!=RSHIFT)||(p->z.flags&&(ztyp(p)&NQ)==LLONG)){ |
| if(handle_llong(f,p)){ |
| *fp=0; |
| continue; |
| } |
| } |
| if(NOPEEPHOLE){ |
| if(p->q1.am||p->q2.am||p->z.am){ |
| ierror(0); |
| p->q1.am=p->q2.am=p->z.am=0; |
| } |
| } |
| #ifdef M68K_16BIT_INT |
| if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==POINTER)){ |
| p->code=c=ASSIGN; |
| p->q2.val.vmax=sizetab[LONG]; |
| } |
| #else |
| if(c==CONVERT&&((t&NQ)==LONG||(t&NQ)==INT||(t&NQ)==POINTER)&&((p->typf2&NQ)==LONG||(p->typf2&NQ)==INT||(p->typf2&NQ)==POINTER)){ |
| p->code=c=ASSIGN; |
| p->q2.val.vmax=sizetab[LONG]; |
| } |
| #endif |
| if(c==CONVERT){ |
| int to; |
| if((t&NQ)==POINTER) t=(UNSIGNED|LONG); |
| if((t&NQ)==LDOUBLE) t=DOUBLE; |
| to=p->typf2&NU; |
| if(to==POINTER) to=UNSIGNED|LONG; |
| if(to==LDOUBLE) to=DOUBLE; |
| #ifdef M68K_16BIT_INT |
| if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT)||to==(UNSIGNED|INT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ)) |
| cc_set=0; |
| #else |
| if((to==(UNSIGNED|CHAR)||to==(UNSIGNED|SHORT))&&!(t&UNSIGNED)&&(t&NQ)>(to&NQ)) |
| cc_set=0; |
| #endif |
| if(ISFLOAT(t)||ISFLOAT(to)){ |
| if(FPU>68000){ |
| int zreg=0,freg=0; |
| if(ISFLOAT(t)&&ISFLOAT(to)){ |
| if(isreg(q1)&&isreg(z)){ |
| if(p->q1.reg!=p->z.reg) |
| emit(f,"\tfmove.x\t%s,%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]); |
| continue; |
| } |
| } |
| if(isreg(z)&&p->z.reg>=fp0) |
| zreg=p->z.reg; |
| if(isreg(q1)&&p->q1.reg>=fp0){ |
| if(!zreg&&(t&UNSIGNED)&&!ISHWORD(t)) |
| zreg=p->q1.reg; |
| else |
| zreg=freg=get_reg(f,2,p,1);} |
| if(!zreg) zreg=freg=get_reg(f,2,p,0); |
| if((to&UNSIGNED)&&x_t[to&NQ]!='l'){ |
| int dreg=get_reg(f,1,p,0); |
| emit(f,"\tmoveq\t#0,%s\n",mregnames[dreg]); |
| move(f,&p->q1,0,0,dreg,to); |
| move(f,0,dreg,0,zreg,LONG); |
| }else{ |
| if(!isreg(q1)||p->q1.reg!=zreg) |
| move(f,&p->q1,0,0,zreg,to); |
| } |
| if(!ISFLOAT(t)){ |
| if((t&UNSIGNED)&&!ISHWORD(t)){ |
| char *s; |
| int dreg1,dreg2; |
| int l1=++label,l2=++label; |
| if(GAS) s="0x"; else s="$"; |
| if(isreg(z)) |
| dreg1=p->z.reg; |
| else |
| dreg1=get_reg(f,1,p,0); |
| if(FPU==68040) |
| dreg2=get_reg(f,1,p,0); |
| if(!freg){ |
| if(!(isreg(q1)&&p->next&&p->next->code==FREEREG&&p->next->q1.reg==zreg)){ |
| freg=get_reg(f,2,p,1); |
| emit(f,"\tfmove.x\t%s,%s\n",mregnames[zreg],mregnames[freg]); |
| zreg=freg; |
| } |
| } |
| emit(f,"\tfcmp.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]); |
| emit(f,"\tfbge\t%s%d\n",labprefix,l1); |
| if(FPU==68040){ |
| emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]); |
| emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]); |
| emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]); |
| emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]); |
| emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix); |
| }else{ |
| emit(f,"\tfintrz\t%s\n",mregnames[zreg]); |
| } |
| emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]); |
| emit(f,"\tbra\t%s%d\n",labprefix,l2); |
| emit(f,"%s%d:\n",labprefix,l1); |
| emit(f,"\tfsub.d\t#%s41e0000000000000,%s\n",s,mregnames[zreg]); |
| if(FPU==68040){ |
| emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]); |
| emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]); |
| emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]); |
| emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]); |
| emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix); |
| }else{ |
| emit(f,"\tfintrz\t%s\n",mregnames[zreg]); |
| } |
| emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]); |
| emit(f,"\tbchg\t#31,%s\n",mregnames[dreg1]); |
| emit(f,"%s%d:\n",labprefix,l2); |
| if(FPU==68040) |
| emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix); |
| move(f,0,dreg1,&p->z,0,t); |
| continue; |
| } |
| /* nach integer, d.h. Kommastellen abschneiden */ |
| if(FPU==68040/*||FPU==68060*/){ |
| /* bei 040 emuliert */ |
| int dreg1,dreg2; |
| if(!NOINTZ){ |
| if(isreg(z)) |
| dreg1=p->z.reg; |
| else |
| dreg1=get_reg(f,1,p,0); |
| dreg2=get_reg(f,1,p,0); |
| emit(f,"\tfmove.l\t%sfpcr,%s\n",rprefix,mregnames[dreg2]); |
| emit(f,"\tmoveq\t#16,%s\n",mregnames[dreg1]); |
| emit(f,"\tor.l\t%s,%s\n",mregnames[dreg2],mregnames[dreg1]); |
| emit(f,"\tand.w\t#-33,%s\n",mregnames[dreg1]); |
| emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg1],rprefix); |
| }else{ |
| dreg1=get_reg(f,1,p,0); |
| } |
| if((t&UNSIGNED)&&ISHWORD(t)){ |
| emit(f,"\tfmove.l\t%s,%s\n",mregnames[zreg],mregnames[dreg1]); |
| emit(f,"\tmove.%c\t%s,",x_t[t&NQ],mregnames[dreg1]); |
| }else{ |
| emit(f,"\tfmove.%c\t%s,",x_t[t&NQ],mregnames[zreg]); |
| } |
| emit_obj(f,&p->z,t);emit(f,"\n"); |
| if(!NOINTZ) |
| emit(f,"\tfmove.l\t%s,%sfpcr\n",mregnames[dreg2],rprefix); |
| continue; |
| }else{ |
| if(!NOINTZ){ |
| if(!isreg(q1)||p->q1.reg!=zreg){ |
| emit(f,"\tfintrz.x\t%s\n",mregnames[zreg]); |
| }else{ |
| int nreg=get_reg(f,2,p,1); |
| emit(f,"\tfintrz.x\t%s,%s\n",mregnames[zreg],mregnames[nreg]); |
| zreg=nreg; |
| } |
| } |
| if((t&UNSIGNED)&&ISHWORD(t)){ |
| int r; |
| if(isreg(z)) r=p->z.reg; else r=get_reg(f,1,p,0); |
| move(f,0,zreg,0,r,LONG); |
| move(f,0,r,&p->z,0,t); |
| }else{ |
| move(f,0,zreg,&p->z,0,t); |
| } |
| continue; |
| } |
| } |
| if((to&UNSIGNED)&&x_t[to&NQ]=='l'){ |
| int nlabel; |
| emit(f,"\ttst.%c\t",x_t[to&NQ]); |
| emit_obj(f,&p->q1,to);emit(f,"\n"); |
| nlabel=++label; |
| emit(f,"\tbge.s\t%s%d\n",labprefix,nlabel); |
| emit(f,"\tfadd.d\t#4294967296,%s\n",mregnames[zreg]); |
| emit(f,"%s%d:\n",labprefix,nlabel); |
| } |
| if(!(p->z.reg)||p->z.reg!=zreg){ |
| move(f,0,zreg,&p->z,0,t); |
| } |
| }else{ |
| cc_set=0; |
| if((to&NQ)==(t&NQ)){ |
| assign(f,p,&p->q1,&p->z,ASSIGN,sizetab[to&NQ],t); |
| continue; |
| } |
| if((to&NQ)==FLOAT&&((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)){ |
| if(!OLD_SOFTFLOAT) |
| ierror(0); |
| saveregs(f,p); |
| assign(f,p,&p->q1,0,PUSH,msizetab[FLOAT],FLOAT); |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieees2d\n\tjbsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieees2d\n\tjsr\t__ieees2d\n\taddq.%s\t#4,%s\n",strshort[1],mregnames[sp]); |
| } |
| pop(4); |
| restoreregsa(f,p); |
| stored0d1(f,&p->z,t); |
| restoreregsd(f,p); |
| continue; |
| } |
| if(((to&NQ)==DOUBLE||(to&NQ)==LDOUBLE)&&(t&NQ)==FLOAT){ |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| assign(f,p,&p->q1,0,PUSH,msizetab[DOUBLE],DOUBLE); |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieeed2s\n\tjbsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieeed2s\n\tjsr\t__ieeed2s\n\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]); |
| } |
| pop(8); |
| restoreregsa(f,p); |
| move(f,0,d0,&p->z,0,t); |
| restoreregsd(f,p); |
| continue; |
| } |
| if(ISFLOAT(to)){ |
| int uns; |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| if(t&UNSIGNED) uns='u'; else uns='s'; |
| assign(f,p,&p->q1,0,PUSH,sizetab[to&NQ],to); |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieeefix%c%c\n\tjbsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieeefix%c%c\n\tjsr\t__ieeefix%c%c\n\taddq.%s\t#%ld,%s\n",x_t[to&NQ],uns,x_t[to&NQ],uns,strshort[1],zm2l(sizetab[to&NQ]),mregnames[sp]); |
| } |
| pop(sizetab[to&NQ]); |
| restoreregsa(f,p); |
| move(f,0,d0,&p->z,0,t); |
| restoreregsd(f,p); |
| continue; |
| }else{ |
| int uns,xt=x_t[to&NQ]; |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| if(to&UNSIGNED) uns='u'; else uns='s'; |
| if(xt!='l'){ |
| emit(f,"\tsubq.%s\t#4,%s\n",strshort[1],mregnames[sp]); |
| push(4); |
| } |
| emit(f,"\tmove.%c\t",xt); |
| emit_obj(f,&p->q1,to); |
| if(xt!='l') |
| emit(f,",(%s)\n",mregnames[sp]); |
| else{ |
| emit(f,",-(%s)\n",mregnames[sp]); |
| push(4); |
| } |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieeeflt%c%c%c\n\tjbsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieeeflt%c%c%c\n\tjsr\t__ieeeflt%c%c%c\n\taddq.%s\t#4,%s\n",uns,xt,x_t[t&NQ],uns,xt,x_t[t&NQ],strshort[1],mregnames[sp]); |
| } |
| pop(4); |
| restoreregsa(f,p); |
| if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE) |
| stored0d1(f,&p->z,t); |
| else |
| move(f,0,d0,&p->z,0,t); |
| restoreregsd(f,p); |
| continue; |
| } |
| } |
| continue; |
| } |
| if((to&NQ)<(t&NQ)){ |
| int zreg; |
| if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7){ |
| zreg=p->z.reg; |
| }else{ |
| zreg=get_reg(f,1,p,0); |
| } |
| if(sizetab[t&NQ]!=sizetab[LONG]||sizetab[to&NQ]!=sizetab[LONG]){ |
| /* aufpassen, falls unsigned und Quelle==Ziel */ |
| if((to&UNSIGNED)&&isreg(q1)&&zreg==p->q1.reg){ |
| unsigned long l; |
| if((to&NQ)==CHAR) l=0xff; else l=0xffff; |
| emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]); |
| continue; |
| } |
| if((to&UNSIGNED)&&p->q1.am&&(zreg==p->q1.am->basereg||zreg==(p->q1.am->dreg&127))){ |
| /* aufpassen, falls unsigned und Ziel im am */ |
| unsigned long l; |
| if((to&NQ)==CHAR) l=0xff; else l=0xffff; |
| move(f,&p->q1,0,0,zreg,to); |
| emit(f,"\tand.%c\t#%lu,%s\n",cf?'l':x_t[t&NQ],l,mregnames[zreg]); |
| }else{ |
| if(to&UNSIGNED) |
| emit(f,"\tmoveq\t#0,%s\n",mregnames[zreg]); |
| move(f,&p->q1,0,0,zreg,to); |
| } |
| if(!(to&UNSIGNED)){ |
| #ifdef M68K_16BIT_INT |
| if((to&NQ)==CHAR&&((t&NQ)==SHORT||(t&NQ)==INT)) emit(f,"\text.w\t%s\n",mregnames[zreg]); |
| if(((to&NQ)==SHORT||(to&NQ)==INT)&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]); |
| #else |
| if((to&NQ)==CHAR&&(t&NQ)==SHORT) emit(f,"\text.w\t%s\n",mregnames[zreg]); |
| if((to&NQ)==SHORT&&msizetab[t&NQ]==4) emit(f,"\text.l\t%s\n",mregnames[zreg]); |
| #endif |
| if((to&NQ)==CHAR&&msizetab[t&NQ]==4){ |
| if(cf||CPU>=68020) |
| emit(f,"\textb.l\t%s\n",mregnames[zreg]); |
| else |
| emit(f,"\text.w\t%s\n\text.l\t%s\n",mregnames[zreg],mregnames[zreg]); |
| } |
| } |
| } |
| if(!isreg(z)||p->z.reg!=zreg){ |
| move(f,0,zreg,&p->z,0,t); |
| } |
| }else{ |
| long diff;int m; |
| m=0; |
| if(p->q1.flags®){ |
| p->q1.val.vmax=l2zm(0L); |
| p->q1.flags|=D16OFF;m=1; |
| } |
| diff=msizetab[to&NQ]-msizetab[t&NQ]; |
| vmax=l2zm(diff); |
| p->q1.val.vmax=zmadd(p->q1.val.vmax,vmax); |
| move(f,&p->q1,0,&p->z,0,t); |
| vmax=l2zm(diff); |
| p->q1.val.vmax=zmsub(p->q1.val.vmax,vmax); |
| if(m) p->q1.flags&=~D16OFF; |
| if(compare_objects(&p->q1,&p->z)) |
| cc_set=0; |
| } |
| continue; |
| } |
| if(ISFLOAT(t)&&FPU>68000) *fp='f'; else *fp=0; |
| if(c==MINUS||c==KOMPLEMENT){ |
| int zreg; |
| if(ISFLOAT(t)){ |
| if(FPU>68000){ |
| if(isreg(z)) zreg=p->z.reg; else zreg=get_reg(f,2,p,1); |
| emit(f,"\tfneg."); |
| if(isreg(q1)) emit(f,"x\t%s",mregnames[p->q1.reg]); |
| else {emit(f,"%c\t",x_t[t&NQ]);emit_obj(f,&p->q1,t);} |
| emit(f,",%s\n",mregnames[zreg]); |
| if(!isreg(z)||p->z.reg!=zreg){ |
| move(f,0,zreg,&p->z,0,t); |
| } |
| continue; |
| }else{ |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t); |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieeeneg%c\n\tjbsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieeeneg%c\n\tjsr\t__ieeeneg%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]); |
| } |
| pop(msizetab[t&NQ]); |
| restoreregsa(f,p); |
| if((t&NQ)!=FLOAT) |
| stored0d1(f,&p->z,t); |
| else |
| move(f,0,d0,&p->z,0,t); |
| restoreregsd(f,p); |
| continue; |
| } |
| } |
| if(!cf&&compare_objects(&p->q1,&p->z)){ |
| emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]); |
| emit_obj(f,&p->q1,t);emit(f,"\n"); |
| continue; |
| } |
| if(isreg(z)&&p->z.reg>=d0/*&&p->z.reg<=d7*/) |
| zreg=p->z.reg; else zreg=get_reg(f,1,p,1); |
| if(!isreg(q1)||p->q1.reg!=zreg){ |
| move(f,&p->q1,0,0,zreg,t); |
| } |
| emit(f,"\t%s.%c\t%s\n",ename[c],x_t[t&NQ],mregnames[zreg]); |
| if(!isreg(z)||p->z.reg!=zreg){ |
| move(f,0,zreg,&p->z,0,t); |
| } |
| continue; |
| } |
| if(c==SETRETURN){ |
| /* Returnwert setzen - q2.val.vmax==size, z.reg==Returnregister */ |
| if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&p->z.reg==d0){ |
| BSET(regs_modified,d0);BSET(regs_modified,10); |
| if(isconst(q1)){ |
| unsigned char *ip=(unsigned char *)&p->q1.val.vdouble; |
| char *s; |
| if(GAS) s="0x"; else s="$"; |
| emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[0],ip[1],ip[2],ip[3],mregnames[d0]); |
| emit(f,"\tmove.l\t#%s%02x%02x%02x%02x,%s\n",s,ip[4],ip[5],ip[6],ip[7],mregnames[d1]); |
| continue; |
| } |
| if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){ |
| emit(f,"\tfmove.d\t%s,-(%s)\n\tmovem.l\t(%s)+,%s\n",mregnames[p->q1.reg],mregnames[sp],mregnames[sp],mregnames[d0d1]); |
| }else{ |
| loadd0d1(f,&p->q1,t); |
| } |
| continue; |
| } |
| if((ISSTRUCT(t)||ISUNION(t))&&p->z.reg==d0){ |
| long l=zm2l(p->q2.val.vmax); |
| emit(f,"\tmovem.l\t");emit_obj(f,&p->q1,t); |
| emit(f,",%s",mregnames[d0]);BSET(regs_modified,d0); |
| if(l>=8) {emit(f,"/%s",mregnames[d1]);BSET(regs_modified,d1);} |
| if(l>=12) {emit(f,"/%s",mregnames[a0]);BSET(regs_modified,a0);} |
| if(l>=16) {emit(f,"/%s",mregnames[a1]);BSET(regs_modified,a1);} |
| emit(f,"\n"); |
| continue; |
| } |
| /* Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig */ |
| if(p->z.reg){ |
| move(f,&p->q1,0,0,p->z.reg,p->typf); |
| BSET(regs_modified,p->z.reg); |
| if(v->tattr&AMIINTERRUPT){ |
| /* if necessary, set condition-codes */ |
| if(p->z.reg!=d0) ierror(0); |
| if(isreg(q1)&&p->q1.reg==d0) |
| emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[d0]); |
| } |
| } |
| continue; |
| } |
| if(c==GETRETURN){ |
| /* Returnwert holen - q2.val.vmax==size, q1.reg==Returnregister */ |
| if(((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE)&&(p->q1.reg==d0||p->q1.reg==d0d1)){ |
| if(isreg(z)&&p->z.reg>=fp0&&p->z.reg<=fp7){ |
| emit(f,"\tmovem.l\t%s,-(%s)\n\tfmove.d\t(%s)+,%s\n",mregnames[d0d1],mregnames[sp],mregnames[sp],mregnames[p->z.reg]); |
| }else{ |
| stored0d1(f,&p->z,t); |
| } |
| continue; |
| } |
| if((ISSTRUCT(t)||ISUNION(t))&&p->q1.reg==d0){ |
| long l=zm2l(p->q2.val.vmax); |
| emit(f,"\tmovem.l\t"); |
| emit(f,"%s",mregnames[d0]); |
| if(l>=8) emit(f,"/%s",mregnames[d1]); |
| if(l>=12) emit(f,"/%s",mregnames[a0]); |
| if(l>=16) emit(f,"/%s",mregnames[a1]); |
| emit(f,",");emit_obj(f,&p->z,t);emit(f,"\n"); |
| continue; |
| } |
| |
| /* Wenn Returnwert ueber Zeiger gesetzt wird, nichts noetig */ |
| cc_set=0; |
| if(p->q1.reg){ |
| move(f,0,p->q1.reg,&p->z,0,p->typf); |
| if(!(p->z.flags®)||(p->z.reg!=p->q1.reg&&p->z.reg>=d0)){ cc_set=&p->z;cc_typ=p->typf;} |
| } |
| continue; |
| } |
| if(c==CALL){ |
| if((p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp("__va_start",p->q1.v->identifier)){ |
| int sr=(USEFRAMEPOINTER||vlas)?fbp:sp; |
| long va_off=0; |
| if(USEFRAMEPOINTER||vlas){ |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[fbp],mregnames[d0]); |
| emit(f,"\tadd.l\t#%ld,%s\n",(long)(8+zm2l(va_offset(v)))+(PROFILER?16:0),mregnames[d0]); |
| }else{ |
| emit(f,"\tmove.l\t%s,%s\n",mregnames[sp],mregnames[d0]); |
| emit(f,"\tadd.l\t#%s%d+%ld,%s\n",labprefix,offlabel,(long)(4+zm2l(va_offset(v)))+loff+(PROFILER?16:0),mregnames[d0]); |
| } |
| BSET(regs_modified,d0); |
| 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); |
| if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)) |
| callee_push(zum2ul(p->q1.v->fi->stack1)); |
| else |
| stack_valid=0; |
| }else{ |
| if((p->q1.flags&(REG|DREFOBJ))==DREFOBJ){ |
| if(1/*CPU<68020*/){ |
| emit(f,"\tpea\t%s%d(pc)\n",labprefix,++label); |
| emit(f,"\tmove.l\t"); |
| }else |
| emit(f,"\t%s\t([",GAS?"jbsr":"jsr"); |
| p->q1.flags&=~DREFOBJ; |
| emit_obj(f,&p->q1,POINTER); |
| p->q1.flags|=DREFOBJ; |
| if(1/*CPU<68020*/){ |
| emit(f,",-(%s)\n",mregnames[sp]); |
| emit(f,"\trts\n"); |
| emit(f,"%s%d%s\n",labprefix,label,GAS?":":""); |
| }else |
| emit(f,"])\n"); |
| }else{ |
| if(GAS){ |
| emit(f,"\tjbsr\t"); |
| }else{ |
| emit(f,"\tjsr\t"); |
| } |
| /* Wenn geta4() aufgerufen wurde, merken. */ |
| if(use_sd&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&!strcmp(p->q1.v->identifier,"geta4")&&p->q1.v->storage_class==EXTERN) |
| geta4=1; |
| if((p->q1.flags&(DREFOBJ|REG|KONST))==DREFOBJ) ierror(0); |
| emit_obj(f,&p->q1,t); |
| emit(f,"\n"); |
| } |
| push(4); |
| if(stack_valid&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_STACK)) |
| callee_push(zum2ul(p->q1.v->fi->stack1)); |
| else |
| stack_valid=0; |
| pop(4); |
| } |
| if(debug_info&&HUNKDEBUG) act_line=0; |
| if(!zmeqto(p->q2.val.vmax,l2zm(0L))){ |
| notpopped+=zm2l(p->q2.val.vmax); |
| dontpop-=zm2l(p->q2.val.vmax); |
| if(!NODELAYEDPOP&&!(pushedreg&30)&&!vlas&&stackoffset==-notpopped){ |
| /* Entfernen der Parameter verzoegern */ |
| }else{ |
| if(debug_info&&HUNKDEBUG&&!GAS){ act_line=p->line; emit(f,"\tdebug\t%d\n",act_line);} |
| emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[zm2l(p->q2.val.vmax)<=8],strshort[zm2l(p->q2.val.vmax)<32768],zm2l(p->q2.val.vmax),mregnames[sp]); |
| pop(zm2l(p->q2.val.vmax)); |
| notpopped-=zm2l(p->q2.val.vmax); |
| } |
| } |
| if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){ |
| bvunite(regs_modified,p->q1.v->fi->regs_modified,RSIZE); |
| }else{ |
| int i; |
| for(i=1;i<=MAXR;i++){ |
| if(regscratch[i]) |
| if(i<fp0||i>fp7||FPU>68000) |
| BSET(regs_modified,i); |
| } |
| } |
| continue; |
| } |
| if(c==TEST){ |
| /* ConditionCodes schon gesetzt? */ |
| cc_set=&p->q1;cc_typ=t; |
| comptyp=t; |
| if(cc_set_tst&&t==cc_typ_tst){ |
| IC *branch; |
| if(t&UNSIGNED){ |
| branch=p->next; |
| while(branch&&(branch->code<BEQ||branch->code>BGT)) |
| branch=branch->next; |
| if(!branch) continue; |
| if(branch->code==BLE) branch->code=BEQ; |
| if(branch->code==BGT) branch->code=BNE; |
| if(branch->code==BGE) {branch->code=BRA;continue;} |
| if(branch->code==BLT) {branch->code=NOP;continue;} |
| } |
| if(compare_objects(&p->q1,cc_set_tst)&&p->q1.am==cc_set_tst->am&&zmeqto(p->q1.val.vmax,cc_set_tst->val.vmax)){ |
| if(DEBUG&512){emit(f,"; tst eliminated: cc=");emit_obj(f,cc_set_tst,t); |
| emit(f,", q1=");emit_obj(f,&p->q1,t);emit(f,"\n");} |
| continue; |
| } |
| } |
| if(CPU<68020&&isreg(q1)&&p->q1.reg>=1&&p->q1.reg<=8){ |
| /* tst ax gibt es nicht bei <68000 :-( */ |
| if(regavailable(1)){ |
| emit(f,"\tmove.%c\t%s,%s\n",x_t[t&NQ],mregnames[p->q1.reg],mregnames[get_reg(f,1,p,0)]); |
| }else{ |
| emit(f,"\tcmp.%c\t#0,%s\n",cf?'l':'w',mregnames[p->q1.reg]); |
| } |
| continue; |
| } |
| if(ISFLOAT(t)&&FPU<=68000){ |
| /* nicht sehr schoen */ |
| int result=get_reg(f,1,p,0); |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t); |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieeetst%c\n\tjbsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieeetst%c\n\tjsr\t__ieeetst%c\n\taddq.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],msizetab[t&NQ],mregnames[sp]); |
| } |
| pop(msizetab[t&NQ]); |
| restoreregsa(f,p); |
| if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]); |
| emit(f,"\ttst.l\t%s\n",mregnames[result]); |
| restoreregsd(f,p); |
| continue; |
| } |
| if(isreg(q1)&&p->q1.reg>=fp0&&p->q1.reg<=fp7){ |
| emit(f,"\tftst.x\t%s\n",mregnames[p->q1.reg]); |
| }else if(p->q1.flags&(VARADR|KONST)){ |
| int r=get_reg(f,1,p,0); |
| emit(f,"\tmove.%c\t",x_t[t&NQ]); |
| emit_obj(f,&p->q1,t); |
| emit(f,",%s\n",mregnames[r]); |
| }else{ |
| emit(f,"\t%stst.%c\t",fp,x_t[t&NQ]);emit_obj(f,&p->q1,t); |
| emit(f,"\n"); |
| } |
| continue; |
| } |
| if(c==ASSIGN||c==PUSH){ |
| if(c==ASSIGN&&compare_objects(&p->q1,&p->z)) cc_set=0; |
| if(c==PUSH) dontpop+=zm2l(p->q2.val.vmax); |
| assign(f,p,&p->q1,&p->z,c,zm2l(p->q2.val.vmax),t); |
| continue; |
| } |
| if(c==ADDRESS){ |
| int zreg; |
| if(isreg(z)&&p->z.reg>=1&&p->z.reg<=8) |
| zreg=p->z.reg; else zreg=get_reg(f,0,p,0); |
| emit(f,"\tlea\t");emit_obj(f,&p->q1,t); |
| emit(f,",%s\n",mregnames[zreg]); |
| if(!isreg(z)||p->z.reg!=zreg){ |
| move(f,0,zreg,&p->z,0,POINTER); |
| } |
| continue; |
| } |
| if(c==COMPARE){ |
| int zreg; |
| comptyp=t; |
| if(isconst(q1)||isreg(q2)){ |
| /* evtl. Argumente von cmp und nachfolgendes bcc umdrehen */ |
| IC *n;obj m; |
| n=p->next; |
| while(n){ |
| if(n->code>=BEQ&&n->code<BRA){ |
| if(!p->z.flags){ |
| if(DEBUG&1) printf("arguments of cmp exchanged\n"); |
| m=p->q1;p->q1=p->q2;p->q2=m; |
| p->z.flags=1; |
| } |
| /* nachfolgenden Branch umdrehen */ |
| switch(n->code){ |
| case BGT: n->code=BLT;break; |
| case BLT: n->code=BGT;break; |
| case BGE: n->code=BLE;break; |
| case BLE: n->code=BGE;break; |
| } |
| break; |
| } |
| if(n->code==FREEREG) n=n->next; else break; /* compare ohne branch => leerer Block o.ae. */ |
| } |
| } |
| if(ISFLOAT(t)){ |
| if(FPU>68000){ |
| if(isreg(q1)&&p->q1.reg>=fp0){ |
| zreg=p->q1.reg; |
| }else{ |
| zreg=get_reg(f,2,p,0); |
| move(f,&p->q1,0,0,zreg,t); |
| } |
| if(isreg(q2)){emit(f,"\tfcmp.x\t%s,%s\n",mregnames[p->q2.reg],mregnames[zreg]);continue;} |
| emit(f,"\tfcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t); |
| emit(f,",%s\n",mregnames[zreg]); |
| continue; |
| }else{ |
| /* nicht sehr schoen */ |
| int result=get_reg(f,1,p,0); |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t); |
| assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t); |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieeecmp%c\n\tjbsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieeecmp%c\n\tjsr\t__ieeecmp%c\n\tadd.%s\t#%ld,%s\n",x_t[t&NQ],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]); |
| } |
| pop(2*msizetab[t&NQ]); |
| restoreregsa(f,p); |
| if(result!=d0) emit(f,"\tmove.l\t%s,%s\n",mregnames[d0],mregnames[result]); |
| emit(f,"\ttst.l\t%s\n",mregnames[result]); |
| restoreregsd(f,p); |
| continue; |
| } |
| } |
| if(cf&&x_t[t&NQ]!='l'){ |
| if(isreg(q1)) zreg=p->q1.reg; else zreg=get_reg(f,1,p,0); |
| loadext(f,zreg,&p->q1,t); |
| if(isconst(q2)){ |
| emit(f,"\tcmp.l\t"); |
| emit_obj(f,&p->q2,t); |
| }else{ |
| int r; |
| if(isreg(q2)) r=p->q2.reg; else r=get_reg(f,1,p,0); |
| loadext(f,r,&p->q2,t); |
| emit(f,"\tcmp.l\t%s",mregnames[r]); |
| } |
| emit(f,",%s\n",mregnames[zreg]); |
| continue; |
| } |
| if((p->q2.flags&(KONST|VARADR))&&!(p->q1.flags&(KONST|VARADR))&&(!cf||isreg(q1))){ |
| emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t); |
| emit(f,",");emit_obj(f,&p->q1,t);emit(f,"\n"); |
| continue; |
| } |
| if(isreg(q1)){ |
| zreg=p->q1.reg; |
| }else{ |
| zreg=get_reg(f,1,p,1); /* hier evtl. auch Adressregister nehmen */ |
| move(f,&p->q1,0,0,zreg,t); |
| } |
| emit(f,"\tcmp.%c\t",x_t[t&NQ]);emit_obj(f,&p->q2,t); |
| emit(f,",%s\n",mregnames[zreg]); |
| continue; |
| } |
| if(c==ADDI2P||c==SUBIFP){ |
| int zreg=-1,r; |
| |
| /* hier die zweite Alternative mit isreg() schreiben? */ |
| if((((p->q2.flags®)&&(p->z.flags®)&&p->q2.reg==p->z.reg&&(!(p->q1.flags®)||p->q1.reg!=p->z.reg))|| |
| (compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q1,&p->z)))){ |
| obj m; |
| if(c==ADDI2P&&x_t[t&NQ]=='l'){ |
| m=p->q1;p->q1=p->q2;p->q2=m; |
| }else{ |
| if(!cf&&x_t[t&NQ]=='l'&&isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){ |
| m=p->q1;p->q1=p->q2;p->q2=m; |
| c=ADDI2P; |
| emit(f,"\tneg.%c\t",x_t[t&NQ]); |
| emit_obj(f,&p->q1,t);emit(f,"\n"); |
| }else{ |
| zreg=get_reg(f,0,p,0); |
| } |
| } |
| } |
| |
| if(isreg(q1)&&p->q1.reg<=8&&isreg(z)&&p->z.reg<=8&&p->q1.reg!=p->z.reg){ |
| /* q1 und z Adressregister => lea nehmen */ |
| if(isconst(q2)){ |
| eval_const(&p->q2.val,t); |
| if(c==SUBIFP) vmax=zmsub(l2zm(0L),vmax); |
| if(CPU>=68020||(zmleq(vmax,l2zm(32767))&&zmleq(l2zm(-32768),vmax))){ |
| emit(f,"\tlea\t(%ld",zm2l(vmax)); |
| if(!GAS&&zm2l(vmax)>0x7fff) |
| emit(f,".l"); |
| emit(f,",%s),%s\n",mregnames[p->q1.reg],mregnames[p->z.reg]); |
| continue; |
| } |
| }else if(c==ADDI2P&&isreg(q2)){ |
| emit(f,"\tlea\t(%s,%s.%c),%s\n",mregnames[p->q1.reg],mregnames[p->q2.reg],x_t[t&NQ],mregnames[p->z.reg]); |
| continue; |
| } |
| } |
| if(compare_objects(&p->q1,&p->z)){ |
| if(isconst(q2)&&(!cf||isquickkonst2(&p->q2.val,t))){ |
| if(c==ADDI2P) |
| emit(f,"\tadd%s.l\t",quick[isquickkonst2(&p->q2.val,t)]); |
| else |
| emit(f,"\tsub%s.l\t",quick[isquickkonst2(&p->q2.val,t)]); |
| emit_obj(f,&p->q2,t);emit(f,","); |
| emit_obj(f,&p->z,POINTER);emit(f,"\n"); |
| continue; |
| } |
| if(isreg(q1)&&(x_t[t&NQ]=='l'||p->q1.reg<=8)){ |
| if(c==ADDI2P) |
| emit(f,"\tadd.%c\t",x_t[t&NQ]); |
| else |
| emit(f,"\tsub.%c\t",x_t[t&NQ]); |
| emit_obj(f,&p->q2,t);emit(f,",%s\n",mregnames[p->z.reg]); |
| continue; |
| } |
| if(isreg(q2)&&p->q2.reg>=9&&p->q2.reg<=16){ |
| r=p->q2.reg; |
| }else{ |
| r=get_reg(f,1,p,0); |
| move(f,&p->q2,0,0,r,t); |
| } |
| if(x_t[t&NQ]!='l'&&(!isreg(z)||p->z.reg<1||p->z.reg>8)){ |
| /* wenn Ziel kein Adressregister, muss short erst auf long */ |
| /* char darf hier nicht auftreteten und long passt schon */ |
| if(t&UNSIGNED){ |
| if(CPU>=68040) |
| emit(f,"\tand.l\t#65535,%s\n",mregnames[r]); |
| else |
| emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[r],mregnames[r],mregnames[r]); |
| }else |
| emit(f,"\text.l\t%s\n",mregnames[r]); |
| t=POINTER; |
| } |
| /* if(c==ADDI2P) |
| emit(f,"\tadd.%c\t%s,",x_t[t&NQ],mregnames[r]); |
| else |
| emit(f,"\tsub.%c\t%s,",x_t[t&NQ],mregnames[r]); |
| emit_obj(f,&p->z,t);emit(f,"\n");*/ |
| if(c==ADDI2P) |
| add(f,0,r,&p->z,0,t); |
| else |
| sub(f,0,r,&p->z,0,t); |
| continue; |
| } |
| if(isreg(z)&&zreg==-1&&p->z.reg>=1&&p->z.reg<=d7) |
| zreg=p->z.reg; |
| else |
| zreg=get_reg(f,0,p,0); |
| /* Spezialfall, falls Ziel Datenregister und short */ |
| /* nicht schoen, aber auf die Schnelle... */ |
| if(x_t[t&NQ]!='l'&&zreg>8){ |
| move(f,&p->q2,0,0,zreg,t); |
| if(t&UNSIGNED){ |
| if(CPU>=68040) |
| emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]); |
| else |
| emit(f,"\tswap\t%s\n\tclr.w\t%s\n\tswap\t%s\n",mregnames[zreg],mregnames[zreg],mregnames[zreg]); |
| }else |
| emit(f,"\text.l\t%s\n",mregnames[zreg]); |
| if(c==SUBIFP) emit(f,"\tneg.l\t%s\n",mregnames[zreg]); |
| add(f,&p->q1,0,0,zreg,POINTER); |
| if(!isreg(z)||p->z.reg!=zreg) |
| move(f,0,zreg,&p->z,0,POINTER); |
| continue; |
| } |
| if(!isreg(q1)||p->q1.reg!=zreg){ |
| move(f,&p->q1,0,0,zreg,POINTER); |
| } |
| if(c==ADDI2P) |
| add(f,&p->q2,0,0,zreg,t); |
| else |
| sub(f,&p->q2,0,0,zreg,t); |
| if(!isreg(z)||p->z.reg!=zreg){ |
| move(f,0,zreg,&p->z,0,POINTER); |
| } |
| continue; |
| } |
| if((c>=OR&&c<=AND)||c==MULT||c==ADD){ |
| if(!isreg(q1)&&!isreg(z)&&isreg(q2)){ |
| obj o; |
| o=p->q1;p->q1=p->q2;p->q2=o; |
| } |
| } |
| switch_IC(p); |
| if((c>=OR&&c<=AND)||(c>=LSHIFT&&c<=MOD)){ |
| int zreg,q1reg,q2reg; |
| if(isconst(q2)&& |
| (!(p->q1.flags®)||!(p->z.flags®)||p->q1.reg!=p->z.reg)&& |
| (!(p->q1.flags&VAR)||!(p->z.flags&VAR)||p->q1.v!=p->z.v)&& |
| ((c>=OR&&c<=AND)||c==ADD||c==MULT)){ |
| obj o; |
| if(c==MULT){ |
| eval_const(&p->q2.val,t); |
| if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)&&!pof2(vumax)){ |
| o=p->q1;p->q1=p->q2;p->q2=o; |
| } |
| }else{ |
| if(!cf||!ISHWORD(t)){ |
| o=p->q1;p->q1=p->q2;p->q2=o; |
| } |
| } |
| } |
| if(ISFLOAT(t)){ |
| if(FPU>68000){ |
| if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){ |
| obj m; |
| if(c==ADD||c==MULT){ |
| m=p->q1;p->q1=p->q2;p->q2=m; |
| }else{ |
| if(isreg(q2)){ |
| if(c==SUB){ |
| emit(f,"\tfneg.x\t%s\n",mregnames[p->q2.reg]); |
| m=p->q1;p->q1=p->q2;p->q2=m; |
| p->code=c=ADD; |
| }else{ |
| int tmp=get_reg(f,2,p,0); |
| move(f,&p->q2,0,0,tmp,t); |
| p->q2.reg=tmp; |
| p->q2.flags=REG; |
| } |
| } |
| } |
| } |
| if(isreg(z)&&p->z.reg>=fp0) |
| zreg=p->z.reg; |
| else |
| zreg=get_reg(f,2,p,1); |
| if(!isreg(q1)||p->q1.reg!=p->z.reg) |
| move(f,&p->q1,0,0,zreg,t); |
| emit(f,"\tf%s.",ename[c]); |
| if(isreg(q2)) |
| emit(f,"x\t"); |
| else |
| emit(f,"%c\t",x_t[t&NQ]); |
| emit_obj(f,&p->q2,t); |
| emit(f,",%s\n",mregnames[zreg]); |
| if(!isreg(z)||p->z.reg!=zreg){ |
| move(f,0,zreg,&p->z,0,t); |
| } |
| continue; |
| }else{ |
| if(!OLD_SOFTFLOAT) ierror(0); |
| saveregs(f,p); |
| assign(f,p,&p->q2,0,PUSH,msizetab[t&NQ],t); |
| assign(f,p,&p->q1,0,PUSH,msizetab[t&NQ],t); |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__ieee%s%c\n\tjbsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]); |
| }else{ |
| emit(f,"\tpublic\t__ieee%s%c\n\tjsr\t__ieee%s%c\n\tadd.%s\t#%ld,%s\n",ename[c],x_t[t&NQ],ename[c],x_t[t&NQ],strshort[1],2*msizetab[t&NQ],mregnames[sp]); |
| } |
| pop(2*msizetab[t&NQ]); |
| restoreregsa(f,p); |
| if((t&NQ)==DOUBLE||(t&NQ)==LDOUBLE) |
| stored0d1(f,&p->z,t); |
| else |
| move(f,0,d0,&p->z,0,t); |
| restoreregsd(f,p); |
| continue; |
| } |
| } |
| if(((c==MULT||c==DIV)||(c==MOD&&(p->typf&UNSIGNED)))&&isconst(q2)){ |
| /* ersetzt mul etc. mit Zweierpotenzen */ |
| /* hier evtl. noch Fehler */ |
| long ln; |
| eval_const(&p->q2.val,t); |
| if(zmleq(l2zm(0L),vmax)&&zumleq(ul2zum(0UL),vumax)){ |
| if(ln=pof2(vumax)){ |
| if(c==MOD){ |
| vmax=zmsub(vmax,l2zm(1L)); |
| p->code=AND; |
| }else{ |
| vmax=l2zm(ln-1); |
| if(c==DIV){ |
| p->code=RSHIFT; |
| shiftisdiv=1; |
| }else |
| p->code=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,INT); |
| p->typf2=INT; |
| } |
| } |
| } |
| } |
| if(c==DIV||c==MOD){ |
| if(x_t[t&NQ]=='l'&&CPU<68020){ |
| /* das hier ist auch nicht allzu schoen */ |
| char *fname; |
| cc_set=0; /* Library-Funktionen setzen cc nicht immer */ |
| saveregs(f,p); |
| emit(f,"\tmove.l\t"); emit_obj(f,&p->q2,t); |
| emit(f,",-(%s)\n",mregnames[sp]); |
| push(4); |
| emit(f,"\tmove.l\t"); emit_obj(f,&p->q1,t); |
| emit(f,",-(%s)\n",mregnames[sp]); |
| push(4); |
| if(t&UNSIGNED) fname="divu"; else fname="divs"; |
| scratch_modified(); |
| if(GAS){ |
| emit(f,"\t.global\t__l%s\n\tjbsr\t__l%s\n",fname,fname); |
| }else{ |
| emit(f,"\tpublic\t__l%s\n\tjsr\t__l%s\n",fname,fname); |
| } |
| emit(f,"\taddq.%s\t#8,%s\n",strshort[1],mregnames[sp]); |
| if(c==MOD) emit(f,"\tmove.l\td1,d0\n"); |
| pop(8); |
| restoreregsa(f,p); |
| move(f,0,d0,&p->z,0,t); |
| restoreregsd(f,p); |
| continue; |
| } |
| |
| } |
| /* hier die zweite Alternative mit isreg() schreiben? */ |
| if(compare_objects(&p->q2,&p->z)&&!compare_objects(&p->q2,&p->q1)){ |
| obj m; |
| if((c>=OR&&c<=AND)||c==ADD||c==SUB){ |
| if(c!=SUB){ |
| m=p->q1;p->q1=p->q2;p->q2=m; |
| }else{ |
| if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){ |
| m=p->q1;p->q1=p->q2;p->q2=m; |
| c=ADD; |
| emit(f,"\tneg.%c\t",x_t[t&NQ]); |
| emit_obj(f,&p->q1,t);emit(f,"\n"); |
| } |
| } |
| } |
| } |
| if(compare_objects(&p->q1,&p->z)){ |
| if((c>=OR&&c<=AND)||c==ADD||c==SUB){ |
| int r; |
| if(isconst(q2)&&(!cf||isreg(z)||((c==ADD||c==SUB)&&isquickkonst2(&p->q2.val,t&NQ)))){ |
| if(cf&&((t&NQ)==CHAR||ISHWORD(t))){ |
| if(isreg(q1)) r=p->q1.reg; else r=get_reg(f,1,p,1); |
| loadext(f,r,&p->q1,t); |
| emit(f,"\t%s.l\t",ename[c]); |
| emit_obj(f,&p->q2,t); |
| emit(f,",%s\n",mregnames[r]); |
| move(f,0,r,&p->z,0,t); |
| continue; |
| }else{ |
| if(c==ADD) {add(f,&p->q2,0,&p->z,0,t);continue;} |
| if(c==SUB) {sub(f,&p->q2,0,&p->z,0,t);continue;} |
| emit(f,"\t%s.%c\t",ename[c],x_t[t&NQ]); |
| emit_obj(f,&p->q2,t);emit(f,","); |
| emit_obj(f,&p->z,t);emit(f,"\n"); |
| } |
| continue; |
| } |
| if(!isreg(z)&&(!cf||x_t[t&NQ]=='l')){ |
| if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7) |
| r=p->q2.reg; else r=get_reg(f,1,p,0); |
| if(!isreg(q2)||p->q2.reg!=r){ |
| move(f,&p->q2,0,0,r,t); |
| } |
| emit(f,"\t%s.%c\t%s,",ename[c],x_t[t&NQ],mregnames[r]); |
| emit_obj(f,&p->z,t);emit(f,"\n"); |
| continue; |
| } |
| } |
| } |
| /* bei xor oder asl (ausser 0<=const<=8) muss q2 in Register */ |
| if(isreg(q2)&&p->q2.reg>=d0&&p->q2.reg<=d7){ |
| q2reg=p->q2.reg; |
| }else{ |
| if(c==LSHIFT||c==RSHIFT||c==XOR){ |
| int t2=q2typ(p)&NU; |
| eval_const(&p->q2.val,t2); |
| if(c==XOR||!isconst(q2)||!isquickkonst2(&p->q2.val,t2)){ |
| if((c==LSHIFT||c==RSHIFT)&&(p->typf2&NQ)==LLONG){ |
| if(!isreg(q2)){ |
| q2reg=get_reg(f,1,p,0); |
| emit(f,"\tmove.l\t"); |
| emit_lword(f,&p->q2); |
| emit(f,",%s\n",mregnames[q2reg]); |
| }else{ |
| if(!reg_pair(p->q2.reg,&rp)) ierror(0); |
| q2reg=rp.r2; |
| } |
| }else{ |
| q2reg=get_reg(f,1,p,0); |
| move(f,&p->q2,0,0,q2reg,t2); |
| } |
| }else q2reg=0; |
| }else{ |
| q2reg=0; |
| } |
| } |
| if(c==MOD&&!ISHWORD(t)){ |
| int modreg; |
| if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&p->z.reg!=q2reg) |
| zreg=p->z.reg; else zreg=get_reg(f,1,p,0); |
| modreg=get_reg(f,1,p,1); |
| if(modreg==zreg) modreg=get_reg(f,1,p,0); |
| move(f,&p->q1,0,0,modreg,t); |
| if(0 /*CPU==68060*/){ |
| /* div?l.l wird da emuliert? */ |
| emit(f,"\tsmi\t%s\n\textb.l\t%s\n",mregnames[zreg],mregnames[zreg]); |
| if(t&UNSIGNED) emit(f,"\tdivu.%c\t",x_t[t&NQ]); else emit(f,"\tdivs.%c\t",x_t[t&NQ]); |
| }else{ |
| if(t&UNSIGNED) emit(f,"\tdivul.%c\t",x_t[t&NQ]); else emit(f,"\tdivsl.%c\t",x_t[t&NQ]); |
| } |
| emit_obj(f,&p->q2,t); |
| emit(f,",%s:%s\n",mregnames[zreg],mregnames[modreg]); |
| move(f,0,zreg,&p->z,0,t); |
| cc_set=0; |
| continue; |
| } |
| if(isreg(z)&&p->z.reg>=d0&&p->z.reg<=d7&&(p->z.reg!=q2reg||(isreg(q1)&&p->q1.reg==q2reg))) |
| zreg=p->z.reg; else zreg=get_reg(f,1,p,1); |
| if(isreg(q1)&&p->q1.reg>=d0&&p->q1.reg<=d7) |
| q1reg=p->q1.reg; else q1reg=0; |
| if(q1reg!=zreg){ |
| move(f,&p->q1,0,0,zreg,t); |
| } |
| if(c!=MULT&&c!=DIV&&c!=MOD&&c!=ADD&&c!=SUB){ |
| if(cf&&c==RSHIFT){ |
| if(cf&&(t&NU)==CHAR) |
| emit(f,"\textb.l\t%s\n",mregnames[zreg]); |
| else if(cf&&(t&NU)==SHORT) |
| emit(f,"\text.w\t%s\n",mregnames[zreg]); |
| if(cf&&(t&NU)==(UNSIGNED|CHAR)) |
| emit(f,"\tand.l\t#255,%s\n",mregnames[zreg]); |
| else if(cf&&(t&NU)==(UNSIGNED|SHORT)) |
| emit(f,"\tand.l\t#65535,%s\n",mregnames[zreg]); |
| } |
| if(shiftisdiv&&!(t&UNSIGNED)){ |
| unsigned long l; |
| eval_const(&p->q2.val,p->typf2); |
| l=(1<<zum2ul(vumax))-1; |
| if(isreg(q1)&&p->q1.reg==zreg) |
| emit(f,"\ttst.%c\t%s\n",x_t[t&NQ],mregnames[zreg]); |
| emit(f,"\tbge\t%s%d\n",labprefix,++label); |
| emit(f,"\tadd%s.%c\t#%ld,%s\n",(l<=7?"q":""),x_t[t&NQ],l,mregnames[zreg]); |
| emit(f,"%s%d:\n",labprefix,label); |
| } |
| if(c==RSHIFT&&!(t&UNSIGNED)) |
| emit(f,"\tasr.%c\t",cf?'l':x_t[t&NQ]); |
| else |
| emit(f,"\t%s.%c\t",ename[c],cf?'l':x_t[t&NQ]); |
| if(q2reg) |
| emit(f,"%s",mregnames[q2reg]); |
| else |
| emit_obj(f,&p->q2,q2typ(p)); |
| emit(f,",%s\n",mregnames[zreg]); |
| }else{ |
| if(c==ADD) add(f,&p->q2,q2reg,0,zreg,t); |
| if(c==SUB) sub(f,&p->q2,q2reg,0,zreg,t); |
| if(c==MULT||c==DIV||c==MOD) mult(f,&p->q2,q2reg,0,zreg,t,c,p); |
| } |
| if((!isreg(z)||p->z.reg!=zreg)){ |
| move(f,0,zreg,&p->z,0,t); |
| } |
| continue; |
| } |
| ierror(0); |
| } |
| if(notpopped){ |
| emit(f,"\tadd%s.%s\t#%ld,%s\n",quick[notpopped<=8],strshort[notpopped<32768],notpopped,mregnames[sp]); |
| pop(notpopped);notpopped=0; |
| } |
| function_bottom(f,v,zm2l(offset)); |
| if(debug_info&&!HUNKDEBUG){ |
| emit(f,"%s%d:\n",labprefix,++label); |
| dwarf2_function(f,v,label); |
| if(f) section=-1; |
| } |
| pushflag=0; |
| } |
| |
| /*FIXME*/ |
| int shortcut(int code,int typ) |
| { |
| if(!cf&&(code==COMPARE||code==ADD||code==SUB||code==AND||code==OR||code==XOR||code==LSHIFT||code==RSHIFT)) return(1); |
| if(!cf&&code==MULT&&(typ&NQ)!=CHAR) return 1; |
| |
| return 0; |
| } |
| void init_db(FILE *f) |
| { |
| if(!HUNKDEBUG){ |
| if(GAS) |
| dwarf2_setup(sizetab[POINTER],".byte",".2byte",".4byte",".4byte","l","_",".section"); |
| else |
| dwarf2_setup(sizetab[POINTER],"dc.b","dc.w","dc.l","dc.l","l","_","section"); |
| dwarf2_print_comp_unit_header(f); |
| } |
| } |
| void cleanup_db(FILE *f) |
| { |
| if(!HUNKDEBUG&&f){ |
| dwarf2_cleanup(f); |
| if(f) section=-1; |
| } |
| } |
| void cleanup_cg(FILE *f) |
| { |
| title(f); |
| if(f&&stack_check){ |
| if(GAS) |
| emit(f,"\t.global\t___stack_check\n"); |
| else |
| emit(f,"\tpublic\t___stack_check\n"); |
| } |
| /*printf("pushed %d, saved %d, removed allocreg %d\n",missing,savedemit,savedalloc);*/ |
| return; |
| } |
| |
| /* mark instructions which can (probably) be implemented with faster |
| machine-code than the IC migh suggest, e.g. an addition which can |
| be merged with a load bz use of target addressing-modes; |
| the optimizer should hesitate to modifz such instructions if it's not |
| a definite win */ |
| |
| static int is_single_eff_ic(IC *p) |
| { |
| Var *v; |
| if(p->code!=ADDI2P&&p->code!=SUBIFP) |
| return 0; |
| if(!isconst(q2)){ |
| if(CONSERVATIVE_SR){ |
| if((p->q2.flags&(VAR|DREFOBJ))!=VAR) |
| return 0; |
| if(p->q2.v->storage_class==STATIC||p->q2.v->storage_class==EXTERN) |
| return 0; |
| }else |
| return 0; |
| } |
| if((p->q1.flags&(VAR|DREFOBJ))!=VAR) |
| return 0; |
| if(p->q1.v->storage_class==STATIC||p->q1.v->storage_class==EXTERN) |
| return 0; |
| if((p->z.flags&(VAR|DREFOBJ))!=VAR) |
| return 0; |
| if(p->z.v->storage_class==STATIC||p->z.v->storage_class==EXTERN) |
| return 0; |
| v=p->z.v; |
| for(p=p->next;p;p=p->next){ |
| int c=p->code; |
| if(c==LABEL||(c>=BEQ&&c<=BRA)) |
| return 0; |
| if((p->q1.flags&VAR)&&p->q1.v==v){ |
| if(p->q1.flags&DREFOBJ) |
| return 1; |
| else |
| return 0; |
| } |
| if((p->q2.flags&VAR)&&p->q2.v==v){ |
| if(p->q2.flags&DREFOBJ) |
| return 1; |
| else |
| return 0; |
| } |
| if((p->z.flags&VAR)&&p->z.v==v){ |
| if(p->z.flags&DREFOBJ) |
| return 1; |
| else |
| return 0; |
| } |
| } |
| } |
| void mark_eff_ics(void) |
| { |
| IC *p; |
| for(p=first_ic;p;p=p->next){ |
| if(is_single_eff_ic(p)) |
| p->flags|=EFF_IC; |
| else |
| p->flags&=~EFF_IC; |
| } |
| } |
| |
| int reg_pair(int r,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<=fp7) return 0; |
| if(p){ |
| switch(r){ |
| case d0d1: p->r1=d0;p->r2=d1;break; |
| case d2d3: p->r1=d2;p->r2=d3;break; |
| case d4d5: p->r1=d4;p->r2=d5;break; |
| case d6d7: p->r1=d6;p->r2=d7;break; |
| default: ierror(0); |
| } |
| } |
| return 1; |
| } |
| |
| int emit_peephole(void) |
| { |
| int entries,i,r1,r2,r3,r4; |
| char *asmline[EMIT_BUF_DEPTH],c1,c2,c3,c4,e; |
| |
| if(OLDPEEPHOLE) return 0; |
| i=emit_l; |
| if(emit_f==0) |
| entries=i-emit_f+1; |
| else |
| entries=EMIT_BUF_DEPTH; |
| asmline[0]=emit_buffer[i]; |
| if(entries>=2){ |
| i--; |
| if(i<0) i=EMIT_BUF_DEPTH-1; |
| asmline[1]=emit_buffer[i]; |
| if(sscanf(asmline[1],"\tmove.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&& |
| sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&& |
| c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){ |
| sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1); |
| remove_asm(); |
| savedemit++; |
| return 1; |
| } |
| if(sscanf(asmline[1],"\tmovem.l\t(a7)+,%c%d\n%c",&c1,&r1,&e)==2&& |
| sscanf(asmline[0],"\tmove.l\t%c%d,-(a7%c",&c2,&r2,&e)==3&& |
| c1==c2&&r1==r2&&(c1=='a'||c1=='d')&&r1>=0&&r1<=7&&e==')'){ |
| sprintf(asmline[1],"\tmove.l\t(a7),%c%d\n",c1,r1); |
| remove_asm(); |
| savedemit++; |
| return 1; |
| } |
| |
| if(sscanf(asmline[1],"\tmove.l\t%c%d,%c%d\n%c",&c1,&r1,&c2,&r2,&e)==4&& |
| sscanf(asmline[0],"\tmove.l\t%c%d,%c%d\n%c",&c3,&r3,&c4,&r4,&e)==4&& |
| c1==c4&&r1==r4&&c2==c3&&r2==r3&&r1>=0&&r1<=7&&r2>=0&&r2<=7&& |
| (c1=='a'||c1=='d')&&(c2=='a'||c2=='d')){ |
| /* create tst instruction if condition codes of address register are needed */ |
| if(c1=='d'&&c2=='a'&&cc_set!=0&&(cc_set->flags&(REG|DREFOBJ))==REG&&cc_set->reg==a0+r2) |
| sprintf(asmline[0],"\ttst.l\t%s\n",mregnames[d0+r1]); |
| else |
| remove_asm(); |
| savedemit++; |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| char *use_libcall(int c,int t,int t2) |
| { |
| static char fname[32]; |
| char *ret=0; |
| int f; |
| |
| t&=NU; |
| t2&=NU; |
| |
| if(c==LSHIFT&&((t&NQ)==LLONG)) return "_lshint64"; |
| if(c==RSHIFT&&t==LLONG) return "_rshsint64"; |
| if(c==RSHIFT&&t==(UNSIGNED|LLONG)) return "_rshuint64"; |
| |
| |
| if(FPU>68000){ |
| if(c!=CONVERT) return 0; |
| if((!ISFLOAT(t)||(t2&NQ)!=LLONG)&& |
| (!ISFLOAT(t2)||(t&NQ)!=LLONG)) |
| return 0; |
| } |
| if(OLD_SOFTFLOAT) return 0; |
| |
| if(t==LDOUBLE) t=DOUBLE; |
| if(t2==LDOUBLE) t2=DOUBLE; |
| if(FLOAT64){ |
| if(t==FLOAT) t=DOUBLE; |
| if(t2==FLOAT) t2=DOUBLE; |
| } |
| |
| if(c==COMPARE){ |
| if(ISFLOAT(t)){ |
| sprintf(fname,"_ieeecmp%c",x_t[t]); |
| ret=fname; |
| } |
| }else if(c==CONVERT){ |
| if(t2==INT) t2=(zm2l(sizetab[INT])==4?LONG:SHORT); |
| if(t2==(UNSIGNED|INT)) t2=(sizetab[INT]==4?(UNSIGNED|LONG):(UNSIGNED|SHORT)); |
| if(t==FLOAT&&t2==DOUBLE) return "_ieeed2s"; |
| if(t==DOUBLE&&t2==FLOAT) return "_ieees2d"; |
| if(t==DOUBLE&&t2==DOUBLE) return 0; |
| if(t==FLOAT||t==DOUBLE){ |
| if((t2&NQ)==LLONG) |
| sprintf(fname,"_%cint64toflt%s",(t2&UNSIGNED)?'u':'s',t==FLOAT?"32":"64"); |
| else |
| sprintf(fname,"_ieeeflt%c%c",(t2&UNSIGNED)?'u':'s',x_t[t]); |
| ret=fname; |
| } |
| if(t2==FLOAT||t2==DOUBLE){ |
| if((t&NQ)==LLONG) |
| sprintf(fname,"_flt%sto%cint64",t2==FLOAT?"32":"64",(t&UNSIGNED)?'u':'s'); |
| else |
| sprintf(fname,"_ieeefix%c%c%c",x_t[t2],(t2&UNSIGNED)?'u':'s',x_t[t&NQ]); |
| ret=fname; |
| } |
| }else if(ISFLOAT(t)){ |
| if(c==MINUS){ |
| sprintf(fname,"_ieeeneg%c",x_t[t&NQ]); |
| ret=fname; |
| }else if(c>=ADD&&c<=DIV){ |
| sprintf(fname,"_ieee%s%c",ename[c],x_t[t&NQ]); |
| ret=fname; |
| } |
| if(c==TEST){ |
| sprintf(fname,"_ieeetst%c",x_t[t&NQ]); |
| ret=fname; |
| } |
| }else if(CPU<68020&&!OLDLIBCALLS){ |
| if((c==DIV||c==MOD)&&ISINT(t)&&zm2l(sizetab[t&NQ])==4){ |
| sprintf(fname,"_%s%c",ename[c],(t&UNSIGNED)?'u':'s'); |
| ret=fname; |
| } |
| } |
| return ret; |
| } |
| |
| |
| int reg_parm(treg_handle *p,type *t,int mode,type *fkt) |
| { |
| int f; |
| |
| if(!fkt||fkt->flags!=FUNKT) |
| ierror(0); |
| |
| if(!fkt->next) |
| ierror(0); |
| |
| if(stdargs(fkt)) |
| return 0; |
| |
| f=t->flags&NQ; |
| if(mode/*||f==LLONG||!ISSCALAR(f)*/) |
| return 0; |
| if(ISPOINTER(f)){ |
| if(p->ar>ascratch) |
| return 0; |
| else |
| return a0+p->ar++; |
| } |
| if(ISFLOAT(f)||f==LLONG){ |
| if(FPU<=68000||f==LLONG){ |
| if(rparmtype==PARMSAS) return 0; |
| if(f!=FLOAT){ |
| if(p->dr!=0) return 0; |
| p->dr+=2; |
| return d0d1; |
| } |
| if(p->dr>dscratch) |
| return 0; |
| else |
| return d0+p->dr++; |
| }else{ |
| if(p->fr>fscratch) |
| return 0; |
| else |
| return fp0+p->fr++; |
| } |
| } |
| if(!ISINT(f)) return 0; |
| if(p->dr>dscratch) |
| return 0; |
| else |
| return d0+p->dr++; |
| } |
| |
| int handle_pragma(const char *s) |
| { |
| if(!strncmp("stdargs-on",s,10)){ |
| add_stdargs=1; |
| return 1; |
| } |
| if(!strncmp("stdargs-off",s,11)){ |
| add_stdargs=0; |
| return 1; |
| } |
| return 0; |
| } |
| |
| void add_var_hook_pre(const char *identifier, type *t, int storage_class,const_list *clist) |
| { |
| if(!add_stdargs) return; |
| if(ISFUNC(t->flags)) |
| add_attr(&t->next->attr,"__stdargs"); |
| } |