Mercurial > hg > CbC > old > device
diff mc-codegen.c @ 61:8ffb8ca3fe34
separation of architecture dependent part.
author | kono |
---|---|
date | Thu, 20 Feb 2003 03:29:15 +0900 |
parents | |
children | 0b068058dd67 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mc-codegen.c Thu Feb 20 03:29:15 2003 +0900 @@ -0,0 +1,909 @@ +/* Micro-C Generic Code Generatation Part */ +/* $Id$ */ + +#define EXTERN extern +#include "mc.h" +#include "mc-codegen.h" +#include "mc-code.h" + +int creg; /* current register */ +int dreg; /* temporary register */ +int reg_sp; /* REGister Stack-Pointer */ + +/* + 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]] + */ + +void remove0(int *parent,int e) ; +void remove0_all(int *parent,int e) ; +int is_same_type(int e1,int e2); +void jump(int e1, int env); +void machinop(int e1); +void sassign(int e1); +void assign(int e1); +void assop(int e1); + +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; +} + +int +free_register_count(void) +{ + int i,count; + count = 0; + for(i=0;i<MAX_REGISTER;i++) { + if (! regs[i] && ! regv[i]) count++; + } + return count; +} + +void +free_all_register(void) +{ + int i; + for(i=0;i<MAX_REGISTER;i++) { + regs[i]=regv[i]=0; + } + creg = get_register(); + dreg = get_register(); + return; +} + +void +use_register_var(int i) { + regv[i]=1; +} + +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(); + 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; + text_mode(); +} + +int +virtual(int real) +{ + int real_v,i; + real_v = -1; + for(i=0;i<MAX_REGISTER;i++) { + if (rname[i]==real) { + real_v=i; + break; + } + } + return real_v; +} + +int +pop_register(void) +{ /* レジスタから値を取り出す */ + return reg_stack[--reg_sp]; +} + +int +stack_used(void) { + return reg_stack[--reg_sp]<0; +} + +void +emit_pop_free(int xreg) +{ + if (xreg==dreg) { + regv[dreg]=0; + } else if (xreg!=-1) { + free_register(xreg); + } +} + +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*/; + NMTBL *n; + + if (chk) return; + e2 = cadr(e1); + switch (car(e1)){ + case GVAR: + code_gvar(e1); + regv[creg]=1; + return; + case RGVAR: + code_rgvar(e1); + regv[creg]=1; + return; + case CRGVAR: + code_crgvar(e1); + regv[creg]=1; + return; + case LVAR: + code_lvar(lvar(e2)); + regv[creg]=1; + return; + case REGISTER: + /* this is of course redundant... */ + /* we can use rname for this? */ + /* or why not creg=e2? */ + code_register(e2); + regv[creg]=1; + return; + case RLVAR: + code_rlvar(lvar(e2)); + regv[creg]=1; + return; + case CRLVAR: + code_crlvar(lvar(e2)); + regv[creg]=1; + return; + case FNAME: + code_fname(((NMTBL *)(e2))->nm); + regv[creg]=1; + return; + case CONST: /* 代入する値が0でも特別な処理はしない */ + code_const(e2); + 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); + code_neg(); + return; + case BNOT: /* ~ */ + g_expr(e2); + code_not(); + return; + case LNOT: /* ! */ + g_expr(e2); + code_lnot(); + return; + case PREINC: + code_preinc(e1,e2); + return; + case POSTINC: + code_postinc(e1,e2); + return; + case CPOSTINC: + /* char *p; *p++ */ + code_cpostinc(e1,e2); + return; + case CPREINC: + code_cpreinc(e1,e2); + return; + case CPOSTDEC: + code_cpostdec(e1,e2); + return; + case CPREDEC: + code_cpredec(e1,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); + code_set_fixed_creg(0); + g_expr(caddr(e1)); + /* e4 = rname[creg]; this is a bad idea */ + code_set_fixed_creg(1); + jmp(e3=fwdlabel()); + fwddef(e2); + code_set_fixed_creg(0); + g_expr(cadddr(e1)); + code_set_fixed_creg(1); + fwddef(e3); + return; + case SASS: + 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(); + code_return(creg); + regv[creg]=1; + return; + case ENVIRONMENT: + code_environment(creg); + regv[creg]=1; + return; + default: + code_bool(e1); + 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,code_gt(cond)); + return; + case UGT: + rexpr(e1,l1,code_ugt(cond)); + return; + case GE: + rexpr(e1,l1,code_ge(cond)); + return; + case UGE: + rexpr(e1,l1,code_uge(cond)); + return; + case LT: + rexpr(e1,l1,code_ge(!cond)); + return; + case ULT: + rexpr(e1,l1,code_uge(!cond)); + return; + case LE: + rexpr(e1,l1,code_gt(!cond)); + return; + case ULE: + rexpr(e1,l1,code_ugt(!cond)); + return; + case EQ: + rexpr(e1,l1,code_eq(cond)); + return; + case NEQ: + rexpr(e1,l1,code_eq(!cond)); + 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: + code_cmp_crgvar(e1); + jcond(l1,cond); + return; + case CRLVAR: + code_cmp_crlvar(lvar(e2)); + jcond(l1,cond); + return; + case RGVAR: + code_cmp_rgvar(e1); + jcond(l1,cond); + return; + case RLVAR: + code_cmp_rlvar(lvar(e2)); + jcond(l1,cond); + return; + case REGISTER: + code_cmp_register(e2); + 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); + code_cmp_register(creg); + jcond(l1,cond); + return; + } +} + + +/* 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,register_var(regs++)), 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; + } else { + if (disp_offset-arg_size<disp) disp = disp_offset-arg_size; + } + + /* 複雑な式を前もって計算しておく */ + /* 必要なら局所変数を用いる。 */ + /* 局所変数へのオフセットを覚えておく */ + + 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; + 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); + code_frame_pointer(e3); + emit_pop_free(e3); + } else if (fnptr->sc==FUNCTION) { + code_fix_frame_pointer(disp_offset); + } + + if (car(e2) == FNAME) { + code_jmp(code0->nm); + } else { + e2 = emit_pop(0); + code_indirect_jmp(e2); + 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 +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) +{ + int e2,e3,e4,byte; + + byte=(car(e1) == CASS); + /* e2=e4 */ + e2 = cadr(e1); + e3 = cadr(e2); + e4 = caddr(e1); + switch(car(e2)) { + case GVAR: /* i=3 */ + g_expr(e4); + code_assign_gvar(e2,byte); + return; + case LVAR: + g_expr(e4); + code_assign_lvar(lvar(cadr(e2)),byte); + return; + case REGISTER: + g_expr(e4); + if (creg!=cadr(e2)) + code_assign_register(cadr(e2),byte); + 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); + code_assign(e2,byte); + emit_pop_free(e2); + regv[creg]=1; + return; +} + +void +assop(int e1) +{ + int e2,e3,byte,op; + + /* 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) { + code_register_assop(cadr(e2),op,byte); + regv[creg]=1; + return; + } + emit_push(); + g_expr(e2); + code_assop(op,byte); + regv[creg]=1; + return; +} + + +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_source(char *s) +{ + printf("%s",s); +} + +void +ret(void) +{ + code_set_fixed_creg(1); + jmp(retlabel); +} + +/* end */