Mercurial > hg > CbC > old > device
view mc-codegen.c @ 894:989bdd85e8af
a little better zfill
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Sun, 06 Apr 2014 16:02:30 +0900 |
parents | 3542a0e38a54 |
children | 62498a76e716 |
line wrap: on
line source
/* Micro-C Generic Code Generation Part */ /* ************************************************************************ ** Copyright (C) 2006 Shinji Kono ** 連絡先: 琉球大学情報工学科 河野 真治 ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) ** ** このソースのいかなる複写,改変,修正も許諾します。ただし、 ** その際には、誰が貢献したを示すこの部分を残すこと。 ** 再配布や雑誌の付録などの問い合わせも必要ありません。 ** 営利利用も上記に反しない範囲で許可します。 ** バイナリの配布の際にはversion messageを保存することを条件とします。 ** このプログラムについては特に何の保証もしない、悪しからず。 ** ** Everyone is permitted to do anything on this program ** including copying, modifying, improving, ** as long as you don't try to pretend that you wrote it. ** i.e., the above copyright notice has to appear in all copies. ** Binary distribution requires original version messages. ** You don't have to ask before copying, redistribution or publishing. ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. *********************************************************************** */ #include <stdio.h> #include "mc.h" #include "mc-parse.h" #include "mc-codegen.h" #include "mc-code.h" #include "mc-switch.h" #include "mc-inline.h" #include "conv/conv.h" extern Converter *conv; int use; /* generated value will be used */ char *init_src; int size_of_pointer; int size_of_int; int size_of_short; int size_of_float; int size_of_double; int size_of_longlong; int size_of_vector; int bit_of_byte; int endian; int struct_align; static void assign(int e1); #if ASM_CODE static void gen_asm(int asm0,int in,int out,int opt,int e); #endif 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 machinop(int e1); static int register_to_lvar(int e); static void remove0(int *parent,int e) ; static void sassign(int e1); static int gen_decl_data0(int v,int target_type,int init,int offset); #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(); } /** make register argments and save it into memory (sigh...) we should postpone code_save_argument_register */ extern void arg_register(NMTBL *fnptr, int in) { code_arg_register(fnptr, in); } extern int gexpr(int e1,int use0) { if (chk==1) return INT; gexpr_init(); use = use0; 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); 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); use=suse; return t; } /* gexpr for used flag untouched */ extern int g_expr0(int e1) { int e2,e3,t,d,t1; NMTBL *n; if (inmode) { error(-1); // return (parse = list3(ST_COMP,parse,e1)); } if (!e1 ||(!control && !IS_STATEMENT(car(e1)))) return VOID; for(;e1;e1=e2) { code_gexpr(e1); conv->expr_(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 URGVAR: code_rgvar(e1,USE_CREG); return UNSIGNED; 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: if (lp64) code_crlvar(e2,USE_CREG,1,size_of_int); else code_rlvar(e2,USE_CREG); return INT; case URLVAR: if (lp64) code_crlvar(e2,USE_CREG,0,size_of_int); else code_rlvar(e2,USE_CREG); return UNSIGNED; 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(ncaddr(e1),USE_CREG); return ADDRESS; case LABEL: if (car(e2)!=LVAR) error(-1); code_label_value(cadr(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 STRINGS: code_strings(e2,USE_CREG) ; return ADDRESS; case STRING: code_string(e1,USE_CREG); return ADDRESS; case FUNCTION: if (car(e2)==FNAME&&is_code(ncaddr(e2))) { // error(FNERR); jump(e1,0); return VOID; } t = function(e1); return t; case JUMP: if (car(e2)==FNAME&&is_function(ncaddr(e2))) { // error(GTERR); return function(e1); } jump(e2,caddr(e1)); return VOID; case ARRAY: if (chk==2) { // for generation check (?) indop(e1); t = type; g_expr0(e2); g_expr0(caddr(e1)); code_gexpr(e1); return t; } e1=binop(ADD,e2,caddr(e1),cadddr(e1),caddddr(e1)); e1 = indop(e1); t = type; g_expr0(e1); return t; case PERIOD: nptr = ncadddr(e1); type = caddr(e1); e1 = strop(e2,0); t = type; if (chk) return t; g_expr0(e1); return t; case ARROW: nptr = ncadddr(e1); type = caddr(e1); e1 = strop(e2,1); t = type; if (chk) return t; g_expr0(e1); return t; case INLINE: return gen_inline(e1,0); 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 COND: /* a?0:1 should consider non-brach instruction */ case UCOND: d = INT; goto cond_case; case LUCOND: case LCOND: d = LONGLONG; goto cond_case; case DCOND: d = DOUBLE; goto cond_case; case FCOND: d = FLOAT; cond_case: 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); gen_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: dassign(e1); return FLOAT; case DASS: dassign(e1); return DOUBLE; case FASSOP: dassop(e1); return FLOAT; case DASSOP: 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 BUILTINP: /* Too late. Should be evaluated in pexpr. */ code_const(is_const(e2),USE_CREG); return INT; case BUILTIN_FABSF: code_builtin_fabsf(e2); return FLOAT; case BUILTIN_FABS: case BUILTIN_FABSL: code_builtin_fabs(e2); return DOUBLE; case BUILTIN_INFF: code_builtin_inff(); return FLOAT; case BUILTIN_INF: case BUILTIN_INFL: code_builtin_inf(); return DOUBLE; case COMMA: g_expr_u(e2); return g_expr0(caddr(e1)); case RETURN: n = ncaddr(e1); if (retcont==0) retcont=fwdlabel(); code_return(USE_CREG); return VOID; case ENVIRONMENT: code_environment(USE_CREG); return ADDRESS; case LCALL: code_save_stacks(); gen_jmp(e2); fwddef(caddr(e1)); return VOID; #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 case CAST: error(-1); // correct_type is too late for contains_p type = cadddr(e1); e2 = correct_type(e2,caddr(e1)); continue; case DECL_DATA: e1 = gen_decl_data(e1,0); return e1; case ST_DECL: checkretpening(); st_decl(e1); break; case ST_IF: checkretpening(); st_if(e1); break; case ST_DO: checkretpening(); st_do(e1); break; case ST_WHILE: checkretpening(); st_while(e1); break; case ST_FOR: checkretpening(); st_for(e1); break; case ST_SWITCH: checkretpening(); st_switch(e1); break; case ST_COMP: checkretpening();st_comp(e1); break; case ST_BREAK: st_break(e1); break; case ST_CONTINUE: st_continue(e1); break; case ST_CASE: st_case(e1); break; case ST_DEFAULT: st_default(e1); break; case ST_RETURN: st_return(e1); break; case ST_GOTO: checkret(); st_goto(e1); break; case ST_ASM: checkret(); st_asm(e1); break; case ST_LABEL: st_label(e1); break; case ST_COMMENT: st_comment(e1); break; case ST_OP: checkretpening(); e3=caddr(e1); e1=binop(e2,car(e1),cadr(e3),caddr(e3),cadddr(e3)); continue; case IVAR: error(-1); break; case 0: error(-1); break; // empty case default: code_bool(e1,USE_CREG); /* type? */ return INT; } } return VOID; } extern int rop_dual(int 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 */ /* l1 ... label for branch */ /* return 0 if l1 is not used, otherwise return l1 */ static int bexpr_u(int e1, char cond, int l1) { int op = car(e1); conv->expr_(e1); if (chk) return l1; // is this switch really useful? 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: switch(car(cadr(e1))) { case CONST: case DCONST: case FCONST: case LCONST: return 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 int bexpr(int e1, char cond, int l1) { int uses = use; use=1; l1 = bexpr_u(e1, cond, l1); use = uses; return l1; } /* branch expression generator */ /* if (cond?e1:!e1) goto l1 */ /* 1 or 0 is return for code_bool */ extern int b_expr(int e1, char cond, int l1,int err) { int e2,l2,t; code_save_stacks(); if (!control) return l1; l2 = 0; e2=cadr(e1); switch(car(e1)) { case LNOT: return b_expr(e2,!cond,l1,0); case GT: case GE: case LT: case LE: case EQ: case NEQ: return rexpr(e1,l1,cond,INT); return l1; case UGT: case UGE: case ULT: case ULE: return rexpr(e1,l1,cond,UNSIGNED); #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: return drexpr(cadr(e1),caddr(e1),l1,car(e1),cond); case FOP+LT: case FOP+LE: case DOP+LT: case DOP+LE: return drexpr(caddr(e1),cadr(e1),l1,rop_dual(car(e1)),cond); #endif #if LONGLONG_CODE case LOP+GT: case LOP+GE: case LOP+EQ: case LOP+NEQ: case LOP+UGT: case LOP+UGE: return lrexpr(cadr(e1),caddr(e1),l1,car(e1),cond); case LOP+LT: case LOP+LE: case LOP+ULT: case LOP+ULE: return lrexpr(caddr(e1),cadr(e1),l1,rop_dual(car(e1)),cond); #endif case LAND: l2=bexpr(e2,0,cond?(l2=fwdlabel()):l1); l1=bexpr_u(caddr(e1),cond,l1); if(cond) fwddef(l2); return l1; case LOR: l2=bexpr(e2,1,cond?l1:(l2=fwdlabel())); l1=bexpr_u(caddr(e1),cond,l1); if(!cond) fwddef(l2); return l1; case CRGVAR: case CURGVAR: conv->bool_(e1); code_cmp_crgvar(e1,USE_CREG,1,l1,cond); return l1; case SRGVAR: case SURGVAR: conv->bool_(e1); code_cmp_crgvar(e1,USE_CREG,size_of_short,l1,cond); return l1; case CRLVAR: case CURLVAR: conv->bool_(e1); code_cmp_crlvar(e2,USE_CREG,1,l1,cond); return l1; case SRLVAR: case SURLVAR: conv->bool_(e1); code_cmp_crlvar(e2,USE_CREG,size_of_short,l1,cond); return l1; case RGVAR: case URGVAR: conv->bool_(e1); code_cmp_rgvar(e1,USE_CREG,l1,cond); return l1; case RLVAR: case URLVAR: conv->bool_(e1); code_cmp_rlvar(e2,USE_CREG,l1,cond); return l1; #if 0 && FLOAT_CODE case DRLVAR: code_cmp_drlvar(e2,USE_CREG,1,l1,cond); return l1; case FRLVAR: code_cmp_drlvar(e2,USE_CREG,0,l1,cond); return l1; case DRGVAR: code_cmp_drgvar(e2,USE_CREG,1,l1,cond); return l1; case FRGVAR: code_cmp_drgvar(e2,USE_CREG,0,l1,cond); return l1; case FREGISTER: code_cmp_dregister(e2,0,l1,cond); return l1; case DREGISTER: code_cmp_dregister(e2,1,l1,cond); return l1; case DCONST: case FCONST: if(control&&((dcadr(e2)!=0.0)^cond)) { gen_jmp(l1); return l1; } else return 0; #endif #if 0 && LONGLONG_CODE case LRLVAR: code_cmp_lrlvar(e2,USE_CREG,l1,cond); return l1; case LRGVAR: code_cmp_lrgvar(e2,USE_CREG,l1,cond); return l1; case LREGISTER: code_cmp_lregister(e2,l1,cond); return l1; case LCONST: if(control&&((lcadr(e2)!=0)^cond)) { gen_jmp(l1); return l1; } else return 0; #endif case REGISTER: conv->bool_(e1); code_cmp_register(e2,l1,cond); return l1; case CONST: if(control&&((cond&&e2)||(!cond&&!e2))) { gen_jmp(l1); return l1; } else return 0; default: if(err) { error(-1); return l1; /* recursive g_expr/b_expr */ } t=g_expr(e1); if (!use) return l1; // Is this really happen? conv->bool_(e1); 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 l1; } } extern int is_const(int e) { switch(car(e)) { case ADDRESS: e = cadr(e); return (car(e)==GVAR||car(e)==FNAME||car(e)==LVAR); case STRINGS: case STRING: case GVAR: case EXTRN: case EXTRN1: case FNAME: case CONST: case LCONST: case FCONST: case DCONST: return 1; default: return 0; } } extern int is_code(NMTBL *fnptr) { int type = type_value(fnptr->ty); return (type==CODE|| (type>0 && car(type)==CODE)); } extern int is_function(NMTBL *fnptr) { int type = type_value(fnptr->ty); return (type==FUNCTION || (type>0 && car(type)==FUNCTION)); } extern int is_inline(NMTBL *f) { return (f && !attr_value(f,NOINLINE) && attr_value(f,INLINE)); } extern int function_type(int e1,int *dots) { int ret_type,t; if (e1<0) return INT; ret_type = type_value(cadr(e1)); if (ret_type==CHAR) ret_type=INT; /* check argments type is DOTS? */ t = type_value(caddr(e1)); if (/* t==0 || */ t==DOTS) *dots = 1; else { *dots = 0; for(;t;t = type_value(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 = list3n(LVAR,n->dsp,n); g_expr_u(assign_expr0(list3n(LVAR,n->dsp,n),list3n(tag,reg,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); // // register の大きさはsize_of_int とは限らない。むしろ、 // get_register_var した方が安全... extern void parallel_rassign(int assigns) { int free,tmp,remains,t0=0,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 is_writable(int); /* overlap return list of overlapped target */ static int overlap(int t,int sz,int target) { int s,s0,s1; int t0=cadr(t); int t1=t0+sz; int source; int result=0; if (!is_writable(t)) error(-1); for(;target;target=cadr(target)) { for(source=caddddr(target);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)) { result = list2(target,result); } break; default: if (is_same_type(s,t)) { s1=s0+caddr(source); #if DEBUG_PARALLEL_ASSIGN>1 if (lsrc) printf("## overlap source %d t0 %d t1 %d\n",car(car(t)),t0,t1); if (lsrc) printf("## overlap target %d s0 %d s1 %d\n",car(car(source)),s0,s1); if (lsrc) printf("## overlap equal = %d\n",((t0<=s0&&s0<t1)||(t0<s1&&s1<=t1))); #endif if((t0<=s0&&s0<t1)||(t0<s1&&s1<=t1)) result = list2(target,result); } } } } return result; } 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 = 0; // 使ったら free するべきだよね? code goto の時なら害はないか... /*新しいレジスタ(or スタック)を取得する*/ if (scalar(ty) && sz==size_of_int && (e1=get_register_var(0))!=-1) { // e1=list3(REGISTER,e1,0); if (code_register_overlap(s,e1)) goto use_lvar; *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append5(*target,t,ty,e1,list3(e1,0,sz)); #if FLOAT_CODE } else if (ty==DOUBLE && sz==size_of_double && (e1=get_dregister_var(0,1))!=-1) { if (code_register_overlap(s,e1)) goto use_lvar; *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append5(*target,t,ty,e1,list3(e1,0,sz)); } else if (ty==FLOAT && sz==size_of_float && (e1=get_dregister_var(0,0))!=-1) { if (code_register_overlap(s,e1)) goto use_lvar; *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append5(*target,t,ty,e1,list3(e1,0,sz)); #endif #if LONGLONG_CODE } else if ((ty==LONGLONG||ty==ULONGLONG)&&(e1=get_lregister_var(0))!=-1) { if (code_register_overlap(s,e1)) goto use_lvar; *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append5(*target,t,ty,e1,list3(e1,0,sz)); #endif } else { if (0) { use_lvar:; #if DEBUG_PARALLEL_ASSIGN>1 if (lsrc) printf("## register overrap in save_target\n"); #endif } g_expr_u(assign_expr0((e1=list3n(LVAR,new_lvar(sz),0)),s,ty,ty)); *target = append5(*target,t,ty,e1,list3(e1,0,sz)); *use=list3(t,*use,e1); } } static int circular_dependency(int t,int clist,int target,int history) { int t1,h,sz,s,clist1,t2; for(;clist;clist=cadr(clist)) { /* conflict list */ loop: t1 = car(clist); for(h=history;h;h=cadr(h)) { if (t1==car(h)) { #if DEBUG_PARALLEL_ASSIGN if (lsrc) printf("## circular dependency %d ty %d\n",car(t1),cadr(t1)); #endif return t1; } } for(s=caddddr(t1);s;s=cadr(s)) { /* dependent memory sources */ sz=caddr(s); if ((clist1=overlap(car(s),sz,target))) { if (!cadr(t1)&&!cadr(s)) { history = list2(t,history); t = t1; clist = clist1; goto loop; // tail recursion } else { if ((t2=circular_dependency(t1, clist1,target,list2(t,history)))) { return t2; } } } } } return 0; } // static void remove_a(int source,int s); // remove all child static void parallel_assign(int *target,int *processing,int *use) { int t,s,sz,ty,target0,s1,progress; while(*target) { progress = 0; for(target0=*target;target0; target0=cadr(target0)) { t=car(target0); s=cadddr(target0); sz=size(ty=caddr(target0)); if(is_same_type(t,s) && cadr(t)==cadr(s)) { /*書き込み先が自分自身*/ #if DEBUG_PARALLEL_ASSIGN if (lsrc) printf("## remove same %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); #endif remove_target(target,t,use); progress = 1; } else if (!(s1=overlap(t,sz,*target)) || (cadr(s1)==0 && car(car(s1))==t)) { /* 重なってないので安心して書き込める */ #if DEBUG_PARALLEL_ASSIGN if (s1 && cadr(s1)==0) { if (lsrc) printf("## singleton %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); // this means singleton struct should be copied safely. } else if (lsrc) 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); progress = 1; } else if((t=circular_dependency(target0,s1,*target,0))) { remove_target(target,car(t),use); sz=size(ty=caddr(t)); save_target(car(t),cadddr(t),target,use,sz,ty); progress = 1; #if DEBUG_PARALLEL_ASSIGN if (lsrc) printf("## saving %d ty %d+%d sz %d\n",car(car(t)),ty,cadr(car(t)),sz); #endif break; } } if (!progress) { // can't performe parallel assign // error(-1); target0 = *target; t=car(target0); s=cadddr(target0); sz=size(ty=caddr(target0)); #if DEBUG_PARALLEL_ASSIGN if (lsrc)printf("## can't progress save any %d ty %d+%d sz %d\n",car(s),ty,cadr(t),sz); #endif remove_target(target,t,use); save_target(t,s,target,use,sz,ty); } } } 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 int remove_1(int source,int e) { int sz; if ((sz=is_memory(e))) { remove0((int*)source,e); } return source; } static void remove_a(int source,int s) { contains_p1(source,s,remove_1); } */ // #define SAVE_ALL_NON_MEMORY #ifdef SAVE_ALL_NON_MEMORY 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: case URGVAR: case URLVAR: return 1; } return 0; } #endif static int is_same_type(int e1,int e2) { int ce1=car(e1); int ce2=car(e2); if (ce1==LVAR) { switch(ce2) { case LRLVAR: case LURLVAR: return lp64; case RLVAR: case CRLVAR: case FRLVAR: case DRLVAR: case SRLVAR: case SURLVAR: case CURLVAR: case LVAR: case URLVAR: return 1; } } else if (ce2==LVAR) { switch(ce1) { case LRLVAR: case LURLVAR: return lp64; case RLVAR: case CRLVAR: case FRLVAR: case DRLVAR: case SRLVAR: case SURLVAR: case CURLVAR: case LVAR: case URLVAR: 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 } else if (ce1==REGISTER) { if (lp64 && ce2==LREGISTER) return 1; } else if (ce2==REGISTER) { if (lp64 && ce1==LREGISTER) return 1; } return 0; } static int is_writable(int e1) { switch(car(e1)) { case GVAR : case LVAR : case RLVAR : case LRLVAR: case URLVAR: case LURLVAR: // this is wrong, but ia32 generates this. case REGISTER : return size_of_int; case FREGISTER : return size_of_float; case DREGISTER : return size_of_double; case LREGISTER: return size_of_longlong; } return 0; } extern int reference(int e1) { switch(car(e1)) { case GVAR : case CRGVAR : case CURGVAR : case DRGVAR : case FRGVAR : case LRGVAR : case LURGVAR : case RGVAR: case SRGVAR : case SURGVAR: case URGVAR: return list3n(GVAR,cadr(e1),ncaddr(e1)); case LVAR : case CRLVAR : case CURLVAR : case DRLVAR : case FRLVAR : case LRLVAR: case LURLVAR: case RLVAR: case SRLVAR : case SURLVAR : case URLVAR: return list3n(LVAR,cadr(e1),ncaddr(e1)); case FREGISTER : case REGISTER: case LREGISTER: case DREGISTER: return e1; break; default: error(-1); } return e1; } static int is_memory0(int e1,int *global) { *global=0; switch(car(e1)) { case CRGVAR : case CURGVAR : *global=1; case CRLVAR : case CURLVAR : return 1; case SRGVAR : case SURGVAR: *global=1; case SRLVAR : case SURLVAR : return size_of_short; // case GVAR : case RGVAR: case URGVAR: *global=1; // case LVAR : case RLVAR: case REGISTER : return size_of_int; case FRGVAR : *global=1; case FRLVAR : case FREGISTER : return size_of_float; case DRGVAR : *global=1; case DRLVAR : case DREGISTER : return size_of_double; case LRGVAR : case LURGVAR : *global=1; case LRLVAR : case LURLVAR : case LREGISTER: return size_of_longlong; } return 0; } extern int is_memory(int e1) { int global; return is_memory0(e1,&global); } extern int is_local_memory(int e1) { int global; return is_memory0(e1,&global) && !global; } static int check_source(int source,int e) { int sz; if ((sz=is_memory(e))) { source = list3(e,source,sz); } return source; } // // CbC goto statement with environment // // maximum size of struct divide (don't make it large) #define ASSIGN_STRUCT_DIVIDE 40 #define ARG_OFFSET_CODE 1 extern 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 processing = 0; int use = 0; int envreg = 0; int int_type = lp64?LONGLONG:INT; /* e1 = list4(FUNCTION,code_segment,arglist,ftype); */ if (env) { error(-1); // not supported envreg = get_register_var(0); g_expr_u(assign_expr0(envreg,env,int_type,int_type)); } /* まず、サイズを計算しながら、target を決まった形に落す。 */ /* list5(target,next,ty,source,source_dependency) */ 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=list5(r,target,ty,e2,0); regs++; } else if (ty==FLOAT && (r = get_input_dregister_var(fregs,0,1,0))) { target=list5(r, target,ty,e2,0); fregs++; } else if (ty==DOUBLE && (r = get_input_dregister_var(fregs,0,1,1))) { target=list5(r, target,ty,e2,0); fregs++; } else if ((ty==LONGLONG||ty==ULONGLONG) && (r = get_input_lregister_var(fregs,0,1))) { target=list5(r, target,ty,e2,0); regs+=lp64?1:2; } else if (env) { while(car(e2)==RSTRUCT) e2=cadr(e2); /* envreg contains frame pointer, we need disp_offset. disp_offset for code segment and function should be the same value. If original frame pointer has indeterminate offset, these should fixed in code_fix_frame_pointer. */ g_expr_u(assign_expr0( list2(INDIRECT, lp64?list3(LADD,rvalue_t(envreg,LONGLONG),llist2(LCONST,-arg_size-sz+disp_offset)) :list3(ADD,rvalue_t(envreg,INT),list2(CONST,-arg_size-sz+disp_offset)) ), e2,ty,ty)); } else { while(car(e2)==RSTRUCT) e2=cadr(e2); target=list5(list3n(LVAR,0,0), target,ty,e2,0); } /* keep arg space for register variables */ #if ARG_OFFSET_CODE NMTBL n; arg_size = code_arg_alignment(arg_size, &n, ty, sz,1); #else arg_size += sz; #endif #if DEBUG_PARALLEL_ASSIGN if (lsrc)printf("## target %d ty %d+%d sz %d\n",car(car(target)),ty,cadr(car(target)),sz); #endif } if (env) { /* change the frame pointer during parallel assignment */ target=list5(code_frame_pointer_register(), target,INT,rvalue_t(envreg,INT),0); } /* disp を飛び先似合わせて修正 */ if (is_code(fnptr)) { if (-arg_size<disp) disp = -arg_size; } else { if (disp_offset-arg_size<disp) disp = disp_offset-arg_size; } /* 複雑な式を前もって計算しておく */ /* 必要なら局所変数を用いる。 */ /* 局所変数へのオフセットを覚えておく */ #if ARG_OFFSET_CODE NMTBL n; n.dsp = 0; int arg_offset = 0; target = reverse0(target); #endif for (e2 = target; e2; e2 = cadr(e2)) { t0=car(e2); s0=cadddr(e2); sz=size(ty=caddr(e2)); #if ARG_OFFSET_CODE /* ここで、書込先アドレスを決める */ arg_offset = code_arg_alignment(arg_offset, &n, ty, sz,1); if(car(t0)==LVAR) { cadr(t0) = n.dsp; } #else if(car(t0)==LVAR) { cadr(t0)=-arg_size; // disp_offset?! } arg_size-=sz; #endif #ifdef SAVE_ALL_NON_MEMORY if (!is_simple(car(s0))) { #else if (contains_p(s0,not_simple_p)) { /* } */ #endif /* complex case */ g_expr_u(assign_expr0((e4=list3n(LVAR,new_lvar(sz),0)),s0,ty,ty)); use=list3(ty,use,e1); cadddr(e2)=e4; caddddr(e2)=list3(e4,0,sz); s0=e4; } else if (is_same_type(t0,s0)) { if(cadr(t0)==cadr(s0)) { if(is_writable(s0)) { caddddr(e2)=list3(s0,0,sz); // これなんだっけ? continue; } else error(-1); } } int int_unsigned = lp64?ULONGLONG:UNSIGNED; int int_size = lp64?sizeof(long long):sizeof(int); if(is_writable(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 if (lsrc)printf("## division sz %d\n",sz); #endif caddr(e2) = int_unsigned; caddddr(e2) = list3( cadddr(e2)=list3n(LVAR,cadr(s0),0), 0, int_size); #if DEBUG_PARALLEL_ASSIGN if (lsrc)printf("## div 0 source %d ty %d+%d sz %d\n",car(s0),ty,cadr(s0),int_size); #endif for(e4=int_size;e4<sz;) { cadr(e2) = list5(car(e2),cadr(e2), caddr(e2),cadddr(e2),caddddr(e2)); switch(sz-e4) { case 1: caddr(e2) = UCHAR; r = 1; break; case 2: case 3: caddr(e2) = USHORT; r = size_of_short; break; case 4: if (lp64) { caddr(e2) = UNSIGNED; r = size_of_int; break; } default: caddr(e2) = int_unsigned; r = int_size; } if (e4==int_size) e3=cadr(e2); car(e2) = list3n(LVAR,cadr(t0)+e4,0); caddddr(e2) = list3( cadddr(e2) = list3n(LVAR,cadr(s0)+e4,0),0, r); e4 += r; #if DEBUG_PARALLEL_ASSIGN if (lsrc)printf("## div 1 source %d ty %d+%d sz %d\n",car(s0),ty,cadr(s0),r); #endif } e2 = e3; continue; } caddddr(e2)=list3(s0,0,sz); #if DEBUG_PARALLEL_ASSIGN if (lsrc)printf("## source %d ty %d+%d sz %d\n",car(s0),ty,cadr(s0),sz); #endif } else { /* check used sources in rather complex source */ /* more complex sources are compiled before */ caddddr(e2)=contains_p1(0,s0,check_source); } } /* compute jump address */ e2 = cadr(e1); if (car(e2) == FNAME) { code0=ncaddr(e2); // if (!is_code(code0)) { error(TYERR); return; } } else { /* indirect */ g_expr(e2); emit_push(); } if (chk) return; /* 並列代入を実行 */ parallel_assign(&target,&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) { if (car(envreg)==REGISTER) free_register(cadr(envreg)); else free_lvar(cadr(envreg)); } code_fix_frame_pointer(env); 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; // e3 op e2 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; } if ((op==CMP||op==UCMP) && car(e3)==REGISTER && car(e2)==REGISTER) { if (tosop_operand_safe_p(op)==1) { // both operands are safe tosop(op,cadr(e2),cadr(e3)); return; } } if (car(e3)==REGISTER) { if (tosop_operand_safe_p(op)) { // operand are safe g_expr(e2); tosop(op,USE_CREG,cadr(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); switch (op) { case DCMPGE: case DCMPEQ: case DCMPNEQ: case DCMP: case FCMPGE: case FCMPEQ: case FCMPNEQ: case FCMP: if ((car(e3)==DREGISTER||car(e3)==FREGISTER) && ((car(e2)==DREGISTER||car(e2)==FREGISTER))) { if (tosop_operand_safe_p(op)==1) { dtosop(op,cadr(e2),cadr(e3)); return; } } } if (car(e3)==DREGISTER||car(e3)==FREGISTER) { if (tosop_operand_safe_p(op)) { g_expr(e2); dtosop(op,USE_CREG,cadr(e3)); return; } } 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; } if (car(e3)==LREGISTER && tosop_operand_safe_p(op)) { g_expr(e2); ltosop(op,USE_CREG,cadr(e3)); return; } g_expr(e3); emit_lpush(); g_expr(e2); ltosop(op,USE_CREG,(e2=emit_lpop())); emit_lpop_free(e2); return; } #endif static int llvalue_opt(int e0); static int lvalue_opt(int e0) { int e,e1; if (inmode) return e0; if (car(e0)==LADD) return llvalue_opt(e0); if (car(e0)!=ADD) return e0; if (car(e=caddr(e0))!=CONST) return e0; e1 = cadr(e0); if(car(e1)==ADDRESS) { switch (car(cadr(e1))) { case GVAR: return(list2(ADDRESS, list3n(GVAR,cadr(cadr(e1))+cadr(e),ncaddr(cadr(e1))))); case LVAR: return(list2(ADDRESS, list3n(LVAR,cadr(cadr(e1))+cadr(e), ncaddr(cadr(e1))))); // case INDIRECT: case PERIOD: case ARROW: if (lp64) return list3(LADD,e1,llist2(LCONST,cadr(e))); return list3(ADD,e1,e); default: return e0; } } else if(car(e1)==GVAR) { return(list3n(GVAR,cadr(e1)+cadr(e),ncaddr(e1))); } else if(car(e1)==LVAR) { return(list3n(LVAR,cadr(e1)+cadr(e),ncaddr(e1))); } return e0; } static int llvalue_opt(int e0) { int e,e1; if (inmode) return e0; if (car(e0)!=LADD) return e0; if (car(e=caddr(e0))!=LCONST) return e0; // should we check LCONST is 32bit e1 = cadr(e0); if(car(e1)==ADDRESS) { switch (car(cadr(e1))) { case GVAR: return(list2(ADDRESS, list3n(GVAR,cadr(cadr(e1))+lcadr(e),ncaddr(cadr(e1))))); case LVAR: return(list2(ADDRESS, list3n(LVAR,cadr(cadr(e1))+lcadr(e), ncaddr(cadr(e1))))); case INDIRECT: case PERIOD: case ARROW: return list3(LADD,e1,e); default: return e0; } } else if(car(e1)==GVAR) { return(list3n(GVAR,cadr(e1)+lcadr(e),ncaddr(e1))); } else if(car(e1)==LVAR) { return(list3n(LVAR,cadr(e1)+lcadr(e),ncaddr(e1))); } return e0; } 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; } } e2 = lvalue_opt(e2); if (car(e4)==DECL_DATA && (car(e2)==GVAR || car(e2)==LVAR)) { // we can do optimize any other type of destination ... // but gen_decl_data0 requires nptr (of course wrong decision) int t = caddr(e4); int sinit_vars = init_vars; init_vars = 0; gen_decl_data0(e2,t,e4,0); emit_init_vars(); init_vars = sinit_vars; 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 = 0; if (!(sz==1 || sz==2 || sz==3 || (lp64 && sz==8))) { 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||e5==LREGISTER) { 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; case LREGISTER: code_lassign_lregister(cadr(e2),reg); return; } g_expr(e2); code_assign(USE_CREG,byte,reg); return; } /* e2 is register now */ if (car(e2)!=REGISTER && car(e2)!=LREGISTER) 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: case URGVAR: 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: case URLVAR: 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 if (car(cadr(e4))==STRINGS) { code_strings(cadr(e4),reg); } else code_gvar(cadr(e4),reg); return; case FNAME: code_fname(ncaddr(e4),reg); return; case STRING: code_string(e4,reg); return; case STRINGS: code_strings(cadr(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: lp64? size_of_int : 0; /* e2=e4 */ e2 = cadr(e1); e2 = lvalue_opt(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) { if (e5==REGISTER||e5==LREGISTER) { assign_opt(e5,e2,e4,byte); return; } else if (car(e2)==REGISTER||car(e2)==LREGISTER) { switch(e5) { case ADDRESS: if (!((car(cadr(e4))==STRING)|| (car(cadr(e4))==STRINGS) || car(cadr(e4))==GVAR)) break; case CRGVAR : case CRLVAR : case RGVAR : case RLVAR : case URGVAR : case URLVAR : case CURGVAR : case CURLVAR : case SURGVAR : case SURLVAR : case GVAR : case LVAR : case CONST : case FNAME : case STRING : case STRINGS: 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; 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_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=0,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||e5==REGISTER) { 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: case REGISTER: if (reg!=cadr(e2)) code_lassign_lregister(cadr(e2),reg); return; default: error(-1); } } /* e2 is register now */ if (!(car(e2)==LREGISTER||car(e2)==REGISTER)) error(-1); reg = cadr(e2); switch(e5) { case LRGVAR: case LURGVAR: code_lrgvar(e4,reg); return; case LRLVAR: case LURLVAR: 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||e5==REGISTER) &&(car(e2)==GVAR||car(e2)==LVAR||car(e2)==LREGISTER || car(e2)==REGISTER)) || ((car(e2)==LREGISTER||car(e2)==REGISTER)&& (e5==LRGVAR||e5==LRLVAR||e5==LURLVAR||e5==LURGVAR||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: case REGISTER: 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 */ #if FLOAT_CODE static int double_value(int e2) { 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_value(type)) { case DOUBLE: break; case FLOAT: e2 = list3(CONV,e2,F2D); break; case UNSIGNED: e2 = list3(CONV,e2,U2D); break; case LONGLONG: e2 = list3(CONV,e2,LL2D); break; case ULONGLONG: e2 = list3(CONV,e2,ULL2D); break; default: if(integral(type)) e2 = list3(CONV,e2,I2D); else { error(TYERR); e2 = dlist2(DCONST,1.0); } } } type = set_type_with_attr(DOUBLE,type); return e2; } static int float_value(int e2) { if (0) ; #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_value(type)) { case LONGLONG: e2 = list3(CONV,e2,LL2F); break; case ULONGLONG: e2 = list3(CONV,e2,ULL2F); break; case FLOAT: break; case DOUBLE: e2 = list3(CONV,e2,D2F); break; case UNSIGNED: e2 = list3(CONV,e2,U2F); break; default: if(integral(type)) e2 = list3(CONV,e2,I2F); else { error(TYERR); e2 = dlist2(DCONST,1.0); } } } type = set_type_with_attr(FLOAT,type); return e2; } #endif #if LONGLONG_CODE static int longlong_value(int e2) { if (0) ; 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_value(type)) { case FLOAT: e2 = list3(CONV,e2,F2LL); break; case DOUBLE: e2 = list3(CONV,e2,D2LL); break; case UNSIGNED: e2 = list3(CONV,e2,U2LL); break; case LONGLONG: break; case ULONGLONG: break; default: if(integral(type)) e2 = list3(CONV,e2,I2LL); else if(lp64) ; // else { error(TYERR); e2 = llist2(LCONST,0LL); } } } type = set_type_with_attr(LONGLONG,type); return e2; } static int ulonglong_value(int e2) { if (0); 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) { if (dcadr(e2)<0) e2 = llist2(LCONST,0); e2 = llist2(LCONST,(unsigned long long)dcadr(e2)); } #endif else { switch(type_value(type)) { case FLOAT: e2 = list3(CONV,e2,F2ULL); break; case DOUBLE: e2 = list3(CONV,e2,D2ULL); break; case UNSIGNED: e2 = list3(CONV,e2,U2ULL); break; case LONGLONG: break; case ULONGLONG: break; default: if(integral(type)) e2 = list3(CONV,e2,I2ULL); else if(lp64) ; // else { error(TYERR); e2 = llist2(LCONST,0LL); } } } type = set_type_with_attr(ULONGLONG,type); return e2; } #endif static int int_value(int e2) { int t = type_value(type); if (0); else if(t>0&&car(t)==ARRAY) return e2; else if(scalar(t)) { type = set_type_with_attr(INT,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(t) { case FLOAT: e2 = list3(CONV,e2,F2I); break; case DOUBLE: e2 = list3(CONV,e2,D2I); break; case LONGLONG: e2 = list3(CONV,e2,LL2I); break; case ULONGLONG: e2 = list3(CONV,e2,ULL2I); break; default: error(TYERR); e2 = list2(CONST,1); } } type = set_type_with_attr(INT,type); return e2; } static int char_value(int e2) { int t = type_value(type); if (t!=CHAR&&t!=INT) { e2 = list3(CONV,int_value(e2),I2C); type = set_type_with_attr(INT,type); } return e2; } static int short_value(int e2) { int t = type_value(type); if (t!=SHORT&&t!=INT) { e2 = list3(CONV,int_value(e2),I2S); type = set_type_with_attr(INT,type); } return e2; } static int unsigned_value(int e2) { int t = type_value(type); if(t>0&&car(t)==ARRAY) return e2; if (0); else if(scalar(t)) { type = set_type_with_attr(UNSIGNED,type); return e2; } #if FLOAT_CODE else if (car(e2)==DCONST||car(e2)==FCONST) { if (dcadr(e2)<0) return e2 = list2(CONST,0); e2 = list2(CONST,(int)dcadr(e2)); } #endif #if LONGLONG_CODE else if (car(e2)==LCONST) { if (lcadr(e2)<0) e2 = list2(CONST,0); e2 = list2(CONST,(unsigned)lcadr(e2)); } #endif else { switch(t) { case LONGLONG: e2 = list3(CONV,e2,LL2U); break; case ULONGLONG: e2 = list3(CONV,e2,ULL2U); break; case FLOAT: e2 = list3(CONV,e2,F2U); break; case DOUBLE: e2 = list3(CONV,e2,D2U); break; default: error(TYERR); } } type = set_type_with_attr(UNSIGNED,type); return e2; } static int uchar_value(int e2) { int t = type_value(type); if (t!=UCHAR&&t!=UNSIGNED) { e2 = list3(CONV,unsigned_value(e2),U2UC); type = set_type_with_attr(UNSIGNED,type); } return e2; } static int ushort_value(int e2) { int t = type_value(type); if (t!=USHORT&&t!=UNSIGNED) { e2 = list3(CONV,unsigned_value(e2),U2US); type = set_type_with_attr(UNSIGNED,type); } 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) { /* we should check const / assign violation here */ t = type_value(t); if (t>0) { switch(car(type_value(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; // dispose attr 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))); } default: if(scalar(t)) { if (car(t)!=POINTER) { e2=(type_value(t)==UNSIGNED)? unsigned_value(e2):int_value(e2); } if (lp64) return(list3(LASS,e1,e2)); return(list3(ASS,e1,e2)); } error(TYERR); return list3(ASS,e1,e2); } } 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)); case INT:case UNSIGNED: case ENUM: e2=(t==UNSIGNED)?unsigned_value(e2):int_value(e2); return(list3(ASS,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 } error(TYERR); return list3(ASS,e1,e2); } extern int cond(int t,int e1,int e2,int e3) { int t0 = type_value(t); int t1 = type_value(type); if(car(e1)==CONST) { if(cadr(e1)) {type=set_type_with_attr(t,type);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(t1==DOUBLE||t0==DOUBLE) { e3=double_value(e3); type = t; if (e2) e2=double_value(e2); return(list4(DCOND,e1,e2,e3)); } if(t1==FLOAT||t0==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=set_type_with_attr(t,type);return e2?e2:e1;} else return e3; } if(t1==LONGLONG||t0==LONGLONG) { e3=longlong_value(e3); type = t; if (e2) e2=longlong_value(e2); return(list4(LCOND,e1,e2,e3)); } if(t1==ULONGLONG||t0==ULONGLONG) { e3=ulonglong_value(e3); type = t; if (e2) e2=ulonglong_value(e2); return(list4(LUCOND,e1,e2,e3)); } #endif if(t1==INT||t0==INT) { e3=int_value(e3); type = t; if (e2) e2=int_value(e2); return(list4(COND,e1,e2,e3)); } e3=unsigned_value(e3); type = t; if (e2) e2=unsigned_value(e2); /* if (t!=type) error(TYERR); */ return(list4(UCOND,e1,e2,e3)); } /* assop parse tree generation */ extern int assop(int e1,int e2,int op,int t,int no_float) { int ass=0,u = 0; int t0 = type_value(type); if(!(integral(t0)||t0==FLOAT||t0==DOUBLE|| t0==LONGLONG||t0==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: e2=correct_type(e2,INT); ass = CASSOP; break; case SHORT: e2=correct_type(e2,INT); ass = SASSOP; break; case INT: e2=correct_type(e2,INT); ass = ASSOP; break; case UCHAR: e2=correct_type(e2,UNSIGNED); ass = CUASSOP; u=1; break; case USHORT: e2=correct_type(e2,UNSIGNED); ass = SUASSOP; u=1; break; case UNSIGNED: e2=correct_type(e2,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 = set_type_with_attr(cadr(t),type); /* 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 = set_type_with_attr(t,type); if(integral(t)) return(list4(ass,e1,e2,op)); /* pointer += ... */ if((op!=ADD&&op!=SUB)||car(t)!=POINTER) error(TYERR); if (lp64) { e2=binop(MUL,e2,llist2(LCONST,size(cadr(t))),INT,ULONGLONG); type = set_type_with_attr(t,type); return list4(LASSOP,e1,e2,op+LOP); } e2=binop(MUL,e2,list2(CONST,size(cadr(t))),INT,UNSIGNED); type = set_type_with_attr(t,type); return list4(ASSOP,e1,e2,op); } /* assop code generation */ static void iassop(int e1) { int e2,e3,byte,op,sign,size; int 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 = lp64?size_of_int:0; sign = 1; size = size_of_int; } e2 = cadr(e1); 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|| (car(e2)==INDIRECT&&car(cadr(e2))==REGISTER)) { g_expr0(assign_expr0(e2,list3(op,rvalue_t(e2,t),e3),t,t)); return; } #if 0 /* new = &e2 */ /* *new = *new op e3 */ // e2 が複雑な式でないと却ってだめなこともある // register が取れれば常に有効か? // たぶん、i386 の時には有効だったんだろうなぁ。 int n = list3n(LVAR,new_lvar(size_of_int),0); // get register var? g_expr_u(assign_expr0(n,list2(ADDRESS,e2),INT,INT)); g_expr0(assign_expr0(rvalue_t(n,INT), list3(op,rvalue_t(list2(INDIRECT,rvalue_t(n,INT)),t),e3),t,t)); free_lvar(cadr(n)); return; #endif } 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); if (car(e2)==DREGISTER||car(e2)==FREGISTER) { g_expr(e3); emit_dpush(d); code_register_dassop(cadr(e2),op,d); if (use) code_dregister(cadr(e2),USE_CREG,d); return; } if (car(e3)==DCONST||car(e3)==FCONST) { /* e2 = e2 op e3; */ int t = d?DOUBLE:FLOAT; // oprtc expected if (car(e2)==LVAR||car(e2)==GVAR|| (car(e2)==INDIRECT&&car(cadr(e2))==REGISTER)) { g_expr0(assign_expr0(e2,list3(op,rvalue_t(e2,t),e3),t,t)); return; } } g_expr(e3); 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 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|| (car(e2)==INDIRECT&&car(cadr(e2))==REGISTER)) { g_expr0(assign_expr0(e2,list3(op,rvalue_t(e2,t),e3),t,t)); return; } if (!code_lassop_p) { /* new = &e2 */ /* *new = *new op e3 */ int n = list3n(LVAR,new_lvar(size_of_int),0); g_expr_u(assign_expr0(n,list2(ADDRESS,e2),INT,INT)); g_expr0(assign_expr0(rvalue_t(n,INT), list3(op,rvalue_t(list2(INDIRECT,rvalue_t(n,INT)),t),e3),t,t)); free_lvar(cadr(n)); return; } } g_expr(e3); if (car(e2)==LREGISTER||car(e2)==REGISTER) { 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) { if (!chk) { if (car(csreg)==CONST) { switch(cond) { case 1: case 0: if (cond ^ (cadr(csreg)==e)) gen_jmp(label); break; case LT: if ((cadr(csreg)>e)) gen_jmp(label); break; } } else if (car(csreg)==REGISTER) { code_cmpdimm(e, cadr(csreg),label,cond); } else error(-1); } } extern int csvalue() { return code_csvalue(); } extern void gen_ret() { if (chk) return; code_ret(); } extern void gen_label_call(int l) { if (chk) return; code_label_call(l); } extern int fwdlabel(void) { return labelno++; } extern void fwddef(int l) { if (l==0) return; checkjmp(l); control=1; if (!chk) code_label(l); } extern int backdef(void) { checkjmp(0); control=1; if (!chk) code_label(labelno); return labelno++; } // define case label with default label for switch statement extern void df_label(int cslabel, int dlabel) { int fl; checkjmp(0); fl = 0; if (control) { gen_jmp(fl=fwdlabel()); } fwddef(cslabel); if (dlabel) gen_jmp(dlabel); if (fl) { fwddef(fl); } } extern void ret(void) { if (!is_inline(fnptr)) { if (!chk) code_set_return_register(1); } gen_jmp(retlabel); } extern void opening(char *filename) { emit_init(); if (!chk) code_opening(filename); } extern void closing() { int e; NMTBL *n; inmode = 0; for(e=inline_funcs;e;e=cadr(e)) { n = ncaddr(e); if (is_code(n)||is_function(n)) { if (n->sc!=STATIC || has_attr(n,FNAME)) { // global or used as pointer // generate possibly called inline function pfdecl(n); } } } if (!chk) code_closing(); conv->close_(); } 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 (TERNARY_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 if (IS_STATEMENT(car(e))) { return 1; // may contain anything } else { // if (lsrc)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) { int e1 = car(e); if (!e1) return 0; if (p(e1)) return 1; if (LIST_ARGS(e1)){ /* list arguments */ return contains_in_list_p(caddr(e),p); } else if (UNARY_ARGS(e1)) { /* unary operators */ e = cadr(e); continue; } else if (BINARY_ARGS(e1)) { /* biary operators */ if (contains_p(cadr(e),p)) return 1; e = caddr(e); continue; } else if (TERNARY_ARGS(e1)) { /* 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(e1)) { /* nullary operators */ return 0; } else if (IS_STATEMENT(e1)) { return 1; // may contain anything } else { // if (lsrc)fprintf(stderr,"Unknown Tree ID %d\n",car(e)); error(-1); return 0; } } return 0; } /* gahter accumurated list in all parse tree */ static int contains_in_list_p1(int arg,int e,int (*p)(int,int)) { while(e) { arg=contains_p1(arg,car(e),p); e = cadr(e); } return arg; } extern int contains_p1(int arg,int e,int (*p)(int,int)) { while(e) { int e1 = car(e); if (!e1) return arg; if (LIST_ARGS(e1)){ /* list arguments */ return contains_in_list_p1(arg,caddr(e),p); } else if (UNARY_ARGS(e1)) { /* unary operators */ e = cadr(e); continue; } else if (BINARY_ARGS(e1)) { /* biary operators */ arg=contains_p1(arg,cadr(e),p); e = caddr(e); continue; } else if (TERNARY_ARGS(e1)) { /* tarary operators */ arg=contains_p1(arg,cadr(e), p); arg=contains_p1(arg,caddr(e),p); e = cadddr(e); continue; } else if (NULLARY_ARGS(e1)) { /* nullary operators */ arg=p(arg,e); return arg; } else if (IS_STATEMENT(e1)) { return arg; } else { // if (lsrc)fprintf(stderr,"Unknown Tree ID %d\n",car(e)); // error(-1); return arg; } } return arg; } /* gahter accumurated list in all parse tree for all operator */ static int contains_in_list_p2(int arg,int e,int (*p)(int,int)) { while(e) { arg=contains_p2(arg,car(e),p); e = cadr(e); } return arg; } extern int contains_p2(int arg,int e,int (*p)(int,int)) { while(e) { if (!car(e)) return arg; if (LIST_ARGS(car(e))){ /* list arguments */ arg=p(arg,e); return contains_in_list_p2(arg,caddr(e),p); } else if (UNARY_ARGS(car(e))) { /* unary operators */ arg=p(arg,e); e = cadr(e); continue; } else if (BINARY_ARGS(car(e))) { /* biary operators */ arg=p(arg,e); arg=contains_p2(arg,cadr(e),p); e = caddr(e); continue; } else if (TERNARY_ARGS(car(e))) { /* tarary operators */ arg=p(arg,e); arg=contains_p2(arg,cadr(e), p); arg=contains_p2(arg,caddr(e),p); e = cadddr(e); continue; } else if (NULLARY_ARGS(car(e))) { /* nullary operators */ arg=p(arg,e); return arg; } else if (IS_STATEMENT(car(e))) { return arg; } else { // if (lsrc)fprintf(stderr,"Unknown Tree ID %d\n",car(e)); // error(-1); return arg; } } return arg; } // // globalize parse tree // static int copy_list(int e) { int e1; if (!e) return 0; e1 = copy_expr(car(e)); return glist2(e1,copy_list(cadr(e))); return 0; } extern int copy_expr(int e) { int smode = mode; if (!e || !car(e)) return 0; if (car(e)<0) { mode = GDECL; switch (car(e)){ case CONST: e=list2(car(e),cadr(e)); break; case FCONST: case DCONST: e=dlist2(car(e),dcadr(e)); break; case LCONST: e=llist2(car(e),lcadr(e)); break; case STRING: e=list3n(car(e),cadr(e),ncaddr(e)); break; case STRINGS: e=list3s(car(e),cadr(e),scaddr(e)); break; case STRUCT: // for udpcl e=glist3(car(e),copy_expr(cadr(e)),copy_expr(caddr(e))); break; case ARRAY: e= glist5(car(e),copy_expr(cadr(e)), copy_expr(caddr(e)),cadddr(e),caddddr(e)); break; } mode = smode; return e; } switch (OP(car(e))){ // special cases case ARROW: case PERIOD: return glist4(car(e),copy_expr(cadr(e)),caddr(e),cadddr(e)); case LVAR: case RLVAR:case URLVAR: case GVAR: case RGVAR:case URGVAR: return (e>gfree)?glist3(car(e),cadr(e),caddr(e)):e; case INDIRECT: // case RINDIRECT: return glist2(car(e),copy_expr(cadr(e))); } if (LIST_ARGS(car(e))){ /* list arguments */ return copy_list(caddr(e)); } else if (UNARY_ARGS(car(e))) { /* unary operators */ e = glist2(car(e),copy_expr(cadr(e))); return e; } else if (BINARY_ARGS(car(e))) { /* biary operators */ e = glist3(car(e),copy_expr(cadr(e)),copy_expr(caddr(e))); return e; } else if (TERNARY_ARGS(car(e))||car(e)==STRUCT) { /* ternary operators */ e = glist4(car(e),copy_expr(cadr(e)), copy_expr(caddr(e)), copy_expr(cadddr(e))); return e; } else if (NULLARY_ARGS(car(e))) { /* nullary operators */ if (e>gfree) { // local int smode = mode; switch(car(e)%SOP) { case GVAR: case RGVAR: case URGVAR: case LVAR: case RLVAR: case URLVAR: case REGISTER: case FREGISTER: case DREGISTER: case LREGISTER: case FNAME: case IVAR: case RIVAR: e = glist3n(car(e),cadr(e),ncaddr(e)); break; case STRING: e = glist3n(car(e),cadr(e),ncaddr(e)); break; case STRINGS: e = glist3s(car(e),cadr(e),scaddr(e)); break; case CONST: switch(car(e)) { case CONST: e = glist2(car(e),cadr(e)); break; case DCONST: case FCONST: mode=GDECL; e = dlist2(car(e),dcadr(e)); mode = smode; break; case LCONST: mode=GDECL; e = llist2(car(e),lcadr(e)); mode = smode; break; } break; case LCALL: case LABEL: e = glist2(car(e),cadr(e)); break; case DECL: case COMP: // is this correct? e = glist2(car(e),cadr(e)); break; } } return e; } else if (IS_STATEMENT(car(e))) { // already in global heap return e; // may contain anything } else { // if (lsrc)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; int ty; e = reverse0(e); for(i=out;i;i=cadr(i)) { p = (ncaddr(car(i)))->nm; e1 = car(e); e = cadr(e); repl = code_asm_operand(p,e1,ASM_OUTPUT,repl,0,0); if (!chk && repl) { switch(car(car(repl))) { case REGISTER: ty = INT; break; case LREGISTER: ty = LONGLONG; break; case FREGISTER: ty = FLOAT; break; case DREGISTER: ty = DOUBLE; break; default: continue; } assign = list2(assign_expr0(e1,car(repl),ty,ty),assign); } } repl0 = repl; n = length(repl0); for(i=in;i;i=cadr(i)) { p = (ncaddr(car(i)))->nm; e1 = car(e); e = cadr(e); repl = code_asm_operand(p,e1,ASM_INPUT,repl,n,repl0); if (!chk && repl) { switch(car(car(repl))) { case REGISTER: ty = INT; break; case LREGISTER: ty = LONGLONG; break; case FREGISTER: ty = FLOAT; break; case DREGISTER: ty = DOUBLE; break; default: continue; } g_expr_u(assign_expr0(car(repl),e1,ty,ty)); } } repl = reverse0(repl); p = (ncaddr(asm0))->nm; code_asm(p,repl); for(i=assign;i;i=cadr(i)) { g_expr_u(car(i)); } code_free_asm_operand(repl); // no check for opt } #endif static void set_ctmode(NMTBL *n,int ctmode) { if (ctmode & KONST_BIT) set_attr(n,KONST,0); if (ctmode & VOLATILE_BIT) set_attr(n,VOLATILE,0); if (ctmode & RESTRICT_BIT) set_attr(n,RESTRICT,0); } static int struct_align_offset(int t,int offset) { int strtype=0; if (t>0 && (car(t)==STRUCT||car(t)==UNION)) strtype=1; int sz = size(t); if (lp64 && (sz%size_of_longlong==0)) { offset = align(offset,size_of_longlong); } else if (sz%size_of_int==0||strtype) { offset = align(offset,struct_align); } return offset; } /* define symbol name contents depending on stmode, mode define displacement */ extern NMTBL * def(NMTBL *n,int ctmode) { int sz,nsc,ndsp,align0; int sbit_f = bit_field_disp; int type0 = type_value(type); int attr = attribute; attribute = 0; 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(type0>0&&(car(type0)==FUNCTION || car(type0)==CODE)) { if (mode==GDECL) { fcheck(n); NMTBL *fsave = fnptr; int save = struct_return; fnptr = n; fdecl_struct(n->ty); /* insert extra argument for struct passing */ struct_return = save; fnptr = fsave; set_ctmode(n,ctmode); set_attributes(n,attr); return n; /* function and code segment are defined using fdecl/code_decl */ /* in decl() */ } } // compute size if (mode==GSDECL||mode==LSDECL) { // struct /* Struct fields name lists are in the struct type or tag. */ /* Only name in the table is used. Do not set n->ty! */ /* Struct field may volatile... where do I put? list2(VOLATILE,type)? */ /* disp is pushded and reset in sdecl */ if (type0>0 && car(type0)==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)); #if BIT_FIELD_CODE cadr(caddr(type0)) = code_bit_field_disp( type,&disp,&bit_field_disp,&sz); /* bit_field_disp is next bit posision */ #else error(-1); #endif } else { sz = size(type0); #if STRUCT_ALIGN disp = struct_align_offset(type0,disp); #endif if ((align0=attr_value_in_list(attr,ALIGNED))) { int hoge = disp; if (car(align0)!=CONST) error(-1); // align have to be 2^n align0 = caddr(align0); disp = align(disp,align0); if (lsrc && hoge!=disp) printf("# field %s %d->%d (align %d)\n",n->nm,hoge,disp,align0); } } if (n!=&null_nptr) fields = list4n(type,fields,disp,n); // don't set attribute to n } else if (mode==GUDECL||mode==LUDECL) { // union /* disp is pushded and reset in sdecl */ if (type0>0 && car(type0)==BIT_FIELD) { cadr(caddr(type0)) = 0; sz = size(cadr(type0)); } else { sz = size(type0); } fields = list4n(type,fields,0,n); } 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 { if (mode==GDECL) { compatible(n->ty,type); } else error(RDERR); // on different type } } sz = size(n->ty = type); } switch(mode) { case GDECL: // global variable gen_gdecl(n->nm,gpc); case STADECL: // static variable 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||stmode==LDECL) nsc = STATIC; n->sc = nsc; if (stmode==LDECL) { // this means local static variable 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; set_ctmode(n,ctmode); set_attributes(n,attr); return n; case GSDECL: case LSDECL: // struct disp += sz; return n; case GUDECL: case LUDECL: // union /* In union case, disp contains max size of the member */ if (disp < sz) disp = sz; return n; case GTDECL: // typedef nsc = TYPE; gtypedefed=glist3n(GTDECL,gtypedefed,gnptr); set_attributes(n,attr); break; case LTDECL: // local typedef nsc = TYPE; set_attributes(n,attr); break; case LLDECL: // label def (gcc extension) nsc = FLABEL; if (!inmode) ndsp = fwdlabel(); else ndsp = --disp; // inmode の時は pvartable のoffset を確保する。st_label で // nptr が 0 ならば backdef、st_label よりも先に使われたら // fwdlabel すれば良い。 // scope は parse 時に解決される。 break; case ADECL: // funcion arguments if(type0>0) { if (!integral(type0) && (car(type0)==FUNCTION||car(type0)==CODE)) { type=list2(POINTER,type); n->ty = type; sz = size_of_pointer; type0=type; } else if (car(type0)==ARRAY) { type=list2(POINTER,cadr(type)); n->ty = type; sz = size_of_pointer; type0=type; } } fnptr->dsp=list4n(type,fnptr->dsp,0,n); n->sc = LVAR; if(inmode==INLINE) { n->dsp = args++; n->sc = IVAR; } else { // this is useless, because we cannot know this function is code or function now // we have to fix this later in case of code segment ( in code_arg_register ) args = code_arg_alignment(args,n,type0,sz, is_code(fnptr)); } caddr(fnptr->dsp)=sz; if(type0==VOID) { } else { n->ty = type; } // don't set attribute set_ctmode(n,ctmode); return n; case STAT: /* return (struct hoge)f() case? */ case LDECL: // local variable set_attributes(n,attr); if (stmode==REGISTER && !(inmode==INLINE)) { if(scalar(type0)) { ndsp = get_register_var(n); #if FLOAT_CODE } else if (type0==FLOAT) { ndsp = get_dregister_var(n,0); } else if (type0==DOUBLE) { ndsp = get_dregister_var(n,1); #endif #if LONGLONG_CODE } else if (type0==LONGLONG||type0==ULONGLONG) { ndsp = get_lregister_var(n); #endif } else error(DCERR); nsc = car(ndsp); ndsp = cadr(ndsp); } else if (inmode==INLINE) { nsc = IVAR; ndsp = --disp; } else { code_lvar_alignment(disp,n,type0,sz); set_ctmode(n,ctmode); return n; } n->sc = nsc; n->dsp = ndsp; set_ctmode(n,ctmode); case SFDINIT: return n; default: error(DCERR); } // should be an error? n->sc = nsc; n->dsp = ndsp; set_ctmode(n,ctmode); if (stmode==EXTRN) n->sc = EXTRN; return n; } // standard 32bit alignment // for function extern int code_arg_alignment0(int offset,NMTBL *n, int type0,int sz, int is_code) { if(type0==CHAR||type0==UCHAR) { if (n->dsp==0) { n->dsp = is_code? -offset-size_of_int:offset; if (endian) n->dsp += size_of_int-1; } offset += size_of_int; } else if(type0==SHORT||type0==USHORT) { if (n->dsp==0) { n->dsp = is_code? -offset-size_of_int: offset; if (endian) n->dsp += size_of_int-size_of_short; } offset += size_of_int; } else if(type0>0&&(car(type0)==UNION||car(type0)==STRUCT)) { /* alignment in struct in argument */ /* should be GCD of member alignment */ /* __attribute(alignment(16)) is ignored in argments */ int asz = align(sz,size_of_int); n->dsp = is_code? -offset-asz:offset; offset += asz; } else { /* if (n->dsp==0) (argument list in ADECL is useless, type list can be found in type ) */ n->dsp = is_code? -offset-size_of_int: offset; offset += sz; } return offset; } // standard 32bit alignment for local variable extern int code_lvar_alignment0(int disp0,NMTBL *n,int type0,int sz) { int align; /* local variable alignment is done by new_lvar */ if ((align=attr_value(n,ALIGNED))) { if (car(align)!=CONST) error(-1); n->sc = LVAR; n->dsp = new_lvar_align(sz,caddr(align)); } else { n->sc = LVAR; n->dsp = new_lvar(sz); } return disp; } // for mc-parse.c extern int arg_alignment(int args,NMTBL *n, int type0,int sz, int is_code) { return code_arg_alignment(args,n, type0,sz, is_code); } extern char * nm(NMTBL *n) { int e; NMTBL *str; if (n->attr) { if ((e=attr_value(n,ASM))) { if (car(e)==STRINGS) { // first element only return scaddr(e); // may non terminated } if (car(e)!=STRING) error(-1); str = ncaddr(e); return str->nm; } } return n->nm; } extern void emit_init_vars(void) { int e; if (!init_vars) return; e = reverse0(init_vars); init_vars = 0; if (inmode) { while(e) { parse = list3(ST_COMP,parse,car(e)); e = cadr(e); } return; } while(e) { g_expr_u(car(e)); e = cadr(e); } } static int str_init_eq() { // error(-1); // duplicate struct field value return 2; // allow override keep unique } // // generate constant on global memory // static int emit_name(int e,NMTBL *n, int sz) { switch(car(e)) { case CONST: if (lp64 && sz>4) emit_longlong(e); else emit_int(cadr(e)); return 1; case LCONST: if (lp64 && sz>4) emit_longlong(e); else emit_int(lcadr(e)); return 1; case ADDRESS: if (car(cadr(e))==GVAR) emit_address((ncaddr(cadr(e)))->nm,cadr(cadr(e))); else error(INERR); return 1; case FNAME: emit_address((ncaddr(e))->nm,0); return 1; case GVAR: emit_address((ncaddr(e))->nm,0); return 1; case STRING: emit_string((ncaddr(e))->nm,n->ty); return 1; case STRINGS: emit_strings(ncaddr(e)); return 1; } // if (lsrc)fprintf(stderr,"## type= %d\n",t); return 0; } static void emit_data(int e, int t, NMTBL *n) { t = type_value(t); if(mode!=GDECL && mode!=STADECL) { error(-1); return; } if (chk) return; if (n->dsp != -1) { n->dsp = -1; /* initialized flag */ emit_global(n,t,e); } switch(t) { case EMPTY: if(car(e)!=CONST) error(-1); emit_space(cadr(e)); return; case CHAR: case UCHAR: if (car(e)!=CONST) error(INERR); emit_char(cadr(e)); data_alignment++; return; case SHORT: case USHORT: if (car(e)!=CONST) error(INERR); emit_short(cadr(e)); data_alignment++; return; case DOUBLE: if (car(e)!=DCONST&&car(e)!=FCONST) error(INERR); emit_double(e); return; case FLOAT: if (car(e)!=DCONST&&car(e)!=FCONST) error(INERR); emit_float(e); data_alignment++; return; case LONGLONG: case ULONGLONG: if (car(e)==CONST) { emit_longlong(llist2(LCONST,cadr(e))); return; } else if (car(e)==LCONST) { emit_longlong(e); return; } if (lp64 && emit_name(e,n,size(t))) return; break; default: if (t<0) error(-1); if (car(t)==BIT_FIELD) { /* not yet supported */ error(-1); return; } if (car(t)!=POINTER&&car(t)!=ARRAY) error(-1); case INT: case UNSIGNED: /* including address case */ case ENUM: if (emit_name(e,n,size(t))) return; } error(INERR); } extern int gen_delayed_decl_data(int v,int offset) { int e; int t,sz,offset1=0; int init = decl_str_init; NMTBL *n = ncaddr(v); decl_str_init = 0; sz = size(n->ty); /* decl_str_init output delayed decl data list4(offset,next,expression,list2(type0,type1)); */ while (init) { offset1= car(init); e=caddr(init); t=car(cadddr(init)); if (offset1!=offset) { // make space assign_data(list2(CONST,offset1-offset),EMPTY,v,offset); } type=cadr(cadddr(init)); offset = gen_decl_data0(v,t,e,offset1); init = cadr(init); } if ((sz=(sz-offset))>0) assign_data(list2(CONST,sz),EMPTY,v,offset); decl_str_init = 0; local_nptr = 0; return offset; } static int gen_decl_data_array(int v,int init,int target_type,int offset) { int type0 = cadr(target_type); /* array item type */ int e; for(; init; init = cadr(init)) { // unordered data with tag or array offset if (car(init)!=DECL_DATA_ARRAY) { error(-1); } e = caddr(init); if (!e) continue; // {...,} case e = pexpr(e); offset = gen_decl_data0(v,type0,e,offset); } return offset; } static int gen_decl_data_field(int v,int init,int target_type,int offset) { int type0 = target_type; /* list of fields */ int e,t,type1,foffset; NMTBL *n; for(; init; init = cadr(init)) { // unordered data with tag or array offset if (car(init)!=DECL_DATA_FIELD) { error(-1); } n = ncadddr(init); type1 = search_struct_type(type0,n->nm,&foffset); e = caddr(init); if (car(e)!=DECL_DATA) error(-1); t = caddr(e); decl_str_init=insert_ascend(decl_str_init, glist4(offset+foffset,0,e,glist2(type1,t)),str_init_eq); } return offset; } static int gen_decl_data_list(int v,int init,int target_type,int offset) { int type0 = caddr(target_type); /* list of fields */ int e; for(; init; init = cadr(init)) { if (car(init)==DECL_DATA) { // casted initilizer e = cadr(init); // value if (!e) continue; // {...,} case offset = gen_decl_data0(v,caddr(init),e,offset); continue; } // ordered data if (car(init)!=DECL_DATA_LIST) { error(-1); } e = caddr(init); if (!e) { // {...,} case int sz = size(target_type); zfill(v, offset, sz); offset += sz; continue; } offset = gen_decl_data0(v,car(type0),e,offset); type0 = cadr(type0); } return offset; } static int gen_decl_data0(int v,int target_type,int init,int offset) { int e,t; if (car(init)==DECL_DATA) { switch( car(e=cadr(init))) { case DECL_DATA_LIST: offset = gen_decl_data_list(v,e,target_type,offset); break; case DECL_DATA_FIELD: offset = gen_decl_data_field(v,e,target_type,offset); break; case DECL_DATA_ARRAY: offset = gen_decl_data_array(v,e,target_type,offset); break; default: type = t = caddr(init); // type of source // e = rvalue_t(e,t); offset=assign_data(e,target_type,v,offset); } } else { offset=assign_data(init,target_type,v,offset); } if (decl_str_init) { offset = gen_delayed_decl_data(v,offset); } return offset; } extern int gen_decl_data(int e,int v) { NMTBL *nptr0; int t = caddr(e); int e1,sz; int offset = 0; int sinit_vars = init_vars; init_vars = 0; type = t; sz = size(type); if (v==0) { nptr0 = get_nptr(); nptr0->nm = ""; nptr0->sc = LVAR; nptr0->attr = 0; nptr0->ty = t; nptr0->dsp = new_lvar_align(sz,16); // ?! e1 = list3(RSTRUCT,list3n( nptr0->sc,nptr0->dsp,nptr0),sz); v = list3n(nptr0->sc,nptr0->dsp,nptr0); } else { e1 = 0; } gen_decl_data0(v,t,e,offset); text_mode(0); if (init_vars) emit_init_vars(); g_expr0(e1); init_vars = sinit_vars; return type; } // // local variable initialization // extern void zfill(int var, int offset, int sz) { int fill = sz; if (fill>63) { // call bzero } int ass = list2(CONST,0); while(fill>0) { // should consider alignment int t = UCHAR; if (fill>=size_of_longlong) t = ULONGLONG; else if (fill>=size_of_int) t = UNSIGNED; else if (fill>=size_of_short) t = USHORT; fill -= size(t); int dest = (offset+fill)?( (car(var)==LVAR) ? ( lp64? list3n(LVAR,cadr(var)+offset+fill,ncaddr(var)) : list3n(LVAR,cadr(var)+offset+fill,ncaddr(var)) ) : ( lp64?list3(LADD,var,llist2(LCONST,offset+fill)): list3(ADD,var,list2(CONST,offset+fill)))) : var ; ass = assign_expr0(dest, ass,t,t); } init_vars = list2(ass,init_vars); } extern int assign_data(int e, int t, int v,int offset) { int ass,bfd; int v0 = car(v); NMTBL *n = ncaddr(v); #if STRUCT_ALIGN if (t!=EMPTY) offset = struct_align_offset(t,offset); #endif if (car(e)==ADDRESS||car(e)==GVAR) { if (scalar(t)) { int t1 = list2(POINTER,VOID); if (size(t)>=size(t1)) t = t1; // fake } else { error(TYERR); } } switch (mode) { case GDECL: if (car(e)==RSTRUCT) break; // already done if (!is_const(e)) error(INERR); emit_data(e,t,n); break; case STADECL: if (!local_nptr) { if (!is_const(e)) error(INERR); else emit_data(e,t,n); break; } n = local_nptr; case LDECL: case STAT: // inline case if (t==EMPTY) { /* empty space in partial initialization */ zfill(v,offset,cadr(e)); return offset+cadr(e); } /* If this is a local declared constant, we don't have to assign. But some one may take it's address. We have to generate assign. */ ass = assign_expr0( (v0==REGISTER||v0==DREGISTER||v0==FREGISTER||v0==LREGISTER)? v: (offset? list3n(v0,cadr(v)+offset,ncaddr(v)) : v), e,t,type); init_vars = list2(ass,init_vars); break; case SFDINIT: // if (lsrc)printf("## %d sfdinit c0(e)=%d type=%d t=%d offset=%d\n",lineno,car(e),type,t,offset); decl_str_init=insert_ascend(decl_str_init, glist4(offset,0,e,glist2(t,type)),str_init_eq); break; default: error(DCERR); return offset; } if (t>0&&car(t)==BIT_FIELD) { int sz = 0; bfd = cadr(caddr(t)); /* bit_field_disp */ #if BIT_FIELD_CODE code_bit_field_disp(t,&offset,&bfd,&sz); #endif return offset+sz; } /* constant value field */ if (offset==0 && (has_attr(n,KONST))) { if (is_const(e)) set_attr(n,KONST,e); } return offset+((t==EMPTY)?cadr(e):size(t)); } extern void data_closing(int e) { if (!chk) { if (decl_str_init) gen_delayed_decl_data(e,0); emit_data_closing(ncaddr(e)); } } #define ARG_REORDER_DEBUG 0 /* In K&R style, order of argment list and order of argment type decl are differnt. Fix them. arg defined in f(a,b,c) new_arg defined in int b; short a; char c; */ extern int arg_reorder(int arg,int new_arg) { /* list4(type,fnptr->dsp,(int)n,size); */ int i,j,sz,arg_types = 0; int dsp = 0; NMTBL *n,*n1; /* f(a,b,c) int c; short a; char* b; { } case */ #if ARG_REORDER_DEBUG if (lsrc)fprintf(stderr,"arg_reorder old:\n"); for(j=new_arg;j;j=cadr(j)) { n=ncadddr(j); if (lsrc)fprintf(stderr,"dsp %d %s sz %d type %d\n",n->dsp,n->nm,cadddr(j),car(j)); } if (lsrc)fprintf(stderr,"arg_reorder new:\n"); #endif for(j=arg;j;j=cadr(j)) { n=ncadddr(j); for(i=new_arg;i;i=cadr(i)) { n1=ncadddr(i); if (!neqname(n1->nm,n->nm)) break; // if (n1==n) break; } #if ARG_REORDER_DEBUG if (lsrc)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); ncadddr(j)=ncadddr(i); n1->dsp = n->dsp; n->ty = n1->ty; n->sc = n1->sc; n->attr = n1->attr; caddr(j)=sz= caddr(i); if (sz==1||sz==size_of_short) sz = size_of_int; dsp += sz; } else if(n->sc==IVAR) { n->dsp = dsp; car(j)=car(i); ncadddr(j)=ncadddr(i); n1->dsp = n->dsp; n->ty = n1->ty; n->sc = n1->sc; n->attr = n1->attr; caddr(j)=sz= caddr(i); dsp ++; } arg_types = glist2(n->ty, arg_types); } #if ARG_REORDER_DEBUG if (lsrc)fprintf(stderr,"arg_reorder end:\n"); #endif caddr(fnptr->ty) = reverse0(arg_types); return arg; } NMTBL str_ret; /* If function has a structure return value, it has an extra argument for where to write the structure. It has to be the first argument. We add the argument here and we have to fix all arguments' offset. If this 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; int sargs = args; 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 dummy variable is set in the 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 = inmode?1:size_of_pointer; for(t=fnptr->dsp;t;t=cadr(t)) { n=ncadddr(t); n->dsp += inmode?1:sz; } fnptr->dsp = reverse0(fnptr->dsp); if ((sz=size(cadr(fntype)))==-1) error(TYERR); else { args=0; // set struct var dsp = 0 def(&str_ret,0); args = sargs + (inmode?1:size_of_pointer); struct_return = inmode ?list3(list3n(IVAR,str_ret.dsp,0),sz,type) :list3(list3n(LVAR,str_ret.dsp,0),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) { int type0 = type_value(type); if(!(mode==GDECL||mode==ADECL)|| (car(type0)!=FUNCTION&&car(type0)!=CODE)) error(DCERR); if (n->sc==EMPTY) { n->sc=EXTRN; n->ty=type; } else if(is_code(n)) { // if (car(type0)!=CODE) error(TYERR); compatible(cadr(n->ty),cadr(type)); } else if(is_function(n)) { // if (car(type0)!=FUNCTION) error(TYERR); compatible(cadr(n->ty),cadr(type)); } else { error(DCERR); } } extern int type_compatible(int t1, int t2) { t1 = type_value(t1); t2 = type_value(t2); if(integral(t1)) { if(t1!=t2) return 0; } else if(t1<0 || t2<0) { if(t1!=t2) return 0; } else if(car(t1)!=car(t2)) return 0; else if((car(t1)==STRUCT || car(t1)==UNION) && cadr(t1)!=cadr(t2)) return 0; else if(car(t1)==POINTER || car(t1)==ARRAY ||car(t1)==FUNCTION) return type_compatible(cadr(t1),cadr(t2)); return 1; } static void compatible(int t1, int t2) { if (!type_compatible(t1,t2)) error(TYERR); } extern int scalar(int t) { t = type_value(t); return(integral(t) ||(t>0 && (car(t)==POINTER))); } extern int integral(int t) { t = type_value(t); return(t==INT||t==SIGNED||t==CHAR||t==UNSIGNED|| t==UCHAR||t==SHORT||t==USHORT||t==ENUM || (lp64&&(t==LONGLONG||t==ULONGLONG))); } /* Delayed jmp code generation. A jump code will be delayed until new code generation or new label. If label is equal the jumped label, no jump code is necesarry. */ extern void checkjmp(int l) { int p = pending_jmp; if (p) { pending_jmp = 0; if (p!=l) { control=0; if (!chk) jmp(p); } } } /* Delayed jmp code to function leaveing part. The lastexp in a statement expression is also checked. It also handle the first case statement jump in switch statement. */ extern void checkretpening(void) { if (retpending) { ret(); control=0; retpending=0; } } extern void checkret(void) { int lastexp0; if (!inmode) { code_save_stacks(); // because of statment expression if (cslabel==0) { if (!control) error(CSERR); // no execute code in switch checkjmp(0); control=0; jmp(cslabel=fwdlabel()); } else if (retpending) { ret(); control=0; retpending=0; } if (lastexp) { if(!control) error(-1); lastexp0 = lastexp; lastexp = 0; // checkret can be nest? gexpr(lastexp0,0); } } else if (lastexp) { parse = list3(ST_COMP,parse,lastexp); lastexp = 0; } } /* In casading call of struct valued function, an argument for return position will be replaced by calling function. */ 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; } /* indirect right value , get the value of the variable */ static int indirect(int t,int e1,int type) { 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; } } else if (car(e2)==LADD) { e4=caddr(e2); if (car(e4)==CONST) { offset=cadr(e4); e1=e3; } else if (car(e4)==LCONST) { offset=lcadr(e4); e1=e3; } } return list4(t,e1,offset,type); } /* make right value from original left value. type will be changed. */ extern int rvalue(int e) { int op,c; NMTBL *n; int type0 = type_value(type); int stype; if (e==0) error(-1); op = 0; switch(type0) { case INT: break; case UNSIGNED: op=US; type=set_type_with_attr(UNSIGNED,type); break; case VOID: break; case CHAR: op=COP; type=set_type_with_attr(INT,type); break; case UCHAR: op=COP+US; type=set_type_with_attr(UNSIGNED,type); break; case SHORT: op=SOP; type=set_type_with_attr(SHORT,type); break; case USHORT: op=SOP+US; type=set_type_with_attr(UNSIGNED,type); 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(type0)) break; switch(car(type0)) { case ARRAY: type=set_type_with_attr(list2(POINTER,cadr(type)),type); if(car(e)==INDIRECT) return cadr(e); return list2(ADDRESS,e); case STRUCT: case UNION: if(car(e)==RSTRUCT) return e; /* to make idempotent */ if(car(e)==INDIRECT) return cadr(e); return list3(RSTRUCT,e,cadr(type) /* size */); case FUNCTION: type=set_type_with_attr(cadr(type0),type); return e; case CODE: return e; case POINTER: if (lp64) op=LOP; break; case BIT_FIELD: if (car(e)==BIT_FIELD) { e = list3(RBIT_FIELD,cadr(e),type); /* byte rvalue, store type */ } else { e = list3(RBIT_FIELD,e,type); } type=set_type_with_attr(cadr(type0),type);/* value type */ return e; default: error(TYERR); } } switch(OP(car(e))) { case GVAR: n = ncaddr(e); if (cadr(e)==0 && (c=attr_value(n,KONST))) { if (!has_attr(n,VOLATILE)) return c; } return(list3n(RGVAR+op,cadr(e),ncaddr(e))); case LVAR: n = ncaddr(e); if (cadr(e)==0 && n && (c=attr_value(n,KONST))) { if (!has_attr(n,VOLATILE)) return c; } return(list3n(RLVAR+op,cadr(e),ncaddr(e))); case INDIRECT: return(indirect(RINDIRECT+op,cadr(e),type0)); // cadr(e)? case IVAR: case ARRAY: case PERIOD: case ARROW: return(indirect(RINDIRECT+op,e,type0)); // RIVAR? case BIT_FIELD: return list3(RBIT_FIELD,cadr(e),caddr(e)); case CAST: stype = type; type = cadddr(e); op = rvalue(cadr(e)); e = list4(CAST,op,caddr(e),cadddr(e)); // should be RCAST? type = stype; default:return(e); /* idempotent case? */ } } /* right value with preserving type global variable */ extern int rvalue_t(int e,int type0) { int op,c; NMTBL *n; if (e==0) error(-1); op = 0; switch(type0) { case INT: break; case UNSIGNED: op=US; break; case VOID: break; case CHAR: op=COP; break; case UCHAR: op=COP+US; break; case SHORT: op=SOP; break; case USHORT: op=SOP+US; 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 (type0>0) { if (car(type0)==POINTER) { if (lp64) op=LOP; } else error(-1); } else error(-1); } switch(OP(car(e))) { case GVAR: n = ncaddr(e); if (cadr(e)==0 && (c=attr_value(n,KONST))) { if (!has_attr(n,VOLATILE)) return c; } return(list3n(RGVAR+op,cadr(e),ncaddr(e))); case LVAR: n = ncaddr(e); if (cadr(e)==0 && n && (c=attr_value(n,KONST))) { if (!has_attr(n,VOLATILE)) return c; } return(list3n(RLVAR+op,cadr(e),ncaddr(e))); case INDIRECT: return(indirect(RINDIRECT+op,cadr(e),type0)); // cadr(e)? case IVAR: case ARRAY: case PERIOD: case ARROW: return(indirect(RINDIRECT+op,e,type0)); // RIVAR? case BIT_FIELD: return list3(RBIT_FIELD,cadr(e),caddr(e)); case CAST: op = rvalue_t(cadr(e),cadddr(e)); e = list4(CAST,op,caddr(e),cadddr(e)); // should be RCAST? default:return(e); /* idempotent case? */ } } /* left value check. Can we assign a value to it? */ extern void lcheck(int e) { int t; int type0 = type_value(type); if(scalar(type0)) return; switch(type0) { 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(type0))<0 && t!=STRUCT && t!=UNION) error(LVERR); } /* Indirect operator. */ extern int indop(int e) { int type0 = type_value(type); if(type0!=INT&&type0!=UNSIGNED&&type0!=LONGLONG&&type0!=ULONGLONG) { if(car(type0)==POINTER) type=set_type_with_attr(cadr(type),type); else if(car(type0)==CODE || car(type0)==FUNCTION) { // type=type; } else error(TYERR); } else type= set_type_with_attr(CHAR,type); // ?! if(car(e)==ADDRESS) return(cadr(e)); return(list2(INDIRECT,e)); } /* struct field 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_value(type)); if (t==0) { nptr0=ncadddr(type); if (!nptr0->ty) { error(TYERR); return 0; } t = caddr(type) = caddr(nptr0->ty); } for(;t;t = cadr(t)) { if (neqname(ncadddr(t)->nm,name)==0) { *dsp = caddr(t); return car(t); } } return 0; } /* Structure operation a.b, a->b */ extern int strop(int e,int ind) { int dsp = 0; int type0; int e1 = 0; if (inmode || chk) { e1 = list4n(ind?ARROW:PERIOD,e,type,nptr); } if (ind) e = indop(rvalue(e)); type0 = type_value(type); if (integral(type0)||(car(type0)!=STRUCT && car(type0)!=UNION)) { e=rvalue(e); type0 = type_value(type); } if (type<=0 || (car(type0)!=STRUCT && car(type0)!=UNION)) { error(TYERR); type=INT; return e; } /* type = list4(s,disp,fields,tag_nptr); */ /* print_fields(caddr(type),"strop"); */ type = search_struct_type(type,nptr->nm,&dsp); if (!type) { error(UFLDERR); type=INT; return e; } if (inmode || chk) { // bitfield will be checked after parse return e1; } ind = 0; if (car(e)==INDIRECT) { e = cadr(e); ind = 1; } if(dsp) { switch(OP(car(e))) { case GVAR: // e=list2(INDIRECT,list3(ADD,e,list2(CONST,dsp))); e=list3n(car(e),cadr(e)+dsp,ncaddr(e)); break; case LVAR: e=list3n(car(e),cadr(e) + dsp,ncaddr(e)); /* may have attribute */ break; case IVAR: if (lp64) e=list3(LADD,e,llist2(LCONST,dsp)); else e=list3(ADD,e,list2(CONST,dsp)); break; default: if (lp64) e=list3(LADD,e,llist2(LCONST,dsp)); else e=list3(ADD,e,list2(CONST,dsp)); } } if (ind && !parse_mode && !inmode) { e = list2(INDIRECT,e); } type0 = type_value(type); 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; } /* Binary operator parse tree generation (and optimization) I don't know how to handle type attribute (const/volatie) in binop */ #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,t; 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; e2 = dlist2(dop+CONST,-dcadr(e2)); // op=ADD; dcadr(e2) = -dcadr(e2); } else if(op==DIV) { if(dcadr(e2)==0.0) error(EXERR); op=MUL; e2 = dlist2(dop+CONST,1.0/dcadr(e2)); // 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==ADD||op==SUB||op==MUL||op==DIV) { return(list3(op+dop,e1,e2)); } t = type; type=INT; if(op==LT) { return(list3(GT+dop,e2,e1)); } else if(op==LE) { return(list3(GE+dop,e2,e1)); } else if(op==GT||op==GE||op==EQ||op==NEQ) { 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 lintegral(int t) { return (t==LONGLONG||t==ULONGLONG); } 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); t1=t2=ULONGLONG; } else { if(!(t1>0&&car(t1)==POINTER)) { type=t1; e1=longlong_value(e1); t1 = LONGLONG;} if(!(t2>0&&car(t2)==POINTER)) { type=t2; e2=longlong_value(e2); t2 = LONGLONG;} } 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: if(lintegral(t1)) { if(lintegral(t2)) { le=le1+le2; } else { if(car(t2)!=POINTER) error(TYERR); le=size(cadr(t2))*le1+le2; type=t2; } } else { if(car(t1)!=POINTER) error(TYERR); le=le1+size(cadr(t1))*le2; type=t1; } break; case SUB: if(lintegral(t1)) { le=le1-le2; type=LONGLONG; } else { if(car(t1)!=POINTER) error(TYERR); if(lintegral(t2)) { le=le1-size(cadr(t1))*le2; type=t1; } else { le=(le1-le2)/size(cadr(t1)); 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 LSHIFT: if (t1==ULONGLONG) le=(((unsigned long long)le1)<<le2); else le=le1<<le2; break; case RSHIFT: 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==SUB) { us = 0; type=LONGLONG; } if(op==SUB&&car(e2)==LCONST) { op=ADD; e2=llist2(LCONST,-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==ADD) { if(lintegral(t1)) { if(lintegral(t2)) { // if(t1==INT) type=t2;else type=t1; if (us) type=ULONGLONG; else type=LONGLONG; return(list3(LADD,e1,e2)); } if(car(t2)!=POINTER) error(TYERR); e=lbinop(MUL,e1,llist2(LCONST,size(cadr(t2))),t1,LONGLONG); type=t2; return(lvalue_opt(list3(LADD,e2,e))); } if(car(t1)!=POINTER||!lintegral(t2)) error(TYERR); e=lbinop(MUL,e2,llist2(LCONST,size(cadr(t1))),t2,LONGLONG); type=t1; if (car(e)==LCONST && lcadr(e)==0) return(e1); return(llvalue_opt(list3(LADD,e1,e))); } if(op==SUB) { if(lintegral(t1)) { if(!lintegral(t2)) error(TYERR); if(t1==LONGLONG) type=t2;else type=t1; if (type==ULONGLONG) type=LONGLONG; return(list3(LSUB,e1,e2)); } if(car(t1)!=POINTER) error(TYERR); if(lintegral(t2)) { e=binop(MUL,e2,llist2(LCONST,size(cadr(t1))),t2,LONGLONG); type=t1; if (car(e)==LCONST) error(-1); return(list3(LSUB,e1,e)); } if(car(t2)!=POINTER) error(TYERR); compatible(t1,t2); e=list3(LSUB,e1,e2); e=lbinop(DIV,e,llist2(LCONST,size(cadr(t1))),LONGLONG,LONGLONG); type= LONGLONG; return 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) { 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)); } if (op==DIV||op==MUL||op==ADD||op==SUB||op==MOD) { return(list3(op+LOP,e1,e2)); } type = INT; if(op==LT) { return(list3(GT+LOP+us,e2,e1)); } else if(op==LE) { return(list3(GE+LOP+us,e2,e1)); } else if(op==EQ||op==NEQ) { // EQ/NEQ has no unsign return(list3(op+LOP,e1,e2)); } else if(op==GT||op==GE||op==LT||op==LE) { return(list3(op+LOP+us,e1,e2)); } else error(-1); return 0; /* not reached */ } #endif /* binary integer computation */ extern int binop0(int op, int e1, int e2, int t1, int t2) { int e=0; int us = 0; // for inmode, destructive modification e1,e2,t1,t2 is not allowed if(t1>0&&car(t1)==POINTER) { if (lp64) return lbinop(op,e1,e2,t1,t2); if(!(op==SUB && t2>0&&car(t2)==POINTER)) { type = t2; e2= int_value(e2); t2=INT; } } else if(t2>0&&car(t2)==POINTER) { if (lp64) return lbinop(op,e1,e2,t1,t2); 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); if(integral(t2)) { e=e1-size(cadr(t1))*e2; type=t1; } else { e=(e1-e2)/size(cadr(t1)); type=INT; } } 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; default: error(-1); return list2(CONST,0); } return list2(CONST,e); } if(op==GT||op==GE||op==LT||op==LE) { return(car(e1)==CONST?list3(rop_dual(op)+us,e2,e1):list3(op+us,e1,e2)); } else if(op==EQ||op==NEQ) { return(car(e1)==CONST?list3(op,e2,e1):list3(op,e1,e2)); } if(op==SUB&&car(e2)==CONST) { op=ADD; e2=list2(CONST,-cadr(e2)); } if((op==ADD||op==MUL||op==BOR||op==EOR||op==BAND)&& (car(e1)!=CONST)) { switch(car(e2)) { case RGVAR: case RLVAR: case URGVAR: case URLVAR: case SRGVAR: case SRLVAR: case SURGVAR: case SURLVAR: case CRGVAR: case CRLVAR: case CURGVAR: case 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; if (us) type=UNSIGNED; else type=INT; return(list3(ADD,e1,e2)); } if(car(t2)!=POINTER) error(TYERR); e=binop0(MUL,e1,list2(CONST,size(cadr(t2))),t1,INT); type=t2; return lvalue_opt(list3(ADD,e2,e)); } if(car(t1)!=POINTER||!integral(t2)) error(TYERR); e=binop0(MUL,e2,list2(CONST,size(cadr(t1))),t2,INT); type=t1; if (car(e)==CONST && cadr(e)==0) return(e1); return(lvalue_opt(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=binop0(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=binop0(DIV,e,list2(CONST,size(cadr(t1))),INT,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)); } extern int binop(int op, int e1, int e2, int t1, int t2) { int e = binop0(op,e1,e2,t1,t2); // we have to execute this to fix type if (inmode) return list3(ST_OP,op,list4(e1,e2,t1,t2)); return e; } /* arugment type of binary operator */ extern int type_of_bop(int op) { int us; if (op>0) { switch(OP(op)) { case UMUL: case UDIV: case UMOD: case URSHIFT: case ULSHIFT: case ULT: case UCMP: case UCMPGE: case UGE: case UGT: case ULE: us = 1; break; case MUL: case DIV: case MOD: case ADD: case SUB: case CMP: case RSHIFT: case LSHIFT: case GT: case GE: case LT: case LE: case EQ: case NEQ: case BAND: case EOR: case BOR: case CMPGE: case CMPEQ: case CMPNEQ: us = 0; break; default: return 0; } switch(OP_TAG(op) + us) { case SOP: return SHORT; case SOP+US: return USHORT; case COP: return CHAR; case COP+US: return UCHAR; case DOP: return DOUBLE; case FOP: return FLOAT; case LOP: return LONGLONG; case LOP+US: return ULONGLONG; case US: return UNSIGNED; case 0: return INT; } } return 0; } /* type of result of conversion operator */ extern int type_of_conv(int op) { switch(op) { case LL2D: case ULL2D: case F2D: case I2D: case U2D: return DOUBLE; case LL2F: case ULL2F: case D2F: case I2F: case U2F: return FLOAT; case LL2I: case ULL2I: case D2I: case F2I: case I2C: case I2S: return INT; case D2LL: case F2LL: case I2LL: case U2LL: return LONGLONG; case D2ULL: case F2ULL: case I2ULL: case U2ULL: return ULONGLONG; case LL2U: case ULL2U: case D2U: case F2U: case U2UC: case U2US: return UNSIGNED; } return 0; } extern int skip_cast(int e) { int t,t1; if (car(e)==CAST) { t = caddr(e); t1 = cadddr(e); if ( type_compatible(t, t1) ) { return cadr(e); } } return e; } /* coarse for function/code segments arguments */ extern int correct_type(int e,int t0) { int t = type_value(t0),t1; // e = rvalue(e); #if BIT_FIELD_CODE // if (type>0 && car(type)==BIT_FIELD) e = rvalue(e); #endif if (t==DOTS) { if (type==FLOAT) t=DOUBLE; else if (type==CHAR) t=INT; else if (type==UCHAR) t=UNSIGNED; else if (type==SHORT) t=INT; else if (type==USHORT) t=UNSIGNED; } // is this correct? if ((t1=type_value(type))>0 && car(type_value(type))==ARRAY && car(e)==GVAR) { if (!chk) e=list2(ADDRESS,e); } if (t>0) { switch(car(t)) { case POINTER: if (cadr(t)>0) { switch(car(cadr(t))) { case FUNCTION: // type でチェックするべきだよね? 本来... // compatible(cadr(t),cadr(type)); // ではあかんの? if (car(e)==FNAME) { NMTBL *n = ncaddr(e); int targ0 = caddr(cadr(t)); int targ1 = caddr(n->ty); if (is_function(n)) { // return type compatible(cadr(cadr(t)),cadr(n->ty)); } // arguments for (;targ0;targ0=cadr(targ0),targ1=cadr(targ1)) { if (car(targ0)==DOTS) break; compatible(car(targ0),car(targ1)); } } break; default: if (!(t1>0&&car(t1)==ARRAY) && !scalar(t1)) error(TYERR); } } else { if (!(t1>0&&car(t1)==ARRAY) && !scalar(t1)) error(TYERR); } break; case STRUCT: case UNION: if (scalar(t1)) error(TYERR); else if(size(t)!=size(type)) error(TYERR); break; } } else { switch(t) { case DOTS: return e; case UNSIGNED: e = unsigned_value(e); t = UNSIGNED; break; case CHAR: e = char_value(e); t = INT; break; case UCHAR: e = uchar_value(e); t = UNSIGNED; break; case SHORT: e = short_value(e); t = INT; break; case USHORT: e = ushort_value(e); t = UNSIGNED; break; #if FLOAT_CODE case FLOAT: e = float_value(e); break; case DOUBLE: e = double_value(e); break; #endif #if LONGLONG_CODE case LONGLONG: e = longlong_value(e); break; case ULONGLONG: e = ulonglong_value(e); break; #endif default: if (integral(t)) e = int_value(e); } } type = set_type_with_attr(t,t0); return e; } /* Integer Constant expression is required */ extern int cexpr(int e) { if (car(e) == CONV) { switch(caddr(e)) { case I2C: case I2S: case U2UC: case U2US: e=cadr(e); break; default: error(-1); // illeagal int constant } } 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) { // if (lsrc)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 LONGLONG_CODE if (post) { n1 = list3n(LVAR,new_lvar(size_of_longlong),0); code_lassign_lvar(cadr(n1),USE_CREG); } if (!code_lassop_p) { n2 = list3n(LVAR,new_lvar(size_of_longlong),0); 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 error(TYERR); #endif } else { if (post) { n1 = list3n(LVAR,new_lvar(size_of_int),0); code_assign_lvar(cadr(n1),USE_CREG,size_of_int); } 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, int align) { disp-=sz; if (align) { disp &= ~(align-1); } else if (sz>=4 && (disp & (4-1))) { // alignment 4 disp &= ~(4-1); } return disp; } /* Allocate new local variable in flat scope */ extern int new_lvar_align(int size,int align) { int lvar,plvar; /* Can we reuse previously freed local variable? */ for (plvar = 0,lvar = lvar_free_list;lvar;lvar = cadr(lvar)) { if (caddr(lvar)==size && (~align|| car(lvar)%align==0)) { if (plvar) cadr(plvar) = cadr(lvar); else lvar_free_list = cadr(lvar); break; } plvar = lvar; } if (!lvar) { lvar_list = glist3((lvar=new_lvar0(size,align)),lvar_list,size); } else { cadr(lvar) = lvar_list; lvar_list = lvar; lvar = car(lvar_list); } return lvar; } extern int new_lvar(int size) { // system dependent? return new_lvar_align(size,0); } /* Free the allocated local variable. It may be reused again. */ extern void free_register_var(int reg_arg_list) { int arg; for(;reg_arg_list;reg_arg_list=cadr(reg_arg_list)) { arg = car(reg_arg_list); if (car(arg)==REGISTER||car(arg)==DREGISTER||car(arg)==FREGISTER ||car(arg)==LREGISTER) { free_register(cadr(arg)); } else if (car(arg)==LVAR&&cadr(arg)<0) free_lvar(cadr(arg)); } } 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_comment(char *s) { if (!chk) code_comment(s); } 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) { control=0; if (!pending_jmp) { pending_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 unsigned make_mask(int from,int to) { unsigned mask = 0; unsigned bit = 1; int i; if (from<0||from>31) error(-1); for (i=31;from<=i;i--,bit<<=1) { if (i<=to) { mask |= bit; } } return mask; } extern unsigned long long make_mask_64(int from,int to) { unsigned long long mask = 0; unsigned long long bit = 1; int i; if (from<0||from>63) error(-1); for (i=63;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 global pointer needs dynamic loading or table. it may used again, put it to a register as a cache. */ extern void init_ptr_cache() { int i; for(i=0;i<MAX_PTR_CACHE-1;i++) { ptr_cache=glist3n(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(ncaddr(ptcptr)&&car(ptcptr)==r) { free_register(r); car(ptcptr)=-1; ncaddr(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 = car(ptcptr); ptcptr=cadr(ptcptr); } return r; } extern void clear_ptr_cache() { int ptcptr=ptr_cache; while(ptcptr!=ptr_cache_last) { free_register(car(ptcptr)); car(ptcptr)=-1; ncaddr(ptcptr)=0; ptcptr=cadr(ptcptr); } ptr_cache_last = ptr_cache; } extern int get_ptr_cache(NMTBL *nptr) { int r; int ptcptr=ptr_cache; NMTBL *g = nptr; int prev=0,p; // linear search cache while(ptcptr!=ptr_cache_last) { if(ncaddr(ptcptr)==g) { if (prev) { // make this top cadr(prev)=cadr(ptcptr); cadr(ptcptr) = ptr_cache; ptr_cache = ptcptr; } return car(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(car(prev)); car(ptcptr)=-1; ncaddr(ptcptr)=0; ptr_cache_last = prev; } else error(-1); } r = get_register(0); // some ptr cache may remove by this car(p = cadr(ptr_cache_last)) = r; ncaddr(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 */