Mercurial > hg > CbC > old > device
view mc-code-ia32.c @ 133:7d436c08e949
separate float / double flow
author | kono |
---|---|
date | Fri, 02 May 2003 14:26:54 +0900 |
parents | d497c39add36 |
children | 069960078249 |
line wrap: on
line source
/* Micro-C Code Generatation Part for intel386 */ /* $Id$ */ #define EXTERN extern #include "mc.h" #include "mc-codegen.h" #include "mc-code.h" #define SAVE_STACKS 1 #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; 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つまで使う*/ #define 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 MAX_FPU_STACK 7 int MAX_INPUT_REGISTER_VAR = 0; int MAX_CODE_INPUT_REGISTER_VAR = 2; int MAX_INPUT_DREGISTER_VAR = 0; int MAX_CODE_INPUT_DREGISTER_VAR = 0; /* -28 -8 local2 -24 -4 local1 -20 8 arg3 -16 4 arg2 -12 0 arg1 local2 -20 4 -8 (%edi) local1 <-- -16 0 local variable -4 (%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; static int code_disp_label; static int func_disp_label; static int lvar(int l) { if (is_code(fnptr)) { return l+code_disp_offset; } else if (l<0) { return l+disp_offset; } else { return l+arg_offset; } } /* creg currrent virtual register dreg spare virtual register rname[creg] currrent real register rname[dreg] spare real register regs[] virtual register usage regv[] value in virtual register flag reg_name[rname[creg]] freg current floating point register fregv calue in floating point register */ static int dreg; /* general temporal register */ int ia32regs[REAL_MAX_REGISTER]; int ia32regv[REAL_MAX_REGISTER]; int ia32rname[REAL_MAX_REGISTER]; int *regv = ia32regv; int *regs = ia32regs; static int *rname = ia32rname; int ia32fregs[1]; int ia32fregv[1]; int freg; int *fregv = ia32fregv; int *fregs = ia32fregs; #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]; static void use_register(int virt, int real, int move); static int virtual(int real); static void shift(char *op, int reg); static void ld_indexx(int byte, int n, int xreg); static void data_mode(char *name); static int edx_setup(); static void edx_cleanup(); static void local_table(void); static char * fload(int d); static int code_d1(double d); static int code_d2(double d); static void code_save_stacks(); static void code_save_fstacks(); 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[creg]=0; regv[dreg]=0; } int register_var(int r) { return virtual(r+REG_ESI); } int get_register(void) { /* 使われていないレジスタを調べる */ int i; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) { /* 使われていないなら */ regs[i]=1; /* そのレジスタを使うことを宣言し */ return i; /* その場所を表す番号を返す */ } } return -1; /* 空いている場所がないなら、それを表す -1 を返す */ } void free_register(int i) { /* いらなくなったレジスタを開放 */ regv[i]=regs[i]=0; } int get_input_register_var(int i,NMTBL *nptr,int is_code) { if (is_code) { if (i>=MAX_CODE_INPUT_REGISTER_VAR) return 0; i = virtual(i+REG_ESI); regs[i]=regv[i]=1; return list3(REGISTER,i,(int)nptr); } else { return 0; } } int get_input_fregister_var(int i,NMTBL *nptr,int is_code) { return 0; } int get_fregister(void) { return -1; } void free_fregister(int i) { error(-1); } int register_full(void) { int i; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) { return 0; } } return 1; } int free_register_count(void) { int i,count; count = 0; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i] && ! regv[i]) count++; } return count; } void free_all_register(void) { int i; for(i=0;i<MAX_REGISTER;i++) { regs[i]=regv[i]=0; } creg = get_register(); dreg = get_register(); return; } void register_usage(char *s) { int i; if (chk) return; printf("# %d: %s:",lineno,s); printf(" creg=%s dreg=%s ",register_name(creg,0),register_name(dreg,0)); for(i=0;i<MAX_REGISTER;i++) { printf("%d",regs[i]); } printf(":"); for(i=0;i<MAX_REGISTER;i++) { printf("%d",regv[i]); } #if 0 printf(" regs_stack",register_name(creg,0),register_name(dreg,0)); for(i=reg_sp;i>=0;i--) { if(reg_stack[i]>=0) printf(" %s",register_name(reg_stack[i],0)); } #endif printf(" f:%d",freg_sp); printf("\n"); } void code_arg_register() { } void gexpr_init(void) { while(reg_sp > 0) { if (reg_stack[--reg_sp]>=0) free_register(reg_stack[reg_sp]); } freg_sp = 0; text_mode(); gexpr_code_init(); register_usage("gexpr_init"); } void emit_init(void) { int i; for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; regv[i]=0;rname[i]=i;} free_all_register(); reg_sp = 0; freg_sp = 0; text_mode(); } int virtual(int real) { int real_v,i; real_v = -1; for(i=0;i<MAX_REGISTER;i++) { if (rname[i]==real) { real_v=i; break; } } return real_v; } int pop_register(void) { /* レジスタから値を取り出す */ return reg_stack[--reg_sp]; } void emit_pop_free(int xreg) { if (xreg==dreg) { regv[dreg]=0; } else if (xreg>=0) { free_register(xreg); } } int get_register_var(NMTBL *nptr) { int i; for(i=REG_ESI;i<REG_ESP;i++) { if (! regs[i]) { /* 使われていないなら */ regs[i]=1; /* そのレジスタを使うことを宣言し */ regv[i]=0; return list3(REGISTER,i,(int)nptr); /* その場所を表す番号を返す */ } } return list2(LVAR,new_lvar(size_of_int)); } int get_fregister_var(NMTBL *nptr) { return list2(LVAR,new_lvar(size_of_double)); } 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() { 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"); error(-1); } printf("\tpopl %s\n",register_name(dreg,0)); regv[dreg]=1; return dreg; } else if (xreg<= -REG_LVAR_OFFSET) { code_rlvar(xreg+REG_LVAR_OFFSET,dreg); free_lvar(xreg+REG_LVAR_OFFSET); regv[dreg]=1; return dreg; } return xreg; } void code_label(int labelno) { printf("_%d:\n",labelno); } void code_gvar(int e1,int creg) { printf("\tmovl $%s,%s\n",((NMTBL*)cadr(e1))->nm,register_name(creg,0)); regv[creg]=1; } void code_rgvar(int e1,int creg) { printf("\tmovl %s,%s\n",((NMTBL*)cadr(e1))->nm,register_name(creg,0)); regv[creg]=1; } void code_crgvar(int e1,int creg){ printf("\tmovsbl %s,%s\n",((NMTBL*)cadr(e1))->nm,register_name(creg,0)); regv[creg]=1; } void code_lvar(int e2,int creg) { printf("\tlea %d(%%ebp),%s\n",lvar(e2),register_name(creg,0)); regv[creg]=1; } void code_register(int e2,int creg) { printf("\tmovl %s,%s\n",register_name(e2,0),register_name(creg,0)); regv[creg]=1; } void code_rlvar(int e2,int reg) { printf("\tmovl %d(%%ebp),%s\n",lvar(e2),register_name(reg,0)); regv[creg]=1; } void code_crlvar(int e2,int reg) { printf("\tmovsbl %d(%%ebp),%s\n",lvar(e2),register_name(reg,0)); regv[creg]=1; } void code_fname(NMTBL *n,int creg) { printf("\tmovl $%s,%s\n",n->nm,register_name(creg,0)); regv[creg]=1; } void code_const(int e2,int creg) { printf("\tmovl $%d,%s\n",e2,register_name(creg,0)); regv[creg]=1; } void code_neg(int creg) { printf("\tnegl %s\n", register_name(creg,0)); } void code_not(int creg) { printf("\tnotl %s\n", register_name(creg,0)); } void code_lnot(int creg) { 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,int reg) { 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(reg,0)); regv[reg]=1; 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,int reg) { char *xrn; if (car(e2)==REGISTER) { printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(reg,0)); printf("\taddl $%d,%s\n",caddr(e1),register_name(cadr(e2),0)); regv[reg]=1; 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,int reg) { char *xrn; if (car(e2)==REGISTER) { printf("\tmovbl (%s),%s\n",register_name(cadr(e2),0), register_name(reg,0)); printf("\taddl $%d,%s\n",caddr(e1),register_name(cadr(e2),0)); regv[reg]=1; 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,int reg) { if (car(e2)==REGISTER) { printf("\taddl $%d,%s\n",caddr(e1),register_name(cadr(e2),0)); printf("\tmovsbl (%s),%s\n",register_name(cadr(e2),0), register_name(reg,0)); regv[reg]=1; 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,int reg) { if (car(e2)==REGISTER) { printf("\tmovsbl (%s),%s\n",register_name(cadr(e2),0), register_name(reg,0)); printf("\tdecl %s\n",register_name(cadr(e2),0)); regv[reg]=1; 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,int reg) { if (car(e2)==REGISTER) { printf("\tdecl %s\n",register_name(cadr(e2),0)); printf("\tmovsbl (%s),%s\n",register_name(cadr(e2),0), register_name(reg,0)); regv[reg]=1; 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(int creg) { printf("\tleal _%d,%s\n",retcont,register_name(creg,0)); regv[creg]=1; } void code_environment(int creg) { printf("\tmovl %%ebp,%s\n",register_name(creg,0)); regv[creg]=1; } 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); regv[creg]=1; } 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",((NMTBL*)cadr(e1))->nm); } void code_cmp_crlvar(int e1) { printf("\tcmpb $0,%d(%%ebp)\n",lvar(e1)); } void code_cmp_rgvar(int e1) { printf("\tcmpl $0,%s\n",((NMTBL*)cadr(e1))->nm); } void code_cmp_rlvar(int e1) { printf("\tcmpl $0,%d(%%ebp)\n",lvar(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 code_string(int e1,int creg) { 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; } int function(int e1) { int e2,e3,e4,nargs,t,ret_type; NMTBL *n=0; int save,saved; ret_type = cadddr(e1); #ifdef SAVE_STACKS code_save_stacks(); #endif 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); 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; if (ret_type==DOUBLE||ret_type==FLOAT) { fregv[freg]=1; regv[creg]=0; } else if (ret_type==VOID) { fregv[freg]=0; regv[creg]=0; } else { fregv[freg]=0; regv[creg]=1; } return ret_type; } 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)); } int rindirect(int e1) /* *(p +5 ) */ { char *op; int e2,e3,byte,t; 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)); t=DOUBLE; break; case CRINDIRECT: case RINDIRECT: default: op = ((byte = (car(e1) == CRINDIRECT)) ? "movsbl" : "movl"); printf("\t%s (%s),%s\n",op,register_name(creg,0),register_name(creg,0)); t=byte?CHAR:INT; } return t; } char * move(int byte) { return byte?"movb":"movl"; } void code_assign_gvar(int e2,int creg,int byte) { if (byte) use_data_reg(creg,1); printf("\t%s %s,%s\n",move(byte),register_name(creg,byte),((NMTBL*)cadr(e2))->nm); } void code_assign_lvar(int e2,int creg,int byte) { if (byte) use_data_reg(creg,1); printf("\t%s %s,%d(%%ebp)\n",move(byte),register_name(creg,byte),lvar(e2)); } void code_assign_register(int e2,int byte,int creg) { printf("\tmovl %s,%s\n",register_name(creg,0),register_name(e2,0)); } void code_assign(int e2,int byte,int creg) { if (byte) use_data_reg(creg,1); 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; } else if (oreg<= -REG_LVAR_OFFSET) { code_rlvar(oreg+REG_LVAR_OFFSET,dreg); free_lvar(oreg+REG_LVAR_OFFSET); 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: case CMP: 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\tidivl %s\n",orn); else printf("\txor %%edx,%%edx\n\tdivl %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\tidivl %s\n",orn); else printf("\txor %%edx,%%edx\n\tdivl %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); else if (oreg==dreg) regv[dreg]=0; } 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 if (reg<= -REG_LVAR_OFFSET) { use_register(dreg,REG_ECX,0); code_rlvar(reg+REG_LVAR_OFFSET,dreg); reg = dreg; regv[dreg]=0; } else { use_register(dreg,REG_ECX,0); printf("\tpopl %%ecx\n"); regv[dreg]=0; } 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)); } int code_csvalue() { return rname[creg]; /* for switch value */ } void code_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,int t) { g_expr(list3(CMP,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) { int sz; disp &= -size_of_int; if (control) code_set_return_register(1); if (retcont) { if (control) jmp(retlabel); fwddef(retcont); if (cadr(fnptr->ty)==FLOAT||cadr(fnptr->ty)==DOUBLE) { printf("\tfldl %d(%%ebp)\n",-size_of_double); } else if (cadr(fnptr->ty)>0&&( car(cadr(fnptr->ty))==STRUCT || car(cadr(fnptr->ty))==UNION)) { sz = size(cadr(fnptr->ty)); printf("\tlea %d(%%ebp),%s\n",-sz,register_name(dreg,0)); printf("\tmovl %d(%%ebp),%s\n",disp-size_of_int, register_name(creg,0)); emit_copy(dreg,creg,sz,0,1,1); } else if (cadr(fnptr->ty)!=VOID) { use_register(creg,REG_EAX,0); printf("\tmovl %s,%s\n",reg_name[REG_ESI],register_name(creg,0)); } } fwddef(retlabel); 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,int type) { if (type==FLOAT||type==DOUBLE) { } else use_register(creg,REG_EAX,mode); } void code_set_return_register(int mode) { if (fnptr->ty==DOUBLE||fnptr->ty==FLOAT) { } else { 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",((NMTBL *)cadr(cadr(e)))->nm); } else if(car(e)==GVAR) { printf("\t.long %s\n",((NMTBL *)cadr(e))->nm); } 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->sc == STATIC) && 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); } /* 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 freg,int d) { printf("\t%s %s\n",fstore(d),((NMTBL*)cadr(e2))->nm); } void code_dassign_lvar(int e2,int freg,int d) { printf("\t%s %d(%%ebp)\n",fstore(d),lvar(e2)); } void code_dassign_fregister(int e,int d,int freg) { error(-1); } void code_dassign(int e2,int freg,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 freg) { 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_fconst(int e2,int freg) { code_dconst(e2,freg); } void code_dneg(int freg) { printf("\tfchs\n"); } void code_fneg(int freg) { code_dneg(freg); } void code_d2i(int freg,int creg) { 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("\tfistpl %d(%%esp)\n",size_of_int); printf("\tmovl %s, (%%esp)\n",register_name(creg,0)); printf("\tfldcw (%%esp)\n"); printf("\tpopl %s\n",register_name(creg,0)); printf("\tpopl %s\n",register_name(creg,0)); } void code_i2d(int creg,int freg) { printf("\tpushl %s\n",register_name(creg,0)); printf("\tfildl (%%esp)\n"); printf("\tlea %d(%%esp),%%esp\n",size_of_int); } void code_d2u(int freg,int creg) { 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, (%%esp)\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(int creg,int freg) { 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_d2f(int freg) { } void code_f2d(int freg) { } void code_f2i(int freg,int creg) { code_d2i(freg,creg); } void code_f2u(int freg,int creg) { code_d2u(freg,creg); } void code_i2f(int creg,int freg) { code_i2d(creg,freg); } void code_u2f(int creg,int freg) { code_u2d(creg,freg); } void code_drgvar(int e2,int d,int freg) { printf("\t%s %s\n",fload(d),((NMTBL*)cadr(e2))->nm); } void code_drlvar(int e2,int d,int freg) { printf("\t%s %d(%%ebp)\n",fload(d),lvar(e2)); } void code_cmp_drgvar(int e2) { printf("\tfcomp %s\n",((NMTBL*)cadr(e2))->nm); } void code_cmp_drlvar(int e2) { printf("\tfcomp %d(%%ebp)\n",lvar(e2)); } void dtosop(int op,int e1) { switch(op) { case FADD: case DADD: printf("\tfaddp %%st,%%st(1)\n"); break; case FSUB: case DSUB: printf("\tfsubp %%st,%%st(1)\n"); break; case FDIV: case DDIV: printf("\tfdivp %%st,%%st(1)\n"); break; case FMUL: case DMUL: printf("\tfmulp %%st,%%st(1)\n"); break; case FCMP: case DCMP: 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) */ emit_dpop(d); /* do nothing for 387 */ 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,int freg) { 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,int freg) { 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(DCMP,e1,e2)); switch(op) { case DOP+GE: case FOP+GE: printf("\ttestb\t$5,%%ah\n"); printf("\tjne\t_%d\n",l1); break; case DOP+GT: case FOP+GT: printf("\ttestb\t$69,%%ah\n"); printf("\tjne\t_%d\n",l1); break; case DOP+EQ: case FOP+EQ: printf("\tandb\t$69,%%ah\n"); printf("\txorb\t$64,%%ah\n"); printf("\tjne\t_%d\n",l1); break; case DOP+NEQ: case FOP+NEQ: printf("\tandb\t$69,%%ah\n"); printf("\txorb\t$64,%%ah\n"); printf("\tje\t_%d\n",l1); break; } } void code_fregister(int e2,int freg) { error(-1); } void code_cmp_fregister(int r) { error(-1); } int pop_fregister() { if (freg_sp<0) { error(-1); return -1;} printf("# fpop: %d\n",freg_sp-1); return freg_stack[--freg_sp]; } int emit_dpop(int type) { int xreg; if ((xreg=pop_fregister())==-1) { } else if (xreg<= -REG_LVAR_OFFSET) { code_drlvar(REG_LVAR_OFFSET+xreg,1,freg); free_lvar(xreg+REG_LVAR_OFFSET); /* pushed order is reversed. We don't need this for comutable operator, but it is ok to do this. */ printf("\tfxch\t%%st(1)\n"); } return xreg; } void emit_dpop_free(int e1) { } void emit_dpush(int type) { if (freg_sp>=MAX_FPU_STACK) code_save_fstacks(); if (freg_sp>MAX_MAX) error(-1); freg_stack[freg_sp++]=-1; printf("# fpush:%d\n",freg_sp); } void code_save_stacks() { /* temporal registers or stacks in fpu are saved in local variable */ int xreg,sp,screg; sp=reg_sp; while(sp-->0) { if ((xreg=reg_stack[sp])>=0) { screg=creg; if(creg!=xreg) { if (xreg!=dreg) free_register(xreg); creg = xreg; } code_assign_lvar( (reg_stack[sp]=new_lvar(size_of_int)),creg,0); reg_stack[sp]= reg_stack[sp]-REG_LVAR_OFFSET; regv[xreg]=0; creg=screg; } } code_save_fstacks(); } void code_save_fstacks() { int xreg,sp,uses; uses = use; use = 0; sp=freg_sp; while(sp-->0) { if ((xreg=freg_stack[sp])==-1) { code_dassign_lvar( (freg_stack[sp]=new_lvar(size_of_double)),freg,1); freg_stack[sp]= freg_stack[sp]-REG_LVAR_OFFSET; } } use = uses; } /* end */