Mercurial > hg > CbC > old > device
view mc-nop-386.c @ 469:cf1c2c42b7c8
fix iassop
author | kono |
---|---|
date | Sat, 30 Jul 2005 20:54:40 +0900 |
parents | 1c2a9232ea93 |
children |
line wrap: on
line source
/* Micro-C Code Generatation Part for intel386 */ /* $Id$ */ #define EXTERN extern #include "mc.h" extern int get_register_var(void); extern void bexpr(int e1, char cond, int l1); extern void closing(void); extern void cmpdimm(int e, int csreg); extern void code_enter(char *name) ; extern void code_enter1(int args); extern void code_init(void); extern void code_leave(char *name) ; extern void leave(int control,char *name) ; extern void def_label(int cslabel, int dlabel) ; extern void emit_data(int e, int t, NMTBL *n); extern void emit_init(void); extern void enter(char *name) ; extern void enter1() ; extern void g_expr(int e1); extern void gen_comment(char *s); extern void gen_gdecl(char *n, int gpc) ; extern void gen_source(char *s); extern void gexpr(int e1); extern void jcond(int l, char cond); extern void jmp(int l); extern void opening(char *filename); extern void ret(void); extern int assign_expr0(int e,int e1,int type,int type1); extern int integral(int t); extern void tree_print_t(int e,int t); extern int rvalue_t(int e,int t); static int edx_setup() ; static int lvar(int l); static void jump(int e1, int env); static void data_mode(char *name); static void text_mode(void); static void assign(int e1); static void assop(int e1); static void b_expr(int e1, char cond, int l1,int err); static void emit_push(void); static void free_register(int i); static void function(int e1); static void global_table(void) ; /* static void indexy(char *op, char *gvar); */ /* static void jmp_eq_label(int l); */ /* static void jmp_label(int l); */ static void ld_indexx(int byte, int n, int xreg); static void local_table(void) ; static void machinop(int e1); static void rexpr(int e1, int l1, char *s); static void rindirect(int e1); static void sassign(int e1); static void shift(char *op, int xreg) ; /* static void st_indexx(int byte, int n, int xreg); */ static void string(int e1); static void tosop(int op,int reg); static void edx_cleanup(); static void use_register(int virt, int real, int move); static void emit_copy(int from,int to,int length,int offset,int value,int det); static int is_same_type(int s,int t); extern void error(int n); extern int fwdlabel(void); extern void fwddef(int l); extern int backdef(void); extern int size(int t); extern int list4(int e1, int e2, int e3,int e4); extern int list3(int e1, int e2, int e3); extern int list2(int e1, int e2); extern int scalar(int); extern int reverse0(int); extern void remove0(int *list,int element); extern int append4(int target,int t,int ty,int e1); #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; static int creg; /* current register */ static int dreg; /* temporary register */ static 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]; /* 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]] */ #define MAX_MAX 10 static int rname[MAX_MAX]; static int regs[MAX_MAX]; /* 使われているレジスタを示すフラグ */ static int reg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ static int regv[MAX_MAX]; /* 値が入っているかどうか */ 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 */ } } 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 register_full(void) { int i; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) { return 0; } } return 1; } static 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; } static 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 use_register_var(int i) { regv[i]=1; } static int creg_regvar = -1; static int creg_regvar_back; static int creg_back; void creg_destroy() { creg_back = creg; creg_regvar_back = creg_regvar; if (creg_regvar>=0) creg = creg_regvar; creg_regvar=-1; } void creg_un_destroy() { creg = creg_back; creg_regvar = creg_regvar_back; } void register_usage(char *s) { int i; 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("\n"); } void gexpr_init(void) { while(reg_sp > 0) { free_register(reg_stack[--reg_sp]); } text_mode(); use_register(creg,REG_EAX,0); regv[dreg]=0; creg_regvar = -1; register_usage("gexpr_init"); } void emit_init(void) { int i; for(i=0;i<REAL_MAX_REGISTER;i++) { regs[i]=0; regv[i]=0;rname[i]=i;} free_all_register(); reg_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; } } /* if (real_v == -1) error(-1); */ return real_v; } 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); } int pop_register(void) { /* レジスタから値を取り出す */ return reg_stack[--reg_sp]; } int stack_used(void) { return reg_stack[--reg_sp]<0; } 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; } static void emit_pop_free(int xreg) { if (xreg==dreg) { regv[dreg]=0; } else if (xreg!=-1) { free_register(xreg); } } 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 gexpr(int e1) { gexpr_init(); #if 0 if(lineno==2862) { g_expr(e1); /*break here*/ return; } #endif g_expr(e1); } int csvalue() { return rname[creg]; /* for switch value */ } void g_expr(int e1) { int e2,e3/*,e4*/; char *xrn; NMTBL *n; if (chk) return; e2 = cadr(e1); switch (car(e1)){ case GVAR: /* use_pointer(creg,0); */ printf("\tmovl $%s,%s\n",(char *)caddr(e1),register_name(creg,0)); regv[creg]=1; return; case RGVAR: /* use_pointer(creg,0); */ printf("\tmovl %s,%s\n",(char *)caddr(e1),register_name(creg,0)); regv[creg]=1; return; case CRGVAR: printf("\tmovsbl %s,%s\n",(char *)caddr(e1),register_name(creg,0)); regv[creg]=1; return; case LVAR: /* use_pointer(creg,0); */ printf("\tlea %d(%%ebp),%s\n",lvar(e2),register_name(creg,0)); regv[creg]=1; return; case REGISTER: /* this is of course redundant... */ /* we can use rname for this? */ /* or why not creg=e2? */ printf("\tmovl %s,%s\n",register_name(e2,0),register_name(creg,0)); regv[creg]=1; return; case RLVAR: printf("\tmovl %d(%%ebp),%s\n",lvar(e2),register_name(creg,0)); regv[creg]=1; return; case CRLVAR: printf("\tmovsbl %d(%%ebp),%s\n",lvar(e2),register_name(creg,0)); regv[creg]=1; return; case FNAME: printf("\tmovl $%s,%s\n",((NMTBL *)e2)->nm,register_name(creg,0)); regv[creg]=1; return; case CONST: /* 代入する値が0でも特別な処理はしない */ printf("\tmovl $%d,%s\n",e2,register_name(creg,0)); regv[creg]=1; return; case STRING: string(e1); regv[creg]=1; return; case FUNCTION: function(e1); regv[creg]=1; return; case CODE: jump(e2,caddr(e1)); return; case INDIRECT: g_expr(e2); return; case RINDIRECT: case CRINDIRECT: rindirect(e1); return; case ADDRESS: g_expr(e2); return; case MINUS: /* レジスタに対し、neglを実行すれば実現可能 */ g_expr(e2); /* use_data_reg(creg,1); */ printf("\tnegl %s\n", register_name(creg,0)); return; case BNOT: /* ~ */ g_expr(e2); /* use_data_reg(creg,1); */ printf("\tnotl %s\n", register_name(creg,0)); return; case LNOT: /* ! */ g_expr(e2); 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)); return; case PREINC: 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); return; case POSTINC: 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); return; case CPOSTINC: /* char *p; *p++ */ 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); return; case CPREINC: 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)); return; case CPOSTDEC: 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)); return; case CPREDEC: 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); return; case MUL: case UMUL: case DIV: case UDIV: case MOD: case UMOD: case LSHIFT: case ULSHIFT: case RSHIFT: case URSHIFT: case ADD: case SUB: case BAND: case EOR: case BOR: machinop(e1); return; case COND: e2=fwdlabel(); b_expr(cadr(e1),0,e2,0); use_register(creg,REG_EAX,0); g_expr(caddr(e1)); /* e4 = rname[creg]; this is a bad idea */ use_register(creg,REG_EAX,1); jmp(e3=fwdlabel()); fwddef(e2); use_register(creg,REG_EAX,0); g_expr(cadddr(e1)); /* use_register(creg,e4,1); */ use_register(creg,REG_EAX,1); fwddef(e3); return; case STASS: sassign(e1); return; case ASS: case CASS: assign(e1); return; case ASSOP: case CASSOP: assop(e1); return; case RSTRUCT: g_expr(e2); return; case COMMA: g_expr(e2); g_expr(caddr(e1)); return; case RETURN: n = (NMTBL *)e2; if (retcont==0) retcont=fwdlabel(); printf("\tleal _%d,%s\n",retcont,register_name(creg,0)); regv[creg]=1; return; case ENVIRONMENT: printf("\tmovl %%ebp,%s\n",register_name(creg,0)); regv[creg]=1; return; default: 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; } } void bexpr(int e1, char cond, int l1) { gexpr_init(); b_expr(e1,cond,l1,0); } void b_expr(int e1, char cond, int l1,int err) { int e2,l2; if (chk) return; e2=cadr(e1); switch(car(e1)) { case LNOT: b_expr(e2,!cond,l1,0); return; case GT: rexpr(e1,l1,cond?"g":"le"); return; case UGT: rexpr(e1,l1,cond?"a":"be"); return; case GE: rexpr(e1,l1,cond?"ge":"l"); return; case UGE: rexpr(e1,l1,cond?"ae":"b"); return; case LT: rexpr(e1,l1,cond?"l":"ge"); return; case ULT: rexpr(e1,l1,cond?"b":"ae"); return; case LE: rexpr(e1,l1,cond?"le":"g"); return; case ULE: rexpr(e1,l1,cond?"be":"a"); return; case EQ: rexpr(e1,l1,cond?"e":"ne"); return; case NEQ: rexpr(e1,l1,cond?"ne":"e"); return; case LAND: b_expr(e2,0,cond?(l2=fwdlabel()):l1,0); b_expr(caddr(e1),cond,l1,0); if(cond) fwddef(l2); return; case LOR: b_expr(e2,1,cond?l1:(l2=fwdlabel()),0); b_expr(caddr(e1),cond,l1,0); if(!cond) fwddef(l2); return; case CRGVAR: printf("\tcmpb $0,%s\n",(char *)caddr(e1)); jcond(l1,cond); return; case CRLVAR: printf("\tcmpb $0,%d(%%ebp)\n",lvar(e2)); jcond(l1,cond); return; case RGVAR: printf("\tcmpl $0,%s\n",(char *)caddr(e1)); jcond(l1,cond); return; case RLVAR: printf("\tcmpl $0,%d(%%ebp)\n",lvar(e2)); jcond(l1,cond); return; case REGISTER: printf("\tcmpl $0,%s\n",register_name(e2,0)); jcond(l1,cond); return; case CONST: if((cond&&e2)||(!cond&&!e2)) jmp(l1); return; default: if(err) { error(-1); return; /* recursice g_expr/b_expr */ } g_expr(e1); printf("\tcmpl $0,%s\n",register_name(creg,0)); jcond(l1,cond); return; } } 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; } /* goto arguments list */ /* target list4(list2(tag,disp),cdr,ty,source_expr) */ /* source expr=listn(tag,...) */ /* source (after) list2(tag,disp) */ /* source list list3(e,cdr,sz) */ #define DEBUG_PARALLEL_ASSIGN 1 int overrap(int t,int sz,int source) { int s,s0,s1; int t0=cadr(t); int t1=t0+sz; for(;source;source=cadr(source)) { s=car(source); s0=cadr(s); if(car(s)==REGISTER && car(t)==REGISTER) { if(s0==t0) return s; } else if (is_same_type(s,t)) { s1=s0+caddr(source); #if DEBUG_PARALLEL_ASSIGN>1 printf("# ovedrrap source %d t0 %d t1 %d\n",car(car(t)),t0,t1); printf("# ovedrrap target %d s0 %d s1 %d\n",car(car(source)),s0,s1); printf("# ovedrrap equal = %d\n",((t0<=s0&&s0<t1)||(t0<s1&&s1<=t1))); #endif if((t0<=s0&&s0<t1)||(t0<s1&&s1<=t1)) return s; } } return 0; } void remove_target(int *target,int t,int *use) { int use0=*use; while(use0) { if (car(use0)==t) { free_register(caddr(use0)); break; } use0 = cadr(use0); } remove0(target,t); } void save_target(int t,int s,int *target,int *use,int sz,int ty) { int e1; /*新しいレジスタ(or スタック)を取得する*/ if (sz==size_of_int && (e1=get_register())!=-1) { *use=list3(t,*use,e1); e1=list2(REGISTER,e1); g_expr(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); } else { disp-=sz; g_expr(assign_expr0((e1=list2(LVAR,disp)),s,ty,ty)); *target = append4(*target,t,ty,e1); } } int circular_dependency(int t,int s,int *target,int *source) { int target0=*target; int t1,sz,ty,s1; while(target0) { if (cadddr(target0)==s) { t1=car(target0); s=cadddr(target0); sz=size(ty=caddr(target0)); if(t==t1) { #if DEBUG_PARALLEL_ASSIGN printf("# circular dependency %d ty %d+%d sz %d\n",car(t1),ty,cadr(t1),sz); #endif return 1; } if ((s1=overrap(t1,sz,*source))) { /* another overrap start over */ return circular_dependency(t,s1,target,source); } } target0=cadr(target0); } return 0; } void parallel_assign(int *target,int *source,int *processing,int *use) { int t,s,sz,ty,target0,s1; while(*target) { target0=*target; while(target0) { t=car(target0); s=cadddr(target0); sz=size(ty=caddr(target0)); if(car(t)==car(s) && cadr(t)==cadr(s)) { /*書き込み先が自分自身*/ #if DEBUG_PARALLEL_ASSIGN printf("# remove same %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); #endif remove_target(target,t,use); /* 破壊されては困るので、source listからは除かない */ } else if (!(s1=overrap(t,sz,*source))) { /* 重なってないので安心して書き込める */ #if DEBUG_PARALLEL_ASSIGN printf("# normal assign %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); #endif g_expr(assign_expr0(t,s,ty,ty)); remove_target(target,t,use); remove0(source,s); } else { if(circular_dependency(t,s1,target,source)) { #if DEBUG_PARALLEL_ASSIGN printf("# saving %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); #endif remove_target(target,t,use); remove0(source,s); save_target(t,s,target,use,sz,ty); } } target0=cadr(target0); } } } void remove0(int *parent,int e) { int list; while ((list=*parent)) { if (car(list)==e) { *parent= cadr(list); return; } else { parent=&cadr(list); } } } void remove0_all(int *parent,int e) { int list; while ((list=*parent)) { if (car(list)==e) { *parent= cadr(list); } else { parent=&cadr(list); } } } int is_simple(int e1) { return ( e1==CONST || e1==FNAME || e1==LVAR || e1==REGISTER || e1==GVAR || e1==RGVAR || e1==RLVAR || e1==CRLVAR || e1==CRGVAR ); } int is_same_type(int e1,int e2) { int ce1=car(e1); int ce2=car(e2); return ( (ce1==LVAR && (ce2==RLVAR||ce2==CRLVAR)) || (ce2==LVAR && (ce1==RLVAR||ce1==CRLVAR)) || (ce1==GVAR && (ce2==RGVAR||ce2==CRGVAR)) || (ce2==GVAR && (ce1==RGVAR||ce1==CRGVAR)) ); } int is_memory(int e1) { int ce1=car(e1); return ( ce1==LVAR ||ce1==RLVAR||ce1==CRLVAR || ce1==GVAR ||ce1==RGVAR||ce1==CRGVAR || ce1==REGISTER ); } void jump(int e1, int env) { int e2,e3,e4,sz,arg_size,ty,max_regs,regs; int t0,s0; NMTBL *code0; int target = 0; int source = 0; int processing = 0; int use = 0; /* まず、サイズを計算しながら、決まった形に落す。 */ arg_size = 0; regs = 0; max_regs = MAX_REGISTER_VAR-1; for (e3 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) { e2 = car(e3); sz = size(ty=caddr(e3)); if (regs <= max_regs&&scalar(ty)) { target=list4(list2(REGISTER,virtual((regs++)+REG_ESI)), target,ty,e2); } else { target=list4(list2(LVAR,0), target,ty,e2); arg_size += sz; } #if DEBUG_PARALLEL_ASSIGN printf("# target %d ty %d+%d sz %d\n",car(car(target)),ty,cadr(car(target)),sz); #endif } /* disp を飛び先似合わせて修正 */ if (fnptr->sc==CODE) { if (-arg_size<disp) disp = -arg_size; jump_offset = 0; } else { if (disp_offset-arg_size<disp) disp = disp_offset-arg_size; jump_offset = 0; } /* 複雑な式を前もって計算しておく */ /* 必要なら局所変数を用いる。 */ /* 局所変数へのオフセットを覚えておく */ for (e2 = target; e2; e2 = cadr(e2)) { t0=car(e2); s0=cadddr(e2); sz=size(ty=caddr(e2)); if(car(t0)==LVAR) { /* ここで、書込先アドレスを決める */ cadr(t0)=-arg_size+jump_offset; arg_size-=sz; } if (!is_simple(car(s0))) { disp-=sz; g_expr(assign_expr0((e4=list2(LVAR,disp)),s0,ty,ty)); cadddr(e2)=e4; s0=e4; } else if (is_same_type(t0,s0)) { if(cadr(t0)==cadr(s0)) { #if DEBUG_PARALLEL_ASSIGN printf("# remove same memory %d ty %d+%d sz %d\n",car(t0),ty,cadr(t0),sz); #endif /* we should check size also (but currently useless */ remove0(&target,t0); /* still we have source to avoid overwrite */ } } if(is_memory(s0)) { source=list3(s0,source,sz); #if DEBUG_PARALLEL_ASSIGN printf("# source %d ty %d+%d sz %d\n",car(car(source)),ty,cadr(car(source)),sz); #endif } } /* compute jump address */ e2 = cadr(e1); if (car(e2) == FNAME) { code0=(NMTBL *)cadr(e2); if (code0->sc!=CODE) { error(TYERR); return; } } else { /* indirect */ g_expr(e2); emit_push(); } if (env) { g_expr(env); emit_push(); } /* 並列代入を実行 */ parallel_assign(&target,&source,&processing,&use); while (use) { free_register(caddr(use)); use=cadr(use); } if(target) error(-1); if (env) { /* change the frame pointer */ e3 = emit_pop(0); printf("\tmovl %s,%%ebp\n",register_name(e3,0)); emit_pop_free(e3); } else if (fnptr->sc==FUNCTION) { printf("\tlea %d(%%ebp),%%ebp\n",disp_offset); } if (car(e2) == FNAME) { printf("\tjmp %s\n",code0->nm); } else { e2 = emit_pop(0); printf("\tjmp *%s\n",register_name(e2,0)); emit_pop_free(e2); } } void machinop(int e1) { int e2,e3,op; e2 = cadr(e1); op = car(e1); e3 = caddr(e1); g_expr(e3); emit_push(); g_expr(e2); tosop(car(e1),(e2=pop_register())); emit_pop_free(e2); regv[creg]=1; return; } 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)); } void sassign(int e1) { int e2,e3,e4,sz,xreg,det; /* structure assignment */ e2 = cadr(e1); /* pointer variable to the struct */ e3 = cadr(e2); /* offset of the variable (distination) */ e4 = caddr(e1); /* right value (source) */ sz = cadddr(e1); /* size of struct or union */ g_expr(e4); emit_push(); g_expr(e2); xreg = emit_pop(0); /* 一般的にはコピーのオーバラップの状況は実行時にしかわからない */ /* しかし、わかる場合もある */ if (car(e4)==RSTRUCT) e4=cadr(e4); if (is_same_type(e2,e4)) { if(cadr(e2)<cadr(e4)) sz=-sz; det=1; } else { det = 0; } emit_copy(xreg,creg,sz,0,1,det); emit_pop_free(xreg); return; } void assign(int e1) { char *op; int e2,e3,e4,byte; op = ((byte=(car(e1) == CASS))? "movb" : "movl"); /* e2=e4 */ e2 = cadr(e1); e3 = cadr(e2); e4 = caddr(e1); switch(car(e2)) { case GVAR: /* i=3 */ g_expr(e4); if (byte) use_data_reg(creg,1); printf("\t%s %s,%s\n",op,register_name(creg,byte),(char *)caddr(e2)); return; case LVAR: g_expr(e4); if (byte) use_data_reg(creg,1); printf("\t%s %s,%d(%%ebp)\n",op,register_name(creg,byte),lvar(cadr(e2))); return; case REGISTER: g_expr(e4); if (creg!=cadr(e2)) printf("\tmovl %s,%s\n",register_name(creg,0),register_name(cadr(e2),0)); return; } g_expr(e2); emit_push(); use_data_reg(creg,0); g_expr(e4); if (byte) use_data_reg(creg,1); e2 = emit_pop(0); printf("\t%s %s,(%s)\n",op,register_name(creg,byte),register_name(e2,0)); emit_pop_free(e2); regv[creg]=1; return; } void assop(int e1) { int e2,e3,byte,op,reg; char *xrn; int xreg,edx; /* e2 op= e3 */ byte = (car(e1) == CASSOP); e2 = cadr(e1); if (car(e2)==INDIRECT) e2=cadr(e2); e3 = caddr(e1); op = cadddr(e1); g_expr(e3); if (car(e2)==REGISTER) { xreg = creg; creg = reg = cadr(e2); tosop(op,xreg); creg = xreg; printf("\tmovl %s,%s\n",register_name(reg,0),register_name(creg,0)); regv[creg]=1; return; } emit_push(); g_expr(e2); 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); regv[creg]=1; return; } 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); */ } int fwdlabel(void) { return labelno++; } void fwddef(int l) { control=1; printf("_%d:\n",l); } int backdef(void) { control=1; printf("_%d:\n",labelno); return labelno++; } void def_label(int cslabel, int dlabel) { int fl; fl = 0; if (control) { jmp(fl=fwdlabel()); } fwddef(cslabel); if (dlabel) jmp(dlabel); if (fl) { fwddef(fl); } } void gen_comment(char *s) { printf("## %s",s); } void gen_source(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) { disp=(disp-(size_of_int-1))&(-(size_of_int-1)); 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"); disp=(disp-(size_of_int-1))&(-(size_of_int-1)); 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 ret(void) { use_register(creg,REG_EAX,1); jmp(retlabel); } 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 */