blob: 3e96a312c7562dd2e394286a59b0d16df1328342 [file] [log] [blame]
/* $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,&ltyp},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&REG)&&p->q1.reg==r) return 0;
if((p->q2.flags&REG)&&p->q2.reg==r) return 0;
if((p->z.flags&REG)&&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&REG){
if(p->q1.reg==i) continue;
if(reg_pair(p->q1.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
}
if(p->q2.flags&REG){
if(p->q2.reg==i) continue;
if(reg_pair(p->q2.reg,&rp)&&(rp.r1==i||rp.r2==i)) continue;
}
if(p->z.flags&REG){
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&REG)||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&REG)||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&REG)||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&REG)||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&REG)||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))&&regavailable(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))&&regavailable(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&REG)&&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&REG)&&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&REG){
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&REG)&&!(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)&&section!=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&REG)&&p->q2.reg==reg)
return zm2l(sizetab[p->typf&NQ]);
return 4;
}
if(c==CONVERT){
if((p->z.flags&REG)&&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&REG)||p2->q2.reg!=r)&&(!(p2->z.flags&REG)||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&REG)||p2->q1.reg!=r)&&(!(p2->z.flags&REG)||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&REG)||p2->q2.reg!=r)&&(!(p2->q1.flags&REG)||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&REG)&&p2->q1.reg==r) break;
if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
if((p2->z.flags&REG)&&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&REG)||p->q2.reg!=r)&&(!(p->z.flags&REG)||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&REG)&&p2->q1.reg==r) break;
if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
if((p2->z.flags&REG)&&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&REG)||p->q1.reg!=r)&&(!(p->z.flags&REG)||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&REG)&&p2->q1.reg==r) break;
if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
if((p2->z.flags&REG)&&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&REG)||p->q1.reg!=r)&&(!(p->q2.flags&REG)||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&REG)&&p2->q1.reg==r) break;
if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
if((p2->z.flags&REG)&&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&REG)&&p2->q1.reg==idx) break;
if((p2->q2.flags&REG)&&p2->q2.reg==idx) break;
if((p2->z.flags&REG)&&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&REG)||p2->q2.flags!=r)&&(!(p2->z.flags&REG)||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&REG)||p2->q1.flags!=r)&&(!(p2->z.flags&REG)||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&REG)||p2->q2.flags!=r)&&(!(p2->z.flags&REG)||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&REG)&&p2->q1.reg==r) break;
if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
if((p2->z.flags&REG)&&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&REG)&&p2->q1.reg==r) break;
if((p2->q2.flags&REG)&&p2->q2.reg==r) break;
if((p2->z.flags&REG)&&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&REG) q1reg=p->q1.reg; else q1reg=0;
if(p->q2.flags&REG) q2reg=p->q2.reg; else q2reg=0;
if(p->z.flags&REG) 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)&&reg_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&REG)){
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)&&reg_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&REG)&&q->reg>=fp0)||(z&&(z->flags&REG)&&z->reg>=fp0)){
if(c==ASSIGN&&(q->flags&REG)&&(z->flags&REG)&&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&REG)&&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&REG)&&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&REG)&&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&REG)){
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]=&ltyp;}
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&&section!=SPECIAL)
emit(f,"%ld\n",zm2l(size));
else
emit(f,"\t.space\t%ld\n",zm2l(size));
newobj=0;
}else{
/*if(section!=BSS&&section!=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*/)&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&&section!=CODE){emit(f,codename);if(f) section=CODE;}
if(!v->clist&&section!=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*/)&&section!=DATA){emit(f,dataname);if(f) section=DATA;}
if(v->clist&&constflag&&!CONSTINDATA/*&&!use_sd*/&&section!=CODE){emit(f,codename);if(f) section=CODE;}
if(!v->clist&&section!=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&REG))||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&&regs[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&&regs[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&&regs[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&&regs[ar])){
if(regs[r]||(ar&&regs[ar])){
emit(f,"%s%d%s\n",labprefix,label,GAS?":":"");
if(ar&&regs[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&REG)&&!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&REG)&&!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&REG)&&!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&REG)&&(p->z.flags&REG)&&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&REG){
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&REG)||(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&REG)&&(p->z.flags&REG)&&p->q2.reg==p->z.reg&&(!(p->q1.flags&REG)||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&REG)||!(p->z.flags&REG)||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");
}