Mercurial > hg > CbC > old > device
view mc-code-ia32.c @ 443:f2d2e27a00a0 inline-before
minor fix
author | kono |
---|---|
date | Sun, 21 Nov 2004 01:27:21 +0900 |
parents | a531bbf572e3 |
children | 8bec605d1701 |
line wrap: on
line source
/* Micro-C Code Generation Part for intel386 */ /* $Id$ */ #include <stdio.h> #include "mc.h" #include "mc-parse.h" #include "mc-codegen.h" #include "mc-code.h" char *l_include_path[] = { "/usr/include/", "/usr/include/linux/", "/usr/include/diet/", "/usr/lib/gcc-lib/i386-linux/2.95.4/include/", "/usr/lib/gcc-lib/i386-redhat-linux/2.96/include/", "/usr/lib/dietlibc/include/", 0 }; int data_alignment = 0; #define SIZE_OF_INT 4 #define SIZE_OF_SHORT 2 #define SIZE_OF_FLOAT 4 #define SIZE_OF_DOUBLE 8 #define SIZE_OF_LONGLONG 8 #define ENDIAN 0 #define ENDIAN_L 0 #define ENDIAN_D 0 #define SAVE_STACKS 1 #define TEXT_EMIT_MODE 0 #define DATA_EMIT_MODE 1 #define RODATA_EMIT_MODE 2 #define DOT_SIZE 1 static int output_mode = TEXT_EMIT_MODE; static int creg; static int lreg; int code_lassop_p = 0; static int MAX_REGISTER=6; /* intel386のレジスタを6つまで使う*/ #define REAL_MAX_REGISTER 8 /* intel386のレジスタが8つということ*/ static int MAX_DATA_REG=4; static int MAX_POINTER=3; int MAX_REGISTER_VAR=2; // static int MAX_FREGISTER=1; #define MAX_FPU_STACK 7 #define REG_VAR 3 // static int MAX_INPUT_REGISTER_VAR = 0; static int MAX_CODE_INPUT_REGISTER_VAR = 2; // static int MAX_INPUT_DREGISTER_VAR = 0; // static int MAX_INPUT_FREGISTER_VAR = 0; // static int MAX_CODE_INPUT_DREGISTER_VAR = 0; static int reg_sp; /* REGister Stack-Pointer */ static int reg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ static int stack_depth = 0; /* floating point registers */ static int freg_sp; /* floating point REGister Stack-Pointer */ static int freg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ static int reg_var; static int regvar[2]; /* -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 */ static int arg_offset; int disp_offset = -12; #define func_disp_offset -12 #define code_disp_offset 0 // static 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 current virtual register dreg spare virtual register rname[creg] current 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 value in floating point register */ static int dreg; /* general temporal register */ #define REAL_MAX_LREGISTER 2 static int ia32regs[REAL_MAX_REGISTER+REAL_MAX_LREGISTER]; static int ia32regv[REAL_MAX_REGISTER+REAL_MAX_LREGISTER]; static int ia32rname[REAL_MAX_REGISTER+REAL_MAX_LREGISTER]; static int *regv = ia32regv; static int *regs = ia32regs; static int *rname = ia32rname; static int ia32fregs[1]; static int ia32fregv[1]; static int freg; static int *fregv = ia32fregv; static 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 is_int_reg(reg) (reg<REG_EBP) #define REG_LCREG 8 #define REG_L 9 #define regv_l(r) (virtual(r==REG_L?REG_ESI:REG_EAX)) #define regv_h(r) (virtual(r==REG_L?REG_EDI:REG_EDX)) #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,int creg); static void ld_indexx(int byte, int n, int xreg,int reg,int sign); static void data_mode(char *name); static void text_mode(); static int edx_setup(int rreg); static void edx_cleanup(); static void local_table(void); #if FLOAT_CODE static char * fload(int d); static int code_d1(double d); static int code_d2(double d); static void code_save_fstacks(); #endif static void code_save_stacks(); static void jcond(int l, char cond); #if LONGLONG_CODE static int code_l1(long long d); static int code_l2(long long d); #endif #define use_int(reg) if (reg==-1) reg=use_int0() static int use_int0() { lreg = 0; if (!is_int_reg(creg)) { creg = virtual(REG_EBX); regs[creg]=1;} return creg; } #define use_longlong(reg) reg=use_longlong0(reg) static int use_longlong0(int reg) { int i; if (reg==USE_CREG) reg = REG_LCREG; if (!lreg) { code_save_stacks(); // make edx,eax free use_register(creg,REG_EBX,regv[creg]); use_register(dreg,REG_ECX,regv[dreg]); for(i=0;i<reg_var;i++) use_register(regvar[i],REG_ESI+i,1); } creg = lreg = reg; return lreg; } char * l_edx(int i) { return i==REG_L?"%edi":"%edx"; } char * l_eax(int i) { return i==REG_L?"%esi":"%eax"; } static char *init_src0 = "\ #define va_list int\n\ #define va_start(ap,arg) ap=(((int)(&arg))+sizeof(arg))\n\ #define va_arg(ap,type) (*((type *)ap)++)\n\ #define va_end\n\ #define __i386__ 1\n\ #define __LITTLE_ENDIAN__ 1\n\ #define __STDC__ 1\n\ #define size_t int\n\ #define __externsion__\n\ #define __restrict\n\ #define __gnuc_va_list int\n\ #define __flexarr\n\ #define __const const\n\ #define __THORW\n\ #define __attribute__(a)\n\ #define __inline__\n\ #define wchar_t int\n\ #define __GNUC__ 2\n\ "; extern void code_init(void) { /* called only once */ init_src = init_src0; size_of_int = SIZE_OF_INT; size_of_short = SIZE_OF_SHORT; size_of_float = SIZE_OF_FLOAT; size_of_double = SIZE_OF_DOUBLE; size_of_longlong = SIZE_OF_LONGLONG; endian = ENDIAN; arg_offset = 8; // func_disp_offset = -12; disp_offset = -12; 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"; } extern void emit_reinit() { /* called for each file */ } char * register_name(int i,int byte) { if (i<0) { error(REG_ERR); return "%eax"; } if (byte==1 && rname[i] <= REG_EDX) { return reg_name_l[rname[i]]; } else if (byte==SIZE_OF_SHORT && rname[i] <= REG_EDX) { return reg_name_w[rname[i]]; } else { return reg_name[rname[i]]; /* 0 or 4 means int */ } } /* int use_int(int i) { return i;} int use_float(int i) { return i;} int use_double(int i) { return i;} int use_longlong(int i) { return i; } */ void gexpr_code_init(void){ use_register(creg,REG_EAX,0); regv[creg]=0; regv[dreg]=0; } void code_gexpr(int e){ } 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; if(i==REAL_MAX_REGISTER) { regv[virtual(REG_ESI)]=regv[virtual(REG_EDI)]=0; } } extern void use_ptr_cache(int r) { error(-1); } extern void code_ptr_cache_def(int r,NMTBL *nptr) { error(-1); } 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]=INPUT_REG; return list3(REGISTER,i,(int)nptr); } else { return 0; } } int get_input_dregister_var(int i,NMTBL *nptr,int is_code,int d) { return 0; } int get_input_lregister_var(int i,NMTBL *nptr,int is_code) { int h,l; if (is_code) { if (i+1>=MAX_CODE_INPUT_REGISTER_VAR) return 0; h = virtual(REG_ESI); l = virtual(REG_EDI); regs[h]=regs[l]=INPUT_REG; regv[h]=regv[l]=INPUT_REG; return list2(LREGISTER,REG_L); } return 0; } int get_dregister(int d) { return -1; } int get_lregister_var(NMTBL *n) { int h,l; h = virtual(REG_ESI); l = virtual(REG_EDI); if (regv[REAL_MAX_REGISTER]==0&®s[h]==0&®s[l]==0) { regs[h]=regs[l]=REG_VAR; regv[h]=regv[l]=REG_VAR; regv[REAL_MAX_REGISTER]=1; reg_var=2; regvar[0]=h; regvar[1]=l; return list2(LREGISTER,REG_L); } return list2(LVAR,new_lvar(SIZE_OF_LONGLONG)); } int get_lregister() { return -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(int d) { int i,count; count = 0; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i] && ! regv[i]) count++; } return d?0:count; } void free_all_register(void) { int i; for(i=0;i<MAX_REGISTER+REAL_MAX_LREGISTER;i++) { regs[i]=regv[i]=0; } creg = get_register(); dreg = get_register(); reg_var = 0; return; } extern int code_register_overlap(int s,int t) { if (car(s)==REGISTER) { if (car(t)==REGISTER) return cadr(s)==cadr(t); if (car(t)==LREGISTER) return cadr(s)==virtual(REG_ESI)|| cadr(s)==virtual(REG_EDI); } else if (car(s)==LREGISTER) { if (car(t)==LREGISTER) return 1; if (car(t)==REGISTER) return cadr(t)==virtual(REG_ESI)|| cadr(t)==virtual(REG_EDI); } return 0; } 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(NMTBL *fnptr) { int args = fnptr->dsp; NMTBL *n; int reg_var = 0; int freg_var = 0; int type; int reg; int is_code0 = is_code(fnptr); while (args) { /* process in reverse order */ n = (NMTBL*)caddr(args); type = n->ty; // printf("# %s %d %d\n",n->nm,n->dsp,n->ty); if (scalar(type)) { if ((reg = get_input_register_var(reg_var,n,is_code0))) { n->sc = REGISTER; n->dsp = cadr(reg); regv[n->dsp]= 1; regs[n->dsp]= INPUT_REG; reg_var++; cadddr(args)=SIZE_OF_INT; /* why we need this? */ } } else if (type==FLOAT||type==DOUBLE) { if ((reg = get_input_dregister_var(freg_var,n,is_code0,1))) { n->sc = DREGISTER; n->dsp = cadr(reg); fregv[n->dsp]= 1; fregs[n->dsp]= INPUT_REG; freg_var++; cadddr(args)=size(type); /* why we need this? */ } } args = cadr(args); } } void gexpr_init(void) { if (reg_sp>0) error(-1); if (freg_sp>0) error(-1); reg_sp = 0; freg_sp = 0; stack_depth = 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; } 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||xreg==creg) { regv[dreg]=0; } else if (xreg>=0) { free_register(xreg); } } int get_register_var(NMTBL *nptr) { int i; for(i=REG_ESI;i<REG_EBP;i++) { if (! regs[i]) { /* 使われていないなら */ regs[i]=REG_VAR; /* そのレジスタを使うことを宣言し */ regv[i]=0; regvar[reg_var++]=i; return list3(REGISTER,i,(int)nptr); /* その場所を表す番号を返す */ } } return list2(LVAR,new_lvar(SIZE_OF_INT)); } int get_dregister_var(NMTBL *nptr,int d) { return list2(LVAR,new_lvar(d?SIZE_OF_DOUBLE:SIZE_OF_FLOAT)); } 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 emit_push() { int new_reg,old; new_reg = get_register(); if (new_reg==creg) error(-1); old = creg; if(new_reg<0) { /* もうレジスタがない */ if (reg_sp>=MAX_MAX) error(-1); reg_stack[reg_sp++] = -1; printf("\tpushl %s\n",register_name(creg,0)); stack_depth += SIZE_OF_INT; /* creg is used soon, don't regv[creg]=0 */ } else { reg_stack[reg_sp++] = creg; /* push するかわりにレジスタを使う */ creg = new_reg; regv[creg]=1; } return old; } 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; stack_depth -= SIZE_OF_INT; 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; } int stack_top(int type) { int xreg; if (type==INT) { xreg = reg_stack[reg_sp]; if (xreg<= -REG_LVAR_OFFSET) { return list2(LVAR,REG_LVAR_OFFSET+xreg); } else { return list2(REGISTER,xreg); } } else { xreg = freg_stack[freg_sp]; if (xreg<= -REG_LVAR_OFFSET) { return list2(LVAR,REG_LVAR_OFFSET+xreg); } else { return list2(DREGISTER,xreg); } } return xreg; } void code_label(int labelno) { printf("_%d:\n",labelno); } void code_gvar(int e1,int creg) { use_int(creg); if (cadr(e1)) { printf("\tmovl $%s+%d,%s\n",((NMTBL*)caddr(e1))->nm,cadr(e1), register_name(creg,0)); } else { printf("\tmovl $%s,%s\n",((NMTBL*)caddr(e1))->nm,register_name(creg,0)); } regv[creg]=1; } void code_rgvar(int e1,int creg) { use_int(creg); if (cadr(e1)) { printf("\tmovl %s+%d,%s\n",((NMTBL*)caddr(e1))->nm,cadr(e1), register_name(creg,0)); } else printf("\tmovl %s,%s\n",((NMTBL*)caddr(e1))->nm,register_name(creg,0)); regv[creg]=1; } static char *cload(int sign,int sz) { return sz==1?(sign?"movsbl":"movzbl"):sz==SIZE_OF_SHORT?(sign?"movswl":"movzwl"):"movl"; } void code_crgvar(int e1,int creg,int sign,int sz){ use_int(creg); if (cadr(e1)) { printf("\t%s %s+%d,%s\n",cload(sign,sz), ((NMTBL*)caddr(e1))->nm,cadr(e1),register_name(creg,0)); } else printf("\t%s %s,%s\n",cload(sign,sz), ((NMTBL*)caddr(e1))->nm,register_name(creg,0)); regv[creg]=1; } void code_lvar(int e2,int creg) { use_int(creg); printf("\tlea %d(%%ebp),%s\n",lvar(e2),register_name(creg,0)); regv[creg]=1; } void code_register(int e2,int creg) { use_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) { use_int(reg); printf("\tmovl %d(%%ebp),%s\n",lvar(e2),register_name(reg,0)); regv[creg]=1; } extern void code_i2c(int reg) { use_int(reg); use_data_reg(reg,1); printf("\t%s %s,%s\n",cload(1,1), register_name(reg,1),register_name(reg,0)); } extern void code_i2s(int reg) { use_int(reg); use_data_reg(reg,1); printf("\t%s %s,%s\n",cload(1,SIZE_OF_SHORT), register_name(reg,2),register_name(reg,0)); } extern void code_u2uc(int reg) { use_int(reg); use_data_reg(reg,1); printf("\t%s %s,%s\n",cload(0,1), register_name(reg,1),register_name(reg,0)); } extern void code_u2us(int reg) { use_int(reg); use_data_reg(reg,1); printf("\t%s %s,%s\n",cload(0,SIZE_OF_SHORT), register_name(reg,2),register_name(reg,0)); } void code_crlvar(int e2,int reg,int sign,int sz) { use_int(reg); printf("\t%s %d(%%ebp),%s\n",cload(sign,sz),lvar(e2),register_name(reg,0)); regv[creg]=1; } void code_fname(NMTBL *n,int creg) { use_int(creg); printf("\tmovl $%s,%s\n",n->nm,register_name(creg,0)); regv[creg]=1; } void code_label_value(int label,int reg) { use_int(reg); printf("\tleal _%d,%s\n",label,register_name(reg,0)); regv[creg]=1; } void code_const(int e2,int creg) { use_int(creg); printf("\tmovl $%d,%s\n",e2,register_name(creg,0)); regv[creg]=1; } void code_neg(int creg) { use_int(creg); printf("\tnegl %s\n", register_name(creg,0)); } void code_not(int creg) { use_int(creg); printf("\tnotl %s\n", register_name(creg,0)); } void code_lnot(int creg) { char *xrn; use_int(creg); 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 dir,int sign,int sz,int reg) { char *xrn; if (car(e2)==REGISTER) { use_int(reg); printf("\taddl $%d,%s\n",dir,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); use_int(reg); printf("\t%s $%d,(%s)\n",(sz==1)?"addb":(sz==SIZE_OF_SHORT)?"addw":"addl",dir,xrn); printf("\t%s (%s),%s\n",cload(sign,sz),xrn,register_name(reg,0)); } void code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) { char *xrn; if (car(e2)==REGISTER) { use_int(reg); printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(reg,0)); printf("\taddl $%d,%s\n",dir,register_name(cadr(e2),0)); regv[reg]=1; return; } g_expr(e2); emit_push(); xrn = register_name((e2=emit_pop(0)),0); use_int(reg); printf("\t%s (%s),%s\n",cload(sign,sz),xrn,register_name(reg,0)); printf("\t%s $%d,(%s)\n",(sz==1)?"addb":(sz==SIZE_OF_SHORT)?"addw":"addl",dir,xrn); emit_pop_free(e2); } void code_return(int creg) { use_int(creg); printf("\tleal _%d,%s\n",retcont,register_name(creg,0)); regv[creg]=1; } void code_environment(int creg) { use_int(creg); printf("\tmovl %%ebp,%s\n",register_name(creg,0)); regv[creg]=1; } static int rexpr_bool(int e1,int reg); #if FLOAT_CODE static int drexpr_bool(int e1,int reg); #endif void code_bool(int e1,int reg) { char *xrn; int e2,e3; if (rexpr_bool(e1,reg)) return; #if FLOAT_CODE if (drexpr_bool(e1,reg)) return; #endif b_expr(e1,1,e2=fwdlabel(),1); /* including > < ... */ if (use) { use_int(reg); xrn = register_name(reg,0); printf("\txorl %s,%s\n",xrn,xrn); jmp(e3=fwdlabel()); fwddef(e2); printf("\tmovl $1,%s\n",xrn); fwddef(e3); regv[reg]=1; } else { fwddef(e2); } } static char * code_gt(int cond) { return (cond?"g":"le"); } static char * code_ugt(int cond) { return (cond?"a":"be"); } static char * code_ge(int cond) { return (cond?"ge":"l"); } static char * code_uge(int cond) { return (cond?"ae":"b"); } static char * code_eq(int cond) { return (cond?"e":"ne"); } void code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) { use_int(reg); if (cadr(e1)) { if (sz==1) printf("\tcmpb $0,%s+%d\n",((NMTBL*)caddr(e1))->nm,cadr(e1)); else if (sz==SIZE_OF_SHORT) printf("\tcmpw $0,%s+%d\n",((NMTBL*)caddr(e1))->nm,cadr(e1)); } else { if (sz==1) printf("\tcmpb $0,%s\n",((NMTBL*)caddr(e1))->nm); else if (sz==SIZE_OF_SHORT) printf("\tcmpw $0,%s\n",((NMTBL*)caddr(e1))->nm); } jcond(label,cond); } void code_cmp_crlvar(int e1,int reg,int sz,int label,int cond) { use_int(reg); if (sz==1) printf("\tcmpb $0,%d(%%ebp)\n",lvar(e1)); else if (sz==SIZE_OF_SHORT) printf("\tcmpw $0,%d(%%ebp)\n",lvar(e1)); jcond(label,cond); } void code_cmp_rgvar(int e1,int reg,int label,int cond) { use_int(reg); if (cadr(e1)) printf("\tcmpl $0,%s+%d\n",((NMTBL*)caddr(e1))->nm,cadr(e1)); else printf("\tcmpl $0,%s\n",((NMTBL*)caddr(e1))->nm); jcond(label,cond); } void code_cmp_rlvar(int e1,int reg,int label,int cond) { use_int(reg); printf("\tcmpl $0,%d(%%ebp)\n",lvar(e1)); jcond(label,cond); } void code_cmp_register(int e2,int label,int cond) { use_int(e2); printf("\tcmpl $0,%s\n",register_name(e2,0)); jcond(label,cond); } void code_string(int e1,int creg) { char *s; int lb; use_int(creg); s=(char *)cadr(e1); lb = emit_string_label(); 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) { /* length <0 means upward direction copy */ use_int(from); use_int(to); 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 (length <0) { if (length > -MAX_COPY_LEN) { for(;length<=-4;length+=4,offset-=4) emit_copy(from,to,-4,offset-4,0,det); for(;length<=-2;length+=2,offset-=2) emit_copy(from,to,-2,offset-2,0,det); if(length<0) emit_copy(from,to,length,offset-1,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; } printf("\tpushl %%esi\n"); printf("\tpushl %%edi\n"); printf("\tpushl %%ecx\n"); printf("\tpushl %s\n",register_name(from,0)); printf("\tpushl %s\n",register_name(to,0)); printf("\tpushl %s\n",register_name(dreg,0)); printf("\tpopl %%ecx\n"); printf("\tpopl %%edi\n"); printf("\tpopl %%esi\n"); if (length<0) { printf("\tmovl $%d,%%ecx\n",-length/4); printf("\taddl $%d,%%esi\n",-length-4); printf("\taddl $%d,%%edi\n",-length-4); printf("\tstd\n\trep\n\tmovsl\n"); printf("\tpopl %%ecx\n"); printf("\tpopl %%edi\n"); printf("\tpopl %%esi\n"); if(length%4) { emit_copy(from,to,length,offset+length/SIZE_OF_INT,0,det); } } else { printf("\tmovl $%d,%%ecx\n",length/4); printf("\tcld\n\trep\n\tmovsl\n"); printf("\tpopl %%ecx\n"); printf("\tpopl %%edi\n"); printf("\tpopl %%esi\n"); if(length%4) { emit_copy(from,to,length,offset+length/SIZE_OF_INT,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(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); stack_depth += length*SIZE_OF_INT; return length/SIZE_OF_INT; } int function(int e1) { int e2,e3,e4,nargs,t,ret_type; NMTBL *n=0; int save,saved; int stack_depth_save = stack_depth; ret_type = cadr(cadddr(e1)); if (ret_type==CHAR) ret_type=INT; #ifdef SAVE_STACKS code_save_stacks(); #if FLOAT_CODE code_save_fstacks(); #endif #endif if (free_register_count(0)<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)) { if (car(e4)==REGISTER) { printf("\tpushl %s\n",register_name(cadr(e4),0)); } else { g_expr(e4); printf("\tpushl %s\n",register_name(creg,0)); } stack_depth += SIZE_OF_INT; } else if (t==LONGLONG||t==ULONGLONG) { if (car(e4)==LREGISTER) { printf("\tpushl %s\n\tpushl %s\n",l_edx(cadr(e4)),l_eax(cadr(e4))); } else { g_expr(e4); printf("\tpushl %%edx\n\tpushl %%eax\n"); } ++nargs; stack_depth += SIZE_OF_INT*2; } 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; stack_depth += SIZE_OF_DOUBLE; 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; stack_depth += SIZE_OF_FLOAT; 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_EBX,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) { } else if (ret_type==LONGLONG||ret_type==ULONGLONG) { use_longlong0(USE_CREG); regv[creg]=1; } else if (ret_type==VOID) { regv[freg]=0; regv[creg]=0; } else { if (!is_int_reg(creg)) { lreg=0; creg=virtual(REG_EAX); } use_register(creg,REG_EAX,0); fregv[freg]=0; regv[creg]=1; } stack_depth = stack_depth_save; return ret_type; } void code_alloca(int e1,int reg) { char *crn,*drn; int edx; g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); use_int(reg); if (stack_depth>0) { edx = edx_setup(-1); crn = register_name(reg,0); drn = register_name(edx,0); printf("\tmovl %%esp,%s\n",drn); printf("\tsubl %s,%%esp\n",crn); printf("\tmovl %%esp,%s\n",crn); emit_copy(edx,creg,stack_depth,0,1,1); printf("\taddl $%d,%s\n",stack_depth,register_name(creg,0)); edx_cleanup(); } else { crn = register_name(reg,0); printf("\tsubl %s,%%esp\n",crn); printf("\tmovl %%esp,%s\n",crn); } } void code_frame_pointer(int e3) { use_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) { use_int(e2); printf("\tjmp *%s\n",register_name(e2,0)); } void code_rindirect(int e1, int reg,int offset, int sign,int byte) { char *crn,*op; g_expr(e1); op=cload(sign,byte); crn = register_name(creg,0); use_int(reg); printf("\t%s %d(%s),%s\n",op,offset,crn,register_name(reg,0)); } #if FLOAT_CODE int code_drindirect(int e1, int reg,int offset, int d) { g_expr(e1); printf("\t%s (%s)\n",fload(d),register_name(creg,0)); return DOUBLE; } #endif #if LONGLONG_CODE static void lload(int creg,int offset,int reg) { char *crn = register_name(creg,0); use_longlong(reg); if((reg==REG_L&&rname[creg]==REG_ESI)||(rname[creg]==REG_EAX)) { printf("\tmovl %d(%s),%s\n",offset+SIZE_OF_INT,crn,l_edx(reg)); printf("\tmovl %d(%s),%s\n",offset,crn,l_eax(reg)); } else { printf("\tmovl %d(%s),%s\n",offset,crn,l_eax(reg)); printf("\tmovl %d(%s),%s\n",offset+SIZE_OF_INT,crn,l_edx(reg)); } } int code_lrindirect(int e1, int reg, int offset, int us) { int reg0; g_expr(e1); regv[reg0=creg]=1; use_longlong(reg); lload(reg0,offset,reg); return LONGLONG; } #endif char * move(int byte) { return byte==1?"movb":byte==SIZE_OF_SHORT?"movw":"movl"; } void code_assign_gvar(int e2,int creg,int byte) { use_int(creg); if (byte) use_data_reg(creg,1); if (cadr(e2)) printf("\t%s %s,%s+%d\n",move(byte),register_name(creg,byte),((NMTBL*)caddr(e2))->nm,cadr(e2)); else printf("\t%s %s,%s\n",move(byte),register_name(creg,byte),((NMTBL*)caddr(e2))->nm); } void code_assign_lvar(int e2,int creg,int byte) { use_int(creg); 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) { use_int(creg); if (creg!=e2) printf("\tmovl %s,%s\n",register_name(creg,0),register_name(e2,0)); } void code_assign(int e2,int byte,int creg) { use_int(e2); use_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)); regv[creg]=1; } void code_register_assop(int e2,int reg0,int op,int byte) { int reg; int xreg = creg; creg = reg = e2; tosop(op,reg,xreg); creg = xreg; // printf("\tmovl %s,%s\n",register_name(reg,0),register_name(creg,0)); regs[creg]=regv[creg]=1; } void code_assop(int op,int reg,int byte,int sign) { char *xrn; int xreg; int edx = edx_setup(-1); use_int(reg); xrn = register_name(xreg = emit_pop(0),0); /* pop e3 value */ regv[xreg]=regs[xreg]=1; printf("\tmovl %s,%s # assop \n",register_name(reg,0),register_name(edx,0)); regv[edx]=1; ld_indexx(byte,0,edx,reg,sign); tosop(op,reg,xreg); printf("\t%s %s,(%s)\n",move(byte),register_name(reg,byte),register_name(edx,0)); edx_cleanup(); emit_pop_free(xreg); regv[creg]=1; } void tosop(int op,int reg,int oreg) { int dx; char *orn,*crn; use_int(reg); switch(op) { case LSHIFT: case ULSHIFT: shift("sall",oreg,reg); regv[creg]=1; return; case RSHIFT: shift("sarl",oreg,reg); regv[creg]=1; return; case URSHIFT: shift("shrl",oreg,reg); regv[creg]=1; 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(REG_EDX); 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(REG_EDX); orn = register_name(oreg,0); if (op==MOD) 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!=creg&&oreg>=0) free_register(oreg); else if (oreg==dreg) regv[dreg]=0; regv[creg]=1; } int code_const_op_p(int op,int e) { if (car(e)!=CONST) return 0; if (op==DIV||op==UDIV) return ilog(cadr(e)); if (op==MOD||op==UMOD) return 0; else return 1; } void oprtc(int op,int reg,int orn) { char *crn; int datareg; use_int(reg); crn = register_name(reg,0); orn = cadr(orn); datareg=(rname[reg]<MAX_DATA_REG); switch(op) { case LSHIFT: case ULSHIFT: printf("\tsall $%d,%s\n",orn,crn); return; case DIV: orn = ilog(orn); case RSHIFT: printf("\tsarl $%d,%s\n",orn,crn); return; case UDIV: orn = ilog(orn); case URSHIFT: printf("\tshrl $%d,%s\n",orn,crn); return; case ADD: printf("\taddl $%d,%s\n",orn,crn); break; case SUB: case CMP: printf("\tsubl $%d,%s\n",orn,crn); break; case BAND: if (datareg&&(orn & ~255)==~255) printf("\tandb $%d,%s\n",orn,register_name(reg,1)); else if (datareg&&(orn & ~65535)==~65535) printf("\tandw $%d,%s\n",orn,register_name(reg,2)); else printf("\tandl $%d,%s\n",orn,crn); break; case EOR: printf("\txorl $%d,%s\n",orn,crn); break; case BOR: if (datareg&&(orn & ~255)==0) printf("\tor $%d,%s\n",orn,register_name(reg,1)); else if (datareg&&(orn & ~65535)==0) printf("\tor $%d,%s\n",orn,register_name(reg,2)); else printf("\torl $%d,%s\n",orn,crn); break; case MUL: case UMUL: if (ilog(orn)) { printf("\tsall $%d,%s\n",ilog(orn),crn); } else printf("\t%s $%d,%s\n","imull",orn,crn); break; default: error(-1); } } static int edx_stack=0; int edx_setup(int rreg) { int edx_save; /* make real EDX (or rreg) register empty */ if (free_register_count(0)<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; if (rreg!=-1) use_register(edx_save,rreg,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,int creg) { use_int(creg); 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,int reg,int sign) { use_int(reg); if (n) printf("\t%s %d(%s),%s\n",cload(sign,byte),n, register_name(xreg,0),register_name(reg,0)); else printf("\t%s (%s),%s\n",cload(sign,byte), register_name(xreg,0),register_name(reg,0)); } int code_csvalue() { return rname[creg]; /* for switch value */ } void code_cmpdimm(int e, int csreg,int label,int cond) { /* used in dosiwtch() */ if(chk) return; use_register(creg,csreg,0); printf("\tcmpl $%d,%s\n",e,register_name(creg,0)); jcond(label,cond); } 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"); } static char * code_cond(int op,int cond) { switch(op) { case GT: return code_gt(cond); case UGT: return code_ugt(cond); case GE: return code_ge(cond); case UGE: return code_uge(cond); case LT: return code_ge(!cond); case ULT: return code_uge(!cond); case LE: return code_gt(!cond); case ULE: return code_ugt(!cond); case EQ: return code_eq(cond); case NEQ: return code_eq(!cond); default: return 0; } } static int rexpr_bool(int e1,int reg) { char *s; if (!(s=code_cond(car(e1),1))) return 0; g_expr(list3(CMP,cadr(e1),caddr(e1))); use_int(reg); use_data_reg(reg,0); printf("\tset%s\t%s\n",s,register_name(reg,1)); printf("\tmovzbl %s,%s\n",register_name(reg,1),register_name(reg,0)); return 1; } int rexpr(int e1, int l1, int cond,int t) { g_expr(list3(CMP,cadr(e1),caddr(e1))); printf("\tj%s\t_%d\n",code_cond(car(e1),cond),l1); return l1; } static void jcond(int l, char cond) { if (chk) return; printf("\tj%s\t_%d\n",cond==LT?code_ge(0):cond?"ne":"e",l); } void jmp(int l) { 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) { text_mode(); 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_disp_offset=%d\n",args,disp,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-8); 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) { text_mode(); 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() { text_mode(); 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(); } int code_get_fixed_creg(int reg,int type) { if (type==FLOAT||type==DOUBLE) { return 0; } else if (type==LONGLONG||type==ULONGLONG) { use_longlong(reg); return reg; } else { use_int(reg); return rname[reg]; } } void code_set_fixed_creg(int reg,int mode,int type) { if (type==FLOAT||type==DOUBLE) { } else if (type==LONGLONG||type==ULONGLONG) { } else { use_register(creg,reg,mode); } } void code_set_return_register(int mode) { if (fnptr->ty==DOUBLE||fnptr->ty==FLOAT) { } else if (fnptr->ty==LONGLONG||fnptr->ty==ULONGLONG) { use_longlong0(USE_CREG); } else { use_register(creg,REG_EAX,mode); } } void gen_gdecl(char *n, int gpc) { /* if (stmode!=STATIC) printf(".globl %s\n",n); */ } extern 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); } extern int emit_string_label() { int lb; printf(".section\t.rodata\n"); lb=fwdlabel(); printf("_%d:\n",lb); output_mode = RODATA_EMIT_MODE; return lb; } void align(int t) { int d; switch(t) { case CHAR: case UCHAR: return; case SHORT: case USHORT: d = data_alignment & 1; break; default: d = data_alignment & 3; } if (d) { printf("\t.align 2\n"); data_alignment = 0; } } extern void emit_global(char *name,int t) { data_mode(name); printf(".globl\t%s\n",name); align(t); printf("%s:\n",name); } extern void emit_space(int sp) { data_mode(0); printf("\t.space\t%d\n",sp); } extern void emit_char(int d) { data_mode(0); printf("\t.byte %d\n",d); } extern void emit_short(int d) { data_mode(0); printf("\t.short %d\n",d); } extern void emit_int(int d) { data_mode(0); printf("\t.long %d\n",d); } extern void emit_longlong(int e) { #if LONGLONG_CODE long long ll = lcadr(e); data_mode(0); #if (ENDIAN_L==0) printf("\t.long\t0x%x,0x%x\n",code_l1(ll),code_l2(ll)); #else printf("\t.long\t0x%x,0x%x\n",code_l2(ll),code_l1(ll)); #endif #endif } extern void emit_double(int e) { #if FLOAT_CODE double d = dcadr(e); data_mode(0); #if (ENDIAN_D==0) printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d)); #else printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d)); #endif #endif } extern void emit_float(int e) { #if FLOAT_CODE float f = dcadr(e); data_mode(0); printf("\t.long\t0x%x\n",*(int *)&f); #endif } extern void emit_address(char *s,int offset) { data_mode(0); if (offset) printf("\t.long %s+%d\n",s,offset); else printf("\t.long %s\n",s); } extern void emit_label(int labelno) { data_mode(0); printf("\t.long _%d\n",labelno); } extern void emit_data_closing(NMTBL *n) { #ifdef DOT_SIZE int lb; #endif if (chk) return; if (mode==GDECL) { data_mode(0); #ifdef DOT_SIZE lb=fwdlabel(); printf("_%d:\n",lb); printf("\t.size\t%s,_%d-%s\n",n->nm,lb,n->nm); #endif } } #if LONGLONG_CODE static long long ll0 = 1LL; static int code_l1(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[1]:j[0]; } static int code_l2(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[0]:j[1]; } #endif void global_table(void) { NMTBL *n; int init; init=0; for(n=global_list;n;n = n->next) { 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=local_static_list;n;n = n->next) { if (n->sc == GVAR) { if (init==0) { data_mode(0); init=1; } if (n->dsp!= -1) /* -1 means initialized global */ 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); } #if FLOAT_CODE /* 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) { if (cadr(e2)) printf("\t%s %s+%d\n",fstore(d),((NMTBL*)caddr(e2))->nm,cadr(e2)); else printf("\t%s %s\n",fstore(d),((NMTBL*)caddr(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_dregister(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; static int code_d1(double d) { int *i = (int *)&d0; int *j = (int *)&d; return (i[1] == 0x3ff00000)?j[0]:j[1]; } static 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 d) { int lb; double value = dcadr(e2); if (value==0.0) { printf("\tfldz\n"); return; } if (value==1.0) { printf("\tfld1\n"); return; } printf(" \t.section\t.rodata\n\t.align 8\n"); lb=fwdlabel(); printf("_%d:\n",lb); #if ENDIAN_D==0 printf("\t.long\t0x%x,0x%x\n",code_d1(value),code_d2(value)); #endif if (output_mode==TEXT_EMIT_MODE) { printf(".text\n"); } else { text_mode(); } printf("\tfldl _%d\n",lb); } void code_dneg(int freg,int d) { printf("\tfchs\n"); } void code_d2i(int reg) { use_int(reg); 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 reg) { 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 reg) { use_int(reg); printf("\tlea -%d(%%esp),%%esp\n",SIZE_OF_INT*3); printf("\tfnstcw (%%esp)\n"); printf("\tmovl (%%esp), %s\n",register_name(reg,0)); printf("\tmovb $12, 1(%%esp)\n"); printf("\tfldcw (%%esp)\n"); printf("\tmovl %s, (%%esp)\n",register_name(reg,0)); printf("\tfistpll %d(%%esp)\n",SIZE_OF_INT); printf("\tfldcw (%%esp)\n"); printf("\tmovl %d(%%esp),%s\n",SIZE_OF_INT,register_name(reg,0)); printf("\tlea %d(%%esp),%%esp\n",SIZE_OF_INT*3); } void code_u2d(int reg) { 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 reg) { } void code_f2d(int reg) { } void code_f2i(int reg) { code_d2i(reg); } void code_f2u(int reg) { code_d2u(reg); } void code_i2f(int reg) { code_i2d(reg); } void code_u2f(int reg) { code_u2d(reg); } void code_drgvar(int e2,int d,int freg) { if (cadr(e2)) printf("\t%s %s+%d\n",fload(d),((NMTBL*)caddr(e2))->nm,cadr(e2)); else printf("\t%s %s\n",fload(d),((NMTBL*)caddr(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,int reg,int d,int label,int cond) { if (cadr(e2)) printf("\tfcomp %s+%d\n",((NMTBL*)caddr(e2))->nm,cadr(e2)); else printf("\tfcomp %s\n",((NMTBL*)caddr(e2))->nm); jcond(label,cond); } void code_cmp_drlvar(int e2,int reg,int d,int label,int cond) { printf("\tfcomp %d(%%ebp)\n",lvar(e2)); jcond(label,cond); } void dtosop(int op,int reg,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 reg,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,reg,0); printf("\t%s (%s)\n",fstore(d),register_name(creg,0)); } void code_register_dassop(int reg,int op,int d) { error(-1); } 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)); } #define COND_BRANCH 1 #define COND_VALUE 2 /* return 1 if boolean expression */ int drexpr0(int e1, int e2,int l1, int op,int cond,int reg,int mode) { char *s; if (!cond) { switch(op) { case FOP+GT: return drexpr0(e2,e1,l1,FOP+GE,1,reg,mode); case FOP+GE: return drexpr0(e2,e1,l1,FOP+GT,1,reg,mode); case FOP+EQ: op=FOP+NEQ; break; case FOP+NEQ: op=FOP+EQ; break; case DOP+GT: return drexpr0(e2,e1,l1,DOP+GE,1,reg,mode); case DOP+GE: return drexpr0(e2,e1,l1,DOP+GT,1,reg,mode); case DOP+EQ: op=DOP+NEQ; break; case DOP+NEQ: op=DOP+EQ; break; default: return 0; } } s = "e"; switch(op) { case DOP+GE: case FOP+GE: g_expr(list3(DCMP,e1,e2)); printf("\ttestb\t$5,%%ah\n"); break; case DOP+GT: case FOP+GT: g_expr(list3(DCMP,e1,e2)); printf("\ttestb\t$69,%%ah\n"); break; case DOP+EQ: case FOP+EQ: g_expr(list3(DCMP,e1,e2)); printf("\tandb\t$69,%%ah\n"); printf("\txorb\t$64,%%ah\n"); break; case DOP+NEQ: case FOP+NEQ: g_expr(list3(DCMP,e1,e2)); printf("\tandb\t$69,%%ah\n"); printf("\txorb\t$64,%%ah\n"); s = "ne"; break; default: return 0; } if (mode==COND_BRANCH) { printf("\tj%s\t_%d\n",s,l1); } else { use_int(reg); use_data_reg(reg,0); printf("\tset%s\t%s\n",s,register_name(reg,1)); printf("\tmovzbl\t%s,%s\n", register_name(reg,1),register_name(reg,0)); } return 1; } int drexpr(int e1, int e2,int l1, int op,int cond) { drexpr0(e1, e2,l1, op,cond,USE_CREG,COND_BRANCH); return l1; } static int drexpr_bool(int e1, int reg) { return drexpr0(cadr(e1), caddr(e1),0, car(e1),1,reg,COND_VALUE); } void code_dregister(int e2,int freg,int d) { error(-1); } void code_cmp_dregister(int e2,int d,int label,int cond) { if (e2!=USE_CREG) error(-1); printf("\tfldz\n"); printf("\tfucompp\n"); printf("\tfnstsw\t%%ax\n"); printf("\tandb\t$69,%%ah\n"); printf("\txorb\t$64,%%ah\n"); jcond(label,cond); } 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 d) { 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 commutable operator, but it is ok to do this. */ printf("\tfxch\t%%st(1)\n"); } return xreg; } void emit_dpop_free(int e1,int d) { } 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); } #endif 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; } } } #if FLOAT_CODE 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; } #endif #if LONGLONG_CODE /* 64bit int part */ static void pcond(char *s,int l1) { printf("\tj%s\t_%d\n",s,l1); } int lrexpr(int e1, int e2,int l1, int op,int cond) { int l2; code_save_stacks(); g_expr(e1); emit_lpush(); g_expr(e2); // we are sure %ecx,%ebx is free printf("\tpopl %%ecx\n"); // LSW printf("\tpopl %%ebx\n"); // MSW printf("\tsubl %%edx,%%ebx\n"); l2 = fwdlabel(); // cond==0 jump on false condtion ( if(x) => rexpr(.. cond=0 ...) ) switch(op) { case LOP+GT: case LOP+GE: pcond(code_gt(1),cond?l1:l2); pcond(code_eq(0),cond?l2:l1); break; case LOP+UGT: case LOP+UGE: pcond(code_ugt(1),cond?l1:l2); pcond(code_eq(0), cond?l2:l1); break; case LOP+EQ: pcond(code_eq(0),(cond?l2:l1)); break; case LOP+NEQ: pcond(code_eq(0),(cond?l1:l2)); break; default: error(-1); } printf("\tsubl %%eax,%%ecx\n"); switch(op) { case LOP+GT: pcond(code_gt(cond), l1); break; case LOP+GE: pcond(code_ge(cond), l1); break; case LOP+UGT: pcond(code_ugt(cond), l1); break; case LOP+UGE: pcond(code_uge(cond), l1); break; case LOP+EQ: pcond(code_eq(cond),l1); break; case LOP+NEQ: pcond(code_eq(!cond),l1); break; } fwddef(l2); return l1; } int emit_lpop() { return 0; } void code_lregister(int e2,int reg) { use_longlong(reg); if (reg!=REG_L) { printf("\tmovl %%esi,%s\n",l_eax(reg)); printf("\tmovl %%edi,%s\n",l_edx(reg)); } } void code_cmp_lregister(int reg,int label,int cond) { char *crn; use_int(reg); crn = register_name(reg,0); printf("\tmovl %%esi,%s\n",crn); printf("\torl %%edi,%s\n",crn); printf("\ttestl %s,%s\n",crn,crn); jcond(label,cond); } void code_cmp_lrgvar(int e1,int e2,int label,int cond) { char *n,*crn; n = ((NMTBL*)caddr(e1))->nm; use_int(e2); crn = register_name(e2,0); if (cadr(e1)) { printf("\tmovl %s+%d,%s\n",n,cadr(e1),crn); printf("\torl %s+%d,%s\n",n,cadr(e1)+4,crn); } else { printf("\tmovl %s,%s\n",n,crn); printf("\torl %s+4,%s\n",n,crn); } printf("\ttestl %s,%s\n",crn,crn); jcond(label,cond); } void code_cmp_lrlvar(int e1,int e2,int label,int cond) { char *crn; use_int(e2); crn = register_name(e2,0); printf("\tmovl %d(%%ebp),%s\n",lvar(e1),crn); printf("\torl %d(%%ebp),%s\n",lvar(e1)+4,crn); printf("\ttestl %s,%s\n",crn,crn); jcond(label,cond); } void code_lassign(int e1,int e2) { char *rn; // e1 = e2 use_longlong(e2); rn = register_name(e1,0); #if ENDIAN_L==0 printf("\tmovl %s,(%s)\n",l_eax(e2),rn); printf("\tmovl %s,4(%s)\n",l_edx(e2),rn); #endif } void code_lassign_gvar(int e1,int e2) { char *n; n = ((NMTBL*)caddr(e1))->nm; use_longlong(e2); #if ENDIAN_L==0 if (cadr(e1)) { printf("\tmovl %s,%s+%d\n",l_eax(e2),n,cadr(e1)); printf("\tmovl %s,%s+%d\n",l_edx(e2),n,cadr(e1)+4); } else { printf("\tmovl %s,%s\n",l_eax(e2),n); printf("\tmovl %s,%s+4\n",l_edx(e2),n); } #endif } void code_lassign_lvar(int e1,int e2) { use_longlong(e2); #if ENDIAN_L==0 printf("\tmovl %s,%d(%%ebp)\n",l_eax(e2),lvar(e1)); printf("\tmovl %s,%d(%%ebp)\n",l_edx(e2),lvar(e1)+4); #endif } void code_lassign_lregister(int e2,int reg) { // e2 = reg use_longlong(reg); if (e2!=reg) { printf("\tmovl %s,%s\n",l_eax(reg),l_eax(e2)); printf("\tmovl %s,%s\n",l_edx(reg),l_edx(e2)); } } void code_lconst(int e1,int creg) { use_longlong(creg); #if ENDIAN_L==0 printf("\tmovl $%d,%s\n",code_l1(lcadr(e1)),l_eax(creg)); printf("\tmovl $%d,%s\n",code_l2(lcadr(e1)),l_edx(creg)); #endif } void code_lneg(int e1) { use_longlong(e1); printf("\tnegl %s\n",l_eax(e1)); printf("\tadcl $0,%s\n",l_edx(e1)); printf("\tnegl %s\n",l_edx(e1)); } void code_lrgvar(int e1,int e2) { char *n; n = ((NMTBL*)caddr(e1))->nm; use_longlong(e2); #if ENDIAN_L==0 if (cadr(e1)) { printf("\tmovl %s+%d,%s\n",n,cadr(e1),l_eax(e2)); printf("\tmovl %s+%d,%s\n",n,cadr(e1)+4,l_edx(e2)); } else { printf("\tmovl %s,%s\n",n,l_eax(e2)); printf("\tmovl %s+4,%s\n",n,l_edx(e2)); } #endif } void code_lrlvar(int e1,int e2) { use_longlong(e2); #if ENDIAN_L==0 printf("\tmovl %d(%%ebp),%s\n",lvar(e1),l_eax(e2)); printf("\tmovl %d(%%ebp),%s\n",lvar(e1)+4,l_edx(e2)); #endif } #define check_lreg(reg) if (reg==REG_L) code_lassign_lregister(reg,REG_LCREG) void ltosop(int op,int reg,int e2) { char *opl,*oph,*call; int lb; // e2 (operand) is on the top of the stack use_longlong(reg); opl = 0; call=0; stack_depth -= SIZE_OF_INT * 2; switch(op) { case LLSHIFT: case LULSHIFT: printf("\tmovl %%ecx,4(%%esp)\n"); printf("\tpopl %%ecx\n"); printf("\tshldl %%eax,%%edx\n"); printf("\tsall %%cl,%%eax\n"); printf("\ttestb $32,%%cl\n"); printf("\tje\t_%d\n",(lb=fwdlabel())); printf("\tmovl %%eax,%%edx\n"); printf("\txorl %%eax,%%eax\n"); fwddef(lb); printf("\tpopl %%ecx\n"); check_lreg(reg); return; case LRSHIFT: printf("\tmovl %%ecx,4(%%esp)\n"); printf("\tpopl %%ecx\n"); printf("\tshrdl %%edx,%%eax\n"); printf("\tsarl %%cl,%%edx\n"); printf("\ttestb $32,%%cl\n"); printf("\tje\t_%d\n",(lb=fwdlabel())); printf("\tmovl %%edx,%%eax\n"); printf("\tsarl $31,%%edx\n"); fwddef(lb); printf("\tpopl %%ecx\n"); check_lreg(reg); return; case LURSHIFT: printf("\tmovl %%ecx,4(%%esp)\n"); printf("\tpopl %%ecx\n"); printf("\tshrdl %%edx,%%eax\n"); printf("\tshrl %%cl,%%edx\n"); printf("\ttestb $32,%%cl\n"); printf("\tje\t_%d\n",(lb=fwdlabel())); printf("\tmovl %%edx,%%eax\n"); printf("\txorl %%edx,%%edx\n"); fwddef(lb); printf("\tpopl %%ecx\n"); check_lreg(reg); return; } switch(op) { case LADD: opl="addl";oph="adcl"; break; case LSUB: opl="subl";oph="sbbl"; break; case LBAND: opl=oph="andl"; break; case LEOR: opl=oph="xorl"; break; case LBOR: opl=oph="orl"; break; case LMUL: case LUMUL: printf("\tpushl %%edx\n"); printf("\tpushl %%eax\n"); printf("\tpushl %%ecx\n"); // 0 saved ecx // 4 c_l // 8 c_h // 12 o_l // 16 o_h printf("\tmull 12(%%esp)\n"); // c_l*o_l -> %edx,%eax printf("\tmovl 4(%%esp),%%ecx\n"); // c_l->%ecx printf("\timull 16(%%esp),%%ecx\n"); // c_l*o_h->%ecx printf("\taddl %%ecx,%%edx\n"); // %edx+%ecx->%edx printf("\tmovl 8(%%esp),%%ecx\n"); // c_h->%ecx printf("\timull 12(%%esp),%%ecx\n"); // c_h*o_l->%ecx printf("\taddl %%ecx,%%edx\n"); // %edx+%ecx->%edx printf("\tpopl %%ecx\n"); // printf("\taddl $8,%%esp\n"); printf("\tlea 16(%%esp),%%esp\n"); return; case LDIV: call="__divdi3"; break; case LUDIV: call="__udivdi3"; break; case LMOD: call="__moddi3"; break; case LUMOD: call="__umoddi3"; break; default: error(-1); } if (opl) { printf("\t%s (%%esp),%%eax\n\t%s 4(%%esp),%%edx\n",opl,oph); printf("\tlea 8(%%esp),%%esp\n"); check_lreg(reg); } else if (call) { printf("\tpushl %%edx\n"); printf("\tpushl %%eax\n"); printf("\tcall %s\n",call); // printf("\taddl $8,%%esp\n"); printf("\tlea 16(%%esp),%%esp\n"); check_lreg(reg); } else { error(-1); } } int code_lconst_op_p(int op,int e) { long long l; if (car(e)==CONST) l = cadr(e); else if (car(e)==LCONST) l = lcadr(e); else return 0; switch(op) { case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: return (0<=l&&l<=63); case LMUL: case LUMUL: case LUDIV: /* case LDIV: */ return -0x10000000LL<l&&l<0x10000000LL && ilog(l); case LADD: case LSUB: case LBAND: case LEOR: case LBOR: return 1; default: return 0; } } void loprtc(int op,int reg,int e) { char *opl,*oph; int vl,il; int vh; long long l; if (car(e)==CONST) l = cadr(e); else if (car(e)==LCONST) l = lcadr(e); else error(-1); vl = code_l1(l); vh = code_l2(l); il = l; use_longlong(reg); opl = 0; switch(op) { case LMUL: case LUMUL: vl=il=ilog(il); case LLSHIFT: case LULSHIFT: if (il==0) return; else if (il==32) { code_register(regv_l(reg),regv_h(reg)); code_const(0,regv_l(reg)); return; } else if (il>32) { code_register(regv_l(reg),regv_h(reg)); printf("\tsall $%d,%s\n",(int)il-32,l_edx(reg)); code_const(0,regv_l(reg)); return; } printf("\tshldl $%d,%s,%s\n",vl,l_eax(reg),l_edx(reg)); printf("\tsall $%d,%s\n",(int)il,l_eax(reg)); return; case LRSHIFT: if (il==0) return; else if (il==32) { code_register(regv_h(reg),regv_l(reg)); code_i2ll(reg); return; } else if (il>32) { code_register(regv_h(reg),regv_l(reg)); printf("\tsarl $%d,%s\n",(int)il-32,l_eax(reg)); code_i2ll(reg); return; } printf("\tshrdl $%d,%s,%s\n",(int)il,l_edx(reg),l_eax(reg)); printf("\tsarl $%d,%s\n",(int)il,l_edx(reg)); return; case LUDIV: il=ilog(il); case LURSHIFT: if (il==0) return; else if (il==32) { code_register(regv_h(reg),regv_l(reg)); code_const(0,regv_h(reg)); return; } else if (il>32) { code_register(regv_h(reg),regv_l(reg)); printf("\tsarl $%d,%s\n",(int)il-32,l_eax(reg)); code_const(0,regv_h(reg)); return; } printf("\tshrdl $%d,%s,%s\n",(int)il,l_edx(reg),l_eax(reg)); printf("\tshrl $%d,%s\n",(int)il,l_edx(reg)); return; } switch(op) { case LADD: opl="addl";oph="adcl"; break; case LSUB: opl="subl";oph="sbbl"; break; case LEOR: opl=oph="xorl"; break; case LBOR: opl=oph="orl"; break; case LBAND: opl=oph="andl"; break; default: error(-1); } printf("\t%s $%d,%s\n\t%s $%d,%s\n",opl,vl,l_eax(reg),oph,vh,l_edx(reg)); } void emit_lpop_free(int e1) { // printf("\taddl $8,%%esp\n"); } void emit_lpush() { stack_depth += SIZE_OF_INT * 2; printf("\tpushl %%edx\n\tpushl %%eax\n"); } void code_i2ll(int reg) { int reg0 = USE_CREG; use_register(creg,REG_EAX,1); regv[creg]=0; use_longlong(reg0); printf("\tcltd\n"); check_lreg(reg); lreg = creg = reg0; } void code_i2ull(int reg) { code_i2ll(reg); } void code_u2ll(int reg) { int reg0 = USE_CREG; use_register(creg,REG_EAX,1); regv[creg]=0; use_longlong(reg0); printf("\txorl %%edx,%%edx\n"); check_lreg(reg); lreg = creg = reg0; } void code_u2ull(int reg) { code_u2ll(reg); } void code_ll2i(int reg) { use_int(reg); if (virtual(REG_EAX)!=reg) printf("\tmovl %%eax,%s\n",register_name(creg,0)); } void code_ll2u(int reg) { code_ll2i(reg); } void code_ull2i(int reg) { code_ll2i(reg); } void code_ull2u(int reg) { code_ll2i(reg); } #if FLOAT_CODE void code_d2ll(int reg) { use_longlong(reg); printf("\tsubl $40,%%esp\n"); printf("\tfnstcw 2(%%esp)\n"); printf("\tmovw 2(%%esp),%%ax\n"); printf("\torw $3072,%%ax\n"); printf("\tmovw %%ax,0(%%esp)\n"); printf("\tfldcw 0(%%esp)\n"); printf("\tfistpll 12(%%esp)\n"); printf("\tfldcw 2(%%esp)\n"); printf("\tmovl 12(%%esp),%%eax\n"); printf("\tmovl 16(%%esp),%%edx\n"); printf("\taddl $40,%%esp\n"); } void code_d2ull(int reg) { use_longlong(reg); printf("\tsubl $16,%%esp\n"); printf("\tfstpl (%%esp)\n"); printf("\tcall __fixunsdfdi\n"); printf("\taddl $16,%%esp\n"); } void code_f2ll(int reg) { code_d2ll(reg); } void code_f2ull(int reg) { use_longlong(reg); printf("\tsubl $16,%%esp\n"); printf("\tfstps (%%esp)\n"); printf("\tcall __fixunssfdi\n"); printf("\taddl $16,%%esp\n"); } void code_ll2d(int reg) { printf("\tsubl $8,%%esp\n"); printf("\tmovl %%eax,(%%esp)\n"); printf("\tmovl %%edx,4(%%esp)\n"); printf("\tfildll (%%esp)\n"); printf("\taddl $8,%%esp\n"); } void code_ll2f(int reg) { code_ll2d(reg); } void code_ull2d(int reg) { code_ll2d(reg); } void code_ull2f(int reg) { code_ll2d(reg); } #endif void code_lpreinc(int e1,int e2,int reg) { int dir = caddr(e1); int creg0; char *crn; if (car(e2)==LREGISTER) { use_longlong(reg); printf("\taddl $%d,%%esi\n",dir); printf("\tadcl $%d,%%edi\n",dir>0?0:-1); if (reg!=REG_L) { code_lregister(REG_L,reg); } return; } g_expr(e2); crn = register_name(creg0=creg,0); printf("\taddl $%d,(%s)\n",dir,crn); printf("\tadcl $%d,4(%s)\n",dir>0?0:-1,crn); use_longlong(reg); lload(creg0,0,reg); } void code_lpostinc(int e1,int e2,int reg) { int dir = caddr(e1); int creg0; char *crn; if (car(e2)==LREGISTER) { use_longlong(reg); if (reg!=REG_L) { code_lregister(REG_L,reg); } printf("\taddl $%d,%%esi\n",dir); printf("\tadcl $%d,%%edi\n",dir>0?0:-1); return; } g_expr(e2); crn = register_name(creg0=creg,0); printf("\taddl $%d,(%s)\n",dir,crn); printf("\tadcl $%d,4(%s)\n",dir>0?0:-1,crn); use_longlong(reg); lload(creg0,0,reg); printf("\taddl $%d,%s\n",-dir,l_eax(reg)); printf("\tadcl $%d,%s\n",-dir>0?0:-1,l_edx(reg)); } void code_lassop(int op,int reg) { error(-1); } void code_register_lassop(int reg,int op) { error(-1); } #endif #if CASE_CODE int code_table_jump_p(int delta) { return 1; } void code_table_jump(int l,int csvalue,int delta,int max,int min,int dlabel) { char *crn; use_register(creg,csvalue,0); crn = register_name(creg,0); printf("\tsubl\t$%d,%s\n",min,crn); printf("\tcmpl\t$%d,%s\n",max-min,crn); printf("\tja\t_%d\n",dlabel); if (delta==1) { printf("\tjmp\t*_%d(,%s,4)\n",l,crn); return; } use_register(creg,REG_EAX,1); edx_setup(-1); switch(delta) { case 2: printf("\tmovl\t$1,%%edx\n"); printf("\tandl\t%%eax,%%edx\n"); printf("\tjne\t_%d\n",dlabel); printf("\tjmp\t*_%d(,%%eax,2)\n",l); break; case 4: printf("\tmovl\t$3,%%edx\n"); printf("\tandl\t%%eax,%%edx\n"); printf("\tjne\t_%d\n",dlabel); printf("\tjmp\t*_%d(%%eax)\n",l); break; default: printf("\tmovl $%d,%%ecx\n",delta); printf("\txor %%edx,%%edx\n\tdivl %%ecx\n"); printf("\tandl\t%%edx,%%edx\n"); printf("\tjne\t_%d\n",dlabel); printf("\tjmp\t*_%d(,%%eax,4)\n",l); break; } edx_cleanup(); } void code_table_open(int l) { output_mode=DATA_EMIT_MODE; printf(" \t.section\t.rodata\n\t.align 4\n"); fwddef(l); } void code_table_value(int label,int table_top) { printf("\t.long _%d\n",label); } void code_table_close() { text_mode(); } #endif #if ASM_CODE /* print an operand */ static void emit_asm_operand(int rstr) { if (car(rstr)==REGISTER) { printf("%s",register_name(cadr(rstr),0)); } else if (car(rstr)==CONST) { printf("%d",cadr(rstr)); } else if (car(rstr)==FNAME) { printf("%s",(char*)cadr(rstr)); } else if (car(rstr)==STRING) { printf("_%d",cadr(rstr)); } else { error(-1); } } /* prepare asm operands char *constraints string int operand expr int mode (ASM_INPUT,ASM_OUTPUT) int replacement list int output operands count int output operands replacement list retrun replacement list list3( operands, next, clobber ) 0 can be shared in input/output 1 can't be used in input */ int code_asm_operand(char *p,int e1,int mode,int repl,int n,int repl0) { int r; int c; int val; int clobber = 0; printf("# constraint %s\n",p); if (*p=='=') { // output register p++; } if (*p=='&') { // earlyclobber p++; clobber = 1; } c = *p; if (c=='r') { if (mode==ASM_INPUT) { for(;repl0;repl0 = cadr(repl0)) { if (car(car(repl0))==REGISTER && caddr(repl0)==0) { r = cadr(car(repl0)); caddr(repl0) = ASM_USED; break; } } r = get_register(); } else { r = get_register(); } repl = list3(list2(REGISTER,r),repl,clobber); } else if (c=='m') { repl = list3(list2(0,0),repl,clobber); } else if (c=='i') { if (car(e1)==GVAR) { e1=list3(FNAME,(int)(((NMTBL *)caddr(e1))->nm),0); } else if (car(e1)==FNAME) { e1=list3(FNAME,(int)(((NMTBL *)cadr(e1))->nm),0); } else if (car(e1)==STRING) { val = emit_string_label(); ascii((char*)cadr(e1)); e1=list3(STRING,val,0); } else if (car(e1)==CONST) { } else error(-1); repl = list3(e1,repl,clobber); } else if (digit(c)) { val = 0; do { val = val*10 + c-'0'; } while (digit(c=*p++)); if (val>MAX_ASM_REG) error(-1); // too large register if (n-val<0) error(-1); repl = list3(car(nth(n-val-1,repl0)),repl,clobber); } else error(-1); return repl; } void code_free_asm_operand(int repl) { for(;repl;repl=cadr(repl)) { if (car(car(repl))==REGISTER) free_register(cadr(car(repl))); } } extern void code_asm(char *asm_str,int repl) { int c,i,rstr,val; char *p; int reg[MAX_ASM_REG]; text_mode(); c = *asm_str; if (c!='\t'&&c!=' ') printf("\t"); for(i=0;repl && i<MAX_ASM_REG;i++) { reg[i] = car(repl); repl = cadr(repl); } p = asm_str; while((c = *p++)) { if (c=='%') { c = *p++; if (!c) { break; } else if (c=='%') { printf("%%"); continue; } else if (!digit(c)) { printf("%%%c",c); continue; } val = 0; do { val = val*10 + c-'0'; } while (digit(c=*p++)) ; p--; if (val>MAX_ASM_REG) error(-1); // too large register rstr = reg[val]; emit_asm_operand(rstr); } else { printf("%c",c); } } printf("\n"); } #endif #if BIT_FIELD_CODE /* bit field alignment calcuration */ static void set_bitsz(int type,int *pbitpos, int *pbitsize, int *psign,int *pbitsz,int *palign,int *pl) { int sign=0,bitsz; int align,l=0; *pbitpos = cadr(caddr(type)); *pbitsize = caddr(caddr(type)); switch(cadr(type)) { case INT: sign=1; bitsz=32; align=4;break; case UNSIGNED: bitsz=32; align=4;break; case CHAR: sign=1; bitsz= 8; align=1;break; case UCHAR: bitsz= 8; align=1;break; case SHORT: sign=1; bitsz=16; align=2;break; case USHORT: sign=1; bitsz=16; align=2;break; case LONGLONG: sign=1; bitsz=64; align=4;l=1; break; case ULONGLONG: bitsz=64; align=4;l=1; break; default: error(-1); } *psign = sign; *pbitsz = bitsz; *palign = align; *pl = l; } /* bit field alignment calcuration this is architecture depenedent */ extern int code_bit_field_disp(int type,int *poffset,int *bfd,int *sz) { int sign,bitsz,align; int i; int bitpos = *bfd; int bitpos0; int bitsize; int offset = *poffset; int l; set_bitsz(type,&bitpos0,&bitsize,&sign,&bitsz,&align,&l); if (bitsize>bitsz) { error(BTERR); bitsize = i; } /* bfd means previous bit field bit offset */ if (bitpos) { /* previous field is bit field and spaces may remain */ /* calc previsous offset */ i= offset-(bitpos+7)/8; for(l = bitpos;l>0;l -= 8,i++) { if ((i & (align-1))==0 && l+bitsize <= bitsz) { /* alignment is correct and space remains */ *poffset=offset=i; i = l+bitsize; *bfd = (i==bitsz)?0:i; *sz = (i+7)/8; // printf("# bitpos=%d bitsize=%d bitsz=%d offset=%d\n",l,bitsize,bitsz,*poffset); return l; } } } /* first bit-field */ if ((i=(offset & (align-1)))) { *poffset = (offset += (align-i)); } bitpos = 0; *bfd = (bitsize==bitsz)?0:bitsize; *sz = (bitsize+7)/8; // printf("# bitpos=%d bitsize=%d bitsz=%d offset=%d\n",bitpos,bitsize,bitsz,*poffset); return bitpos; } /* bit field value */ extern void code_bit_field(int type,int adr,int reg) { int sign,bitsz,l,align; int bitsize,bitpos; int i,size; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size=bitsz/8; // printf("# %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); /* this implementation returns -1 for int i:1; */ if (l==1) { #if LONGLONG_CODE use_int(adr); use_longlong(reg); lload(adr,0,reg); /* shift left */ if ((i=bitsz-bitsize-bitpos)) loprtc(LLSHIFT,reg,list2(CONST,i)); /* shift right */ if ((i=bitsz-bitsize)) loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i)); #endif } else { use_int(adr); use_int(reg); printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), register_name(reg,0)); /* shift left */ if ((i=32-bitsize-bitpos)) oprtc(LSHIFT,reg,list2(CONST,i)); /* shift right */ if ((i=32-bitsize)) oprtc(sign?RSHIFT:URSHIFT,reg,list2(CONST,i)); } } /* bit field replacement */ static void make_mask_and_or(int mask,int reg,int lreg) { printf("# mask 0x%08x ~0x%08x\n",mask,~mask); printf("\tpushl %s\n",register_name(reg,0)); /* make and-mask */ oprtc(BOR,reg,list2(CONST,~mask)); /* do conjunction */ if (lreg==-1) { printf("\tandl %s,4(%%esp)\n",register_name(reg,0)); } else if (lreg==-2) { printf("\tandl %s,8(%%esp)\n",register_name(reg,0)); } else { printf("\tandl %s,%s\n",register_name(reg,0),register_name(lreg,0)); } /* make or-mask */ printf("\tpopl %s\n",register_name(reg,0)); oprtc(BAND,reg,list2(CONST,mask)); /* do disjunction */ if (lreg==-1) { printf("\torl %s,0(%%esp)\n",register_name(reg,0)); } else if (lreg==-2) { printf("\torl %s,4(%%esp)\n",register_name(reg,0)); } else { printf("\torl %s,%s\n",register_name(reg,0),register_name(lreg,0)); printf("\txchg %s,%s\n",register_name(reg,0),register_name(lreg,0)); } } extern void code_bit_replace(int adr,int value,int type) { int sign,bitsz,l,align; int bitsize,bitpos; int mask = 0; int size; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("# %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); if (l) { #if LONGLONG_CODE int push=0; use_int(adr); use_longlong(value); /* shift left */ if (bitpos) loprtc(LLSHIFT,value,list2(CONST,bitpos)); if (bitpos+bitsize>=32) { /* make and-mask upper */ printf("\tpushl %s\n",register_name(adr,0)); push=1; printf("\t%s %d(%s),%s\n",cload(sign,size),4,register_name(adr,0), register_name(adr,0)); mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); make_mask_and_or(mask,regv_h(value),adr); printf("\tmovl 0(%%esp),%s\n",register_name(adr,0)); printf("\t%s %s,4(%s)\n",move(0), l_edx(value), register_name(adr,0)); } if (bitpos<32) { if (!push) { printf("\tpushl %s\n",register_name(adr,0)); push=1;} /* make and-mask lower */ printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), register_name(adr,0)); mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); make_mask_and_or(mask,regv_l(value),adr); printf("\tpopl %s\n",register_name(adr,0)); push=0; printf("\t%s %s,(%s)\n",move(0), l_eax(value), register_name(adr,0)); } if (push) printf("\taddl %%sp,$4\n"); #endif } else { use_int(adr); use_int(value); printf("\tpushl %s\n",register_name(adr,0)); printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), register_name(adr,0)); /* shift left */ if (bitpos) oprtc(LSHIFT,value,list2(CONST,bitpos)); /* make and-mask */ mask = make_mask(32-bitpos-bitsize,31-bitpos); make_mask_and_or(mask,value,adr); printf("\tpopl %s\n",register_name(adr,0)); code_assign(adr,size,value); } if (use) { code_bit_field(type,adr,USE_CREG); } } static void make_mask_and_or_const(int mask,int reg,int c) { int a; // printf("# mask 0x%08x ~0x%08x\n",mask,~mask); a = ~mask|c; if (a!=-1) { /* do conjunction */ if (rname[reg]<MAX_DATA_REG && ((a& ~0xffff)==~0xffff)) { if ((a& ~0xff)==~0xff) printf("\tandb $%d,%s\n",a&0xff,register_name(reg,1)); else printf("\tandw $%d,%s\n",a&0xffff,register_name(reg,2)); } else printf("\tandl $%d,%s\n",a,register_name(reg,0)); } /* make or-mask */ c = mask&c; if (c!=0) { /* do disjunction */ if (rname[reg]<MAX_DATA_REG && (!(c& ~0xffff))) { if (!(c& ~0xff)) printf("\torb $%d,%s\n",c&0xff,register_name(reg,1)); else printf("\torw $%d,%s\n",c&0xffff,register_name(reg,2)); } else printf("\torl $%d,%s\n",c,register_name(reg,0)); } } extern void code_bit_replace_const(int value,int adr,int type) { int sign,bitsz,l,align; int bitpos,bitsize,size; int mask = 0; int c,lvalue; #if LONGLONG_CODE long long lc; #endif set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("# %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); use_int(adr); if (l) { #if LONGLONG_CODE lvalue = get_register(); /* shift left */ lc = lcadr(value); lc <<= bitpos; if (bitpos+bitsize>=32) { printf("\t%s %d(%s),%s\n",cload(sign,size),4,register_name(adr,0), register_name(lvalue,0)); /* make and-mask upper */ mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); make_mask_and_or_const(mask,lvalue,(int)(lc>>32)); printf("\t%s %s,4(%s)\n",move(0),register_name(lvalue,0), register_name(adr,0)); } if (bitpos<32) { printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), register_name(lvalue,0)); /* make and-mask lower */ mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); make_mask_and_or_const(mask,lvalue,(int)(lc)); printf("\t%s %s,(%s)\n",move(0), register_name(lvalue,0),register_name(adr,0)); } free_register(lvalue); #endif } else { lvalue = get_register(); printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), register_name(lvalue,0)); /* shift left */ c = cadr(value); c <<= bitpos; /* make and-mask */ mask = make_mask(32-bitpos-bitsize,31-bitpos); make_mask_and_or_const(mask,lvalue,c); code_assign(adr,size,lvalue); free_register(lvalue); } if (use) code_bit_field(type,adr,USE_CREG); } #endif /* end */