view mc-code-ia32.c @ 87:1738f313f98b floating-point

floating point (at most) done.
author kono
date Wed, 05 Mar 2003 21:07:20 +0900
parents 4d1275f8a5b5
children 917947ffeb7c
line wrap: on
line source

/* Micro-C Code Generatation Part for intel386 */
/* $Id$ */

#define EXTERN extern
#include "mc.h"
#include "mc-codegen.h"

#define TEXT_EMIT_MODE 0
#define DATA_EMIT_MODE 1
#define RODATA_EMIT_MODE 2

static int output_mode = TEXT_EMIT_MODE;
static int data_alignment = 0;

static int code_disp_label;
static int func_disp_label;

/*
                                           -16  -8 local2
                                           -12  -4 local1
                                            -8  8  arg3
                                            -4  4  arg2
                                             0  0  arg1
         local2     -20 4                    0    (%edi)
         local1 <-- -16 0 local variable     0    (%esi)
        %edi        -12  <- disp_offset          %ebp
        %esi         -8
        %ebx         -4
        %ebp = %esp   0
        %eip          4   <- arg_offset
          arg1        8 0
          arg2       12 4
            see enter/enter1/leave           see code_enter
 */
int arg_offset = 8;
int disp_offset = -12;
int func_disp_offset = -12;
int code_disp_offset = 0;
int jump_offset = 0;

int size_of_int = 4;
int size_of_float = 4;
int size_of_double = 8;
int size_of_longlong = 8;
int endian = 0;
int MAX_REGISTER=6;         /* intel386のレジスタを6つまで使う*/
int REAL_MAX_REGISTER=8;    /* intel386のレジスタが8つということ*/
int MAX_DATA_REG=4;    
int MAX_POINTER=3;    
int MAX_REGISTGER_VAR=2;    
int MAX_FREGISTER=1;


#define REG_EAX   0
#define REG_EBX   1
#define REG_ECX   2
#define REG_EDX   3
#define REG_ESI   4
#define REG_EDI   5
#define REG_EBP   6
#define REG_ESP   7


#define DATA_REG 0    
#define POINTER_REG 3    
static char *reg_name[8]; 
static char *reg_name_l[4];
static char *reg_name_w[4];

void use_register(int virt, int real, int move);
void code_preinc(int e1,int e2) ;
void code_cmp_register(int e2) ;
void code_assign_gvar(int e2,int byte) ;
void tosop(int op,int oreg);
void edx_cleanup();
void shift(char *op, int reg);
void ld_indexx(int byte, int n, int xreg);
void jmp(int l);
void local_table(void);
void text_mode(void);
void data_mode(char *name);

char *register_name(int i,int byte);
int register_var(int r);
int get_register_var(void);
void emit_push(void);
int emit_pop(int type);
void code_crlvar(int e2);
void code_preinc(int e1,int e2);
void code_postinc(int e1,int e2);
void code_bool(int e1);
void string(int e1);
void emit_copy(int from,int  to,int length,int offset,int value,int det);
int struct_push(int e4,int t);
void function(int e1);
void code_assop(int op,int byte);
int edx_setup();
void code_opening(char *filename);
void code_closing();
void code_leave(char *name);
int lvar(int l);
void global_table(void);

char * fstore(int d);
char * fload(int d);
int code_d1(double d);
int code_d2(double d);

void
code_init(void)
{
    arg_offset = 8;
    func_disp_offset = -12;
    disp_offset = -12;
    size_of_int = 4;
    endian = 0;
    MAX_REGISTER=6;
    MAX_DATA_REG=4;    
    MAX_POINTER=3;    
    MAX_REGISTER_VAR=2;    

    reg_name[REG_EAX] = "%eax";
    reg_name[REG_EBX] = "%ebx";
    reg_name[REG_ECX] = "%ecx";
    reg_name[REG_EDX] = "%edx";
    reg_name[REG_ESI] = "%esi";
    reg_name[REG_EDI] = "%edi";
    reg_name[REG_EBP] = "%ebp";
    reg_name[REG_ESP] = "%esp";
    reg_name_l[REG_EAX] = "%al";
    reg_name_l[REG_EBX] = "%bl";
    reg_name_l[REG_ECX] = "%cl";
    reg_name_l[REG_EDX] = "%dl";
    reg_name_w[REG_EAX] = "%ax";
    reg_name_w[REG_EBX] = "%bx";
    reg_name_w[REG_ECX] = "%cx";
    reg_name_w[REG_EDX] = "%dx";

}

char *
register_name(int i,int byte)
{
    if (i<0) {
	error(REG_ERR);
	return "%eax";
    }
    if (byte && rname[i] <= REG_EDX) {
	return reg_name_l[rname[i]];
    } else {
	return reg_name[rname[i]]; /* should be error */
    }
}

void
gexpr_code_init(void){
    use_register(creg,REG_EAX,0);
    regv[dreg]=0;
}

int
register_var(int r) {
    return virtual(r+REG_ESI);
}

int
get_register_var(void)
{
    int i;
    for(i=REG_ESI;i<REG_ESP;i++) {
        if (! regs[i]) {    /* 使われていないなら */
            regs[i]=1;      /* そのレジスタを使うことを宣言し */
            regv[i]=0;
            return i;       /* その場所を表す番号を返す */
        }
    }
    return -1;
}

void 
use_register(int virt, int real, int move)
{
    int real_v;
    char *move_op;
    if (rname[virt]==real)
	return;
    real_v = virtual(real);
    move_op = regs[real_v]?"\txchg %s,%s\n":"\tmovl %s,%s\n";
    if (move || (regv[real_v])) {
	printf(move_op,reg_name[rname[virt]],reg_name[real]);
    } 
    rname[real_v] = rname[virt];
    rname[virt] = real; 
}

void 
use_pointer(int virt, int move)
{
    int i;
    if (rname[virt]>=POINTER_REG)
	return;
    for(i=POINTER_REG;i<MAX_REGISTER;i++) {
	if (!regs[virtual(i)]) {
	    use_register(virt,i,move);
	    return;
	}
    }
    /* we prefer EBX */
    use_register(virt,REG_EBX,move);
}

void 
use_data_reg(int virt, int move)
{
    int i;
    if (rname[virt]<MAX_DATA_REG)
	return;
    for(i=0;i<MAX_DATA_REG;i++) {
	if (!regs[virtual(i)]) {
	    use_register(virt,i,move);
	    return;
	}
    }
    /* we prefer EBX */
    use_register(virt,REG_EBX,move);
}


void 
emit_push(void)
{
    int new_reg;
    new_reg = get_register();
    if(new_reg<0) {                     /* もうレジスタがない */
	if (reg_sp>=MAX_MAX) error(-1);
	reg_stack[reg_sp++] =  -1;
	printf("\tpushl %s\n",register_name(creg,0));
	/* creg is used soon, don't regv[creg]=0 */
    } else {
	reg_stack[reg_sp++] = creg;     /* push するかわりにレジスタを使う */
	creg = new_reg;
	regv[creg]=1;
    }
}

int
emit_pop(int type)
{
    int xreg;
    if ((xreg=pop_register())==-1) {
	if (type==POINTER_REG)
	    use_pointer(dreg,0);
	else if (type==DATA_REG)
	    use_data_reg(dreg,0);
if (regv[dreg]) {
    printf("# emit_pop dreg conflict\n");
}
	printf("\tpopl %s\n",register_name(dreg,0));
	xreg = dreg;
	regv[xreg]=1;
    } 
    return xreg;
}


void
code_gvar(int e1) {
    printf("\tmovl $%s,%s\n",(char *)caddr(e1),register_name(creg,0));
}


void
code_rgvar(int e1) {
    printf("\tmovl %s,%s\n",(char *)caddr(e1),register_name(creg,0));
}

void
code_crgvar(e1){
    printf("\tmovsbl %s,%s\n",(char *)caddr(e1),register_name(creg,0));
}


void
code_lvar(int e2) {
    printf("\tlea %d(%%ebp),%s\n",e2,register_name(creg,0));
}


void
code_register(int e2) {
    printf("\tmovl %s,%s\n",register_name(e2,0),register_name(creg,0));
}


void
code_rlvar(int e2) {
    printf("\tmovl %d(%%ebp),%s\n",e2,register_name(creg,0));
}


void
code_crlvar(int e2) {
    printf("\tmovsbl %d(%%ebp),%s\n",e2,register_name(creg,0));
}


void
code_fname(char *e2) {
    printf("\tmovl $%s,%s\n",e2,register_name(creg,0));
}


void
code_const(int e2) {
    printf("\tmovl $%d,%s\n",e2,register_name(creg,0));
}


void
code_neg() {
    printf("\tnegl %s\n", register_name(creg,0));
}


void
code_not() {
    printf("\tnotl %s\n", register_name(creg,0));
}


void
code_lnot() {
    char *xrn;
    use_data_reg(creg,1);
    xrn = register_name(creg,1);
    printf("\tcmpl $0,%s\n", register_name(creg,0));
    printf("\tsete %s\n", xrn);
    printf("\tmovzbl %s,%s\n", xrn,register_name(creg,0));
}

void
code_preinc(int e1,int e2) {
    char *xrn;
    if (car(e2)==REGISTER) {
	printf("\taddl $%d,%s\n",caddr(e1),register_name(cadr(e2),0));
	printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(creg,0));
	return;
    } 
    g_expr(e2);
    xrn = register_name(creg,0);
    printf("\taddl $%d,(%s)\n",caddr(e1),xrn);
    printf("\tmovl (%s),%s\n",xrn,xrn);
}


void
code_postinc(int e1,int e2) {
    char *xrn;
    if (car(e2)==REGISTER) {
	printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(creg,0));
	printf("\taddl $%d,%s\n",caddr(e1),register_name(cadr(e2),0));
	return;
    } 
    g_expr(e2);
    emit_push();  
    xrn = register_name((e2=emit_pop(0)),0);
    printf("\tmovl (%s),%s\n",xrn,register_name(creg,0));
    printf("\taddl $%d,(%s)\n",caddr(e1),xrn);
    emit_pop_free(e2);
}


void
code_cpostinc(int e1,int e2) {
    char *xrn;
    if (car(e2)==REGISTER) {
	printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(creg,0));
	printf("\taddl $%d,%s\n",caddr(e1),register_name(cadr(e2),0));
	return;
    } 
    g_expr(e2);
    emit_push();
    xrn = register_name((e2=emit_pop(0)),1);
    printf("\tmovsbl (%s),%s\n",xrn,register_name(creg,0));
    printf("\tincl (%s)\n",xrn);
    emit_pop_free(e2);
}


void
code_cpreinc(int e1,int e2) {
    if (car(e2)==REGISTER) {
	printf("\taddl $%d,%s\n",caddr(e1),register_name(cadr(e2),0));
	printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(creg,0));
	return;
    } 
    g_expr(e2);
    printf("\tincl (%s)\n",register_name(creg,0));
    printf("\tmovsbl (%s),%s\n",register_name(creg,0),register_name(creg,0));
}


void
code_cpostdec(int e1,int e2) {
    if (car(e2)==REGISTER) {
	printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(creg,0));
	printf("\tdecl %s\n",register_name(cadr(e2),0));
	return;
    } 
    g_expr(e2);
    printf("\tmovsbl (%s),%s\n",register_name(creg,0),register_name(creg,0));
    printf("\tdecl (%s)\n",register_name(creg,0));
}


void
code_cpredec(int e1,int e2) {
    if (car(e2)==REGISTER) {
	printf("\tdecl %s\n",register_name(cadr(e2),0));
	printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(creg,0));
	return;
    } 
    g_expr(e2);
    emit_push();
    e2 = emit_pop(0);
    printf("\tdecl (%s)\n",register_name(e2,0));
    printf("\tmovsbl (%s),%s\n",register_name(e2,0),register_name(creg,0));
    emit_pop_free(e2);
}


void
code_return() {
    printf("\tleal _%d,%s\n",retcont,register_name(creg,0));
}


void
code_environment() {
    printf("\tmovl %%ebp,%s\n",register_name(creg,0));
}


void
code_bool(int e1) {
    char *xrn;
    int e2,e3;
    b_expr(e1,1,e2=fwdlabel(),1);  /* including > < ... */
    xrn = register_name(creg,0);
    printf("\txorl %s,%s\n",xrn,xrn);
    jmp(e3=fwdlabel());
    fwddef(e2);
    printf("\tmovl $1,%s\n",xrn);
    fwddef(e3);
}

char *
code_gt(int cond) {
    return (cond?"g":"le");
}

char *
code_ugt(int cond) {
    return (cond?"a":"be");
}

char *
code_ge(int cond) {
    return (cond?"ge":"l");
}

char *
code_uge(int cond) {
    return (cond?"ae":"b");
}

char *
code_eq(int cond) {
    return (cond?"e":"ne");
}

void
code_cmp_crgvar(int e1) {
    printf("\tcmpb $0,%s\n",(char *)caddr(e1));
}


void
code_cmp_crlvar(int e1) {
    printf("\tcmpb $0,%d(%%ebp)\n",e1);
}


void
code_cmp_rgvar(int e1) {
    printf("\tcmpl $0,%s\n",(char *)caddr(e1));
}


void
code_cmp_rlvar(int e1) {
    printf("\tcmpl $0,%d(%%ebp)\n",e1);
}


void
code_cmp_register(int e2) {
    printf("\tcmpl $0,%s\n",register_name(e2,0));
}


void
ascii(char *s)
{
    printf("\t.string \"");
    while(*s) {
	if (*s=='\n')
	    printf("%cn",92);
	else if (*s<' ')
	    printf("%c%03o",92,*s);
	else if (*s==34)
	    printf("%c%c",92,34);
	else 
	    printf("%c",*s);
	s++;
    }
    printf("%c\n",34);
}

void
string(int e1)
{
    char *s;
    int i,lb;

    if (0) {
	s=(char *)cadr(e1);
	lb=fwdlabel();
	printf("\tjmp _%d\n",lb);
	i=backdef();
	ascii(s);
	printf("\t.align 2\n");
	fwddef(lb);
	printf("\tlea _%d,%s\n",i,register_name(creg,0));
    } else {
	s=(char *)cadr(e1);
	printf(".section\t.rodata\n");
	lb=fwdlabel();
	printf("_%d:\n",lb);
	ascii(s);
	if (output_mode==TEXT_EMIT_MODE) {
	    printf(".text\n");
	} else {
	    text_mode();
	}
	printf("\tlea _%d,%s\n",lb,register_name(creg,0));
    }
}

#define MAX_COPY_LEN 20

void 
emit_copy(int from,int  to,int length,int offset,int value,int det)
{
    int fix = 0;
    /* length <0 means upward direction copy */
    switch (length) {
    case 0:	break;
    case 1: case -1:
	printf("\tmovb %d(%s),%s\n",offset,
	    register_name(from,0), reg_name_l[rname[dreg]] );
	printf("\tmovb %s,%d(%s)\n",reg_name_l[rname[dreg]] ,offset,
	    register_name(to,0));
	break;
    case 2: case -2:
	printf("\tmovw %d(%s),%s\n",offset,
	    register_name(from,0), reg_name_w[rname[dreg]] );
	printf("\tmovw %s,%d(%s)\n",reg_name_w[rname[dreg]] ,offset,
	    register_name(to,0));
	break;
    case 4: case -4:
	printf("\tmovl %d(%s),%s\n",offset,
	    register_name(from,0), register_name(dreg,0));
	printf("\tmovl %s,%d(%s)\n",register_name(dreg,0), offset,
	    register_name(to,0));
	break;
    default:
	if (-MAX_COPY_LEN<length && length <0) {
	    for(;length<=4;length+=4,offset-=4)
		emit_copy(from,to,4,offset,0,det);
	    for(;length<=2;length+=2,offset-=2)
		emit_copy(from,to,2,offset,0,det);
	    if(length>0)
		emit_copy(from,to,length,offset,0,det);
	    break;
	} else if (length <=MAX_COPY_LEN) {
	    for(;length>=4;length-=4,offset+=4)
		emit_copy(from,to,4,offset,0,det);
	    for(;length>=2;length-=2,offset+=2)
		emit_copy(from,to,2,offset,0,det);
	    if(length>0)
		emit_copy(from,to,length,offset,0,det);
	    break;
	}
	if (det) {
/*
   call bcopy
	    g_expr(list3(FUNCTION,,);
	    break;
 */
	}
	use_register(from,REG_ESI,1);
	use_register(to,  REG_EDI,1);
	use_register(dreg,REG_ECX,0);
	if (length<0) {
	    printf("\tmovl $%d,%%ecx\n",-length/4);
	    printf("\taddl $%d,%%esi\n",-length);
	    printf("\taddl $%d,%%edi\n",-length);
	    printf("\tstd\n\trep\n\tmovsl\n");
	    if(length%4) {
		emit_copy(from,to,length,offset+length/4,0,det);
	    }
	} else {
	    printf("\tmovl $%d,%%ecx\n",length/4);
	    fix = (length/4)*4;
	    printf("\tcld\n\trep\n\tmovsl\n");
	    if(length%4) {
		emit_copy(from,to,length,offset+length/4,0,det);
	    }
	}
    }
    if (value) {
    /* creg must point top of the destination data */
    /* this code is necessary for the value of assignment or function call */
    /* otherwise we don't need this */
	if (fix) printf("\tsubl $%d,%s\n",fix,register_name(to,0));
	if(creg!=to) {
	    if (to==dreg) 
		printf("\tmovl %s,%s\n",register_name(to,0),register_name(creg,0));
	    else {
		free_register(creg); creg=to;
	    }
	}
    }
    regv[from]=regv[to]=regv[dreg]=0;
    regv[creg]=1;
}

int
struct_push(int e4,int t) 
{
    int length,xreg,save,lreg,count;
    g_expr(e4);
    length=size(t); 
    if(length%size_of_int) {
	length += size_of_int - (length%size_of_int);
    }
    for(count=0;length<MAX_COPY_LEN;count++,length-=size_of_int) {
	if (length==0) return count;
	else {
	    printf("\tpushl %d(%s)\n",
		length-size_of_int,register_name(creg,0));
	}
    }
    printf("\tsubl $%d,%%esp\n",length);
    if (register_full()) {
	save = 1;
	for(lreg=0;lreg==creg||lreg==dreg;lreg++);
	printf("\tpushl %s\n",register_name(lreg,0));
	xreg = lreg; regv[xreg]=0;
    } else {
	save=0;
	xreg = get_register();
    }
    if (save) 
	printf("\tlea %d(%%esp),%s\n",size_of_int,register_name(xreg,0));
    else
	printf("\tmovl %%esp,%s\n",register_name(xreg,0));
    regv[xreg]=1;
    /* downward direction copy */
    emit_copy(creg,xreg,length,0,0,1);
    /* we have value in creg, it may be changed */
    if (save) {
	if(creg==xreg) {
	    creg = get_register();   /* creg is freed in emit_copy */
	}
	printf("\tpopl %s\n",register_name(xreg,0));
	regv[xreg]=1;
    } else
	free_register(xreg);
    return length/size_of_int;
}

void
function(int e1)
{
    int e2,e3,e4,e5,nargs,t;
    NMTBL *n;
    int save,saved;
    if (free_register_count()<1) {
        for(save = 0;save==dreg||save==creg;save++);
	printf("\tpushl %s\n",register_name(save,0));
        saved = 1;
    } else {
        save = get_register();
        saved = 0;
    }
    regv[save]=0;
    e2 = cadr(e1);
    nargs = 0;
    for (e3 = caddr(e1); e3; e3 = cadr(e3)) {	
	t=caddr(e3);
	n=(NMTBL *)(e5=(cadr(e4 = car(e3))));
	if(scalar(t)) {
	    g_expr(e4);
	    printf("\tpushl %s\n",register_name(creg,0));
	} else if (t==DOUBLE) {
	    g_expr(e4);
	    printf("\tleal\t-8(%%esp),%%esp\n\tfstpl\t(%%esp)\n");
	    nargs += size_of_double/size_of_int;
	    fregv[freg]=0;
	    continue;
	} else if (t==FLOAT) {
	    g_expr(e4);
	    printf("\tleal\t-4(%%esp),%%esp\n\tfstps\t(%%esp)\n");
	    nargs += size_of_float/size_of_int;
	    fregv[freg]=0;
	    continue;
	} else if (car(t)==STRUCT||car(t)==UNION) {
	    nargs += struct_push(e4,t);
	    continue;
	} else {
	    error(TYERR);
	}
	++nargs;
    }
    if (car(e2) == FNAME) {	
	n=(NMTBL *)cadr(e2);
	regv[creg]=0;
	use_register(creg,REG_EAX,0);  /* will be destroyed */
    } else {	
	g_expr(e2);
	regv[creg]=1;
	use_register(creg,REG_EAX,1);  /* will be destroyed */
    }

    /* we don't have to save creg nor dreg */
    regs[creg]=0; regs[dreg]=0;
    regv[dreg]= regv[save]= 0;
    use_register(dreg,REG_EDX,0);  /* will be destroyed */
    use_register(save,REG_ECX,0);  /* will be destroyed */
    regs[creg]=1; regs[dreg]=1;

    if (car(e2) == FNAME) {	
	printf("\tcall\t%s\n",n->nm);
    } else {
	printf("\tcall\t*%s\n",register_name(creg,0));
    }
    if (nargs) printf("\taddl $%d,%%esp\n",size_of_int*nargs);
    if (saved) {
	printf("\tpopl %s\n",register_name(save,0));
    } else {
        free_register(save);
    }
    regv[save]=0;
    regv[creg]=1;
    fregv[freg]=1; /* return type はどこ? fnptr にはあるけど... */
}

void
code_frame_pointer(int e3) {
    printf("\tmovl %s,%%ebp\n",register_name(e3,0));
}


void
code_fix_frame_pointer(int disp_offset) {
    printf("\tlea %d(%%ebp),%%ebp\n",disp_offset);
}


void
code_jmp(char *s) {
    printf("\tjmp %s\n",s);
}


void
code_indirect_jmp(int e2) {
    printf("\tjmp *%s\n",register_name(e2,0));
}

void
rindirect(int e1)   /* *(p +5 ) */
{
    char *op;
    int e2,e3,byte;
    e3 = cadr(e2 = cadr(e1));
    g_expr(e2);
    switch (car(e1)) {
    case FRINDIRECT: case DRINDIRECT:
    printf("\t%s (%s)\n",fload(car(e1)==DRINDIRECT),register_name(creg,0));
    break;
    case CRINDIRECT: case RINDIRECT:
    op = ((byte = (car(e1) == CRINDIRECT)) ? "movsbl" : "movl");
    printf("\t%s (%s),%s\n",op,register_name(creg,0),register_name(creg,0));
    }
}

char *
move(int byte)
{
    return byte?"movb":"movl";
}

void
code_assign_gvar(int e2,int byte) {
    if (byte) use_data_reg(creg,1);
    printf("\t%s %s,%s\n",move(byte),register_name(creg,byte),(char *)caddr(e2));
}

void
code_assign_lvar(int e2,int byte) {
    if (byte) use_data_reg(creg,1);
    printf("\t%s %s,%d(%%ebp)\n",move(byte),register_name(creg,byte),e2);
}

void
code_assign_register(int e2,int byte) {
    printf("\tmovl %s,%s\n",register_name(creg,0),register_name(e2,0));
}

void
code_assign(int e2,int byte) {
    printf("\t%s %s,(%s)\n",move(byte),register_name(creg,byte),register_name(e2,0));
}


void
code_register_assop(int e2,int op,int byte) {
    int reg;
    int xreg = creg;
    creg = reg = e2;
    tosop(op,xreg);
    creg = xreg;
    printf("\tmovl %s,%s\n",register_name(reg,0),register_name(creg,0));
}


void
code_assop(int op,int byte) {
    char *xrn;
    int xreg;
    int edx = edx_setup();
    xrn = register_name(xreg = emit_pop(0),0);       /* pop e3 value */
    regv[xreg]=regs[xreg]=1;
    printf("\tmovl %s,%s  # assop \n",register_name(creg,0),register_name(edx,0));
    regv[edx]=1;
    ld_indexx(byte,0,edx);
    tosop(op,xreg);
    printf("\t%s %s,(%s)\n",byte ? "movb" : "movl",register_name(creg,byte),register_name(edx,0));
    edx_cleanup();
    emit_pop_free(xreg);
}


void
tosop(int op,int oreg)
{
    int dx;
    char *orn,*crn;

    switch(op) {
    case LSHIFT:
    case ULSHIFT:
	shift("sall",oreg);
	return;
    case RSHIFT:
	shift("sarl",oreg);
	return;
    case URSHIFT:
	shift("shrl",oreg);
	return;
    }
    if(oreg==-1) {
        printf("\tpopl %s\n",register_name(dreg,0));
	oreg = dreg;
	regv[dreg]=1;
    }
    regv[oreg]=1; regs[oreg]=1;
    orn = register_name(oreg,0);
    crn = register_name(creg,0);
    switch(op) {
    case ADD:
	printf("\taddl %s,%s\n",orn,crn);
	break;
    case SUB:
	printf("\tsubl %s,%s\n",orn,crn);
	break;
    case BAND: 
	printf("\tandl %s,%s\n",orn,crn);
	break;
    case EOR: 
	printf("\txorl %s,%s\n",orn,crn);
	break;
    case BOR:
	printf("\torl %s,%s\n",orn,crn);
	break;
    case MUL:
    case UMUL:
	printf("\t%s %s,%s\n","imull",orn,crn);
	break;
    case DIV:
    case UDIV:
	use_register(creg,REG_EAX,1);
	edx_setup();
	orn = register_name(oreg,0);
	if (op==DIV)
	    printf("\tcltd\n\tdivl %s\n",orn);
	else 
	    printf("\txor %%edx,%%edx\n\tidivl %s\n",orn);
	edx_cleanup();
	break;
    case MOD:
    case UMOD:
	use_register(creg,REG_EAX,1);
	edx_setup();
	orn = register_name(oreg,0);
	if (op==DIV)
	    printf("\tcltd\n\tdivl %s\n",orn);
	else 
	    printf("\txor %%edx,%%edx\n\tidivl %s\n",orn);
        dx = virtual(REG_EDX);	
	if (dx!=creg) {
	    rname[dx]=rname[creg];
	    rname[creg]=REG_EDX;
	}
	edx_cleanup();
	break;
    }
    if (oreg!=dreg&&oreg>=0)
	free_register(oreg);
}

static int edx_stack=0;

int
edx_setup()
{
    int edx_save;
    /* make real EDX register empty */
    if (free_register_count()<1) {
        for(edx_save = 0;edx_save==dreg||edx_save==creg;edx_save++);
	printf("\tpushl %s\n",register_name(edx_save,0));
        edx_stack = list3(edx_save,edx_stack,0);
    } else {
        edx_save = get_register();
        edx_stack = list3(edx_save,edx_stack,1);
    }
    regv[edx_save]=0;
    use_register(edx_save,REG_EDX,0);
    return edx_save;
}


void
edx_cleanup()
{
    if (caddr(edx_stack)==0) {
	printf("\tpopl %s\n",register_name(car(edx_stack),0));
    } else
	free_register(car(edx_stack));
    edx_stack = cadr(edx_stack);
}

void
shift(char *op, int reg)
{
    if (reg>=0) {
	use_register(reg,REG_ECX,1);
    } else {
	use_register(dreg,REG_ECX,0);
	printf("\tpopl %%ecx\n");
    }
    printf("\t%s %%cl,%s\n",op,register_name(creg,0));
}

void
ld_indexx(int byte, int n, int xreg)
{	
    char *op;

    op = byte ? "movsbl" : "movl";
    if (n) 
	    printf("\t%s %d(%s),%s\n",op,n,register_name(xreg,0),register_name(creg,byte));
    else
	    printf("\t%s (%s),%s\n",op,register_name(xreg,0),register_name(creg,byte));
}

void
cmpdimm(int e, int csreg)
{
    /* used in dosiwtch() */
    if(chk) return;
    use_register(creg,csreg,0);
    printf("\tcmpl $%d,%s\n",e,register_name(creg,0));
}

void
code_opening(char *filename)
{
    printf("\t.file \"%s\"\n",filename);
    printf("\t.version\t\"01.01\"\n");
    /* printf("gcc2_compiled.:\n"); */
    printf(".text\n");
}

void
code_closing()
{
    global_table();
    printf("\t.ident \"Micro-C compiled\"\n");
}

void
rexpr(int e1, int l1, char *s)
{       
    g_expr(list3(SUB,cadr(e1),caddr(e1)));
    printf("\tj%s\t_%d\n",s,l1);
}


void
jcond(int l, char cond)
{       
    if (chk) return;
    printf("\tj%s\t_%d\n",cond?"ne":"e",l);
}

void
jmp(int l)
{       
    control=0;
    if (chk) return;
    printf("\tjmp\t_%d\n",l);
    /* align? */
    /*
      this is not allowed because of ? operator
    regv[creg]=regv[dreg]=0; 
    use_register(creg,REG_EAX,0);
    use_register(dreg,REG_EBX,0);
     */
}

void
gen_comment(char *s)
{
    if (chk) return;
    printf("## %s",s);
}


void
code_enter(char *name)
{
    printf("\t.align 4\n");
    if (stmode!=STATIC)
	printf(".globl %s\n",name);
    printf("\t.type\t%s,@function\n",name);
    printf("%s:\n",name);
}


void
code_enter1(int args)
{
    code_disp_label=fwdlabel();
    printf("\tlea _%d(%%ebp),%%esp\n",code_disp_label);

    printf("## args %d disp %d code_arg_offset=%d code_disp_offset=%d\n",args,disp,code_arg_offset,code_disp_offset); 
}

void
code_leave(char *name)
{
    disp&= -size_of_int;
    printf("\t.set _%d,%d\n",code_disp_label,disp+code_disp_offset);
    printf("_%d:\n",labelno);
    printf("\t.size\t%s,_%d-%s\n",name,labelno,name);
    local_table();
    labelno++;
    free_all_register();
}

void
enter(char *name)
{
    printf("\t.align 2\n");
    if (stmode!=STATIC)
	printf(".globl %s\n",name);
    printf("%s:\n",name);
    printf("\t.type\t%s,@function\n",name);
    printf("\tpushl %%ebp\n");
    printf("\tmovl %%esp,%%ebp\n");
    printf("\tpushl %%ebx\n");
    printf("\tpushl %%esi\n");
    printf("\tpushl %%edi\n");
}

void
enter1()
{
    func_disp_label=fwdlabel();
    printf("\tlea _%d(%%ebp),%%esp\n",func_disp_label); 
    /* if(disp) printf("\tsubl $%d,%%esp\n",-disp); */
}

void
leave(int control, char *name)
{
    if (control)
	use_register(creg,REG_EAX,1);
    if (retcont) {
	if (control)
	    jmp(retlabel);
	fwddef(retcont);
	use_register(creg,REG_EAX,0);
	printf("\tmovl %s,%s\n",reg_name[REG_ESI],register_name(creg,0));
	/* printf("\tleave\n"); */
    }
    fwddef(retlabel);
    /* use_register(creg,REG_EAX,0); too late */
    /* if(disp) printf("\taddl $%d,%%esp\n",-disp);  */
    disp &= -size_of_int;

    printf("\tlea %d(%%ebp),%%esp\n",disp_offset);
    printf("\tpopl %%edi\n");
    printf("\tpopl %%esi\n");
    printf("\tpopl %%ebx\n");
    printf("\tleave\n");
    printf("\tret\n");
    printf("\t.set _%d,%d\n",func_disp_label,disp+disp_offset);
    printf("_%d:\n",labelno);
    printf("\t.size\t%s,_%d-%s\n",name,labelno,name);
    local_table();
    labelno++;
    free_all_register();
}


void
code_set_fixed_creg(int mode) {
    use_register(creg,REG_EAX,mode);
}

void
gen_gdecl(char *n, int gpc)
{
    /*
    if (stmode!=STATIC)
	printf(".globl %s\n",n); 
     */
}

void 
align(int t)
{
    if (t!=CHAR) {
	if (data_alignment & 1)
	    printf("\t.align 2\n");
	data_alignment = 0;
    }
}

void
emit_data(int e, int t, NMTBL *n)
{
    int l;
    double d;
    float f;
    char *name;
    name = n->nm; 
    if(mode!=GDECL)  { 
	error(-1); return;
    }
    if (chk) return;
    if (n->dsp != -1) {
	n->dsp = -1;   /* initiallized flag */
	printf(".globl\t%s\n",name);
	data_mode(name);
	align(t);
	printf("%s:\n",name); 
    } else {
	data_mode(0);
    }
    if(car(e)==CONST) {       
	if (t==CHAR) {
	    printf("\t.byte %d\n",cadr(e));
	    if (data_alignment>0)
		data_alignment++;
	    gpc += 1;
	} else if (t==SHORT) {
	    printf("\t.word %d\n",cadr(e));
	    if (data_alignment>0) data_alignment++;
	    gpc += 2;
	} else {
	    printf("\t.long %d\n",cadr(e));
	    gpc += size_of_int;
	}
    } else if(t==DOUBLE) {       
	d = dcadr(e);
	printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d));
    } else if(t==FLOAT) {       
	f = dcadr(e);
	printf("\t.long\t0x%x\n",*(int *)&f);
    } else if(t!=CHAR) {       
	gpc += size_of_int;
	if(car(e)==ADDRESS&&car(cadr(e))==GVAR) {
	    printf("\t.long %s\n",(char *)caddr(cadr(e)));
	} else if(car(e)==FNAME) {
	    printf("\t.long %s\n",((NMTBL *)cadr(e))->nm);
	} else if(car(e)==STRING) {       
	    if (car(n->ty)!=ARRAY || cadr(n->ty)!=CHAR) {
		l = fwdlabel();
		printf("\t.long _%d\n",l);
		printf(".section\t.rodata\n");
		printf("_%d:\n",l);
		output_mode = RODATA_EMIT_MODE;
	    }
	    ascii((char *)cadr(e));
	} else error(TYERR);
    }
}

void
emit_data_closing(NMTBL *n)
{
    int lb;
    if (chk) return;
    if (mode==GDECL) {
	data_mode(0);
	lb=fwdlabel();
	printf("_%d:\n",lb);
	printf("\t.size\t%s,_%d-%s\n",n->nm,lb,n->nm);
    }
}

void
global_table(void)
{
    NMTBL *n;
    int init;
    init=0;
    for(n=ntable;n < &ntable[GSYMS];n++) {
	if (n->sc == GVAR && n->dsp != -1) {
	    /* n->dsp = -1 means initialized global */
	    if (init==0) {
		data_mode(0);
		init=1;
	    }
	    printf(".comm %s,%d\n",n->nm,size(n->ty));
	}
    }
}

void
local_table(void)
{
    NMTBL *n;
    int init;
    init=0;
    /* static local variables */
    for(n=ntable+GSYMS;n < &ntable[GSYMS+LSYMS];n++) {
	if (n->sc == GVAR) {
	    if (init==0) {
		data_mode(0);
		init=1;
	    }
	    printf(".lcomm %s,%d\n",n->nm,size(n->ty));
	}
    }
}

void
text_mode(void)
{
    if (output_mode!=TEXT_EMIT_MODE) {
	printf(".text\n");
	printf("\t.align 2\n");
	output_mode = TEXT_EMIT_MODE;
    }
}

void
data_mode(char *name)
{
    if (output_mode!=DATA_EMIT_MODE) {
	printf(".data\n");
	output_mode = DATA_EMIT_MODE;
    }
    if (name)
	printf("\t.type\t%s,@object\n",name);
}

int
lvar(int l)
{
    if (fnptr->sc==CODE) {
	return l+code_disp_offset;
    } else if (l<0) {
	return l+disp_offset;
    } else {
	return l+arg_offset;
    }
}

/* floating point */


char *
fstore(int d)
{
    return use?
	(d?"fstl":"fsts"):
	(d?"fstpl":"fstps")
    ;
}

char *
fstore_u(int d)
{
    return d?"fstpl":"fstps";
}

char *
fload(int d)
{
    return d?"fldl":"flds";
}


void code_dassign_gvar(int e2,int d)
{ 
    printf("\t%s %s\n",fstore(d),(char *)caddr(e2)) ;
}

void code_dassign_lvar(int e2,int d)
{ 
    printf("\t%s %d(%%ebp)\n",fstore(d),e2);
}

void code_dassign(int e2,int d)
{ 
    printf("\t%s (%s)\n",fstore(d),register_name(e2,0));
}

static double d0 = 1.0;

int
code_d1(double d)
{
    int *i = (int *)&d0; int *j = (int *)&d;
    return (i[1] == 0x3ff00000)?j[0]:j[1];
}

int
code_d2(double d)
{
    int *i = (int *)&d0; int *j = (int *)&d;
    return (i[1] == 0x3ff00000)?j[1]:j[0];
}

void code_dconst(int e2)
{ 
    int lb;
    double d = dcadr(e2);

    if (d==0.0) {
	printf("\tfldz\n"); return;
    }
    if (d==1.0) {
	printf("\tfld1\n"); return;
    }
    printf(" \t.section\t.rodata\n\t.align 8\n");
    lb=fwdlabel();
    printf("_%d:\n",lb);
    printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d));
    if (output_mode==TEXT_EMIT_MODE) {
	printf(".text\n");
    } else {
	text_mode();
    }
    printf("\tfldl _%d\n",lb);
}

void code_dneg()
{ 
    printf("\tfchs\n");
}

void code_d2i()
{ 
    /* fuck you! */
    printf("\tlea -%d(%%esp),%%esp\n",size_of_int*2);
    printf("\tfnstcw  (%%esp)\n");
    printf("\tmovl    (%%esp), %s\n",register_name(creg,0));
    printf("\tmovb    $12, 1(%%esp)\n");
    printf("\tfldcw   (%%esp)\n");
    printf("\tmovl    %s, (%%ebp)\n",register_name(creg,0));
    printf("\tfistpl  %d(%%esp)\n",size_of_int);
    printf("\tfldcw   (%%esp)\n");
    printf("\tpopl    %s\n",register_name(creg,0));
    printf("\tpopl    %s\n",register_name(creg,0));
}

void code_i2d()
{ 
    printf("\tpushl %s\n",register_name(creg,0));
    printf("\tfildl (%%esp)\n");
    printf("\tlea %d(%%esp),%%esp\n",size_of_int);
}

void code_d2u()
{ 
    /* fuck you! */
    printf("\tlea -%d(%%esp),%%esp\n",size_of_int*3);
    printf("\tfnstcw  (%%esp)\n");
    printf("\tmovl    (%%esp), %s\n",register_name(creg,0));
    printf("\tmovb    $12, 1(%%esp)\n");
    printf("\tfldcw   (%%esp)\n");
    printf("\tmovl    %s, (%%ebp)\n",register_name(creg,0));
    printf("\tfistpll %d(%%esp)\n",size_of_int);
    printf("\tfldcw   (%%esp)\n");
    printf("\tmovl    %d(%%esp),%s\n",size_of_int,register_name(creg,0));
    printf("\tlea %d(%%esp),%%esp\n",size_of_int*3);
}

void code_u2d()
{ 
    printf("\tpushl  %s\n",register_name(creg,0));
    printf("\tpushl  %s\n",register_name(creg,0));
    printf("\tmovl   $0, %d(%%esp)\n",size_of_int);
    printf("\tfildll (%%esp)\n");
    printf("\tlea %d(%%esp),%%esp\n",size_of_int*2);
}

void code_drgvar(int e2,int d)
{ 
    printf("\t%s %s\n",fload(d),(char *)caddr(e2)) ;
}


void code_drlvar(int e2,int d)
{ 
    printf("\t%s %d(%%ebp)\n",fload(d),e2);
}

void code_cmp_drgvar(int e2)
{ 
    printf("\tfcomp %s\n",(char *)caddr(e2)) ;
}

void code_cmp_drlvar(int e2)
{ 
    printf("\tfcomp %d(%%ebp)\n",e2);
}

void dtosop(int op,int e1)
{ 
    switch(op) {
    case DADD: printf("\tfaddp %%st,%%st(1)\n"); break;
    case DSUB: printf("\tfsubp %%st,%%st(1)\n"); break;
    case DDIV: printf("\tfdivp %%st,%%st(1)\n"); break;
    case DMUL: printf("\tfmulp %%st,%%st(1)\n"); break;
    case DCOMP: 
	/* printf("\tfxch\t%%st(1)\n"); */
	printf("\tfucompp\n");
	printf("\tfnstsw\t%%ax\n");
	break;
    }
}

void
code_dassop(int op,int d) {
    /* we have lvalue in creg, applied floating value is in %st(0) */
    printf("\t%s (%s)\n",fload(d),register_name(creg,0));
    dtosop(op,0);
    printf("\t%s (%s)\n",fstore(d),register_name(creg,0));
}

void
code_dpreinc(int e1,int e2,int d) {
    g_expr(e2);
    printf("\t%s (%s)\n",fload(d),register_name(creg,0));
    printf("\tfld1\n");
    if (caddr(e1)>0)
	printf("\tfaddp %%st,%%st(1)\n");
    else
	printf("\tfsubrp %%st,%%st(1)\n");
    printf("\t%s (%s)\n",fstore(d),register_name(creg,0));
}

void
code_dpostinc(int e1,int e2,int d) {
    g_expr(e2);
    printf("\t%s (%s)\n",fload(d),register_name(creg,0));
    if (use)
	printf("\t%s (%s)\n",fload(d),register_name(creg,0));
    printf("\tfld1\n");
    if (caddr(e1)>0)
	printf("\tfaddp %%st,%%st(1)\n");
    else
	printf("\tfsubrp %%st,%%st(1)\n");
    printf("\t%s (%s)\n",(use?fstore_u(d):fstore(d)),register_name(creg,0));
}

void
drexpr(int e1, int e2,int l1, int op)
{       
    g_expr(list3(DCOMP,e1,e2));
    switch(op) {
	case DOP+GE:
	    printf("\ttestb\t$5,%%ah\n");
	    printf("\tjne\t_%d\n",l1);
	    break;
	case DOP+GT:
	    printf("\ttestb\t$69,%%ah\n");
	    printf("\tjne\t_%d\n",l1);
	    break;
	case DOP+EQ:
	    printf("\tandb\t$69,%%ah\n");
	    printf("\txorb\t$64,%%ah\n");
	    printf("\tjne\t_%d\n",l1);
	    break;
	case DOP+NEQ:
	    printf("\tandb\t$69,%%ah\n");
	    printf("\txorb\t$64,%%ah\n");
	    printf("\tje\t_%d\n",l1);
	    break;
    }
}

int dpop_register()
{ 
    return 1;
}

int emit_dpop(int e1)
{ 
    return 1;
}

void emit_dpop_free(int e1)
{ 
}

void emit_dpush()
{ 
}

/* end */