Mercurial > hg > CbC > old > device
view mc-codegen.c @ 436:d92786033042 loprtc-div
loprtc
author | kono |
---|---|
date | Sun, 14 Nov 2004 15:41:05 +0900 |
parents | d3e6359f8501 |
children | 49d4483d5110 |
line wrap: on
line source
/* Micro-C Generic Code Generation Part */ /* $Id$ */ #include <stdio.h> #include "mc.h" #include "mc-parse.h" #include "mc-codegen.h" #include "mc-code.h" int use; /* generated value will be used */ char *init_src; int size_of_int; int size_of_short; int size_of_float; int size_of_double; int size_of_longlong; int bit_of_byte; int endian; int disp_align; static void assign(int e1); static void gen_asm(int asm0,int in,int out,int opt,int e); static void compatible(int t1, int t2); static int contains(int e,int type); static int contains_in_list(int e,int type); static int contains_in_list_p(int e,int (*p)(int)); static void iassop(int e1); static int is_same_type(int e1,int e2); static void jump(int e1, int env); static void machinop(int e1); static int register_to_lvar(int e); static void remove0(int *parent,int e) ; static void sassign(int e1); #if FLOAT_CODE /* floating point */ static void dassop(int e1); static void dmachinop(int e1,int d); static void dassign(int e1); #endif #if LONGLONG_CODE static void lassop(int e1); static void lmachinop(int e1); static void lassign(int e1); #endif #if BIT_FIELD_CODE static int bit_field_repl(int e1,int e2,int t); static int bit_field(int e1,int t); static int bassign(int e1,int e2,int t); static int bassop(int e1,int e2,int op,int t,int post); #endif extern void codegen_init() { /* called only once */ code_init(); } extern void codegen_reinit() { /* called for each file */ emit_reinit(); } extern void codegen_decl_init() { /* called before each declaration */ emit_init(); init_free_lvar_list(); } extern void arg_register(NMTBL *fnptr) { code_arg_register(fnptr); } extern int gexpr(int e1,int use0) { if (chk) return INT; gexpr_init(); use = use0; #if 0 if(lineno==2862) { return g_expr0(e1); /*break here*/ } #endif return g_expr0(e1); } /* gexpr for value unused */ extern int g_expr_u(int e1) { int t; int suse = use; use=0; t=g_expr0(e1); code_gexpr(e1); use=suse; return t; } /* gexpr for value used */ extern int g_expr(int e1) { int t; int suse = use; use=1; t=g_expr0(e1); code_gexpr(e1); use=suse; return t; } /* gexpr for used flag untouched */ extern int g_expr0(int e1) { int e2,e3,t,d,t1; NMTBL *n; code_gexpr(e1); e2 = cadr(e1); switch (car(e1)){ case GVAR: code_gvar(e1,USE_CREG); return ADDRESS; case RGVAR: code_rgvar(e1,USE_CREG); return INT; case CRGVAR: code_crgvar(e1,USE_CREG,1,1); return CHAR; case CURGVAR: code_crgvar(e1,USE_CREG,0,1); return UCHAR; case SRGVAR: code_crgvar(e1,USE_CREG,1,size_of_short); return CHAR; case SURGVAR: code_crgvar(e1,USE_CREG,0,size_of_short); return UCHAR; case LVAR: code_lvar(e2,USE_CREG); return ADDRESS; case REGISTER: code_register(e2,USE_CREG); return INT; #if FLOAT_CODE case DREGISTER: code_dregister(e2,USE_CREG,1); return DOUBLE; case FREGISTER: code_dregister(e2,USE_CREG,0); return FLOAT; #endif #if LONGLONG_CODE case LREGISTER: code_lregister(e2,USE_CREG); return LONGLONG; #endif case RLVAR: code_rlvar(e2,USE_CREG); return INT; case CRLVAR: code_crlvar(e2,USE_CREG,1,1); return CHAR; case CURLVAR: code_crlvar(e2,USE_CREG,0,1); return UCHAR; case SRLVAR: code_crlvar(e2,USE_CREG,1,size_of_short); return CHAR; case SURLVAR: code_crlvar(e2,USE_CREG,0,size_of_short); return UCHAR; #if FLOAT_CODE case FRLVAR: code_drlvar(e2,0,USE_CREG); return FLOAT; case FRGVAR: code_drgvar(e1,0,USE_CREG); return FLOAT; case DRLVAR: code_drlvar(e2,1,USE_CREG); return DOUBLE; case DRGVAR: code_drgvar(e1,1,USE_CREG); return DOUBLE; #endif #if LONGLONG_CODE case LRLVAR: code_lrlvar(e2,USE_CREG); return LONGLONG; case LRGVAR: code_lrgvar(e1,USE_CREG); return LONGLONG; case LURLVAR: code_lrlvar(e2,USE_CREG); return ULONGLONG; case LURGVAR: code_lrgvar(e1,USE_CREG); return ULONGLONG; #endif case FNAME: code_fname((NMTBL *)(e2),USE_CREG); return ADDRESS; case LABEL: code_label_value(e2,USE_CREG); return ADDRESS; case CONST: /* 代入する値が0でも特別な処理はしない */ code_const(e2,USE_CREG); return INT; #if FLOAT_CODE case DCONST: code_dconst(e1,USE_CREG,1); return DOUBLE; case FCONST: code_dconst(e1,USE_CREG,0); return FLOAT; #endif #if LONGLONG_CODE case LCONST: code_lconst(e1,USE_CREG); return LONGLONG; #endif case STRING: code_string(e1,USE_CREG); return ADDRESS; case FUNCTION: t = function(e1); return t; case CODE: jump(e2,caddr(e1)); return VOID; case INDIRECT: return g_expr0(e2); case RINDIRECT: code_rindirect(e2,USE_CREG,caddr(e1),1,0); return INT; case URINDIRECT: code_rindirect(e2,USE_CREG,caddr(e1),0,0); return UNSIGNED; case CRINDIRECT: code_rindirect(e2,USE_CREG,caddr(e1),1,1); return CHAR; case CURINDIRECT: code_rindirect(e2,USE_CREG,caddr(e1),0,1); return UCHAR; case SRINDIRECT: code_rindirect(e2,USE_CREG,caddr(e1),1,size_of_short); return SHORT; case SURINDIRECT: code_rindirect(e2,USE_CREG,caddr(e1),0,size_of_short); return USHORT; #if FLOAT_CODE case FRINDIRECT: return code_drindirect(e2,USE_CREG,caddr(e1),0); case DRINDIRECT: return code_drindirect(e2,USE_CREG,caddr(e1),1); #endif #if LONGLONG_CODE case LRINDIRECT: return code_lrindirect(e2,USE_CREG,caddr(e1),0); case LURINDIRECT: return code_lrindirect(e2,USE_CREG,caddr(e1),1); #endif case ADDRESS: if (car(e2)==REGISTER||car(e2)==DREGISTER||car(e2)==FREGISTER) return register_to_lvar(e2); /* too late? */ else return g_expr0(e2); case MINUS: /* レジスタに対し、neglを実行すれば実現可能 */ g_expr0(e2); code_neg(USE_CREG); return INT; #if LONGLONG_CODE case LMINUS: g_expr0(e2); code_lneg(USE_CREG); return LONGLONG; #endif #if FLOAT_CODE case DMINUS: g_expr0(e2); code_dneg(USE_CREG,1); return DOUBLE; case FMINUS: g_expr0(e2); code_dneg(USE_CREG,0); return FLOAT; #endif case CONV: g_expr0(e2); switch(caddr(e1)) { case I2C: code_i2c(USE_CREG); return INT; case I2S: code_i2s(USE_CREG); return INT; case U2UC: code_u2uc(USE_CREG); return UNSIGNED; case U2US: code_u2us(USE_CREG); return UNSIGNED; #if FLOAT_CODE case I2D: code_i2d(USE_CREG); return DOUBLE; case D2I: code_d2i(USE_CREG); return INT; case U2D: code_u2d(USE_CREG); return DOUBLE; case F2U: code_f2u(USE_CREG); return UNSIGNED; case I2F: code_i2f(USE_CREG); return FLOAT; case F2I: code_f2i(USE_CREG); return INT; case U2F: code_u2f(USE_CREG); return FLOAT; case D2U: code_d2u(USE_CREG); return UNSIGNED; case D2F: code_d2f(USE_CREG); return FLOAT; case F2D: code_f2d(USE_CREG); return DOUBLE; #endif #if LONGLONG_CODE case I2LL: code_i2ll(USE_CREG); return LONGLONG; case I2ULL: code_i2ull(USE_CREG); return ULONGLONG; case U2LL: code_u2ll(USE_CREG); return LONGLONG; case U2ULL: code_u2ull(USE_CREG); return ULONGLONG; case LL2I: code_ll2i(USE_CREG); return INT; case LL2U: code_ll2u(USE_CREG); return UNSIGNED; case ULL2I: code_ull2i(USE_CREG); return INT; case ULL2U: code_ull2u(USE_CREG); return UNSIGNED; #if FLOAT_CODE case D2LL: code_d2ll(USE_CREG); return LONGLONG; case D2ULL: code_d2ull(USE_CREG); return ULONGLONG; case F2LL: code_f2ll(USE_CREG); return LONGLONG; case F2ULL: code_f2ull(USE_CREG); return ULONGLONG; case LL2D: code_ll2d(USE_CREG); return DOUBLE; case LL2F: code_ll2f(USE_CREG); return FLOAT; case ULL2D: code_ull2d(USE_CREG); return DOUBLE; case ULL2F: code_ull2f(USE_CREG); return FLOAT; #endif #endif default: error(-1); return INT; } case BNOT: /* ~ */ g_expr0(e2); code_not(USE_CREG); return INT; case LNOT: /* ! */ g_expr0(e2); code_lnot(USE_CREG); return INT; case PREINC: code_preinc(e1,e2,caddr(e1),1,cadddr(e1),USE_CREG); return INT; case UPREINC: code_preinc(e1,e2,caddr(e1),0,cadddr(e1),USE_CREG); return INT; case POSTINC: code_postinc(e1,e2,caddr(e1),1,cadddr(e1),USE_CREG); return INT; case UPOSTINC: code_postinc(e1,e2,caddr(e1),0,cadddr(e1),USE_CREG); return INT; #if FLOAT_CODE case DPREINC: /* ++d */ code_dpreinc(e1,e2,1,USE_CREG); return DOUBLE; case DPOSTINC: /* d++ */ code_dpostinc(e1,e2,1,USE_CREG); return DOUBLE; case FPREINC: /* ++f */ code_dpreinc(e1,e2,0,USE_CREG); return FLOAT; case FPOSTINC: /* f++ */ code_dpostinc(e1,e2,0,USE_CREG); return FLOAT; #endif #if LONGLONG_CODE case LPREINC: /* ++d */ code_lpreinc(e1,e2,USE_CREG); return LONGLONG; case LPOSTINC: /* d++ */ code_lpostinc(e1,e2,USE_CREG); return LONGLONG; case LUPREINC: /* ++d */ code_lpreinc(e1,e2,USE_CREG); return ULONGLONG; case LUPOSTINC: /* d++ */ code_lpostinc(e1,e2,USE_CREG); return ULONGLONG; #endif 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: case CMP: case CMPGE: case UCMP: case CMPEQ: case CMPNEQ: case UCMPGE: machinop(e1); return INT; #if FLOAT_CODE case DMUL: case DDIV: case DADD: case DSUB: case DCMP: case DCMPGE: case DCMPEQ: case DCMPNEQ: dmachinop(e1,1); return DOUBLE; case FMUL: case FDIV: case FADD: case FSUB: case FCMP: case FCMPGE: case FCMPEQ: case FCMPNEQ: dmachinop(e1,0); return FLOAT; #endif #if LONGLONG_CODE case LMUL: case LUMUL: case LDIV: case LUDIV: case LMOD: case LUMOD: case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: case LADD: case LSUB: case LBAND: case LEOR: case LBOR: case LCMP: lmachinop(e1); return INT; #endif case LCOND: case DCOND: case FCOND: case COND: /* a?0:1 should consider non-brach instruction */ d = (car(e1)==LCOND?LONGLONG: car(e1)==COND?INT:car(e1)==DCOND?DOUBLE:FLOAT); e2=fwdlabel(); if (caddr(e1)) { b_expr(cadr(e1),0,e2,0); g_expr0(caddr(e1)); } else { // gcc extenstion a?:DEF bexpr(cadr(e1),0,e2); // value used } t = code_get_fixed_creg(USE_CREG,d); jmp(e3=fwdlabel()); fwddef(e2); t1=g_expr0(cadddr(e1)); code_set_fixed_creg(t,1,d); fwddef(e3); return t1; case STASS: sassign(e1); return RSTRUCT; case ASS: case CASS: case SASS: assign(e1); return INT; case SASSOP: case SUASSOP: case ASSOP: case CASSOP: case CUASSOP: iassop(e1); return INT; #if FLOAT_CODE case FASS: case DASS: dassign(e1); return DOUBLE; case DASSOP: case FASSOP: dassop(e1); return DOUBLE; #endif #if LONGLONG_CODE case LASS: lassign(e1); return LONGLONG; case LASSOP: case LUASSOP: lassop(e1); return LONGLONG ; #endif case RSTRUCT: g_expr0(e2); return RSTRUCT; case ALLOCA: code_alloca(e2,USE_CREG); return list2(POINTER,CHAR); case COMMA: g_expr_u(e2); return g_expr0(caddr(e1)); case RETURN: n = (NMTBL *)e2; if (retcont==0) retcont=fwdlabel(); code_return(USE_CREG); return VOID; case ENVIRONMENT: code_environment(USE_CREG); return ADDRESS; #if BIT_FIELD_CODE case RBIT_FIELD: return bit_field(e2,caddr(e1) /* type */); case BASS: return bassign(e2,caddr(e1),cadr(cadddr(e1))/* type */); case BPREINC: return bassop(e2,list2(CONST,caddr(e1)),ADD, cadddr(e1)/* type */,0); case BPOSTINC: return bassop(e2,list2(CONST,caddr(e1)),ADD, cadddr(e1)/* type */,1); case BASSOP: return bassop(e2,caddr(e1),car(cadddr(e1)),/* op */ cadr(cadddr(e1))/* type */,0); #endif #if ASM_CODE case ASM: gen_asm(car(e2),cadr(e2),caddr(e2),cadddr(e2),caddr(e1)); /* asm in (str) out (str) opt(str) expr */ return VOID; #endif default: code_bool(e1,USE_CREG); /* type? */ return INT; } } static int rop_dual(op) { // x op y => y dual(op) x switch(op) { case GT: return LT; case UGT: return ULT; case GE: return LE; case UGE: return ULE; case LT: return GT; case ULT: return UGT; case LE: return GE; case ULE: return UGE; case DOP+GT: return DOP+LT; case DOP+GE: return DOP+LE; case DOP+LT: return DOP+GT; case DOP+LE: return DOP+GE; case FOP+GT: return FOP+LT; case FOP+GE: return FOP+LE; case FOP+LT: return FOP+GT; case FOP+LE: return FOP+GE; case LOP+GT: return LOP+LT; case LOP+GE: return LOP+LE; case LOP+LT: return LOP+GT; case LOP+LE: return LOP+GE; case LOP+UGT: return FOP+ULT; case LOP+UGE: return FOP+ULE; case LOP+ULT: return FOP+UGT; case LOP+ULE: return FOP+UGE; } return op; } /* bexpr for value unused */ extern void bexpr_u(int e1, char cond, int l1) { int op = car(e1); if (chk) return; // gexpr_init(); switch(op) { case GT: case UGT: case GE: case UGE: case LT: case ULT: case LE: case ULE: case DOP+GT: case DOP+GE: case DOP+LT: case DOP+LE: case FOP+GT: case FOP+GE: case FOP+LT: case FOP+LE: case FOP+EQ: case FOP+NEQ: case EQ: case NEQ: case DOP+EQ: case DOP+NEQ: if (car(caddr(e1))==CONST||(car(caddr(e1))==DCONST)|| car(caddr(e1))==FCONST) { b_expr(list3(rop_dual(op),caddr(e1),cadr(e1)),cond,l1,0); return; } } b_expr(e1,cond,l1,0); } /* bexpr for value used */ extern void bexpr(int e1, char cond, int l1) { int uses = use; use=1; bexpr_u(e1, cond, l1); use = uses; } /* branch expression generator */ /* if (cond?e1:!e1) goto l1 */ /* 1 or 0 is return for code_bool */ extern void b_expr(int e1, char cond, int l1,int err) { int e2,l2,t; if (!control) return; l2 = 0; e2=cadr(e1); switch(car(e1)) { case LNOT: b_expr(e2,!cond,l1,0); return; case GT: case GE: case LT: case LE: case EQ: case NEQ: rexpr(e1,l1,cond,INT); return; case UGT: case UGE: case ULT: case ULE: rexpr(e1,l1,cond,UNSIGNED); return; #if FLOAT_CODE case DOP+GT: case DOP+GE: case DOP+EQ: case DOP+NEQ: case FOP+GT: case FOP+GE: case FOP+EQ: case FOP+NEQ: drexpr(cadr(e1),caddr(e1),l1,car(e1),cond); return; case FOP+LT: case FOP+LE: case DOP+LT: case DOP+LE: drexpr(caddr(e1),cadr(e1),l1,rop_dual(car(e1)),cond); return; #endif #if LONGLONG_CODE case LOP+GT: case LOP+GE: case LOP+EQ: case LOP+NEQ: case LOP+UGT: case LOP+UGE: lrexpr(cadr(e1),caddr(e1),l1,car(e1),cond); return; case LOP+LT: case LOP+LE: case LOP+ULT: case LOP+ULE: lrexpr(caddr(e1),cadr(e1),l1,rop_dual(car(e1)),cond); return; #endif case LAND: bexpr(e2,0,cond?(l2=fwdlabel()):l1); bexpr_u(caddr(e1),cond,l1); if(cond) fwddef(l2); return; case LOR: bexpr(e2,1,cond?l1:(l2=fwdlabel())); bexpr_u(caddr(e1),cond,l1); if(!cond) fwddef(l2); return; case CRGVAR: case CURGVAR: code_cmp_crgvar(e1,USE_CREG,1,l1,cond); return; case SRGVAR: case SURGVAR: code_cmp_crgvar(e1,USE_CREG,size_of_short,l1,cond); return; case CRLVAR: case CURLVAR: code_cmp_crlvar(e2,USE_CREG,1,l1,cond); return; case SRLVAR: case SURLVAR: code_cmp_crlvar(e2,USE_CREG,size_of_short,l1,cond); return; case RGVAR: code_cmp_rgvar(e1,USE_CREG,l1,cond); return; case RLVAR: code_cmp_rlvar(e2,USE_CREG,l1,cond); return; #if FLOATC_DOE case DRLVAR: code_cmp_drlvar(e2,USE_CREG,1,l1,cond); return; case FRLVAR: code_cmp_drlvar(e2,USE_CREG,0,l1,cond); return; case DRGVAR: code_cmp_drgvar(e2,USE_CREG,1,l1,cond); return; case FRGVAR: code_cmp_drgvar(e2,USE_CREG,0,l1,cond); return; case FREGISTER: code_cmp_dregister(e2,0,l1,cond); return; case DREGISTER: code_cmp_dregister(e2,1,l1,cond); return; case DCONST: case FCONST: if(control&&((dcadr(e2)!=0.0)^cond)) jmp(l1); return; #endif #if LONGLONG_DOE case LRLVAR: code_cmp_lrlvar(e2,1,l1,cond); return; case LRGVAR: code_cmp_lrgvar(e2,1,l1,cond); return; case LREGISTER: code_cmp_lregister(e2,1,l1,cond); return; case LCONST: if(control&&((lcadr(e2)!=0)^cond)) jmp(l1); return; #endif case REGISTER: code_cmp_register(e2,l1,cond); return; case CONST: if(control&&((cond&&e2)||(!cond&&!e2))) jmp(l1); return; default: if(err) { error(-1); return; /* recursive g_expr/b_expr */ } t=g_expr(e1); if (!use) return; if (0) ; #if FLOAT_CODE else if(t==FLOAT) code_cmp_dregister(USE_CREG,0,l1,cond); else if(t==DOUBLE) code_cmp_dregister(USE_CREG,1,l1,cond); #endif #if LONGLONG_CODE else if(t==LONGLONG||t==ULONGLONG) code_cmp_lregister(USE_CREG,l1,cond); #endif else code_cmp_register(USE_CREG,l1,cond); return; } } extern int is_code(NMTBL *fnptr) { int type = fnptr->ty; return type==CODE|| (type>0 && car(type)==CODE); } extern int is_function(NMTBL *fnptr) { int type = fnptr->ty; return type==FUNCTION || (type>0 && car(type)==FUNCTION); } extern int function_type(int e1,int *dots) { int ret_type,t; ret_type = cadr(e1); if (ret_type==CHAR) ret_type=INT; /* check argments type is DOTS? */ t = caddr(e1); if (/* t==0 || */ t==DOTS) *dots = 1; else { *dots = 0; for(;t;t = cadr(t)) { if (car(t)==DOTS) *dots = 1; } } return ret_type; } static int register_to_lvar(int e) { error(REG_ERR); return 0; #if 0 途中でレジスタからLVARに変更しても、間に合わない。 NMTBL *n = (NMTBL*)caddr(e); int reg = cadr(e); int tag = car(e); int lvar; int t; if (!n||n==&null_nptr) error(REG_ERR); switch(tag) { case REGISTER: n->dsp = new_lvar(size_of_int); t = INT; break; case DREGISTER: n->dsp = new_lvar(size_of_double); t = DOUBLE; break; case FREGISTER: n->dsp = new_lvar(size_of_float); t = DOUBLE; break; case LREGISTER: n->dsp = new_lvar(size_of_longlong); t = LONGLONG; break; default: error(-1); } n->sc = LVAR; lvar = list2(LVAR,n->dsp); g_expr_u(assign_expr0(list2(LVAR,n->dsp),list3(tag,reg,(int)n),t,t)); if (tag==REGISTER||tag==DREGISTER||tag==FREGISTER||tag==LREGISTER) { free_register(reg); return g_expr0(lvar); #endif } // parallel assignment of registers. // // target = list3(target_regnum,next,source_regnum); extern void parallel_rassign(int assigns) { int free,tmp,remains,t0,t2,src; tmp = 0; for(;;) { remains = 0; // find free target for(free=assigns;free;free=cadr(free)) { if (!caddr(free)) continue; // already done if (car(free)==caddr(free)) { caddr(free)=0; continue; } remains++; t0 = car(free); // target register // check target is free for(src=assigns;src;src=cadr(src)) { if ((t2=caddr(src)) && t0==t2) break; // target is in source } if (src==0) { break; // free is a free target } } if (remains==0) { if (tmp) free_lvar(tmp); return; } if (free) { // free target if (t0!=caddr(free)) { if (caddr(free)>=0) { code_assign_register(t0,0,caddr(free)); } else { code_rlvar(caddr(free),t0); } } caddr(free)=0; // mark it done } else { // no free target for(free=assigns;free;free=cadr(free)) { if (caddr(free)) break; // not yet done } if (!free) error(-1); tmp = new_lvar(size_of_int); if (tmp>0) error(-1); code_assign_lvar(tmp,caddr(free),0); caddr(free) = tmp; } } } /* 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 0 static int overlap(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); switch(car(s)) { case REGISTER: case DREGISTER: case FREGISTER: case LREGISTER: if (code_register_overlap(s,t)) return s; } if (is_same_type(s,t)) { s1=s0+caddr(source); #if DEBUG_PARALLEL_ASSIGN>1 printf("# overlap source %d t0 %d t1 %d\n",car(car(t)),t0,t1); printf("# overlap target %d s0 %d s1 %d\n",car(car(source)),s0,s1); printf("# overlap 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; } static void remove_target(int *target,int t,int *use) { int use0=*use; int reg; while(use0) { if (car(use0)==t) { reg = car(caddr(use0)); if (reg==REGISTER||reg==FREGISTER||reg==DREGISTER||reg==LREGISTER) free_register(cadr(caddr(use0))); break; } use0 = cadr(use0); } remove0(target,t); } static void save_target(int t,int s,int *target,int *use,int sz,int ty) { int e1; /*新しいレジスタ(or スタック)を取得する*/ if (scalar(ty) && sz==size_of_int && (e1=get_register_var(0))!=-1) { // e1=list3(REGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); #if FLOAT_CODE } else if (ty==DOUBLE && sz==size_of_double && (e1=get_dregister_var(0,1))!=-1) { // e1=list3(DREGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); } else if (ty==FLOAT && sz==size_of_float && (e1=get_dregister_var(0,0))!=-1) { // e1=list3(FREGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); #endif #if LONGLONG_CODE } else if ((ty==LONGLONG||ty==ULONGLONG)&&(e1=get_lregister_var(0))!=-1) { // e1=list3(LREGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); #endif } else { g_expr_u(assign_expr0((e1=list2(LVAR,new_lvar(sz))),s,ty,ty)); *target = append4(*target,t,ty,e1); *use=list3(t,*use,e1); } } static 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=overlap(t1,sz,*source))) { if (s==s1) { #if DEBUG_PARALLEL_ASSIGN printf("# self dependency %d ty %d+%d sz %d\n",car(s1),ty,cadr(s1),sz); #endif return 1; } /* another overlap start over */ s = s1; target0 = *target; continue; } } target0=cadr(target0); } return 0; } static 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=overlap(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_u(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); } } } static void remove0(int *parent,int e) { int list; while ((list=*parent)) { if (car(list)==e) { *parent= cadr(list); return; } else { parent=&cadr(list); } } } /* static void remove0_all(int *parent,int e) { int list; while ((list=*parent)) { if (car(list)==e) { *parent= cadr(list); } else { parent=&cadr(list); } } } */ static int is_simple(int e1) { switch(e1) { case CONST: case FNAME: case LVAR: case REGISTER: case DREGISTER: case FREGISTER: case LREGISTER: case GVAR: case RGVAR: case RLVAR: case CRLVAR: case CRGVAR: case DRLVAR: case FRLVAR: case LRLVAR: case CURLVAR: case SURLVAR: case CURGVAR: case SURGVAR: return 1; } return 0; } static int is_same_type(int e1,int e2) { int ce1=car(e1); int ce2=car(e2); if (ce1==LVAR) { switch(ce2) { case RLVAR: case CRLVAR: case FRLVAR: case DRLVAR: case SRLVAR: case SURLVAR: case CURLVAR: case LVAR: return 1; } } else if (ce2==LVAR) { switch(ce1) { case RLVAR: case CRLVAR: case FRLVAR: case DRLVAR: case SRLVAR: case SURLVAR: case CURLVAR: case LRLVAR: case LVAR: return 1; } } else if (ce1==GVAR) { return 0; #if 0 switch(ce2) { case RGVAR: case CRGVAR: case FRGVAR: case DRGVAR: case SRGVAR: case SURGVAR: case CURGVAR: return 1; } #endif } else if (ce2==GVAR) { return 0; #if 0 switch(ce1) { case RGVAR: case CRGVAR: case FRGVAR: case DRGVAR: case SRGVAR: case SURGVAR: case CURGVAR: case LRGVAR: return 1; } #endif } return 0; } static int is_memory(int e1) { switch(car(e1)) { case LVAR : case RLVAR: case CRLVAR : case DRLVAR : case LRLVAR : case GVAR : case RGVAR: case CRGVAR : case DRGVAR : case LRGVAR : case FRLVAR : case FRGVAR : case CURGVAR : case SURGVAR: case SRGVAR : case REGISTER : case DREGISTER : case FREGISTER : case LREGISTER: return 1; } return 0; } #define ASSIGN_STRUCT_DIVIDE 40 static void jump(int e1, int env) { int e2,e3,e4,sz,arg_size,ty,regs,fregs; int t0,s0,r,reg; NMTBL *code0 = 0; int target = 0; int source = 0; int processing = 0; int use = 0; /* e1 = list4(FUNCTION,code_segment,arglist,ftype); */ /* まず、サイズを計算しながら、target を決まった形に落す。 */ arg_size = 0; regs = 0; fregs = 0; for (e3 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) { e2 = car(e3); sz = size(ty=caddr(e3)); if (scalar(ty) && (r = get_input_register_var(regs,0,1))) { target=list4(r,target,ty,e2); regs++; } else if (ty==FLOAT && (r = get_input_dregister_var(fregs,0,1,0))) { target=list4(r, target,ty,e2); fregs++; } else if (ty==DOUBLE && (r = get_input_dregister_var(fregs,0,1,1))) { target=list4(r, target,ty,e2); fregs++; } else if ((ty==LONGLONG||ty==ULONGLONG) && (r = get_input_lregister_var(fregs,0,1))) { target=list4(r, target,ty,e2); regs+=2; } else { while(car(e2)==RSTRUCT) e2=cadr(e2); target=list4(list2(LVAR,0), target,ty,e2); } /* keep arg space for register variables */ 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 (is_code(fnptr)) { 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))) { g_expr_u(assign_expr0((e4=list2(LVAR,new_lvar(sz))),s0,ty,ty)); use=list3(ty,use,e1); 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 keep source to avoid overwrite */ if(is_memory(s0)) { source=list3(s0,source,sz); continue; } } } if(is_memory(s0)) { if (sz>8 && car(s0)==LVAR && car(t0)==LVAR &&sz<ASSIGN_STRUCT_DIVIDE) { /* large struct generate large save/restore */ /* divide it to avoid large copy */ #if DEBUG_PARALLEL_ASSIGN printf("# division sz %d\n",sz); #endif caddr(e2) = UNSIGNED; source=list3( cadddr(e2), source,4); #if DEBUG_PARALLEL_ASSIGN printf("# div 0 source %d ty %d+%d sz %d\n",car(car(source)),ty,cadr(car(source)),4); #endif for(e4=4;e4<sz;) { cadr(e2) = list4(car(e2),cadr(e2),caddr(e2),cadddr(e2)); switch(sz-e4) { case 1: caddr(e2) = UCHAR; r = 1; break; case 2: case 3: caddr(e2) = USHORT; r = 2; break; default: caddr(e2) = UNSIGNED; r = 4; } if (e4==4) e3=cadr(e2); car(e2) = list2(LVAR,cadr(t0)+e4); cadddr(e2) = list2(LVAR,cadr(s0)+e4); source=list3( cadddr(e2), source,r); e4 += r; #if DEBUG_PARALLEL_ASSIGN printf("# div 1 source %d ty %d+%d sz %d\n",car(car(source)),ty,cadr(car(source)),r); #endif } e2 = e3; continue; } 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 (!is_code(code0)) { 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) { reg = car(caddr(use)); if (reg==REGISTER||reg==FREGISTER||reg==DREGISTER||reg==LREGISTER) free_register(cadr(caddr(use))); else if (car(caddr(use))==LVAR) free_lvar(cadr(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 (is_function(fnptr)) { if (car(e2) != FNAME) { e2 = emit_pop(0); code_fix_frame_pointer(disp_offset); code_indirect_jmp(e2); emit_pop_free(e2); return; } 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); } } static void machinop(int e1) { int e2,e3,op; e2 = cadr(e1); op = car(e1); e3 = caddr(e1); if (code_const_op_p(op,e3)) { g_expr(e2); oprtc(op,USE_CREG,e3); return; } g_expr(e3); emit_push(); g_expr(e2); tosop(op,USE_CREG,(e2=pop_register())); emit_pop_free(e2); return; } #if FLOAT_CODE static void dmachinop(int e1,int d) { int e2,e3,op; e2 = cadr(e1); op = car(e1); e3 = caddr(e1); g_expr(e3); emit_dpush(d); g_expr(e2); dtosop(car(e1),USE_CREG,(e2=emit_dpop(d))); emit_dpop_free(e2,d); return; } #endif #if LONGLONG_CODE static void lmachinop(int e1) { int e2,e3,op; e2 = cadr(e1); op = car(e1); e3 = caddr(e1); if (code_lconst_op_p(op,e3)) { g_expr(e2); loprtc(op,USE_CREG,e3); return; } g_expr(e3); emit_lpush(); g_expr(e2); ltosop(car(e1),USE_CREG,(e2=emit_lpop())); emit_lpop_free(e2); return; } #endif static void sassign(int e1) { int e2,e3,e4,sz,xreg,det,offset; /* 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 */ if (car(e4)==RSTRUCT) { e4 = cadr(e4); } if (is_same_type(e2,e4)) { if (cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } } g_expr(e4); emit_push(); g_expr(e2); xreg = emit_pop(0); /* 一般的にはコピーのオーバラップの状況は実行時にしかわからない */ /* しかし、わかる場合もある */ if (is_same_type(e2,e4)) { if(cadr(e2)<cadr(e4)) { offset=sz; sz=-sz;} else offset=0; det=1; } else { det = 0; offset=0; } emit_copy(xreg,USE_CREG,sz,offset,1,det); emit_pop_free(xreg); return; } static void assign_opt(int e5,int e2,int e4,int byte) { int reg; /* e2=e4 */ if (e5==REGISTER) { reg = cadr(e4); switch(car(e2)) { case GVAR: code_assign_gvar(e2,reg,byte); return; case LVAR: code_assign_lvar(cadr(e2),reg,byte); return; case REGISTER: code_assign_register(cadr(e2),byte,reg); return; } g_expr(e2); code_assign(USE_CREG,byte,reg); return; } /* e2 is register now */ if (car(e2)!=REGISTER) error(-1); reg = cadr(e2); switch(e5) { case CRGVAR: case CURGVAR: code_crgvar(e4,reg,e5==CRGVAR,1); return; case SRGVAR: case SURGVAR: code_crgvar(e4,reg,e5==SRGVAR,size_of_short); return; case RGVAR: code_rgvar(e4,reg); return; case CRLVAR: case CURLVAR: code_crlvar(cadr(e4),reg,e5==CRLVAR,1); return; case SRLVAR: case SURLVAR: code_crlvar(cadr(e4),reg,e5==SRLVAR,size_of_short); return; case RLVAR: code_rlvar(cadr(e4),reg); return; case GVAR: code_gvar(e4,reg); return; case LVAR: code_lvar(cadr(e4),reg); return; case CONST: code_const(cadr(e4),reg); return; case ADDRESS: if (car(cadr(e4))==STRING) code_string(cadr(e4),reg); else code_gvar(cadr(e4),reg); return; case FNAME: code_fname((NMTBL*)cadr(e4),reg); return; case STRING: code_string(e4,reg); return; default: error(-1); } } static void assign(int e1) { int e2,e4,byte,e5; byte=(car(e1) == CASS)?1:(car(e1) == SASS)?size_of_short:0; /* e2=e4 */ e2 = cadr(e1); e4 = caddr(e1);e5=car(e4); if (is_same_type(e2,e4)&&cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } if (!use) { if (e5==REGISTER) { assign_opt(e5,e2,e4,byte); return; } else if (car(e2)==REGISTER) { switch(e5) { case ADDRESS: if (!((car(cadr(e4))==STRING) || car(cadr(e4))==GVAR)) break; case CRGVAR : case CRLVAR : case RGVAR : case RLVAR : case CURGVAR : case CURLVAR : case SURGVAR : case SURLVAR : case GVAR : case LVAR : case CONST : case FNAME : case STRING : assign_opt(e5,e2,e4,byte); return; } } } switch(car(e2)) { case GVAR: /* i=3 */ g_expr(e4); code_assign_gvar(e2,USE_CREG,byte); return; case LVAR: g_expr(e4); code_assign_lvar(cadr(e2),USE_CREG,byte); return; case REGISTER: g_expr(e4); code_assign_register(cadr(e2),byte,USE_CREG); return; } g_expr(e2); emit_push(); g_expr(e4); e2 = emit_pop(0); code_assign(e2,byte,USE_CREG); emit_pop_free(e2); return; } #if FLOAT_CODE static void dassign_opt(int e5,int e2,int e4,int d) { int reg; /* e2=e4 */ if (e5==DREGISTER||e5==FREGISTER) { reg = cadr(e4); switch(car(e2)) { case GVAR: /* i=3 */ code_dassign_gvar(e2,reg,d); return; case LVAR: code_dassign_lvar(cadr(e2),reg,d); return; case DREGISTER: case FREGISTER: if (reg!=cadr(e2)) code_dassign_dregister(cadr(e2),d,reg); return; default: error(-1); } } /* e2 is register now */ if (car(e2)!=DREGISTER && car(e2)!=FREGISTER) error(-1); reg = cadr(e2); switch(e5) { case FRGVAR: case DRGVAR: code_drgvar(e4,d,reg); return; case FRLVAR: case DRLVAR: code_drlvar(cadr(e4),d,reg); return; case FCONST: case DCONST: code_dconst(e4,reg,d); return; default: error(-1); } } static void dassign(int e1) { int e2,e3,e4,d,e5; /* e2=e4 */ e2 = cadr(e1); e3 = cadr(e2); e4 = caddr(e1); e5=car(e4); if (is_same_type(e2,e4)&&cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } if (car(e1)==DASS) d=1; else if (car(e1)==FASS) d=0; else error(-1); if (!use) { switch(e5) { case DRGVAR: case DRLVAR: case DCONST: if (car(e2)!=DREGISTER) break; dassign_opt(e5,e2,e4,d); return; case FRGVAR: case FRLVAR: case FCONST: if (car(e2)!=FREGISTER) break; case DREGISTER: case FREGISTER: dassign_opt(e5,e2,e4,d); return; } } switch(car(e2)) { case GVAR: g_expr(e4); code_dassign_gvar(e2,USE_CREG,d); return; case LVAR: g_expr(e4); code_dassign_lvar(cadr(e2),USE_CREG,d); return; case DREGISTER: case FREGISTER: g_expr(e4); code_dassign_dregister(cadr(e2),d,USE_CREG); return; } g_expr(e2); emit_push(); g_expr(e4); e2 = emit_pop(0); code_dassign(e2,USE_CREG,d); emit_pop_free(e2); return; } #endif #if LONGLONG_CODE static void lassign_opt(int e5,int e2,int e4) { int reg; /* e2=e4 */ if (e5==LREGISTER) { reg = cadr(e4); switch(car(e2)) { case GVAR: /* i=3 */ code_lassign_gvar(e2,reg); return; case LVAR: code_lassign_lvar(cadr(e2),reg); return; case LREGISTER: if (reg!=cadr(e2)) code_lassign_lregister(cadr(e2),reg); return; default: error(-1); } } /* e2 is register now */ if (car(e2)!=LREGISTER) error(-1); reg = cadr(e2); switch(e5) { case LRGVAR: code_lrgvar(e4,reg); return; case LRLVAR: code_lrlvar(cadr(e4),reg); return; case LCONST: code_lconst(e4,reg); return; default: error(-1); } } static void lassign(int e1) { int e2,e3,e4,e5; /* e2=e4 */ e2 = cadr(e1); e3 = cadr(e2); e4 = caddr(e1); e5=car(e4); if (is_same_type(e2,e4)&&cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } if (!use && ( (e5==LREGISTER) || (car(e2)==LREGISTER&&(e5==LRGVAR||e5==LRLVAR||e5==LCONST)) )) { lassign_opt(e5,e2,e4); return; } switch(car(e2)) { case GVAR: g_expr(e4); code_lassign_gvar(e2,USE_CREG); return; case LVAR: g_expr(e4); code_lassign_lvar(cadr(e2),USE_CREG); return; case LREGISTER: g_expr(e4); code_lassign_lregister(cadr(e2),USE_CREG); return; } g_expr(e2); emit_push(); g_expr(e4); e2 = emit_pop(0); code_lassign(e2,USE_CREG); emit_pop_free(e2); return; } #endif /* numerical type conversion */ static int double_value(int e2) { if (type>0&&car(type)==BIT_FIELD) e2=rvalue(e2); #if FLOAT_CODE switch(car(e2)) { case LCONST: #if LONGLONG_CODE e2 = dlist2(DCONST,(double)lcadr(e2)); break; #endif case CONST: e2 = dlist2(DCONST,(double)cadr(e2)); break; case FCONST: e2 = dlist2(DCONST,dcadr(e2)); break; default: switch(type) { case DOUBLE: break; case FLOAT: e2 = list3(CONV,rvalue(e2),F2D); break; case UNSIGNED: e2 = list3(CONV,rvalue(e2),U2D); break; case LONGLONG: e2 = list3(CONV,rvalue(e2),LL2D); break; case ULONGLONG: e2 = list3(CONV,rvalue(e2),ULL2D); break; default: if(integral(type)) e2 = list3(CONV,rvalue(e2),I2D); else { error(TYERR); e2 = dlist2(DCONST,1.0); } } } #else error(TYERR); type = DOUBLE; return list2(CONST,0); #endif type = DOUBLE; return e2; } static int float_value(int e2) { if (type>0&&car(type)==BIT_FIELD) e2=rvalue(e2); if (0) ; #if FLOAT_CODE #if LONGLONG_CODE else if (car(e2)==LCONST) e2 = dlist2(FCONST,(double)lcadr(e2)); #endif else if (car(e2)==CONST) e2 = dlist2(FCONST,(double)cadr(e2)); else if (car(e2)==DCONST) e2 = dlist2(FCONST,dcadr(e2)); else { switch(type) { case LONGLONG: e2 = list3(CONV,rvalue(e2),LL2F); break; case ULONGLONG: e2 = list3(CONV,rvalue(e2),ULL2F); break; case FLOAT: break; case DOUBLE: e2 = list3(CONV,rvalue(e2),D2F); break; case UNSIGNED: e2 = list3(CONV,rvalue(e2),U2F); break; default: if(integral(type)) e2 = list3(CONV,rvalue(e2),I2F); else { error(TYERR); e2 = dlist2(DCONST,1.0); } } } #else else { error(TYERR); e2 = list2(CONST,0); } #endif type = FLOAT; return e2; } static int longlong_value(int e2) { if (type>0&&car(type)==BIT_FIELD) e2=rvalue(e2); if (0) ; #if LONGLONG_CODE else if (car(e2)==CONST) e2 = llist2(LCONST,(long long)cadr(e2)); else if (car(e2)==LCONST) ; #if FLOAT_CODE else if (car(e2)==DCONST||car(e2)==FCONST) e2 = llist2(LCONST,(long long)dcadr(e2)); #endif else { switch(type) { case FLOAT: e2 = list3(CONV,rvalue(e2),F2LL); break; case DOUBLE: e2 = list3(CONV,rvalue(e2),D2LL); break; case UNSIGNED: e2 = list3(CONV,rvalue(e2),U2LL); break; case LONGLONG: break; case ULONGLONG: break; default: if(integral(type)) e2 = list3(CONV,rvalue(e2),I2LL); else { error(TYERR); e2 = llist2(LCONST,0LL); } } } #else else { error(TYERR); e2 = list2(CONST,0); } #endif type = LONGLONG; return e2; } static int ulonglong_value(int e2) { if (type>0&&car(type)==BIT_FIELD) e2=rvalue(e2); if (0); #if LONGLONG_CODE else if (car(e2)==CONST) e2 = llist2(LCONST,(unsigned long long)cadr(e2)); else if (car(e2)==LCONST) ; #if FLOAT_CODE else if (car(e2)==DCONST||car(e2)==FCONST) e2 = llist2(LCONST,(unsigned long long)dcadr(e2)); #endif else { switch(type) { case FLOAT: e2 = list3(CONV,rvalue(e2),F2ULL); break; case DOUBLE: e2 = list3(CONV,rvalue(e2),D2ULL); break; case UNSIGNED: e2 = list3(CONV,rvalue(e2),U2ULL); break; case LONGLONG: break; case ULONGLONG: break; default: if(integral(type)) e2 = list3(CONV,rvalue(e2),I2ULL); else { error(TYERR); e2 = llist2(LCONST,0LL); } } } #else else unsigned_value(e2); #endif type = ULONGLONG; return e2; } static int int_value(int e2) { if (type>0&&car(type)==BIT_FIELD) e2=rvalue(e2); if (0); else if(type>0&&car(type)==ARRAY) return e2; else if(scalar(type)) return e2; #if FLOAT_CODE else if (car(e2)==DCONST||car(e2)==FCONST) e2 = list2(CONST,(int)dcadr(e2)); #endif #if LONGLONG_CODE else if (car(e2)==LCONST) e2 = list2(CONST,(int)lcadr(e2)); #endif else { switch(type) { case FLOAT: e2 = list3(CONV,rvalue(e2),F2I); break; case DOUBLE: e2 = list3(CONV,rvalue(e2),D2I); break; case LONGLONG: e2 = list3(CONV,rvalue(e2),LL2I); break; case ULONGLONG: e2 = list3(CONV,rvalue(e2),ULL2I); break; default: error(TYERR); e2 = list2(CONST,1); } } type = INT; return e2; } static int char_value(int e2) { if (type!=CHAR&&type!=INT) { e2 = list3(CONV,int_value(rvalue(e2)),I2C); type = INT; } return e2; } static int short_value(int e2) { if (type!=SHORT&&type!=INT) { e2 = list3(CONV,int_value(rvalue(e2)),I2S); type = INT; } return e2; } static int unsigned_value(int e2) { if (type>0&&car(type)==BIT_FIELD) e2=rvalue(e2); else if(type>0&&car(type)==ARRAY) return e2; if (0); else if(scalar(type)) return e2; #if FLOAT_CODE else if (car(e2)==DCONST||car(e2)==FCONST) e2 = list2(CONST,(int)dcadr(e2)); #endif #if LONGLONG_CODE else if (car(e2)==LCONST) e2 = list2(CONST,(unsigned)lcadr(e2)); #endif else { switch(type) { case LONGLONG: e2 = list3(CONV,rvalue(e2),LL2U); break; case ULONGLONG: e2 = list3(CONV,rvalue(e2),ULL2U); break; case FLOAT: e2 = list3(CONV,rvalue(e2),F2U); break; case DOUBLE: e2 = list3(CONV,rvalue(e2),D2U); break; default: error(TYERR); } } type = UNSIGNED; return e2; } static int uchar_value(int e2) { if (type!=UCHAR&&type!=UNSIGNED) { e2 = list3(CONV,unsigned_value(rvalue(e2)),U2UC); type = UNSIGNED; } return e2; } static int ushort_value(int e2) { if (type!=USHORT&&type!=UNSIGNED) { e2 = list3(CONV,unsigned_value(rvalue(e2)),U2US); type = UNSIGNED; } return e2; } /* assign statement */ /* keep type */ extern int assign_expr0(int e1,int e2,int t,int type0) { int stype; stype=type; type = type0; e2 = rvalue(e2); e1=assign_expr(e1,e2,t); type=stype; return e1; } /* with conversion (will destroy type global variable) */ extern int assign_expr(int e1,int e2,int t) { switch(t) { case VOID: break; case CHAR:case UCHAR: e2=(t==UCHAR)?unsigned_value(e2):int_value(e2); return(list3(CASS,e1,e2)); case SHORT:case USHORT: e2=(t==USHORT)?unsigned_value(e2):int_value(e2); return(list3(SASS,e1,e2)); #if FLOAT_CODE case DOUBLE: e2=double_value(e2); return(list3(DASS,e1,e2)); case FLOAT: e2=float_value(e2); return(list3(FASS,e1,e2)); #endif #if LONGLONG_CODE case LONGLONG: e2=longlong_value(e2); return(list3(LASS,e1,e2)); case ULONGLONG: e2=ulonglong_value(e2); return(list3(LASS,e1,e2)); #endif default: if(scalar(t)) { e2=(t==UNSIGNED)?unsigned_value(e2):int_value(e2); return(list3(ASS,e1,e2)); } switch(car(t)) { case BIT_FIELD: // type = list4(BIT_FIELD,type, // list3(type /*store type*/,0 /*bit offset*/,bitsize)); e2 = correct_type(e2,cadr(t)); /* value type */ return(list4(BASS,e1,e2,list2(BASS,t))); case STRUCT:case UNION: if (size(t)!=size(type)) error(TYERR); type=t; if(car(e2)==RSTRUCT && car(cadr(e2))==FUNCTION) { replace_return_struct(cadr(e2),e1); return cadr(e2); } else { return (list4(STASS,e1,e2,size(t))); } } } error(TYERR); return list3(ASS,e1,e2); } extern int cond(int t,int e1,int e2,int e3) { if(car(e1)==CONST) { if(cadr(e1)) {type=t;return e2?e2:e1;} else return e3; } #if FLOAT_CODE if(car(e1)==DCONST) { if(dcadr(e1)) {type=t;return e2?e2:e1;} else return e3; } if(type==DOUBLE||t==DOUBLE) { e3=double_value(e3); type = t; if (e2) e2=double_value(e2); return(list4(DCOND,e1,e2,e3)); } if(type==FLOAT||t==FLOAT) { e3=float_value(e3); type = t; if (e2) e2=float_value(e2); return(list4(FCOND,e1,e2,e3)); } #endif #if LONGLONG_CODE if(car(e1)==LCONST) { if(lcadr(e1)) {type=t;return e2?e2:e1;} else return e3; } if(type==LONGLONG||t==LONGLONG) { e3=longlong_value(e3); type = t; if (e2) e2=longlong_value(e2); return(list4(LCOND,e1,e2,e3)); } if(type==ULONGLONG||t==ULONGLONG) { e3=ulonglong_value(e3); type = t; if (e2) e2=ulonglong_value(e2); return(list4(LCOND,e1,e2,e3)); } #endif if(type==INT||(t!=INT&&type==UNSIGNED)) type=t; /* if (t!=type) error(TYERR); */ return(list4(COND,e1,e2,e3)); } extern int assop(int e1,int e2,int op,int t,int no_float) { int ass,u = 0; if(!(integral(type)||type==FLOAT||type==DOUBLE|| type==LONGLONG||type==ULONGLONG )) error(TYERR); switch(t) { #if FLOAT_CODE case FLOAT: if (no_float) error(TYERR); e2=float_value(e2); return(list4(FASSOP,e1,e2,op+FOP)); case DOUBLE: if (no_float) error(TYERR); e2=double_value(e2); return(list4(DASSOP,e1,e2,op+DOP)); #endif #if LONGLONG_CODE case LONGLONG: e2=longlong_value(e2); return(list4(LASSOP,e1,e2,op+LOP)); case ULONGLONG: e2=ulonglong_value(e2); return(list4(LASSOP,e1,e2,op+LOP+((op==MUL+AS||op==DIV+AS)?US:0))); #endif case CHAR: type= INT; ass = CASSOP; break; case SHORT: type= INT; ass = SASSOP; break; case INT: type= INT; ass = ASSOP; break; case UCHAR: type= UNSIGNED; ass = CUASSOP; u=1; break; case USHORT: type= UNSIGNED; ass = SUASSOP; u=1; break; case UNSIGNED: type= UNSIGNED; ass = ASSOP; u=1; break; default: if (t>0 && car(t)==BIT_FIELD) { // type = list4(BIT_FIELD,type, // list3(type /*store type*/,0 /*bit offset*/,symval)); e2 = correct_type(e2,car(caddr(t))); /* store type */ type = cadr(t); /* value type */ return(list4(BASSOP,e1,e2,list2(op,t))); } } if (u) { if (op==RSHIFT||op==LSHIFT) op=op+US; else { switch(type) { case UCHAR: case USHORT: case UNSIGNED: if (op==MUL||op==DIV||op==MOD) op=op+US; } } } type=t; if(integral(t)) return(list4(ass,e1,e2,op)); /* pointer += ... */ if((op!=ADD&&op!=SUB)||car(t)!=POINTER) error(TYERR); e2=binop(MUL,e2,list2(CONST,size(cadr(t))),INT,UNSIGNED); type=t; return list4(ASSOP,e1,e2,op); } static void iassop(int e1) { int e2,e3,byte,op,sign,size; int n,t; /* e2 op= e3 */ switch(car(e1)) { case CUASSOP: byte = 1; sign = 0; size = 1; break; case CASSOP: byte = 1; sign = 1; size = 1; break; case SUASSOP: byte = size_of_short; sign = 0; size = size_of_short; break; case SASSOP: byte = size_of_short; sign = 1; size = size_of_short; break; default: byte = 0; sign = 1; size = size_of_int; } e2 = cadr(e1); if (car(e2)==INDIRECT) e2=cadr(e2); e3 = caddr(e1); op = cadddr(e1); if (car(e2)==REGISTER) { if (code_const_op_p(op,e3)) { oprtc(op,cadr(e2),e3); } else { g_expr(e3); code_register_assop(cadr(e2),USE_CREG,op,byte); } if (use) { code_register(cadr(e2),USE_CREG); } return; } if (car(e3)==CONST) { /* e2 = e2 op e3; */ t = sign?INT:UNSIGNED; // oprtc expected if (car(e2)==LVAR||car(e2)==GVAR) { g_expr(assign_expr0(e2,list3(op,rvalue_t(e2,t),e3),t,t)); return; } /* new = &e2 */ /* *new = *new op e3 */ n = list2(LVAR,new_lvar(size_of_int)); g_expr_u(assign_expr0(n,list2(ADDRESS,e2),INT,INT)); g_expr(assign_expr0(list2(INDIRECT,n),list3(op,n,e3),t,t)); free_lvar(cadr(n)); return; } g_expr(e3); emit_push(); g_expr(e2); code_assop(op,USE_CREG,byte,sign); return; } #if FLOAT_CODE static void dassop(int e1) { int e2,e3,op,d; /* e2 op= e3 */ d = (car(e1) == DASSOP); e2 = cadr(e1); if (car(e2)==INDIRECT) e2=cadr(e2); e3 = caddr(e1); op = cadddr(e1); g_expr(e3); if (car(e2)==DREGISTER||car(e2)==FREGISTER) { emit_dpush(d); code_register_dassop(cadr(e2),op,d); if (use) code_dregister(cadr(e2),USE_CREG,d); return; } emit_dpush(d); g_expr(e2); code_dassop(op,USE_CREG,d); return; } #endif #if LONGLONG_CODE static int long_sign(int op) { return (op==LUDIV||op==LUMOD||op==LULSHIFT||op==LURSHIFT)?ULONGLONG:LONGLONG; } static void lassop(int e1) { int e2,e3,op; int n,t; /* e2 op= e3 */ e2 = cadr(e1); if (car(e2)==INDIRECT) e2=cadr(e2); e3 = caddr(e1); op = cadddr(e1); if (car(e2)==LREGISTER) { if (code_lconst_op_p(op,e3)) { loprtc(op,cadr(e2),e3); if (use) { code_lregister(cadr(e2),USE_CREG); } return; } if (code_lassop_p) { g_expr(e3); emit_lpush(); code_register_lassop(cadr(e2),op); if (use) { code_lregister(cadr(e2),USE_CREG); } return; } } if (!code_lassop_p||car(e3)==LCONST) { /* e2 = e2 op e3; */ t = long_sign(op); if (car(e2)==LREGISTER||car(e2)==LVAR||car(e2)==GVAR) { g_expr(assign_expr0(e2,list3(op,rvalue_t(e2,t),e3),t,t)); return; } /* new = &e2 */ /* *new = *new op e3 */ n = list2(LVAR,new_lvar(size_of_int)); g_expr_u(assign_expr0(n,list2(ADDRESS,e2),INT,INT)); g_expr(assign_expr0(list2(INDIRECT,n), list3(op,list2(LRINDIRECT,n),e3),t,t)); free_lvar(cadr(n)); return; } g_expr(e3); if (car(e2)==LREGISTER) { emit_lpush(); code_register_lassop(cadr(e2),op); if (use) code_lregister(cadr(e2),USE_CREG); return; } emit_lpush(); g_expr(e2); code_lassop(op,USE_CREG); return; } #endif extern void cmpdimm(int e, int csreg,int label,int cond) { code_cmpdimm(e, csreg,label,cond); } extern int csvalue() { return code_csvalue(); } extern int fwdlabel(void) { return labelno++; } extern void fwddef(int l) { control=1; if (!chk) code_label(l); } extern int backdef(void) { control=1; if (!chk) code_label(labelno); return labelno++; } extern 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); } } extern void ret(void) { code_set_return_register(1); jmp(retlabel); } extern void opening(char *filename) { emit_init(); if (!chk) code_opening(filename); } extern void closing() { if (!chk) code_closing(); } static int contains_in_list(int e,int type) { while(e) { if(contains(car(e),type)) return 1; e = cadr(e); } return 0; } static int contains(int e,int type) { while(e) { if (car(e)==type) return 1; if (!car(e)) return 0; if (LIST_ARGS(car(e))){ /* list arguments */ return contains_in_list(caddr(e),type); } else if (UNARY_ARGS(car(e))) { /* unary operators */ e = cadr(e); continue; } else if (BINARY_ARGS(car(e))) { /* biary operators */ if (contains(cadr(e),type)) return 1; e = caddr(e); continue; } else if (TARNARY_ARGS(car(e))) { /* tarary operators */ if (contains(cadr(e), type)) return 1; if (contains(caddr(e),type)) return 1; e = cadddr(e); continue; } else if (NULLARY_ARGS(car(e))) { /* nullary operators */ return 0; } else { // fprintf(stderr,"Unknown Tree ID %d\n",car(e)); error(-1); return 0; } } return 0; } static int contains_in_list_p(int e,int (*p)(int)) { while(e) { if(contains_p(car(e),p)) return 1; e = cadr(e); } return 0; } extern int contains_p(int e,int (*p)(int)) { while(e) { if (!car(e)) return 0; if (p(car(e))) return 1; if (LIST_ARGS(car(e))){ /* list arguments */ return contains_in_list_p(caddr(e),p); } else if (UNARY_ARGS(car(e))) { /* unary operators */ e = cadr(e); continue; } else if (BINARY_ARGS(car(e))) { /* biary operators */ if (contains_p(cadr(e),p)) return 1; e = caddr(e); continue; } else if (TARNARY_ARGS(car(e))) { /* tarary operators */ if (contains_p(cadr(e), p)) return 1; if (contains_p(caddr(e),p)) return 1; e = cadddr(e); continue; } else if (NULLARY_ARGS(car(e))) { /* nullary operators */ return 0; } else { // fprintf(stderr,"Unknown Tree ID %d\n",car(e)); error(-1); return 0; } } return 0; } #if ASM_CODE /* __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (a ddr)); asm string : output constraint parameter : input constraint parameter : opt 1: asm string %1,%2 will be replaced by register or value 2: constraint gcc constraint sting prefix = overwrite by this asm for output & overwrite by this asm and can't be used as input register ignored in this compiler constraints m value expression is modified (no corresponding register) information for compiler r register for input or output input register, output register can be shared 0-9 same operands as outout register in input constraints 3: opt "cc", "memory" ignored in this compiler */ static void gen_asm(int asm0,int in,int out,int opt,int e) { int i,e1,n; int repl = 0; int repl0; int assign = 0; char *p; printf("# asm\n"); in = reverse0(in); out = reverse0(out); e = reverse0(e); for(i=out;i;i=cadr(i)) { p = (char*)cadr(car(i)); e1 = car(e); e = cadr(e); repl = code_asm_operand(p,e1,ASM_OUTPUT,repl,0,0); if (car(car(repl))==REGISTER) { assign = list2(assign_expr0(e1,car(repl),INT,INT),assign); } } repl0 = repl; n = length(repl0); for(i=in;i;i=cadr(i)) { p = (char*)cadr(car(i)); e1 = car(e); e = cadr(e); repl = code_asm_operand(p,e1,ASM_INPUT,repl,n,repl0); if (car(car(repl))==REGISTER) { g_expr_u(assign_expr0(car(repl),e1,INT,INT)); } } repl = reverse0(repl); code_asm((char*)cadr(asm0),repl); for(i=assign;i;i=cadr(i)) { g_expr_u(car(i)); } code_free_asm_operand(repl); // no check for opt } #endif /* define symbol name contents depending on stmode, mode define displacement */ extern NMTBL * def(NMTBL *n) { int sz,nsc,ndsp; int sbit_f = bit_field_disp; bit_field_disp = 0; // default is 0, recover only in bit-field if (n==0) { n=anonymous_nptr(); n->nm = "_"; } nsc=ndsp=0; if (stmode==EXTRN||mode==GDECL) n->ty = type; /* must be in global table/heap */ if(type>0&&(car(type)==FUNCTION || car(type)==CODE)) { if ((mode==GDECL)) { fcheck(n); return n; /* function and code segment are defined using fdecl/code_decl */ /* in decl() */ } } if (mode==GSDECL||mode==LSDECL) { /* Struct fields name lists are in the struct type or tag. */ /* Only name in the table is used. Do not set n->ty! */ if (car(type)==BIT_FIELD) { bit_field_disp=sbit_f; // default is 0, recover only here. // type = list4(BIT_FIELD,value type, // list3(store type,bit offset,bit_width)); cadr(caddr(type)) = code_bit_field_disp( type,&disp,&bit_field_disp,&sz); /* bit_field_disp is next bit posision */ } else { sz = size(type); } if (n!=&null_nptr) fields = list4(type,fields,(int)(n->nm),disp); } else if (mode==GUDECL||mode==LUDECL) { if (car(type)==BIT_FIELD) { cadr(caddr(type)) = 0; sz = size(cadr(type)); } else { sz = size(type); } fields = list4(type,fields,(int)(n->nm),0); } else { if (n->sc!=EMPTY && !(n->sc==EXTRN||n->sc==EXTRN1||n->sc==STATIC)) { /* redefined case */ if (mode==ADECL) { /* K&R arguments case */ if (n->sc==LVAR && n->ty==INT); else if ( n->sc==REGISTER && n->ty==INT); else if ( n->sc==TYPE) { n = lsearch(n->nm,0); } else error(RDERR); } else error(RDERR); } sz = size(n->ty = type); } switch(mode) { case GDECL: gen_gdecl(n->nm,gpc); case STADECL: nsc = GVAR; ndsp = gpc; if (n->dsp!=-1) /* don't set dsp if initialized static */ n->dsp = ndsp; /* emit_data will override this */ if (stmode==EXTRN) nsc = EXTRN; else if (stmode==STATIC) nsc = STATIC; n->sc = nsc; if (stmode==LDECL) { n = new_static_name(n->nm,'.'); if (!n->next) { n->next = local_static_list; local_static_list = n; } } else { if (!n->next) { n->next = global_list; global_list = n; } } gpc +=sz; return n; case GSDECL: case LSDECL: disp += sz; return n; case GUDECL: case LUDECL: if (disp < sz) disp = sz; return n; case GTDECL: nsc = TYPE; gtypedefed=glist2((int)gnptr,gtypedefed); break; case LTDECL: nsc = TYPE; break; case LLDECL: nsc = FLABEL; ndsp = fwdlabel(); break; case ADECL: if(!integral(type)&&(car(type)==FUNCTION||car(type)==CODE)) { type=list2(POINTER,type); n->ty = type; } fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); n->sc = LVAR; if(type==CHAR||type==UCHAR) { if (n->dsp==0) { n->dsp = args; if (endian) n->dsp += size_of_int-1; } args += size_of_int; } else if(type==SHORT||type==USHORT) { if (n->dsp==0) { n->dsp = args; if (endian) n->dsp += size_of_int-size_of_short; } args += size_of_int; #if 0 } else if(type>0&&(type==UNION||type==STRUCT)) { n->dsp = args; args += ((sz+(size_of_int-1))&~(size_of_int-1)); #endif } else { /* if (n->dsp==0) (argument list in ADECL is useless, type list can be found in type ) */ n->dsp = args; args += sz; } cadddr(fnptr->dsp)=sz; if(type==VOID) { } else { n->ty = type; } return n; case STAT: /* return (struct hoge)f() case? */ case LDECL: if (stmode==REGISTER) { if(scalar(type)) { ndsp = get_register_var(n); #if FLOAT_CODE } else if (type==FLOAT) { ndsp = get_dregister_var(n,0); } else if (type==DOUBLE) { ndsp = get_dregister_var(n,1); #endif #if LONGLONG_CODE } else if (type==LONGLONG||type==ULONGLONG) { ndsp = get_lregister_var(n); #endif } else error(DCERR); nsc = car(ndsp); ndsp = cadr(ndsp); } else { nsc = LVAR; ndsp = new_lvar(sz); } n->sc = nsc; n->dsp = ndsp; return n; default: error(DCERR); } n->sc = nsc; n->dsp = ndsp; if (stmode==EXTRN) n->sc = EXTRN; return n; } extern void emit_init_vars(void) { if (!init_vars) return; init_vars = reverse0(init_vars); while(init_vars) { gexpr(car(init_vars),0); init_vars = cadr(init_vars); } } static int str_init_eq() { // error(-1); // duplicate struct field value return 2; // allow override keep unique } static void emit_data(int e, int t, NMTBL *n) { int l; char *name; name = n->nm; if(mode!=GDECL && mode!=STADECL) { error(-1); return; } if (chk) return; if (n->dsp != -1) { n->dsp = -1; /* initialized flag */ emit_global(name,t); } switch(t) { case EMPTY: if(car(e)!=CONST) error(-1); emit_space(cadr(e)); return; case CHAR: case UCHAR: emit_char(cadr(e)); data_alignment++; return; case SHORT: case USHORT: emit_short(cadr(e)); data_alignment++; return; case INT: case UNSIGNED: case ENUM: emit_int(cadr(e)); return; case LONGLONG: case ULONGLONG: emit_longlong(e); return; case DOUBLE: emit_double(e); return; case FLOAT: emit_float(e); data_alignment++; return; default: if (t<0) error(-1); if (car(t)==BIT_FIELD) { return; } if (car(t)!=POINTER&&car(t)!=ARRAY) error(-1); switch(car(e)) { case CONST: emit_int(cadr(e)); return; case ADDRESS: if (car(cadr(e))==GVAR) emit_address(((NMTBL *)caddr(cadr(e)))->nm,cadr(cadr(e))); else error(INERR); return; case FNAME: emit_address(((NMTBL *)cadr(e))->nm,0); return; case GVAR: emit_address(((NMTBL *)caddr(e))->nm,0); return; case STRING: if (car(n->ty)!=ARRAY || cadr(n->ty)!=CHAR) { l = emit_string_label(); ascii((char *)cadr(e)); emit_label(l); } else ascii((char *)cadr(e)); return; } // fprintf(stderr,"# type= %d\n",t); } error(INERR); } extern int assign_data(int e, int t, NMTBL *n,int offset) { int ass,sz,bfd; if(mode==GDECL) { emit_data(e,t,n); } else if(mode==STADECL) { emit_data(e,t,n); } else if(mode==LDECL) { if (t==EMPTY) { /* empty space in partial initialization */ return offset+cadr(e); } ass = assign_expr0( (n->sc==REGISTER||n->sc==DREGISTER||n->sc==FREGISTER||n->sc==LREGISTER)? list3(n->sc,n->dsp,(int)n): list2(LVAR,n->dsp+offset), e,t,type); init_vars = list2(ass,init_vars); } else if(mode==SFDINIT) { decl_str_init=insert_ascend(decl_str_init, list4(offset,0,e,t),str_init_eq); } else { error(DCERR); return offset; } if (t>0&&car(t)==BIT_FIELD) { sz = 0; bfd = cadr(caddr(t)); /* bit_field_disp */ code_bit_field_disp(t,&offset,&bfd,&sz); return offset+sz; } return offset+((t==EMPTY)?cadr(e):size(t)); } extern void data_closing(NMTBL *n) { emit_data_closing(n); } #define ARG_REORDER_DEBUG 0 /* In K&R style, order of argment list and order of argment type decl are differnt. Fix them. */ extern int arg_reorder(int arg,int new_arg) { /* list4(type,fnptr->dsp,(int)n,size); */ int i,j,sz; int dsp = 0; NMTBL *n,*n1; /* f(a,b,c) int c; short a; char* b; { } case */ #if ARG_REORDER_DEBUG fprintf(stderr,"arg_reorder old:\n"); for(j=new_arg;j;j=cadr(j)) { n=(NMTBL *)caddr(j); fprintf(stderr,"dsp %d %s sz %d type %d\n",n->dsp,n->nm,cadddr(j),car(j)); } fprintf(stderr,"arg_reorder new:\n"); #endif for(j=arg;j;j=cadr(j)) { n=(NMTBL *)caddr(j); for(i=new_arg;i;i=cadr(i)) { n1=(NMTBL *)caddr(i); if (!neqname(n1->nm,n->nm)) break; // if (n1==n) break; } #if ARG_REORDER_DEBUG fprintf(stderr,"dsp %d %s %s sz %d type %d\n",dsp,n->nm,n1->nm,cadddr(i),car(i)); #endif if (!i) { /* f(a,b,c) int c; { } case (what?!) */ i = j; n1 = n; } if(n->sc==LVAR) { n->dsp = dsp; car(j)=car(i); caddr(j)=caddr(i); n1->dsp = n->dsp; n->ty = n1->ty; n->sc = n1->sc; cadddr(j)=sz= cadddr(i); if (sz==1||sz==size_of_short) sz = size_of_int; dsp += sz; } } #if ARG_REORDER_DEBUG fprintf(stderr,"arg_reorder end:\n"); #endif return arg; } static NMTBL str_ret; /* If function has structure return value, it has an extra argument for where to write the structure. It have to be a first argument. We add it here and we have to fix all arguments' offset. If it is the last value, we don't have to fix, but gcc has a first argument convention. */ extern void fdecl_struct(int fntype) { int type_save,mode_save,t,sz; NMTBL *n; t = cadr(fntype); if (t>0 && (car(t)==STRUCT||car(t)==UNION)) { mode_save = mode; mode=ADECL; type_save = type; /* extra argument for struct return */ /* this extra dummy arguments are set at calling sequence */ str_ret.nm = "str_ret"; str_ret.sc = EMPTY; str_ret.dsp = 0; str_ret.ty = 0; type=list2(POINTER,t); /* fix all argument's offset */ sz = size(type); for(t=fnptr->dsp;t;t=cadr(t)) { n=(NMTBL *)caddr(t); n->dsp += sz; } fnptr->dsp = reverse0(fnptr->dsp); if ((sz=size(cadr(fntype)))==-1) error(TYERR); else { args = 0; def(&str_ret); struct_return = list3(list2(LVAR,str_ret.dsp),sz,type); caddr(fnptr->ty) = glist2(POINTER,caddr(fnptr->ty)); } type = type_save; mode = mode_save; } else { struct_return = 0; fnptr->dsp = reverse0(fnptr->dsp); } } extern void fcheck(NMTBL *n) { if(!(mode==GDECL||mode==ADECL)|| (car(type)!=FUNCTION&&car(type)!=CODE)) error(DCERR); if (n->sc==EMPTY) { n->sc=EXTRN; n->ty=type; } else if(is_code(n)) compatible(cadr(n->ty),cadr(type)); else if(is_function(n)) compatible(cadr(n->ty),cadr(type)); else { error(DCERR); } } static void compatible(int t1, int t2) { if(integral(t1)) { if(t1!=t2) error(TYERR); } else if(car(t1)!=car(t2)) error(TYERR); else if((car(t1)==STRUCT || car(t1)==UNION) && cadr(t1)!=cadr(t2)) error(TYERR); else if(car(t1)==POINTER || car(t1)==ARRAY ||car(t1)==FUNCTION) compatible(cadr(t1),cadr(t2)); } extern int scalar(int t) { return(integral(t)||car(t)==POINTER); } extern int integral(int t) { return(t==INT||t==SIGNED||t==CHAR||t==UNSIGNED|| t==UCHAR||t==SHORT||t==USHORT||t==ENUM); } extern void checkret(void) { if (cslabel==0) { if (!control) error(-1); // no execute code in switch jmp(cslabel=fwdlabel()); } else if (retpending) { ret(); control=0; retpending=0; } if (lastexp) { gexpr(lastexp,0); lastexp = 0; } } extern void replace_return_struct(int func,int left) { int e = caddr(func); /* arg lists */ while(cadr(e)) e=cadr(e); /* find first arg */ e = car(e); /* return_struct arg */ cadr(e) = left; } /* right value , get the value of the variable */ static int indirect(int t,int e1) { int e2,e3,e4,offset; e2 = e1; offset = 0; e3 = cadr(e2); if (car(e2)==ADD) { e4=caddr(e2); if (car(e4)==CONST) { offset=cadr(e4); e1=e3; } } return list3(t,e1,offset); } extern int rvalue(int e) { int op; if (e==0) error(-1); op = 0; switch(type) { case INT: break; case UNSIGNED: break; case VOID: break; case CHAR: op=COP; type=INT; break; case UCHAR: op=COP+US; type=UNSIGNED; break; case SHORT: op=SOP; type=SIGNED; break; case USHORT: op=SOP+US; type=UNSIGNED; break; case LONGLONG: op=LOP; break; case ULONGLONG: op=LOP+US; break; case FLOAT: op=FOP; break; case DOUBLE: op=DOP; break; case CODE: return e; case 0: error(-1); return e; default: if (integral(type)) break; switch(car(type)) { case ARRAY: type=list2(POINTER,cadr(type)); if(car(e)==INDIRECT) return cadr(e); return list2(ADDRESS,e); case STRUCT: case UNION: if(car(e)==RSTRUCT) return e; /* ??? */ return list3(RSTRUCT,e,cadr(type) /* size */); case FUNCTION: type=cadr(type); return e; case CODE: return e; case POINTER: break; case BIT_FIELD: e = list3(RBIT_FIELD,cadr(e),type); /* byte rvalue, store type */ type = cadr(type); /* value type */ return e; break; default: error(TYERR); } } switch(car(e)) { case GVAR: return(list3(RGVAR+op,cadr(e),caddr(e))); case LVAR: return(list2(RLVAR+op,cadr(e))); case INDIRECT: return(indirect(RINDIRECT+op,cadr(e))); default:return(e); /* idempotent case? */ } } extern int rvalue_t(int e,int t) { int stype = type; type = t; e = rvalue(e); type = stype; return e; } extern void lcheck(int e) { int t; if(scalar(type)) return; switch(type) { case DOUBLE: case FLOAT : case LONGLONG: case ULONGLONG: return; default: switch(car(e)) { case GVAR: case LVAR: case INDIRECT : case REGISTER : case DREGISTER : case FREGISTER : case LREGISTER: return; } } if ((t=car(type))<0 && t!=STRUCT && t!=UNION) error(LVERR); } extern int indop(int e) { if(type!=INT&&type!=UNSIGNED) { if(car(type)==POINTER) type=cadr(type); else if(car(type)==CODE || car(type)==FUNCTION) type=type; else error(TYERR); } else type= CHAR; // ?! if(car(e)==ADDRESS) return(cadr(e)); return(list2(INDIRECT,e)); } /* filed name search */ /* type = list4(s,disp,fields,tag_nptr); */ extern int search_struct_type(int type,char *name,int *dsp) { int t; NMTBL *nptr0; t = caddr(type); if (t==0) { nptr0=(NMTBL*)cadddr(type); t = caddr(type) = caddr(nptr0->ty); } for(;t;t = cadr(t)) { if (neqname((char *)caddr(t),name)==0) { *dsp = cadddr(t); return car(t); } } return 0; } extern int strop(int e,int ind) { int dsp = 0; if (ind) e = indop(rvalue(e)); if (integral(type)||(car(type)!=STRUCT && car(type)!=UNION)) e=rvalue(e); /* type = list4(s,disp,fields,tag_nptr); */ /* print_fields(caddr(type),"strop"); */ type = search_struct_type(type,nptr->nm,&dsp); if (!type) { error(TYERR); type=INT; return e; } if(dsp) { switch(car(e)) { case GVAR: // e=list2(INDIRECT,list3(ADD,e,list2(CONST,dsp))); e=list3(GVAR,cadr(e)+dsp,caddr(e)); break; case LVAR: e=list2(LVAR,cadr(e) + dsp); break; case INDIRECT: e=list2(INDIRECT,list3(ADD,cadr(e),list2(CONST,dsp))); break; default: e=list2(INDIRECT,list3(ADD,e,list2(CONST,dsp))); } } else { switch(car(e)) { case GVAR: case LVAR: case INDIRECT: break; default: e=list2(INDIRECT,e); } } if (type>0&&car(type)==BIT_FIELD) { // n->ty = list4(BIT_FIELD,type,bit_offset, bit_size); e=list3(BIT_FIELD,e,type); // ??? } return e; } #if FLOAT_CODE /* binary floating computation */ #define DTYPE(dop) (dop==DOP?DOUBLE:FLOAT) static int fdbinop(int op, int e1, int e2, int t1, int t2, int dop) { double d1,d2,d; int b=0; if (dop==DOP) { type=t1; e1=double_value(e1); type=t2; e2=double_value(e2); } else { type=t1; e1=float_value(e1); type=t2; e2=float_value(e2); } if(car(e1)==dop+CONST&&car(e2)==dop+CONST) { d1=dcadr(e1); d2=dcadr(e2); switch(op) { case ADD: d=d1+d2; break; case SUB: d=d1-d2; break; case MUL: d=d1*d2;break; case DIV: if(!d2) error(EXERR);d=d1/d2;break; default: switch(op) { case GT: b=(d1>d2);break; case GE: b=(d1>=d2);break; case LT: b=(d1<d2);break; case LE: b=(d1<=d2);break; case EQ: b=(d1==d2);break; case NEQ: b=(d1!=d2);break; default: error(EXERR); } type = INT; return list2(CONST,b); } return dlist2(dop+CONST,d); } if(car(e1)==dop+CONST) { if ((op==SUB||op==ADD)&&dcadr(e1)==0.0) { return e2; } else if (op==MUL&&dcadr(e1)==1.0) { return e2; } else if (op==MUL&&-dcadr(e1)==1.0) { return list2(dop+MINUS,e2); } } if(car(e2)==dop+CONST) { if ((op==SUB||op==ADD)&&dcadr(e2)==0.0) { return e1; } if ((op==DIV||op==MUL)&&dcadr(e2)==1.0) { return e1; } if ((op==DIV||op==MUL)&&-dcadr(e2)==1.0) { return list2(DMINUS,e1); } if (op==SUB) { op=ADD; dcadr(e2) = -dcadr(e2); } else if(op==DIV) { if(dcadr(e2)==0.0) error(EXERR); op=MUL; dcadr(e2)=1/dcadr(e2); } } if ((op==ADD||op==MUL) && ( car(e1)==dop+CONST || car(e2)==DRLVAR || car(e2)==DRGVAR || car(e2)==FRLVAR || car(e2)==FRGVAR )) { return(list3(op+dop,e2,e1)); } if(op==LT) { type=INT; return(list3(GT+dop,e2,e1)); } else if(op==LE) { type=INT; return(list3(GE+dop,e2,e1)); } else if(op==GT||op==GE||op==EQ||op==NEQ) { type=INT; return(list3(op+dop,e1,e2)); } else if(op==ADD||op==SUB||op==MUL||op==DIV) return(list3(op+dop,e1,e2)); else { error(-1); return e1; } } static int dbinop(int op, int e1, int e2, int t1, int t2) { return fdbinop(op, e1, e2, t1, t2,DOP); } static int fbinop(int op, int e1, int e2, int t1, int t2) { return fdbinop(op, e1, e2, t1, t2,FOP); } #endif #if LONGLONG_CODE static int lbinop(int op, int e1, int e2, int t1, int t2) { int e=0; long long le1, le2; long long le = 0; int us = ((t1==ULONGLONG||t1==UNSIGNED)&&(t2==ULONGLONG||t2==UNSIGNED)); if (us||(t1==ULONGLONG&&(op==LSHIFT||op==RSHIFT))) { type=t1; e1=ulonglong_value(e1); type=t2; e2=ulonglong_value(e2); } else { type=t1; e1=longlong_value(e1); type=t2; e2=longlong_value(e2); } if(car(e1)==LCONST&&car(e2)==LCONST) { le1=lcadr(e1); le2=lcadr(e2); switch(op) { case BOR: le=le1|le2;break; case EOR: le=le1^le2;break; case BAND: le=le1&le2;break; case ADD: le=le1+le2;break; case SUB: le=le1-le2; type=LONGLONG; break; case MUL: le=le1*le2;break; case DIV: if(!le2) error(EXERR); if (us) le=(((unsigned long long )le1)/((unsigned long long )le2)); else e=(le1/le2); case MOD: if(!le2) error(EXERR); if (us) le=(((unsigned long long )le1)%((unsigned long long )le2)); else e=(le1%le2); case RSHIFT: if (t1==ULONGLONG) le=(((unsigned long long)le1)<<le2); else le=le1<<le2; break; case LSHIFT: if (t1==ULONGLONG) le=(((unsigned long long)le1)>>le2); else le=le1>>le2; break; default: switch(op) { case EQ: e=(le1==le2);break; case NEQ: e=(le1!=le2);break; case LT: le=le1;le1=le2;le2=le; case GT: if (us) e=((unsigned long long)le1>(unsigned long long)le2); else e=(le1>le2); break; case LE: le=le1;le1=le2;le2=le; case GE: if (us) e=((unsigned long long)le1>=(unsigned long long)le2); else e=(le1>=le2); break; default: error(-1); return list2(CONST,0); } type = INT; return list2(CONST,e); } return llist2(LCONST,le); } if(op==LT) { type = INT; return(list3(GT+LOP+us,e2,e1)); } else if(op==LE) { type = INT; return(list3(GE+LOP+us,e2,e1)); } else if(op==GT||op==GE||op==LT||op==LE) { type = INT; return(list3(op+LOP+us,e1,e2)); } if(op==SUB) { us = 0; type=LONGLONG; } if(op==SUB&&car(e2)==LCONST) { op=ADD; lcadr(e2)=-lcadr(e2); } if((op==ADD||op==MUL||op==BOR||op==EOR||op==BAND)&& (car(e1)!=LCONST) && ( car(e2)==LRGVAR||car(e2)==LRLVAR|| car(e2)==LURGVAR||car(e2)==LURLVAR )) { e=e1;e1=e2;e2=e;e=t1;t1=t2;t2=e; } if((op==MUL||op==DIV)&&car(e2)==LCONST&&lcadr(e2)==1) return e1; if(op==BOR||op==EOR||op==BAND||op==ADD||op==SUB||op==EQ||op==NEQ) return(list3(op+LOP,e1,e2)); if(op==LSHIFT && car(e2)==LCONST) { if (lcadr(e2)==0) return e1; else if (lcadr(e2)>63) return llist2(LCONST,0); } if(op==RSHIFT && car(e2)==LCONST) { if (lcadr(e2)==0) return e1; } if(op==LSHIFT||op==RSHIFT) return(list3(op+LOP+(t1==ULONGLONG),e1,e2)); return(list3(op+LOP+us,e1,e2)); } #endif /* binary integer computation */ extern int binop(int op, int e1, int e2, int t1, int t2) { int e=0; int us = 0; if(t1>0&&car(t1)==POINTER) { type = t2; e2= int_value(e2); t2=INT; } else if(t2>0&&car(t2)==POINTER) { type = t1; e1= int_value(e1); t1=INT; } #if FLOAT_CODE else if(t1==DOUBLE||t2==DOUBLE) return dbinop(op,e1,e2,t1,t2); else if(t1==FLOAT||t2==FLOAT) return fbinop(op,e1,e2,t1,t2); #endif #if LONGLONG_CODE else if(t1==LONGLONG||t2==LONGLONG||t1==ULONGLONG||t2==ULONGLONG) return lbinop(op,e1,e2,t1,t2); #endif if (t1==UNSIGNED) { if (t2==UNSIGNED || (car(e2)==CONST && cadr(e2)>0)) us = 1; } if (t2==UNSIGNED) { if (t1==UNSIGNED || (car(e1)==CONST && cadr(e1)>0)) us = 1; } if(car(e1)==CONST&&car(e2)==CONST) { e1=cadr(e1); e2=cadr(e2); type= INT; switch(op) { case BOR: e=e1|e2;break; case EOR: e=e1^e2;break; case BAND: e=e1&e2;break; case ADD: if(integral(t1)) { if(integral(t2)) { e=e1+e2; } else { if(car(t2)!=POINTER) error(TYERR); e=size(cadr(t2))*e1+e2; type=t2; } } else { if(car(t1)!=POINTER) error(TYERR); e=e1+size(cadr(t1))*e2; type=t1; } break; case SUB: if(integral(t1)) { e=e1-e2; type=INT; } else { if(car(t1)!=POINTER) error(TYERR); e=e1-size(cadr(t1))*e2; type=t1; } break; case MUL: e=e1*e2;break; case DIV: if(!e2) error(EXERR); if (us) e=(((unsigned)e1)/((unsigned)e2)); else e=e1/e2; break; case MOD: if(!e2) error(EXERR); if (us) e=(((unsigned)e1)%((unsigned)e2)); else e=e1%e2; break; case RSHIFT: if (t1==UNSIGNED) e=(((unsigned)e1)>>((unsigned)e2)); else e=e1>>e2; break; case LSHIFT: if (t1==UNSIGNED) e=(((unsigned)e1)<<((unsigned)e2)); else e=e1<<e2; break; case EQ: e=(e1==e2);break; case NEQ: e=(e1!=e2);break; case LT: e=e1;e1=e2;e2=e; case GT: if (us) e=(((unsigned)e1)>((unsigned)e2)); else e=(e1>e2); break; case LE: e=e1;e1=e2;e2=e; case GE: if (us) e=(((unsigned)e1)>=((unsigned)e2)); else e=(e1>=e2); break; e=(e1<=e2);break; default: error(-1); return list2(CONST,0); } return list2(CONST,e); } if(op==LT) { return(list3(GT+us,e2,e1)); } else if(op==LE) { return(list3(GE+us,e2,e1)); } else if(op==GT||op==GE||op==LT||op==LE) { return(list3(op+us,e1,e2)); } else if(op==EQ||op==NEQ) { return(list3(op,e1,e2)); } if(op==SUB&&car(e2)==CONST) { op=ADD; cadr(e2)=-cadr(e2); } if((op==ADD||op==MUL||op==BOR||op==EOR||op==BAND)&& (car(e1)!=CONST&& ( car(e2)==RGVAR||car(e2)==RLVAR|| car(e2)==URGVAR||car(e2)==URLVAR|| car(e2)==SRGVAR||car(e2)==SRLVAR|| car(e2)==SURGVAR||car(e2)==SURLVAR|| car(e2)==CRGVAR||car(e2)==CRLVAR|| car(e2)==CURGVAR||car(e2)==CURLVAR ))) { e=e1;e1=e2;e2=e;e=t1;t1=t2;t2=e; } if(op==ADD) { if(integral(t1)) { if(integral(t2)) { if(t1==INT) type=t2;else type=t1; return(list3(ADD,e1,e2)); } if(car(t2)!=POINTER) error(TYERR); e=binop(MUL,e1,list2(CONST,size(cadr(t2))),t1,INT); type=t2; return(list3(ADD,e,e2)); } if(car(t1)!=POINTER||!integral(t2)) error(TYERR); e=binop(MUL,e2,list2(CONST,size(cadr(t1))),t2,INT); type=t1; if (car(e)==CONST && cadr(e)==0) return(e1); if (car(e)==CONST) { if(car(e1)==ADDRESS&&car(cadr(e1))!=GVAR) { return(list2(ADDRESS,list2(car(cadr(e1)), cadr(cadr(e1))+cadr(e)))); } else if(car(e1)==GVAR) { return(list3(GVAR,cadr(e1)+cadr(e),caddr(e1))); } else if(car(e1)==LVAR) { return(list2(LVAR,cadr(e1)+cadr(e))); } } return(list3(ADD,e1,e)); } if(op==SUB) { if(integral(t1)) { if(!integral(t2)) error(TYERR); if(t1==INT) type=t2;else type=t1; if (type==UNSIGNED) type=INT; return(list3(SUB,e1,e2)); } if(car(t1)!=POINTER) error(TYERR); if(integral(t2)) { e=binop(MUL,e2,list2(CONST,size(cadr(t1))),t2,INT); type=t1; if (car(e)==CONST) error(-1); return(list3(SUB,e1,e)); } if(car(t2)!=POINTER) error(TYERR); compatible(t1,t2); e=list3(SUB,e1,e2); e=binop(DIV,e,list2(CONST,size(cadr(t1))),UNSIGNED,INT); type= INT; return e; } if(!integral(t1)||!integral(t2)) error(TYERR); // if(t1==INT) type=t2; else type=t1; /* ??? */ if (us) type=UNSIGNED; else type=INT; if((op==MUL||op==DIV)&&car(e2)==CONST&&cadr(e2)==1) return e1; if(op==BOR||op==EOR||op==BAND) return(list3(op,e1,e2)); if(op==LSHIFT||op==RSHIFT) return(list3(op+(t1==UNSIGNED?US:0),e1,e2)); // which ops remain? return(list3(op+us,e1,e2)); } /* coarse for function/code segments arguments */ extern int correct_type(int e,int t) { int t1; /* e = rvalue(e); */ #if BIT_FIELD_CODE if (type==BIT_FIELD) e = rvalue(e); #endif if (type==FLOAT && t==DOTS) { t=DOUBLE;} // fall thru if (type==CHAR && t==DOTS) { t=INT;} // fall thru if (t==DOTS) return e; else if (t==UNSIGNED) e = unsigned_value(e); else if (t==CHAR) { e = char_value(e); t = INT; } else if (t==UCHAR) { e = uchar_value(e); t = UNSIGNED; } else if (t==SHORT) { e = short_value(e); t = INT; } else if (t==USHORT) { e = ushort_value(e); t = UNSIGNED; } else if (integral(t)) e = int_value(e); #if FLOAT_CODE else if (t==FLOAT) e = float_value(e); else if (t==DOUBLE) e = double_value(e); #endif #if LONGLONG_CODE else if (t==LONGLONG) e = longlong_value(e); else if (t==ULONGLONG) e = ulonglong_value(e); #endif else if ((t1=car(t))==STRUCT||t1==UNION) { if(size(t)!=size(type)) error(TYERR); } /* else error(TYERR); */ type = t; return e; } extern int cexpr(int e) { if (car(e) != CONST) error(CNERR); return (cadr(e)); } #define is_long_type(type) (type==LONGLONG||type==ULONGLONG) #if BIT_FIELD_CODE /* bitfield struct { char a:1; unsigned int b:10; } System dependent bit alignment is defined by code_bit_field_disp. type of bitfield represents type of the value these values are stored in a stored type which can be different from value type. */ static int bit_field(int e1,int t) { int reg; if (car(e1)==BIT_FIELD) { printf("# bit_field_bug\n"); e1 = cadr(e1); } g_expr(e1); emit_push(); code_bit_field(t, reg = emit_pop(0), USE_CREG); emit_pop_free(reg); return cadr(t); /* value type */ } static int bit_field_repl(int e1,int e2,int t) { /* e1 = e2 */ if ((car(e2)==CONST||car(e2)==LCONST)) { g_expr(e1); code_bit_replace_const(e2,USE_CREG,t); return t; } g_expr(e1); emit_push(); g_expr(e2); code_bit_replace(e2=emit_pop(0),USE_CREG,t); emit_pop_free(e2); return t; } static int bassign(int e2,int e3,int t) { int type = cadr(t); /* e2 = e3 */ if (car(e2)==BIT_FIELD) { e2 = cadr(e2); } bit_field_repl(e2,e3,t); return type; } static int bassop(int e2,int e3,int op,int t,int post) { /* n = bit_field address code_bit_field if (post) n1 = value value op= operand n bit-repl value if (post) n1; */ /* e2 = e2 op e3; */ /* new = &e2 */ /* *new = *new op e3 */ int suse = use; int lo = (type==LONGLONG||type==ULONGLONG); int n1=0,n2=0; int reg; g_expr(list2(ADDRESS,cadr(e2))); reg = emit_push(); code_bit_field(t, reg, USE_CREG); use=1; if (lo) { if (post) { n1 = list2(LVAR,new_lvar(size_of_longlong)); code_lassign_lvar(cadr(n1),USE_CREG); } if (!code_lassop_p) { n2 = list2(LVAR,new_lvar(size_of_longlong)); code_lassign_lvar(cadr(n2),USE_CREG); lassign(list4(LASSOP,n2,e3,op+LOP)); } else { emit_lpush(); g_expr(e3); code_register_lassop(USE_CREG,op+LOP); } } else { if (post) { n1 = list2(LVAR,new_lvar(size_of_int)); code_assign_lvar(cadr(n1),USE_CREG,0); } emit_push(); g_expr(e3); code_register_assop((e2=emit_pop(0)),USE_CREG,op,size(type)); if (use) { code_register(e2,USE_CREG); } emit_pop_free(e2); } use=post?0:suse; code_bit_replace(e2=emit_pop(0),USE_CREG,t); emit_pop_free(e2); use = suse; if (post&&use) { g_expr(rvalue_t(n1,type));} if (n1) free_lvar(cadr(n1)); if (n2) free_lvar(cadr(n2)); return type; } #endif /* temporal local variable free list */ static int lvar_list,lvar_free_list; extern int new_lvar0(int sz) { switch (disp_align) { default: case 0: return disp-=sz; case 4: disp-=sz; if (sz>=4) disp &= -4; return disp; } } extern int new_lvar(int size) { int lvar,plvar; for (plvar = 0,lvar = lvar_free_list;lvar;lvar = cadr(lvar)) { if (caddr(lvar)==size) { if (plvar) cadr(plvar) = cadr(lvar); else lvar_free_list = cadr(lvar); break; } plvar = lvar; } if (!lvar) { lvar_list = glist3((lvar=new_lvar0(size)),lvar_list,size); } else { cadr(lvar) = lvar_list; lvar_list = lvar; lvar = car(lvar_list); } return lvar; } extern void free_lvar(int disp) { int lvar,plvar; for (plvar = 0,lvar = lvar_list;lvar;lvar = cadr(lvar)) { if (car(lvar)==disp) { if (plvar) cadr(plvar) = cadr(lvar); else lvar_list = cadr(lvar); break; } plvar = lvar; } if (!lvar) error(-1); cadr(lvar) = lvar_free_list; lvar_free_list = lvar; } extern void init_free_lvar_list() { int lvar; while((lvar=lvar_list)) { lvar_list=cadr(lvar_list); free_glist3(lvar); } while((lvar=lvar_free_list)) { lvar_free_list=cadr(lvar_free_list); free_glist3(lvar); } } extern void gen_code_enter(char *name) { code_enter(name); } extern void gen_code_enter1(int args) { code_enter1(args); } extern void gen_code_leave(char *name) { code_leave(name); } extern void gen_enter(char *name) { enter(name); } extern void gen_enter1() { enter1(); } extern void gen_leave(int control, char *name) { leave(control,name); } extern void gen_jmp(int l) { jmp(l); } extern void gen_indirect_goto(int e1) { g_expr(e1); code_indirect_jmp(USE_CREG); } /* make bit mask MSB 1 2 3 4 .... 29 30 31 LSB */ extern int make_mask(int from,int to) { int mask = 0; int bit = 1; int i; if (from<0||from>32) error(-1); for (i=31;from<=i;i--,bit<<=1) { if (i<=to) { mask |= bit; } } return mask; } #define MAX_PTR_CACHE 10 static int ptr_cache=0; static int ptr_cache_last=0; /* global name pointer cache */ extern void init_ptr_cache() { int i; for(i=0;i<MAX_PTR_CACHE-1;i++) { ptr_cache=glist3(0,ptr_cache,0); } ptr_cache_last=ptr_cache; } extern void clear_ptr_cache_reg(int r) { int ptcptr=ptr_cache; int prev = 0; while(ptcptr!=ptr_cache_last) { if(car(ptcptr)&&caddr(ptcptr)==r) { free_register(r); caddr(ptcptr)=-1; car(ptcptr)=0; // remove me if (prev) cadr(prev) = cadr(ptcptr); else ptr_cache = cadr(ptcptr); // add me to the next of ptr_cache_last cadr(ptcptr) = cadr(ptr_cache_last); cadr(ptr_cache_last) = ptcptr; return; } ptcptr=cadr(prev=ptcptr); } } extern int last_ptr_cache() { int ptcptr=ptr_cache; int r = 0; while(ptcptr!=ptr_cache_last) { r = caddr(ptcptr); ptcptr=cadr(ptcptr); } return r; } extern void clear_ptr_cache() { int ptcptr=ptr_cache; while(ptcptr!=ptr_cache_last) { free_register(caddr(ptcptr)); caddr(ptcptr)=-1; car(ptcptr)=0; ptcptr=cadr(ptcptr); } ptr_cache_last = ptr_cache; } extern int get_ptr_cache(NMTBL *nptr) { int r; int ptcptr=ptr_cache; int g = (int)nptr; int prev=0,p; // linear search cache while(ptcptr!=ptr_cache_last) { if(car(ptcptr)==g) { if (prev) { // make this top cadr(prev)=cadr(ptcptr); cadr(ptcptr) = ptr_cache; ptr_cache = ptcptr; } return caddr(ptcptr); } ptcptr=cadr(prev=ptcptr); } if (!cadr(ptr_cache_last)) { // cache is full if (prev) { // remove oldest cache and it becomes the last free_register(caddr(prev)); caddr(ptcptr)=-1; car(ptcptr)=0; ptr_cache_last = prev; } else error(-1); } r = get_register(0); // some ptr cache may remove by this caddr(p = cadr(ptr_cache_last)) = r; car(p) = g; use_ptr_cache(r); cadr(ptr_cache_last) = cadr(p); cadr(p) = ptr_cache; ptr_cache = p; code_ptr_cache_def(r,nptr); return r; } extern int ilog(int i) { /* number of bit (i-1) is better? */ switch(i) { case 2: return 1; case 4: return 2; case 8: return 3; case 16: return 4; case 32: return 5; case 64: return 6; case 128: return 7; case 256: return 8; case 512: return 9; case 1024: return 10; case 2048: return 11; case 4096: return 12; case 8192: return 13; case 16384: return 14; case 32768: return 15; case 65536: return 16; case 131072: return 17; case 262144: return 18; case 524288: return 19; } return 0; } /* end */