Mercurial > hg > CbC > old > device
view mc-codegen.c @ 320:183726ccd83d
asm minor fix. ia32 table jmp fix.
author | kono |
---|---|
date | Sat, 19 Jun 2004 00:13:36 +0900 |
parents | 22d92986c7f7 |
children | e5d40f8c4cce |
line wrap: on
line source
/* Micro-C Generic Code Generatation Part */ /* $Id$ */ #define EXTERN extern #include "mc.h" #include "mc-codegen.h" #include "mc-code.h" int use; /* generated value will be used */ static void remove0(int *parent,int e) ; /* static void remove0_all(int *parent,int e) ; */ static int is_same_type(int e1,int e2); static void jump(int e1, int env); static void machinop(int e1); static void sassign(int e1); static void assign(int e1); static void assop(int e1); static int g_expr0(int e1); static int register_to_lvar(int e); static void bexpr_u(int e1, char cond, int l1); static void code_asm(int asm0,int in,int out,int opt,int e); #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 void codegen_init() { code_init(); } void arg_register(NMTBL *fnptr) { code_arg_register(fnptr); } int gexpr(int e1,int use0) { if (chk) return INT; gexpr_init(); use = use0; #if 0 if(lineno==2862) { return g_expr0(e1); /*break here*/ } #endif return g_expr0(e1); } int g_expr_u(int e1) { int t; int suse = use; use=0; t=g_expr0(e1); code_gexpr(e1); use=suse; return t; } int g_expr(int e1) { int t; int suse = use; use=1; t=g_expr0(e1); code_gexpr(e1); use=suse; return t; } int g_expr0(int e1) { int e2,e3,t,d,t1; NMTBL *n; code_gexpr(e1); e2 = cadr(e1); switch (car(e1)){ case GVAR: code_gvar(e1,USE_CREG); return ADDRESS; case RGVAR: code_rgvar(e1,USE_CREG); return INT; case CRGVAR: code_crgvar(e1,USE_CREG,1,1); return CHAR; case CURGVAR: code_crgvar(e1,USE_CREG,0,1); return UCHAR; case SRGVAR: code_crgvar(e1,USE_CREG,1,size_of_short); return CHAR; case SURGVAR: code_crgvar(e1,USE_CREG,0,size_of_short); return UCHAR; case LVAR: code_lvar(e2,USE_CREG); return ADDRESS; case REGISTER: code_register(e2,USE_CREG); return INT; #if FLOAT_CODE case DREGISTER: code_dregister(e2,USE_CREG,1); return DOUBLE; case FREGISTER: code_dregister(e2,USE_CREG,0); return FLOAT; #endif #if LONGLONG_CODE case LREGISTER: code_lregister(e2,USE_CREG); return LONGLONG; #endif case RLVAR: code_rlvar(e2,USE_CREG); return INT; case CRLVAR: code_crlvar(e2,USE_CREG,1,1); return CHAR; case CURLVAR: code_crlvar(e2,USE_CREG,0,1); return UCHAR; case SRLVAR: code_crlvar(e2,USE_CREG,1,size_of_short); return CHAR; case SURLVAR: code_crlvar(e2,USE_CREG,0,size_of_short); return UCHAR; #if FLOAT_CODE case FRLVAR: code_drlvar(e2,0,USE_CREG); return FLOAT; case FRGVAR: code_drgvar(e1,0,USE_CREG); return FLOAT; case DRLVAR: code_drlvar(e2,1,USE_CREG); return DOUBLE; case DRGVAR: code_drgvar(e1,1,USE_CREG); return DOUBLE; #endif #if LONGLONG_CODE case LRLVAR: code_lrlvar(e2,USE_CREG); return LONGLONG; case LRGVAR: code_lrgvar(e1,USE_CREG); return LONGLONG; case LURLVAR: code_lrlvar(e2,USE_CREG); return ULONGLONG; case LURGVAR: code_lrgvar(e1,USE_CREG); return ULONGLONG; #endif case FNAME: code_fname((NMTBL *)(e2),USE_CREG); return ADDRESS; case CONST: /* 代入する値が0でも特別な処理はしない */ code_const(e2,USE_CREG); return INT; #if FLOAT_CODE case DCONST: code_dconst(e1,USE_CREG,1); return DOUBLE; case FCONST: code_dconst(e1,USE_CREG,0); return FLOAT; #endif #if LONGLONG_CODE case LCONST: code_lconst(e1,USE_CREG); return LONGLONG; #endif case STRING: code_string(e1,USE_CREG); return ADDRESS; case FUNCTION: t = function(e1); return t; case CODE: jump(e2,caddr(e1)); return VOID; case INDIRECT: return g_expr0(e2); case RINDIRECT: return code_rindirect(e2,USE_CREG,caddr(e1),1); case URINDIRECT: return code_rindirect(e2,USE_CREG,caddr(e1),0); case CRINDIRECT: return code_crindirect(e2,USE_CREG,caddr(e1),1); case CURINDIRECT: return code_crindirect(e2,USE_CREG,caddr(e1),0); case SRINDIRECT: return code_srindirect(e2,USE_CREG,caddr(e1),1); case SURINDIRECT: return code_srindirect(e2,USE_CREG,caddr(e1),0); #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)) { #if FLOAT_CODE case I2D: code_i2d(USE_CREG); return DOUBLE; case D2I: code_d2i(USE_CREG); return INT; case U2D: code_u2d(USE_CREG); return DOUBLE; case F2U: code_f2u(USE_CREG); return UNSIGNED; case I2F: code_i2f(USE_CREG); return FLOAT; case F2I: code_f2i(USE_CREG); return INT; case U2F: code_u2f(USE_CREG); return FLOAT; case D2U: code_d2u(USE_CREG); return UNSIGNED; case D2F: code_d2f(USE_CREG); return FLOAT; case F2D: code_f2d(USE_CREG); return DOUBLE; #endif #if LONGLONG_CODE case I2LL: code_i2ll(USE_CREG); return LONGLONG; case I2ULL: code_i2ull(USE_CREG); return ULONGLONG; case U2LL: code_u2ll(USE_CREG); return LONGLONG; case U2ULL: code_u2ull(USE_CREG); return ULONGLONG; case LL2I: code_ll2i(USE_CREG); return INT; case LL2U: code_ll2u(USE_CREG); return UNSIGNED; case ULL2I: code_ull2i(USE_CREG); return INT; case ULL2U: code_ull2u(USE_CREG); return UNSIGNED; #if FLOAT_CODE case D2LL: code_d2ll(USE_CREG); return LONGLONG; case D2ULL: code_d2ull(USE_CREG); return ULONGLONG; case F2LL: code_f2ll(USE_CREG); return LONGLONG; case F2ULL: code_f2ull(USE_CREG); return ULONGLONG; case LL2D: code_ll2d(USE_CREG); return DOUBLE; case LL2F: code_ll2f(USE_CREG); return FLOAT; case ULL2D: code_ull2d(USE_CREG); return DOUBLE; case ULL2F: code_ull2f(USE_CREG); return FLOAT; #endif #endif default: error(-1); return INT; } case BNOT: /* ~ */ g_expr0(e2); code_not(USE_CREG); return INT; case LNOT: /* ! */ g_expr0(e2); code_lnot(USE_CREG); return INT; case PREINC: code_preinc(e1,e2,caddr(e1),1,cadddr(e1),USE_CREG); return INT; case UPREINC: code_preinc(e1,e2,caddr(e1),0,cadddr(e1),USE_CREG); return INT; case POSTINC: code_postinc(e1,e2,caddr(e1),1,cadddr(e1),USE_CREG); return INT; case UPOSTINC: code_postinc(e1,e2,caddr(e1),0,cadddr(e1),USE_CREG); return INT; #if FLOAT_CODE case DPREINC: /* ++d */ code_dpreinc(e1,e2,1,USE_CREG); return DOUBLE; case DPOSTINC: /* d++ */ code_dpostinc(e1,e2,1,USE_CREG); return DOUBLE; case FPREINC: /* ++f */ code_dpreinc(e1,e2,0,USE_CREG); return FLOAT; case FPOSTINC: /* f++ */ code_dpostinc(e1,e2,0,USE_CREG); return FLOAT; #endif #if LONGLONG_CODE case LPREINC: /* ++d */ code_lpreinc(e1,e2,USE_CREG); return LONGLONG; case LPOSTINC: /* d++ */ code_lpostinc(e1,e2,USE_CREG); return LONGLONG; case LUPREINC: /* ++d */ code_lpreinc(e1,e2,USE_CREG); return ULONGLONG; case LUPOSTINC: /* d++ */ code_lpostinc(e1,e2,USE_CREG); return ULONGLONG; #endif case MUL: case UMUL: case DIV: case UDIV: case MOD: case UMOD: case LSHIFT: case ULSHIFT: case RSHIFT: case URSHIFT: case ADD: case SUB: case BAND: case EOR: case BOR: case CMP: case CMPGE: case UCMP: case CMPEQ: case CMPNEQ: case UCMPGE: machinop(e1); return INT; #if FLOAT_CODE case DMUL: case DDIV: case DADD: case DSUB: case DCMP: case DCMPGE: case DCMPEQ: case DCMPNEQ: dmachinop(e1,1); return DOUBLE; case FMUL: case FDIV: case FADD: case FSUB: case FCMP: case FCMPGE: case FCMPEQ: case FCMPNEQ: dmachinop(e1,0); return FLOAT; #endif #if LONGLONG_CODE case LMUL: case LUMUL: case LDIV: case LUDIV: case LMOD: case LUMOD: case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: case LADD: case LSUB: case LBAND: case LEOR: case LBOR: case LCMP: lmachinop(e1); return INT; #endif case LCOND: case DCOND: case FCOND: case COND: /* a?0:1 should consider non-brach instruction */ d = (car(e1)==LCOND?LONGLONG: car(e1)==COND?INT:car(e1)==DCOND?DOUBLE:FLOAT); e2=fwdlabel(); b_expr(cadr(e1),0,e2,0); g_expr0(caddr(e1)); t = code_get_fixed_creg(USE_CREG,d); jmp(e3=fwdlabel()); fwddef(e2); t1=g_expr0(cadddr(e1)); code_set_fixed_creg(t,1,d); fwddef(e3); return t1; case STASS: sassign(e1); return RSTRUCT; case ASS: case CASS: case SASS: assign(e1); return INT; case ASSOP: case CASSOP: case CUASSOP: assop(e1); return INT; #if FLOAT_CODE case FASS: case DASS: dassign(e1); return DOUBLE; case DASSOP: case FASSOP: dassop(e1); return DOUBLE; #endif #if LONGLONG_CODE case LASS: lassign(e1); return LONGLONG; case LASSOP: case LUASSOP: lassop(e1); return LONGLONG ; #endif case RSTRUCT: g_expr0(e2); return RSTRUCT; case ALLOCA: code_alloca(e2,USE_CREG); return list2(POINTER,CHAR); case COMMA: g_expr_u(e2); return g_expr0(caddr(e1)); case RETURN: n = (NMTBL *)e2; if (retcont==0) retcont=fwdlabel(); code_return(USE_CREG); return VOID; case ENVIRONMENT: code_environment(USE_CREG); return ADDRESS; #if ASM_CODE case ASM: code_asm(car(e2),cadr(e2),caddr(e2),cadddr(e2),caddr(e1)); /* asm in (str) out (str) opt(str) expr */ return VOID; #endif default: code_bool(e1,USE_CREG); /* type? */ return INT; } } #define dual_ops(op) \ (op==GT|| op==UGT|| op==GE|| op==UGE|| op==LT|| \ op==ULT|| op==LE|| op==ULE|| \ op==DOP+GT|| op==DOP+GE|| op==DOP+LT|| op==DOP+LE || \ op==FOP+GT|| op==FOP+GE|| op==FOP+LT|| op==FOP+LE || \ op==FOP+EQ|| op==FOP+NEQ || \ op==EQ|| op==NEQ|| op==DOP+EQ|| op==DOP+NEQ) int rop_dual(op) { // x op y => y dual(op) x switch(op) { case GT: return LT; case UGT: return ULT; case GE: return LE; case UGE: return ULE; case LT: return GT; case ULT: return UGT; case LE: return GE; case ULE: return UGE; case DOP+GT: return DOP+LT; case DOP+GE: return DOP+LE; case DOP+LT: return DOP+GT; case DOP+LE: return DOP+GE; case FOP+GT: return FOP+LT; case FOP+GE: return FOP+LE; case FOP+LT: return FOP+GT; case FOP+LE: return FOP+GE; case LOP+GT: return LOP+LT; case LOP+GE: return LOP+LE; case LOP+LT: return LOP+GT; case LOP+LE: return LOP+GE; case LOP+UGT: return FOP+ULT; case LOP+UGE: return FOP+ULE; case LOP+ULT: return FOP+UGT; case LOP+ULE: return FOP+UGE; } return op; } void bexpr_u(int e1, char cond, int l1) { int op = car(e1); if (chk) return; // gexpr_init(); if (dual_ops(op) && (car(caddr(e1))==CONST||(car(caddr(e1))==DCONST))) b_expr(list3(rop_dual(op),caddr(e1),cadr(e1)),cond,l1,0); else b_expr(e1,cond,l1,0); } void bexpr(int e1, char cond, int l1) { int uses = use; use=1; bexpr_u(e1, cond, l1); use = uses; } void b_expr(int e1, char cond, int l1,int err) { int e2,l2,t; if (!control) return; l2 = 0; e2=cadr(e1); switch(car(e1)) { case LNOT: b_expr(e2,!cond,l1,0); return; case GT: case GE: case LT: case LE: case EQ: case NEQ: rexpr(e1,l1,cond,INT); return; case UGT: case UGE: case ULT: case ULE: rexpr(e1,l1,cond,UNSIGNED); return; #if FLOAT_CODE case DOP+GT: case DOP+GE: case DOP+EQ: case DOP+NEQ: case FOP+GT: case FOP+GE: case FOP+EQ: case FOP+NEQ: drexpr(cadr(e1),caddr(e1),l1,car(e1),cond); return; case FOP+LT: case FOP+LE: case DOP+LT: case DOP+LE: drexpr(caddr(e1),cadr(e1),l1,rop_dual(car(e1)),cond); return; #endif #if LONGLONG_CODE case LOP+GT: case LOP+GE: case LOP+EQ: case LOP+NEQ: case LOP+UGT: case LOP+UGE: lrexpr(cadr(e1),caddr(e1),l1,car(e1),cond); return; case LOP+LT: case LOP+LE: case LOP+ULT: case LOP+ULE: lrexpr(caddr(e1),cadr(e1),l1,rop_dual(car(e1)),cond); return; #endif case LAND: bexpr(e2,0,cond?(l2=fwdlabel()):l1); bexpr_u(caddr(e1),cond,l1); if(cond) fwddef(l2); return; case LOR: bexpr(e2,1,cond?l1:(l2=fwdlabel())); bexpr_u(caddr(e1),cond,l1); if(!cond) fwddef(l2); return; case CRGVAR: case CURGVAR: code_cmp_crgvar(e1,USE_CREG,1,l1,cond); return; case SRGVAR: case SURGVAR: code_cmp_crgvar(e1,USE_CREG,size_of_short,l1,cond); return; case CRLVAR: case CURLVAR: code_cmp_crlvar(e2,USE_CREG,1,l1,cond); return; case SRLVAR: case SURLVAR: code_cmp_crlvar(e2,USE_CREG,size_of_short,l1,cond); return; case RGVAR: code_cmp_rgvar(e1,USE_CREG,l1,cond); return; case RLVAR: code_cmp_rlvar(e2,USE_CREG,l1,cond); return; #if FLOATC_DOE case DRLVAR: code_cmp_drlvar(e2,USE_CREG,1,l1,cond); return; case FRLVAR: code_cmp_drlvar(e2,USE_CREG,0,l1,cond); return; case DRGVAR: code_cmp_drgvar(e2,USE_CREG,1,l1,cond); return; case FRGVAR: code_cmp_drgvar(e2,USE_CREG,0,l1,cond); return; case FREGISTER: code_cmp_dregister(e2,0,l1,cond); return; case DREGISTER: code_cmp_dregister(e2,1,l1,cond); return; case DCONST: case FCONST: if(control&&((dcadr(e2)!=0.0)^cond)) jmp(l1); return; #endif #if LONGLONG_DOE case LRLVAR: code_cmp_lrlvar(e2,1,l1,cond); return; case LRGVAR: code_cmp_lrgvar(e2,1,l1,cond); return; case LREGISTER: code_cmp_lregister(e2,1,l1,cond); return; case LCONST: if(control&&((lcadr(e2)!=0)^cond)) jmp(l1); return; #endif case REGISTER: code_cmp_register(e2,l1,cond); return; case CONST: if(control&&((cond&&e2)||(!cond&&!e2))) jmp(l1); return; default: if(err) { error(-1); return; /* recursive g_expr/b_expr */ } t=g_expr(e1); if (!use) return; if (0) ; #if FLOAT_CODE else if(t==FLOAT) code_cmp_dregister(USE_CREG,0,l1,cond); else if(t==DOUBLE) code_cmp_dregister(USE_CREG,1,l1,cond); #endif #if LONGLONG_CODE else if(t==LONGLONG||t==ULONGLONG) code_cmp_lregister(USE_CREG,l1,cond); #endif else code_cmp_register(USE_CREG,l1,cond); return; } } int is_code(NMTBL *fnptr) { int type = fnptr->ty; return type==CODE|| (type>0 && car(type)==CODE); } int is_function(NMTBL *fnptr) { int type = fnptr->ty; return type==FUNCTION || (type>0 && car(type)==FUNCTION); } int function_type(int e1,int *dots) { int ret_type,t; ret_type = cadr(e1); if (ret_type==CHAR) ret_type=INT; /* check argments type is DOTS? */ t = caddr(e1); if (/* t==0 || */ t==DOTS) *dots = 1; else { *dots = 0; for(;t;t = cadr(t)) { if (car(t)==DOTS) *dots = 1; } } return ret_type; } static int register_to_lvar(int e) { error(REG_ERR); return 0; #if 0 途中でレジスタからLVARに変更しても、間に合わない。 NMTBL *n = (NMTBL*)caddr(e); int reg = cadr(e); int tag = car(e); int lvar; int t; if (!n||n==&null_nptr) error(REG_ERR); if (tag==REGISTER) { n->dsp = new_lvar(size_of_int); t = INT; } else if (tag==DREGISTER) { n->dsp = new_lvar(size_of_double); t = DOUBLE; } else if (tag==FREGISTER) { n->dsp = new_lvar(size_of_float); t = DOUBLE; } else if (tag==LREGISTER) { n->dsp = new_lvar(size_of_longlong); t = LONGLONG; } else error(-1); n->sc = LVAR; lvar = list2(LVAR,n->dsp); g_expr_u(assign_expr0(list2(LVAR,n->dsp),list3(tag,reg,(int)n),t,t)); if (tag==REGISTER||tag==DREGISTER||tag==FREGISTER||tag==LREGISTER) { free_register(reg); return g_expr0(lvar); #endif } // parallel assignment of registers. // // target = list3(target_regnum,next,source_regnum); void parallel_rassign(int assigns) { int free,tmp,tmp_target,remains,t0,t2,src; tmp = 0; for(;;) { remains = 0; // find free target for(free=assigns;free;free=cadr(free)) { if (!caddr(free)) continue; // already done 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) { code_rlvar(tmp,tmp_target); } return; } if (free) { // free target if (t0!=caddr(free)) code_assign_register(t0,0,caddr(free)); } 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); tmp_target = car(free); code_assign_lvar(tmp,caddr(free),0); } caddr(free)=0; // mark it done } } /* 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 int overrap(int t,int sz,int source) { int s,s0,s1; int t0=cadr(t); int t1=t0+sz; for(;source;source=cadr(source)) { s=car(source); s0=cadr(s); if(car(s)==REGISTER && car(t)==REGISTER) { if(s0==t0) return s; } else if (is_same_type(s,t)) { s1=s0+caddr(source); #if DEBUG_PARALLEL_ASSIGN>1 printf("# ovedrrap source %d t0 %d t1 %d\n",car(car(t)),t0,t1); printf("# ovedrrap target %d s0 %d s1 %d\n",car(car(source)),s0,s1); printf("# ovedrrap equal = %d\n",((t0<=s0&&s0<t1)||(t0<s1&&s1<=t1))); #endif if((t0<=s0&&s0<t1)||(t0<s1&&s1<=t1)) return s; } } return 0; } void remove_target(int *target,int t,int *use) { int use0=*use; int reg; while(use0) { if (car(use0)==t) { reg = car(caddr(use0)); if (reg==REGISTER||reg==FREGISTER||reg==DREGISTER) free_register(cadr(caddr(use0))); break; } use0 = cadr(use0); } remove0(target,t); } void save_target(int t,int s,int *target,int *use,int sz,int ty) { int e1; /*新しいレジスタ(or スタック)を取得する*/ if (sz==size_of_int && (e1=get_register())!=-1) { e1=list3(REGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); #if FLOAT_CODE } else if (sz==size_of_double && (e1=get_dregister(1))!=-1) { e1=list3(DREGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); } else if (sz==size_of_float && (e1=get_dregister(0))!=-1) { e1=list3(FREGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); #endif #if LONGLONG_CODE } else if (sz==size_of_longlong && (e1=get_lregister())!=-1) { e1=list3(LREGISTER,e1,0); *use=list3(t,*use,e1); g_expr_u(assign_expr0(e1,s,ty,ty)); *target = append4(*target,t,ty,e1); #endif } else { g_expr_u(assign_expr0((e1=list2(LVAR,new_lvar(sz))),s,ty,ty)); *target = append4(*target,t,ty,e1); *use=list3(t,*use,e1); } } int circular_dependency(int t,int s,int *target,int *source) { int target0=*target; int t1,sz,ty,s1; while(target0) { if (cadddr(target0)==s) { t1=car(target0); s=cadddr(target0); sz=size(ty=caddr(target0)); if(t==t1) { #if DEBUG_PARALLEL_ASSIGN printf("# circular dependency %d ty %d+%d sz %d\n",car(t1),ty,cadr(t1),sz); #endif return 1; } if ((s1=overrap(t1,sz,*source))) { /* another overrap start over */ return circular_dependency(t,s1,target,source); } } target0=cadr(target0); } return 0; } void parallel_assign(int *target,int *source,int *processing,int *use) { int t,s,sz,ty,target0,s1; while(*target) { target0=*target; while(target0) { t=car(target0); s=cadddr(target0); sz=size(ty=caddr(target0)); if(car(t)==car(s) && cadr(t)==cadr(s)) { /*書き込み先が自分自身*/ #if DEBUG_PARALLEL_ASSIGN printf("# remove same %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); #endif remove_target(target,t,use); /* 破壊されては困るので、source listからは除かない */ } else if (!(s1=overrap(t,sz,*source))) { /* 重なってないので安心して書き込める */ #if DEBUG_PARALLEL_ASSIGN printf("# normal assign %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); #endif g_expr_u(assign_expr0(t,s,ty,ty)); remove_target(target,t,use); remove0(source,s); } else { if(circular_dependency(t,s1,target,source)) { #if DEBUG_PARALLEL_ASSIGN printf("# saving %d ty %d+%d sz %d\n",car(t),ty,cadr(t),sz); #endif remove_target(target,t,use); remove0(source,s); save_target(t,s,target,use,sz,ty); } } target0=cadr(target0); } } } void remove0(int *parent,int e) { int list; while ((list=*parent)) { if (car(list)==e) { *parent= cadr(list); return; } else { parent=&cadr(list); } } } /* void remove0_all(int *parent,int e) { int list; while ((list=*parent)) { if (car(list)==e) { *parent= cadr(list); } else { parent=&cadr(list); } } } */ int is_simple(int e1) { return ( e1==CONST || e1==FNAME || e1==LVAR || e1==REGISTER ||e1==DREGISTER || e1==FREGISTER || e1==LREGISTER || e1==GVAR || e1==RGVAR || e1==RLVAR || e1==CRLVAR || e1==CRGVAR || e1==DRLVAR || e1==FRLVAR || e1==LRLVAR || e1==CURLVAR || e1==SURLVAR || e1==CURGVAR || e1==SURGVAR ); } int is_same_type(int e1,int e2) { int ce1=car(e1); int ce2=car(e2); return ( (ce1==LVAR && (ce2==RLVAR||ce2==CRLVAR||ce2==FRLVAR||ce2==DRLVAR)) || (ce1==LVAR && (ce2==SRLVAR||ce2==SURLVAR||ce2==CURLVAR)) || (ce2==LVAR && (ce1==RLVAR||ce1==CRLVAR||ce1==FRLVAR||ce1==DRLVAR)) || (ce2==LVAR && (ce1==SRLVAR||ce1==SURLVAR||ce1==CURLVAR)) || (ce2==LVAR && (ce1==LRLVAR)) || (ce1==GVAR && (ce2==RGVAR||ce2==CRGVAR||ce2==FRGVAR||ce2==DRGVAR)) || (ce1==GVAR && (ce2==SRGVAR||ce2==SURGVAR||ce2==CURGVAR)) || (ce2==GVAR && (ce1==RGVAR||ce1==CRGVAR||ce1==FRGVAR||ce1==DRGVAR)) || (ce2==GVAR && (ce1==SRGVAR||ce1==SURGVAR||ce1==CURGVAR)) || (ce2==GVAR && (ce1==LRGVAR)) ); } int is_memory(int e1) { int ce1=car(e1); return ( ce1==LVAR ||ce1==RLVAR||ce1==CRLVAR || ce1==DRLVAR || ce1==LRLVAR || ce1==GVAR ||ce1==RGVAR||ce1==CRGVAR || ce1==DRGVAR || ce1==LRGVAR || ce1==FRLVAR || ce1==FRGVAR || ce1==CURGVAR ||ce1==SURGVAR||ce1==SRGVAR || ce1==REGISTER|| ce1==DREGISTER || ce1==FREGISTER || ce1==LREGISTER ); } void jump(int e1, int env) { int e2,e3,e4,sz,arg_size,ty,regs,fregs; int t0,s0,r,reg; NMTBL *code0 = 0; int target = 0; int source = 0; int processing = 0; int use = 0; /* まず、サイズを計算しながら、決まった形に落す。 */ arg_size = 0; regs = 0; fregs = 0; for (e3 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) { e2 = car(e3); sz = size(ty=caddr(e3)); if (scalar(ty) && (r = get_input_register_var(regs,0,1))) { target=list4(r,target,ty,e2); regs++; } else if (ty==FLOAT && (r = get_input_dregister_var(fregs,0,1,0))) { target=list4(r, target,ty,e2); fregs++; } else if (ty==DOUBLE && (r = get_input_dregister_var(fregs,0,1,1))) { target=list4(r, target,ty,e2); fregs++; } else { target=list4(list2(LVAR,0), target,ty,e2); } /* keep arg space for register variables */ arg_size += sz; #if DEBUG_PARALLEL_ASSIGN printf("# target %d ty %d+%d sz %d\n",car(car(target)),ty,cadr(car(target)),sz); #endif } /* disp を飛び先似合わせて修正 */ if (is_code(fnptr)) { if (-arg_size<disp) disp = -arg_size; } else { if (disp_offset-arg_size<disp) disp = disp_offset-arg_size; } /* 複雑な式を前もって計算しておく */ /* 必要なら局所変数を用いる。 */ /* 局所変数へのオフセットを覚えておく */ for (e2 = target; e2; e2 = cadr(e2)) { t0=car(e2); s0=cadddr(e2); sz=size(ty=caddr(e2)); if(car(t0)==LVAR) { /* ここで、書込先アドレスを決める */ cadr(t0)=-arg_size; } arg_size-=sz; if (!is_simple(car(s0))) { g_expr_u(assign_expr0((e4=list2(LVAR,new_lvar(sz))),s0,ty,ty)); use=list3(ty,use,e1); cadddr(e2)=e4; s0=e4; } else if (is_same_type(t0,s0)) { if(cadr(t0)==cadr(s0)) { #if DEBUG_PARALLEL_ASSIGN printf("# remove same memory %d ty %d+%d sz %d\n",car(t0),ty,cadr(t0),sz); #endif /* we should check size also (but currently useless) */ remove0(&target,t0); /* still we have source to avoid overwrite */ } } if(is_memory(s0)) { source=list3(s0,source,sz); #if DEBUG_PARALLEL_ASSIGN printf("# source %d ty %d+%d sz %d\n",car(car(source)),ty,cadr(car(source)),sz); #endif } } /* compute jump address */ e2 = cadr(e1); if (car(e2) == FNAME) { code0=(NMTBL *)cadr(e2); if (!is_code(code0)) { error(TYERR); return; } } else { /* indirect */ g_expr(e2); emit_push(); } if (env) { g_expr(env); emit_push(); } /* 並列代入を実行 */ parallel_assign(&target,&source,&processing,&use); while (use) { reg = car(caddr(use)); if (reg==REGISTER||reg==FREGISTER||reg==DREGISTER||reg==LREGISTER) free_register(cadr(caddr(use))); else if (car(caddr(use))==LVAR) free_lvar(cadr(caddr(use))); use=cadr(use); } if(target) error(-1); if (env) { /* change the frame pointer */ e3 = emit_pop(0); code_frame_pointer(e3); emit_pop_free(e3); } else if (is_function(fnptr)) { if (car(e2) != FNAME) { e2 = emit_pop(0); code_fix_frame_pointer(disp_offset); code_indirect_jmp(e2); emit_pop_free(e2); return; } code_fix_frame_pointer(disp_offset); } if (car(e2) == FNAME) { code_jmp(code0->nm); } else { e2 = emit_pop(0); code_indirect_jmp(e2); emit_pop_free(e2); } } void machinop(int e1) { int e2,e3,op; e2 = cadr(e1); op = car(e1); e3 = caddr(e1); if (code_const_op_p(op,e3)) { g_expr(e2); oprtc(op,USE_CREG,e3); return; } g_expr(e3); emit_push(); g_expr(e2); tosop(op,USE_CREG,(e2=pop_register())); emit_pop_free(e2); return; } #if FLOAT_CODE void dmachinop(int e1,int d) { int e2,e3,op; e2 = cadr(e1); op = car(e1); e3 = caddr(e1); g_expr(e3); emit_dpush(d); g_expr(e2); dtosop(car(e1),USE_CREG,(e2=emit_dpop(d))); emit_dpop_free(e2,d); return; } #endif #if LONGLONG_CODE void lmachinop(int e1) { int e2,e3,op; e2 = cadr(e1); op = car(e1); e3 = caddr(e1); if (code_lconst_op_p(op,e3)) { g_expr(e2); loprtc(op,USE_CREG,e3); return; } g_expr(e3); emit_lpush(); g_expr(e2); ltosop(car(e1),USE_CREG,(e2=emit_lpop())); emit_lpop_free(e2); return; } #endif 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 (is_same_type(e2,e4)&&cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } g_expr(e4); emit_push(); g_expr(e2); xreg = emit_pop(0); /* 一般的にはコピーのオーバラップの状況は実行時にしかわからない */ /* しかし、わかる場合もある */ if (car(e4)==RSTRUCT) e4=cadr(e4); if (is_same_type(e2,e4)) { if(cadr(e2)<cadr(e4)) { offset=sz; sz=-sz;} det=1; } else { det = 0; offset=0; } emit_copy(xreg,USE_CREG,sz,offset,1,det); emit_pop_free(xreg); return; } static void assign_opt(int e5,int e2,int e4,int byte) { int reg; /* e2=e4 */ if (e5==REGISTER) { reg = cadr(e4); switch(car(e2)) { case GVAR: code_assign_gvar(e2,reg,byte); return; case LVAR: code_assign_lvar(cadr(e2),reg,byte); return; case REGISTER: code_assign_register(cadr(e2),byte,reg); return; } g_expr(e2); code_assign(USE_CREG,byte,reg); return; } /* e2 is register now */ if (car(e2)!=REGISTER) error(-1); reg = cadr(e2); switch(e5) { case CRGVAR: case CURGVAR: code_crgvar(e4,reg,e5==CRGVAR,1); return; case SRGVAR: case SURGVAR: code_crgvar(e4,reg,e5==SRGVAR,size_of_short); return; case RGVAR: code_rgvar(e4,reg); return; case CRLVAR: case CURLVAR: code_crlvar(cadr(e4),reg,e5==CRLVAR,1); return; case SRLVAR: case SURLVAR: code_crlvar(cadr(e4),reg,e5==SRLVAR,size_of_short); return; case RLVAR: code_rlvar(cadr(e4),reg); return; case GVAR: code_gvar(e4,reg); return; case LVAR: code_lvar(cadr(e4),reg); return; case CONST: code_const(cadr(e4),reg); return; case ADDRESS: if (car(cadr(e4))==STRING) code_string(cadr(e4),reg); else code_gvar(cadr(e4),reg); return; case FNAME: code_fname((NMTBL*)cadr(e4),reg); return; case STRING: code_string(e4,reg); return; default: error(-1); } } void assign(int e1) { int e2,e4,byte,e5; byte=(car(e1) == CASS)?1:(car(e1) == SASS)?size_of_short:0; /* e2=e4 */ e2 = cadr(e1); e4 = caddr(e1);e5=car(e4); if (is_same_type(e2,e4)&&cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } if (!use && ( (e5==REGISTER) || (car(e2)==REGISTER&&( e5== CRGVAR || e5== CRLVAR || e5== RGVAR || e5== RLVAR || e5== CURGVAR || e5== CURLVAR || e5== SURGVAR || e5== SURLVAR || e5== GVAR || e5== LVAR || e5== CONST || e5== FNAME || e5== STRING || (e5==ADDRESS&&car(cadr(e4))==STRING) || (e5==ADDRESS&&car(cadr(e4))==GVAR) )))) { assign_opt(e5,e2,e4,byte); return; } switch(car(e2)) { case GVAR: /* i=3 */ g_expr(e4); code_assign_gvar(e2,USE_CREG,byte); return; case LVAR: g_expr(e4); code_assign_lvar(cadr(e2),USE_CREG,byte); return; case REGISTER: g_expr(e4); code_assign_register(cadr(e2),byte,USE_CREG); return; } g_expr(e2); emit_push(); g_expr(e4); e2 = emit_pop(0); code_assign(e2,byte,USE_CREG); emit_pop_free(e2); return; } #if FLOAT_CODE static void dassign_opt(int e5,int e2,int e4,int d) { int reg; /* e2=e4 */ if (e5==DREGISTER||e5==FREGISTER) { reg = cadr(e4); switch(car(e2)) { case GVAR: /* i=3 */ code_dassign_gvar(e2,reg,d); return; case LVAR: code_dassign_lvar(cadr(e2),reg,d); return; case DREGISTER: case FREGISTER: if (reg!=cadr(e2)) code_dassign_dregister(cadr(e2),d,reg); return; default: error(-1); } } /* e2 is register now */ if (car(e2)!=DREGISTER && car(e2)!=FREGISTER) error(-1); reg = cadr(e2); switch(e5) { case FRGVAR: case DRGVAR: code_drgvar(e4,d,reg); return; case FRLVAR: case DRLVAR: code_drlvar(cadr(e4),d,reg); return; case FCONST: case DCONST: code_dconst(e4,reg,d); return; default: error(-1); } } void dassign(int e1) { int e2,e3,e4,d,e5; /* e2=e4 */ e2 = cadr(e1); e3 = cadr(e2); e4 = caddr(e1); e5=car(e4); if (is_same_type(e2,e4)&&cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } if (car(e1)==DASS) d=1; else if (car(e1)==FASS) d=0; else error(-1); if (!use && ( (e5==DREGISTER) || (e5==FREGISTER) || (car(e2)==DREGISTER&&(e5==DRGVAR||e5==DRLVAR||e5==DCONST))|| (car(e2)==FREGISTER&&(e5==FRGVAR||e5==FRLVAR||e5==FCONST)) )) { 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 void lassign_opt(int e5,int e2,int e4) { int reg; /* e2=e4 */ if (e5==LREGISTER) { reg = cadr(e4); switch(car(e2)) { case GVAR: /* i=3 */ code_lassign_gvar(e2,reg); return; case LVAR: code_lassign_lvar(cadr(e2),reg); return; case LREGISTER: if (reg!=cadr(e2)) code_lassign_lregister(cadr(e2),reg); return; default: error(-1); } } /* e2 is register now */ if (car(e2)!=LREGISTER) error(-1); reg = cadr(e2); switch(e5) { case LRGVAR: code_lrgvar(e4,reg); return; case LRLVAR: code_lrlvar(cadr(e4),reg); return; case LCONST: code_lconst(e4,reg); return; default: error(-1); } } void lassign(int e1) { int e2,e3,e4,e5; /* e2=e4 */ e2 = cadr(e1); e3 = cadr(e2); e4 = caddr(e1); e5=car(e4); if (is_same_type(e2,e4)&&cadr(e2)==cadr(e4)) { if (use) g_expr(e4); return; } if (!use && ( (e5==LREGISTER) || (car(e2)==LREGISTER&&(e5==LRGVAR||e5==LRLVAR||e5==LCONST)) )) { lassign_opt(e5,e2,e4); return; } switch(car(e2)) { case GVAR: g_expr(e4); code_lassign_gvar(e2,USE_CREG); return; case LVAR: g_expr(e4); code_lassign_lvar(cadr(e2),USE_CREG); return; case LREGISTER: g_expr(e4); code_lassign_lregister(cadr(e2),USE_CREG); return; } g_expr(e2); emit_push(); g_expr(e4); e2 = emit_pop(0); code_lassign(e2,USE_CREG); emit_pop_free(e2); return; } #endif void assop(int e1) { int e2,e3,byte,op,sign,size; int n,t; /* e2 op= e3 */ if (car(e1) == CUASSOP) { byte = 1; sign = 0; size = 1; } else if (car(e1) == CASSOP) { byte = 1; sign = 1; size = 1; } else if (car(e1) == SUASSOP) { byte = size_of_short; sign = 0; size = size_of_short; } else if (car(e1) == SASSOP) { byte = size_of_short; sign = 1; size = size_of_short; } else { byte = 0; sign = 1; size = size_of_int; } e2 = cadr(e1); if (car(e2)==INDIRECT) e2=cadr(e2); e3 = caddr(e1); op = cadddr(e1); if (car(e2)==REGISTER) { if (code_const_op_p(op,e3)) { oprtc(op,cadr(e2),e3); } else { g_expr(e3); code_register_assop(cadr(e2),USE_CREG,op,byte); } if (use) { code_register(cadr(e2),USE_CREG); } return; } if (car(e3)==CONST) { /* e2 = e2 op e3; */ t = sign?INT:UNSIGNED; // oprtc expected if (car(e2)==LVAR||car(e2)==GVAR) { g_expr(assign_expr0(e2,list3(op,rvalue_t(e2,t),e3),t,t)); return; } /* new = &e2 */ /* *new = *new op e3 */ n = list2(LVAR,new_lvar(size_of_int)); g_expr_u(assign_expr0(n,list2(ADDRESS,e2),INT,INT)); g_expr(assign_expr0(list2(INDIRECT,n),list3(op,n,e3),t,t)); free_lvar(cadr(n)); return; } g_expr(e3); emit_push(); g_expr(e2); code_assop(op,USE_CREG,byte,sign); return; } #if FLOAT_CODE void dassop(int e1) { int e2,e3,op,d; /* e2 op= e3 */ d = (car(e1) == DASSOP); e2 = cadr(e1); if (car(e2)==INDIRECT) e2=cadr(e2); e3 = caddr(e1); op = cadddr(e1); g_expr(e3); if (car(e2)==DREGISTER||car(e2)==FREGISTER) { emit_dpush(d); code_register_dassop(cadr(e2),op,d); if (use) code_dregister(cadr(e2),USE_CREG,d); return; } emit_dpush(d); g_expr(e2); code_dassop(op,USE_CREG,d); return; } #endif #if LONGLONG_CODE static int long_sign(int op) { return (op==LUDIV||op==LUMOD||op==LULSHIFT||op==LURSHIFT)?ULONGLONG:LONGLONG; } void lassop(int e1) { int e2,e3,op; int n,t; /* e2 op= e3 */ e2 = cadr(e1); if (car(e2)==INDIRECT) e2=cadr(e2); e3 = caddr(e1); op = cadddr(e1); if (car(e2)==LREGISTER) { if (code_lconst_op_p(op,e3)) { loprtc(op,cadr(e2),e3); if (use) { code_lregister(cadr(e2),USE_CREG); } return; } if (code_lassop_p) { g_expr(e3); emit_lpush(); code_register_lassop(cadr(e2),op); if (use) { code_lregister(cadr(e2),USE_CREG); } return; } } if (!code_lassop_p||car(e3)==LCONST) { /* e2 = e2 op e3; */ t = long_sign(op); if (car(e2)==LREGISTER||car(e2)==LVAR||car(e2)==GVAR) { g_expr(assign_expr0(e2,list3(op,rvalue_t(e2,t),e3),t,t)); return; } /* new = &e2 */ /* *new = *new op e3 */ n = list2(LVAR,new_lvar(size_of_int)); g_expr_u(assign_expr0(n,list2(ADDRESS,e2),INT,INT)); g_expr(assign_expr0(list2(INDIRECT,n),list3(op,n,e3),t,t)); free_lvar(cadr(n)); return; } g_expr(e3); if (car(e2)==LREGISTER) { emit_lpush(); code_register_lassop(cadr(e2),op); if (use) code_lregister(cadr(e2),USE_CREG); return; } emit_lpush(); g_expr(e2); code_lassop(op,USE_CREG); return; } #endif void cmpdimm(int e, int csreg,int label,int cond) { code_cmpdimm(e, csreg,label,cond); } int csvalue() { return code_csvalue(); } int fwdlabel(void) { return labelno++; } void fwddef(int l) { control=1; if (!chk) code_label(l); } int backdef(void) { control=1; if (!chk) code_label(labelno); return labelno++; } void def_label(int cslabel, int dlabel) { int fl; fl = 0; if (control) { jmp(fl=fwdlabel()); } fwddef(cslabel); if (dlabel) jmp(dlabel); if (fl) { fwddef(fl); } } void gen_source(char *s) { printf("%s",s); } void ret(void) { code_set_return_register(1); jmp(retlabel); } void opening(char *filename) { emit_init(); if (!chk) code_opening(filename); } void closing() { if (!chk) code_closing(); } int contains_in_list(int e,int type) { while(e) { if(contains(car(e),type)) return 1; e = cadr(e); } return 0; } int contains(int e,int type) { while(e) { if (car(e)==type) return 1; if (!car(e)) return 0; if (LIST_ARGS(car(e))){ /* list arguments */ return contains_in_list(caddr(e),type); } else if (UNARY_ARGS(car(e))) { /* unary operators */ e = cadr(e); continue; } else if (BINARY_ARGS(car(e))) { /* biary operators */ if (contains(cadr(e),type)) return 1; e = caddr(e); continue; } else if (TARNARY_ARGS(car(e))) { /* tarary operators */ if (contains(cadr(e), type)) return 1; if (contains(caddr(e),type)) return 1; e = cadddr(e); continue; } else if (NULLARY_ARGS(car(e))) { /* nullary operators */ return 0; } else { fprintf(stderr,"Unknown Tree ID %d\n",car(e)); error(-1); return 0; } } return 0; } 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; } int contains_p(int e,int (*p)(int)) { while(e) { if (!car(e)) return 0; if (p(car(e))) return 1; if (LIST_ARGS(car(e))){ /* list arguments */ return contains_in_list_p(caddr(e),p); } else if (UNARY_ARGS(car(e))) { /* unary operators */ e = cadr(e); continue; } else if (BINARY_ARGS(car(e))) { /* biary operators */ if (contains_p(cadr(e),p)) return 1; e = caddr(e); continue; } else if (TARNARY_ARGS(car(e))) { /* tarary operators */ if (contains_p(cadr(e), p)) return 1; if (contains_p(caddr(e),p)) return 1; e = cadddr(e); continue; } else if (NULLARY_ARGS(car(e))) { /* nullary operators */ return 0; } else { fprintf(stderr,"Unknown Tree ID %d\n",car(e)); error(-1); return 0; } } return 0; } #if ASM_CODE /* __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (a ddr)); asm string : output constraint parameter : input constraint parameter : opt 1: asm string %1,%2 will be replaced by register or value 2: constraint gcc constraint sting prefix = overwrite by this asm for output & overwrite by this asm and can't be used as input register ignored in this compiler constraints m value expression is modified (no coresponding 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 code_asm(int asm0,int in,int out,int opt,int e) { int i,e1,n; int repl = 0; int repl0; int assign = 0; char *p; printf("# asm\n"); in = reverse0(in); out = reverse0(out); e = reverse0(e); for(i=out;i;i=cadr(i)) { p = (char*)cadr(car(i)); e1 = car(e); e = cadr(e); repl = asm_operand(p,e1,ASM_OUTPUT,repl,0,0); if (car(car(repl))==REGISTER) { assign = list2(assign_expr0(e1,car(repl),INT,INT),assign); } } repl0 = repl; n = length(repl0); for(i=in;i;i=cadr(i)) { p = (char*)cadr(car(i)); e1 = car(e); e = cadr(e); repl = asm_operand(p,e1,ASM_INPUT,repl,n,repl0); if (car(car(repl))==REGISTER) { g_expr_u(assign_expr0(car(repl),e1,INT,INT)); } } repl = reverse0(repl); replace_asm_string((char*)cadr(asm0),repl); for(i=assign;i;i=cadr(i)) { g_expr_u(car(i)); } free_asm_operand(repl); // no check for opt } #endif /* end */