Mercurial > hg > CbC > old > device
diff mc-code-ia32.c @ 61:8ffb8ca3fe34
separation of architecture dependent part.
author | kono |
---|---|
date | Thu, 20 Feb 2003 03:29:15 +0900 |
parents | |
children | 129f4802b027 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mc-code-ia32.c Thu Feb 20 03:29:15 2003 +0900 @@ -0,0 +1,1304 @@ +/* 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 endian = 0; +int MAX_REGISTER=6; /* intel386のレジスタを4つまで使う*/ +int REAL_MAX_REGISTER=8; /* intel386のレジスタが8つということ*/ +int MAX_DATA_REG=4; +int MAX_POINTER=3; +int MAX_REGISTGER_VAR=2; + +EXTERN int creg; /* current register */ +EXTERN int dreg; /* temporary register */ +EXTERN int reg_sp; /* REGister Stack-Pointer */ + + +#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]; + +extern int creg; /* current register */ +extern int dreg; /* temporary register */ +extern int reg_sp; /* REGister Stack-Pointer */ + +#define MAX_MAX 10 +int rname[MAX_MAX]; +int regs[MAX_MAX]; /* 使われているレジスタを示すフラグ */ +int reg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ +int regv[MAX_MAX]; /* 値が入っているかどうか */ + + +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 global_table(void); +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); +void emit_push_x(int xreg); +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 opening(char *filename); +void code_leave(char *name); +int lvar(int l); + +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 */ + } +} + +extern int rname[MAX_MAX]; +extern int regs[MAX_MAX]; /* 使われているレジスタを示すフラグ */ +extern int reg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ +extern int regv[MAX_MAX]; /* 値が入っているかどうか */ + +extern int creg_regvar; + +void +gexpr_code_init(void){ + use_register(creg,REG_EAX,0); + regv[dreg]=0; + creg_regvar = -1; +} + +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) { /* もうレジスタがない */ + 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; + } +} + +void +emit_push_x(int xreg) +{ + int new_reg; + new_reg = get_register(); + if(new_reg<0) { /* もうレジスタがない */ + reg_stack[reg_sp++] = -1; + printf("\tpushl %s\n",register_name(xreg,0)); + /* creg is used soon, don't regv[xreg]=0 */ + } else { + reg_stack[reg_sp++] = xreg; /* push するかわりにレジスタを使う */ + xreg = new_reg; + regv[xreg]=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",lvar(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; + g_expr(e4); + length=size(t); + if(length%size_of_int) { + length += size_of_int - (length%size_of_int); + } + if (length==4) { + printf("\tpushl (%s)\n",register_name(creg,0)); return 1; + } + if (length==8) { + printf("\tpushl 4(%s)\n",register_name(creg,0)); + printf("\tpushl (%s)\n",register_name(creg,0)); return 2; + } + 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 (car(t)==STRUCT||car(t)==UNION) { + nargs += struct_push(e4,t); + continue; + } else { + error(TYERR); + } + ++nargs; + } + if (car(e2) == FNAME) { + n=(NMTBL *)cadr(e2); + } else { + use_register(creg,REG_EAX,0); + g_expr(e2); + } + + /* we don't have to save creg nor dreg */ + regs[creg]=0; regs[dreg]=0; + regv[creg]= regv[dreg]= regv[save]= 0; + use_register(creg,REG_EAX,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; +} + +void +code_frame_pointer(int e3) { + printf("\tmovl %s,%%ebp\n",register_name(e3,0)); +} + + +void +code_fix_frame_pointer(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; + + op = ((byte = (car(e1) == CRINDIRECT)) ? "movsbl" : "movl"); + e3 = cadr(e2 = cadr(e1)); + g_expr(e2); + 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() */ + use_register(creg,csreg,0); + printf("\tcmpl $%d,%s\n",e,register_name(creg,0)); +} + +void +opening(char *filename) +{ + printf("\t.file \"%s\"\n",filename); + printf("\t.version\t\"01.01\"\n"); + printf("gcc2_compiled.:\n"); + printf(".text\n"); + emit_init(); +} + +void +closing(void) +{ + 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) +{ + printf("\tj%s\t_%d\n",cond?"ne":"e",l); +} + +void +jmp(int l) +{ + control=0; + 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) +{ + 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) +{ + 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); */ + 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; + char *name; + name = n->nm; + if(mode!=GDECL) { + error(-1); 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 { + printf("\t.long %d\n",cadr(e)); + gpc += size_of_int; + } + } 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 (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; + } +} + +/* end */