Mercurial > hg > CbC > old > device
view mc-inline.c @ 856:d9dd3e6e7c5f
macro compatibility
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 22 Nov 2011 05:44:49 +0900 |
parents | 59ebc5cb2a99 |
children | 5313ed059cee |
line wrap: on
line source
/* Micro-C Partial Evaluator 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. ***********************************************************************/ /* Inline handler inline code is stored as parse tree expr already has parse tree statement part is handled here st_hoge() code generator (called from gexpr()) p_hoge() partial evaluator called in gen_inline() after p_hoge(), it contains no ST_* node. PVAR has an offset for pvartable, it can be constant, local variable or global variable other complex expression is evaluated before the code expansion We always perform inline expansion. Non static inline function can be referenced from other. Real function body is generated by pfdecl() in mc-parse.c. */ #include <stdio.h> #include "mc.h" #include "mc-parse.h" #include "mc-codegen.h" #include "mc-switch.h" #include "mc-code.h" #include "mc-inline.h" static int pvartable; static int pdisp; static int ret_register,ret_reg_mode; static int inline_lvars; /* Basic code generator from parse tree */ extern void st_decl(int e1){ // NMTBL *n = (NMTBL *)caddr(e1); // int stmode = cadddr(e1); } extern void st_if(int e1){ int l1,l2,slfree; int e2=caddr(e1),e3; // conv->if_(); slfree=lfree; checkret(); l1 = bexpr(car(e2),0,fwdlabel()); // conv->if_then_(); g_expr_u(cadr(e2)); checkret(); if ((e3=caddr(e2))) { // else // conv->if_else_(); if ((l2 = control)) gen_jmp(l2=fwdlabel()); fwddef(l1); g_expr_u(e3); checkret(); if (l2) fwddef(l2); } else { fwddef(l1); } // conv->if_endif_(); } extern void st_do(int e1){ int sbreak,scontinue,l; sbreak=blabel; scontinue=clabel; blabel=fwdlabel(); clabel=fwdlabel(); control=1; checkret(); l=backdef(); // conv->dowhile_(); g_expr_u(cadddr(e1)); checkret(); // conv->dowhile_cond_(); bexpr(caddr(e1),1,l); // conv->dowhile_end_(); fwddef(blabel); clabel=scontinue; blabel=sbreak; } extern void st_while(int e1){ int sbreak,scontinue,e; sbreak=blabel; scontinue=clabel; blabel=fwdlabel(); control=1; checkret(); clabel=backdef(); // conv->while_(); // conv->while_body_(); if(!(e=cadddr(e1))) { bexpr(caddr(e1),1,clabel); // conv->sm_(); } else { bexpr(caddr(e1),0,blabel); g_expr_u(e); checkret(); if(control) gen_jmp(clabel); } // conv->while_end_(); fwddef(blabel); clabel=scontinue; blabel=sbreak; } extern void st_for(int e1){ int p0,p1,p2,body; int l,e; int sbreak=blabel; int scontinue=clabel; e = caddr(e1); p0 = car(e); p1 = cadr(e); p2 = caddr(e); body = cadddr(e); blabel=fwdlabel(); // conv->for_(); if (p0) { checkret(); g_expr_u(p0); } // conv->for1_(); control=1; checkret(); l=backdef(); if (p1) { bexpr(p1,0,blabel); } // conv->for2_(); // conv->for_body_(); if (!p2) { clabel=l; g_expr_u(body); checkret(); } else { clabel=fwdlabel(); g_expr_u(body); checkret(); fwddef(clabel); g_expr_u(p2); } // conv->for_end_(); gen_jmp(l); fwddef(blabel); clabel=scontinue; blabel=sbreak; } extern void st_switch(int e1){ int sbreak,scase,sdefault,slfree,svalue,slist; int cst,e; checkret(); slist = cslist; cslist = 0; sbreak=blabel; /* save parents break label */ blabel=fwdlabel(); sdefault=dlabel; /* save parents default label */ dlabel=0; scase=cslabel; /* save parents next case label */ // conv->switch_(); slfree=lfree; svalue=csvalue1; /* save parents switch value */ e =caddr(e1); /* switch value */ if (car(e)==CONST) { cst = 1; csvalue1=glist2(CONST,cadr(e)); gen_jmp( cslabel=fwdlabel()); } else { cst = 0; g_expr(e); /* switch value */ csvalue1=csvalue() ; cslabel = control = 0; } // conv->switch_body_(); g_expr_u(cadddr(e1)); // conv->switch_end_(); checkret(); #if CASE_CODE if (!cst) { if (control) gen_jmp(blabel); genswitch(cslist,cslabel); } else if (!cslist) { if(dlabel) df_label(cslabel,dlabel); else { fwddef(cslabel); } cslist= 1; } #else if (!(cst && cslist)) { if(dlabel) df_label(cslabel,dlabel); else fwddef(cslabel); } #endif free_glist2(csvalue1); if (cst && !cslist) { if(pending_jmp!=cslabel) fwddef(cslabel); else pending_jmp = 0; // cslabel is here } fwddef(blabel); csvalue1=svalue; cslabel=scase; dlabel=sdefault; blabel=sbreak; cslist = slist; } extern void st_comp(int e1){ g_expr_u(caddr(e1)); } extern void st_break(int e1){ checkret(); // conv->break_(); if (control) gen_jmp(blabel); } extern void st_continue(int e1){ checkret(); // conv->continue_(); if (control) gen_jmp(clabel); } extern void st_case(int e1){ #if CASE_CODE int l=0,clist=caddr(e1),c; int cst = (car(csvalue1)==CONST); if (cst) { c=cadr(csvalue1); for(;clist;clist=cadr(clist)) { if (car(clist)==c) break; } if (!clist) return; // no match } else l = fwdlabel(); if (retpending) { ret(); retpending=0; } if (cst) { if (cslist) { // may duplicat csvalue return; } cslist=1; fwddef(cslabel); return; } if (!cslabel) { if (!control) { cmpdimm(car(clist),csvalue1,cslabel=fwdlabel(),1); caddr(clist)=0; } else { error(-1); } } while(clist) { caddr(clist) = l; clist = cadr(c=clist); cadr(c) = 0; // insert destroy cadr of clist cslist=insert_ascend(cslist,c,docase_eq); } fwddef(l); control=1; #else int c,clist,l; int cst = (car(csvalue1)==CONST); clist = caddr(e1); if (cst) { c=cadr(csvalue1); for(;clist;clist=cadr(clist)) { if (car(clist)==c) break; // no match } if (!clist) return; } if (cst) { if (!cslist) { if (retpending) { ret(); retpending=0; } fwddef(cslabel); cslist = 1; } // else error(CSERR); return; } if (retpending) { ret(); retpending=0; } l=fwdlabel(); if (control) { control=0; gen_jmp(l); } if (cslabel) fwddef(cslabel); while(cadr(clist)) { cmpdimm(car(clist),csvalue1,l,0); clist=cadr(clist); } cmpdimm(car(clist),csvalue1,cslabel=fwdlabel(),1); if (l) fwddef(l); #endif } extern void st_default(int e1){ // int cst = (car(csvalue1)==CONST); control=1; checkret(); if (dlabel) error(STERR); // double default: dlabel = backdef(); // conv->case_(0,1); } extern void st_return(int e1){ int e,t; if (!cslabel) gen_jmp(cslabel = fwdlabel()); if(!(e=caddr(e1))) { // no return value retpending = 1; return; } t = type_value(cadr(fnptr->ty)); if (t>0 && (car(t)==STRUCT || car(t)==UNION)) { // copy is included in e, pass the pointer t = list2(POINTER,type_value(cadr(fnptr->ty))); } if (e) { g_expr(e); } if (e && t!=VOID) { if (ret_reg_mode==0) { // return value register is not fixed ret_reg_mode=1; ret_register = code_get_fixed_creg(USE_CREG,t); } else { code_set_fixed_creg(ret_register,1,t); } } // conv->return_end_(); retpending = 1; } extern void st_goto(int e){ int e1; checkret(); e1 = caddr(e); if (car(e1)==RINDIRECT) { gen_indirect_goto(cadr(e1)); return ; } else if (car(e1)==RLVAR) { gen_indirect_goto(e1); return ; } else if (car(e1)==LVAR||car(e1)==FLABEL) { gen_jmp(cadr(e1)); control=0; return ; } else if (car(e1)==JUMP) { /* CbC continuation */ // conv->jump_(env); // should be separate function jump(cadr(e1),caddr(e1)); control=0; // conv->sm_(); return ; } else { error(-1); } } #if ASM_CODE extern void st_asm(int e1){ checkret(); g_expr_u(list3(ASM,caddr(e1),cadddr(e1))); } #endif extern void st_label(int e1){ int lb = caddr(e1); control=1; checkret(); if (car(lb)==LVAR) { // label variable case } else if (car(lb)!=FLABEL) error(-1); fwddef(cadr(lb)); } static char *plinebuf; // last comment in parse tree (for compiler debug) static int plineno; extern void st_comment(int e1){ glineno++; printf("## %d ",glineno); plineno = caddr(e1); gen_comment(plinebuf=(char *)ncadddr(e1)); } /* partial evaluator */ static int p_vartable(int adisp,int ldisp) { int i; int pvartable = getfree(adisp-ldisp); // have to be local heap pdisp = pvartable-ldisp; for(i=ldisp;i<0;i++) { heap[pdisp+i] = 0; } return pvartable; } extern int p_lvar(int e1) { int sz = is_memory(e1); int d = cadr(e1); int d1,e; if ((d1=(heap[pdisp+d]))) return d1; fprintf(stderr,"## undeclared ivar %d\n",d); error(-1); e = heap[pdisp+d]=list3(LVAR,new_lvar(sz),0); inline_lvars = glist2(e,inline_lvars); return e; } static int pfunction(int e) { // list4(INLINE,e1,arglist,ftype); // include code segement case int e1 = pexpr(cadr(e)); int arglist = caddr(e); int newargs = 0; int ftype = cadddr(e); int e3; for (e3 = arglist; e3; e3 = cadr(e3)) { newargs = list3( pexpr(car(e3)), newargs, caddr(e3)); } newargs = reverse0(newargs); return list4(car(e),e1,newargs,ftype); } static int prindirect(int e) { #if 0 int offset = caddr(e); int e1 = pexpr(cadr(e)); e1 = binop(ADD,e1,list2(CONST,offset),list2(POINTER,type),INT); type = cadddr(e); if (car(e1)==LVAR) return rvalue(e1); if (OP(car(e1))==REGISTER && car(cadr(e))==IVAR) return rvalue(e1); return list3(car(e),e1,0); #else int lvar; int offset = caddr(e); int type0; if (offset!=0) error(-1); type = cadddr(e); type0 = type_value(type); if (type0>0 && car(type0)==POINTER) type=set_type_with_attr(cadr(type),type); if (car(lvar=cadr(e))==IVAR) { lvar=p_lvar(cadr(e)); // can be anything.... switch(car(lvar)) { case LVAR: type = cadddr(e); return rvalue(lvar); case REGISTER: case DREGISTER: case FREGISTER: case LREGISTER: case CONST: case FCONST: case DCONST: case LCONST: // should do type check if (offset) error(-1); return lvar; default: error(-1); } } int e2 = pexpr(cadr(e)); if (car(e2)==INDIRECT) e2 = cadr(e2); if (OP(car(e2))==ADD) { int c = caddr(e2); if (car(c)==CONST) { e2 = cadr(e2); offset = cadr(c); } else if (car(c)==LCONST) { e2 = cadr(e2); offset = lcadr(c); } } return list3(car(e),e2,offset); #endif } static int pindirect(int e) { //int lvar; //if (car(lvar=cadr(e))==IVAR) // lvar=p_lvar(cadr(e)); // can be anything.... #if 1 return pexpr(cadr(e)); #else return list3(car(e),pexpr(cadr(e)),caddr(e)); #endif } static int paddress(int e) { // if (car(cadr(e))==INDIRECT) return pexpr(cadr(cadr(e))); return list2(car(e),pexpr(cadr(e))); } static int p_conv(int e1,int e2) { int t,stype = type; if (is_const(e2) && (t=type_of_conv(e1))) { type = INT; e1 = correct_type(e2,t); type = stype; return e1; } return list3(CONV,pexpr(e2),e1); } static int pbinop(int op,int e1,int e2) { e1 = pexpr(e1); e2 = pexpr(e2); if (is_const(e1)||is_const(e2)) { int t; if((t= type_of_bop(op))) return binop(OP(op),e1,e2,t,t); } return list3(op,e1,e2); } static int plor(int op,int e1,int e2) { int e = pexpr(e1); return list3(op,e,pexpr(e2)); } static int pland(int op,int e1,int e2) { int e = pexpr(e1); return list3(op,e,pexpr(e2)); } static int psassign(int e) { int e1 = pexpr(cadr(e)); int e2 = pexpr(caddr(e)); return list4(car(e),e1,e2,cadddr(e)); } static int passign(int e) { int e1 = pexpr(cadr(e)); int e2 = pexpr(caddr(e)); return list3(car(e),e1,e2); } static int passop(int e) { int e1 = pexpr(cadr(e)); int e2 = pexpr(caddr(e)); return list4(car(e),e1,e2,cadddr(e)); } static int pdassign(int e) { int e1 = pexpr(cadr(e)); int e2 = pexpr(caddr(e)); return list3(car(e),e1,e2); } static int pdassop(int e) { int e1 = pexpr(cadr(e)); int e2 = pexpr(caddr(e)); return list4(car(e),e1,e2,cadddr(e)); } static int plassign(int e) { int e1 = pexpr(cadr(e)); int e2 = pexpr(caddr(e)); return list3(car(e),e1,e2); } static int plassop(int e) { int e1 = pexpr(cadr(e)); int e2 = pexpr(caddr(e)); return list4(car(e),e1,e2,cadddr(e)); } static int palloc(int e) { int e1 = pexpr(e); if (car(e1)==CONST) return list2(ADDRESS,list3(LVAR,new_lvar_align(cadr(e1),16),0)); return list2(ALLOCA,e1); } static int pcomma(int e1,int e2) { int e = pexpr(e1); return list3(COMMA,e,pexpr(e2)); } static int prbit_field(int e) { int e1 = list3(car(e),pexpr(cadr(e)),caddr(e)); type = cadr(caddr(e)); // value type return e1; } static int pbassign(int e) { // list4(BASS,e1,e2,list2(BASS,t))); int e1=pexpr(caddr(e)); return list4(car(e),pexpr(cadr(e)),e1,cadddr(e)); } static int pbassop(int e) { int e1 = caddr(e); if (car(e)==BASSOP) e1=pexpr(e1); return list4(car(e),pexpr(cadr(e)),e1,cadddr(e)); } /* variable initialization with offset */ static int passign_data(int var,int target_type, int e,int t,int offset) { int ass,sz,bfd; #if STRUCT_ALIGN if (t!=EMPTY) { int strtype=0; if (t>0 && (car(t)==STRUCT||car(t)==UNION)) strtype=1; sz = size(t); if (lp64 && (sz%size_of_longlong==0||strtype)) { offset = align(offset,size_of_longlong); } else if (sz%size_of_int==0||strtype) { offset = align(offset,size_of_int); } } #endif if (car(e)==ADDRESS||car(e)==GVAR) { if (scalar(t)) { t = list2(POINTER,VOID); // fake } else if (t>0 && car(t)==ARRAY) { } else { error(TYERR); } } if (t==EMPTY) { /* empty space in partial initialization */ return offset+cadr(e); } type = t; // e = rvalue_t(e,t); if (!scalar(type) && (type>0 && (car(type)!=ADDRESS && car(type)!=ARRAY))) e = correct_type(e,target_type); /* 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( offset? lp64?list3(LADD,var,llist2(LCONST,offset)): // binop? list3(ADD,var,list2(CONST,offset)): var, e,target_type,t); // already correct_typed init_vars = list2(ass,init_vars); if (t>0&&car(t)==BIT_FIELD) { 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; } return offset+size(target_type); } static int pdecl_data(int var, int target_type, int init,int offset); static void pflush_decl_data(int var,int sz) { int offset; int offset0=0; int e; int t,offset1=0; int smode=mode; int init = decl_str_init; decl_str_init = 0; mode = STADECL; /* decl_str_init output delayed decl data list4(offset,next,expression,list2(type0,type1)); */ while (init) { offset= car(init); e=caddr(init); t=car(cadddr(init)); // type of source type=cadr(cadddr(init)); // destination type if (offset!=offset0) { // make space passign_data(var,EMPTY,list2(CONST,offset-offset0),EMPTY,offset0); } e = pexpr(e); // offset0 = passign_data(var,type,e,t,offset); offset0 = pdecl_data(var,type,e,offset); init = cadr(init); } offset = offset0; if ((sz=(offset1+sz-offset))>0) passign_data(var,EMPTY,list2(CONST,sz),EMPTY,offset0); local_nptr = 0; mode=smode; } static int str_init_eq() { // error(-1); // duplicate struct field value return 2; // allow override keep unique } static int pdecl_data_array(int var,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 = pexpr(caddr(init)); offset = pdecl_data(var,type0,e,offset); } return offset; } #if 0 static void pzfill(int var, int offset, int sz) { int c0 = list2(CONST,0); int l0 = llist2(LCONST,0L); while(sz>0) { int t,c; switch(sz) { case 1: t = UCHAR; c = c0; break; case 2: t = USHORT; c = c0; break; case 4: t = UNSIGNED; c = c0; break; default: t = ULONGLONG; c = l0; break; } int ass = assign_expr0( offset? lp64?list3(LADD,var,llist2(LCONST,offset)): // binop? list3(ADD,var,list2(CONST,offset)): var, c ,t,t); // already correct_typed init_vars = list2(ass,init_vars); sz -= size(t); offset += size(t); } } #endif static int pdecl_data_field(int var,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 pdecl_data_list(int var,int init,int target_type,int offset) { int type0 = caddr(target_type); /* list of fields */ int e; for(; init; init = cadr(init),type0 = cadr(type0)) { if (car(init)==DECL_DATA) { // casted initilizer ? //error(-1); e = cadr(init); // value if (!e) continue; // {...,} case e = pexpr(e); offset = pdecl_data(var,caddr(init),e,offset); continue; } // ordered data if (car(init)!=DECL_DATA_LIST) { error(-1); } e = caddr(init); if (!e) continue; // {...,} case e = pexpr(e); offset = pdecl_data(var,car(type0),e,offset); } return offset; } static int pdecl_data(int var, int target_type, int init,int offset) { int t,e; int save_decl_str_init = decl_str_init; decl_str_init = 0; target_type = type_value(target_type); if (init==0) { // empty declaration // it can happen like a = (struct hoge){}; return offset; } e = cadr(init); if (car(init)==DECL_DATA) { switch(car(e)) { case DECL_DATA_LIST: offset = pdecl_data_list(var,e,target_type,offset); break; case DECL_DATA_FIELD: offset = pdecl_data_field(var,e,target_type,offset); break; case DECL_DATA_ARRAY: offset = pdecl_data_array(var,e,target_type,offset); break; default: type = caddr(init); e = rvalue(e); e = pexpr(e); t = caddr(init); // type of source offset = passign_data(var,target_type,e,t,offset); } } else { error(-1); } if (decl_str_init) { int sz = size(target_type); pflush_decl_data(var,sz); } decl_str_init = save_decl_str_init; return offset; } // handle local variable declaration // initialization is accumrated in init argument // should consider int k=some_compile_time_constant; static int p_decl(int e) { // list4(ST_DECL,parse,(int)n,list3(mode,stmode,ctmode),init); int ctmode=caddr(e); NMTBL *n=ncaddddr(e); int dsp = n->dsp; int v=0; int sstmode = stmode; int smode = mode; int save_init_vars = init_vars; int init = cadddr(e); // variable initialization init_vars = 0; // in real partial evaluation, we have to check whether this variable // is used or not. if (ctmode) { mode = car(ctmode); stmode = cadr(ctmode); ctmode = caddr(ctmode); } else { mode = LDECL; stmode = 0; ctmode = 0; } switch(stmode) { case EXTRN: case EXTRN1: case STATIC: // def(n,ctmode); we don't need this. already done. // stmode = sstmode; if (init) error(-1); stmode = sstmode; mode = smode; init_vars = save_init_vars; return pexpr(cadr(e)); #if 1 case REGISTER: switch(n->ty) { case ULONGLONG: case LONGLONG: v = get_lregister_var(n); break; case FLOAT: v = get_dregister_var(n,0); break; case DOUBLE: v = get_dregister_var(n,1); break; default: if (scalar(n->ty)) v = get_register_var(n); else error(TYERR); } break; #endif // case LLDECL: LLDECL is mode, not stmode (bad design) // v = list2(FLABEL,fwdlabel()); break; default: if (mode==STADECL) { if (init) { v = list3n(GVAR,0,n); gen_decl_data(init,v); } stmode = sstmode; mode = smode; init_vars = save_init_vars; return pexpr(cadr(e)); } if (n->sc==FLABEL) v = list3n(LVAR,fwdlabel(),n); else { NMTBL tn; tn = *n; code_lvar_alignment(disp,&tn,n->ty,size(n->ty)); v = list3n(LVAR,tn.dsp,n); } } if (n->sc!=FLABEL) inline_lvars = glist2(v,inline_lvars); if (heap[pdisp+dsp]) { fprintf(stderr,"## double p_decl %s %s\n",(ncaddr(heap[pdisp+dsp]))->nm,n->nm); error(-1); } heap[pdisp+dsp]=v; stmode = sstmode; mode = smode; if (init) { pdecl_data(v,n->ty,init,0); if (init_vars) { int e1 = pexpr(cadr(e)); init_vars = reverse0(init_vars); while (init_vars) { e1 = list3(ST_COMP,e1,car(init_vars)); init_vars = cadr(init_vars); } init_vars = save_init_vars; return e1; } } init_vars = save_init_vars; return pexpr(cadr(e)); } static int p_if(int e1) { int cond,l1,l2; int e2=caddr(e1),e3; cond = pexpr(car(e2)); // conv->if_then_(); l1 = pexpr(cadr(e2)); if ((e3=caddr(e2))) { // else l2 = pexpr(e3); } else { l2 = 0; } return list3(ST_IF,pexpr(cadr(e1)),list3(cond,l1,l2)); } static int p_do(int e) { int e2 = pexpr(caddr(e)); int e3 = pexpr(cadddr(e)); return list4(ST_DO,pexpr(cadr(e)),e2,e3); } static int p_while(int e) { int e2 = pexpr(caddr(e)); int e3 = pexpr(cadddr(e)); return list4(ST_WHILE,pexpr(cadr(e)),e2,e3); } static int p_for(int e) { int e1=caddr(e); int p0=pexpr(car(e1)); int p1=pexpr(cadr(e1)); int p2=pexpr(caddr(e1)); int p3=pexpr(cadddr(e1)); // unfolding for constant case? return list3(ST_FOR,pexpr(cadr(e)), list4(p0,p1,p2,p3)); } static int p_switch(int e) { int e2 = pexpr(caddr(e)); // switch variable int e3 = pexpr(cadddr(e)); // a statement in switch // if cadr(e) is a constant, we have to prune case statement. // No we cannot. A statement in case may contain labels or // falling down entry. // case constants are need to be pexpred in p_case. return list4(ST_SWITCH,pexpr(cadr(e)),e2,e3); } static int p_comp(int e) { int e1; e1=pexpr(caddr(e)); return list3(ST_COMP,pexpr(cadr(e)),e1); } static int p_break(int e) { return list2(ST_BREAK,pexpr(cadr(e))); } static int p_continue(int e) { return list2(ST_CONTINUE,pexpr(cadr(e))); } static int p_case(int e) { int new=0,clist = caddr(e); // insert destory clist, we have to copy it now // car(clist) have to be expred, it may contain operators. for(;clist;clist=cadr(clist)) // new=glist3(cexpr(pexpr(car(clist))),new,0); new=glist3(car(clist),new,0); return list3(ST_CASE,pexpr(cadr(e)),reverse0(new)); } static int p_default(int e) { // should be removed if case value is a constant return list2(ST_DEFAULT,pexpr(cadr(e))); } static int p_return(int e) { int e1=pexpr(caddr(e)); return list3(ST_RETURN,pexpr(cadr(e)),e1); } static int p_goto(int e) { int e1,lb,e2; if ((e1=caddr(e))) { switch(car(e1)) { case RINDIRECT: e1=pexpr(e1); break; case CODE: e2=pexpr(cadr(e1)); e1=list3(JUMP,e2,pexpr(caddr(e1))); break; case FLABEL: /* error(-1); */ break; case IVAR: lb = cadr(e1); if (!(e1=heap[pdisp+lb])) { e1 = heap[pdisp+lb]=list2(FLABEL,fwdlabel()); } break; case JUMP: e1 = list3(JUMP,pexpr(cadr(e1)),pexpr(caddr(e1))); break; default: error(-1); } } return list3(ST_GOTO,pexpr(cadr(e)),e1); } static int p_list_expr(int e) { int e3,new = 0; for (e3 = e; e3; e3 = cadr(e3)) { new= list2( pexpr(car(e3)), new); } return reverse0(new); } static int p_asm(int e) { int param=caddr(e); int e1 = p_list_expr(cadddr(e)); return list4(ST_ASM,pexpr(cadr(e)),param,e1); } static int p_label(int e) { int e1,lb; if ((e1=caddr(e))) { switch(car(e1)) { case FLABEL: /* error(-1); */ break; case IVAR: lb = cadr(e1); if (!(e1=heap[pdisp+lb])) { e1 = heap[pdisp+lb]=list2(FLABEL,fwdlabel()); } } } return list3(ST_LABEL,pexpr(cadr(e)),e1); } static int p_label_var(int e) { int d,e1; switch(car(e1=e)) { case LVAR: /* error(-1) */ break; case IVAR: // should this done in p_decl? (in __label__?) d = cadr(e); if (!(e1=(heap[pdisp+d]))) { // error(-1); e1 = heap[pdisp+d]=list3(LVAR,fwdlabel(),caddr(e)); } } return list2(LABEL,e1); } static int p_bool(int e) { error(-1); return e; } static int p_comment(int e) { glineno++; plineno = caddr(e); return list4n(ST_COMMENT,pexpr(cadr(e)),caddr(e),ncadddr(e)); } static int p_inline(int e) { int e3; int narg; /* inline function arguments */ narg = 0; for (e3 = caddr(e); e3; e3 = cadr(e3)) { narg=list3(pexpr(car(e3)),narg,caddr(e3)); } return list4(INLINE,cadr(e),reverse0(narg),cadddr(e)); } extern int pexpr(int e1) { int e2,e3; // if (inmode) error(-1); if (e1==0) return 0; e2 = cadr(e1); switch (car(e1)){ case GVAR: case RGVAR: case CRGVAR: case CURGVAR: case SRGVAR: case URGVAR: case SURGVAR: case REGISTER: case DREGISTER: case FREGISTER: case FRGVAR: case DRGVAR: case LREGISTER: case LRGVAR: case LURGVAR: case CONST: case DCONST: case FCONST: case LCONST: case STRING: case STRINGS: case FNAME: case FLABEL: case BUILTIN_INF: case BUILTIN_INFF: case BUILTIN_INFL: return e1; case RSTRUCT: // list3(RSTRUCT,e,size) return pexpr(e2); case LABEL: return p_label_var(e2); case LVAR: case URLVAR: case RLVAR: case CRLVAR: case CURLVAR: case SRLVAR: case SURLVAR: case FRLVAR: case DRLVAR: case LRLVAR: case LURLVAR: return e1; case IVAR: return p_lvar(e1); case CODE: case FUNCTION: return pfunction(e1); case JUMP: e2 = pexpr(e2); return list3(car(e1),e2,pexpr(cadddr(e1))); case ARRAY: e2 = pexpr(e2); e1 = binop(ADD,e2,pexpr(caddr(e1)),cadddr(e1),caddddr(e1)); return indop(e1); case PERIOD: e2 = pexpr(e2); nptr = ncadddr(e1); type = caddr(e1); return strop(e2,0); case ARROW: type = caddr(e1); e2 = rvalue(e2); e2 = pexpr(e2); nptr = ncadddr(e1); type = caddr(e1); return strop(e2,1); case INLINE: return p_inline(e1); case INDIRECT: return pindirect(e1); case RINDIRECT: case URINDIRECT: case CRINDIRECT: case CURINDIRECT: case SRINDIRECT: case SURINDIRECT: case FRINDIRECT: case DRINDIRECT: case LRINDIRECT: case LURINDIRECT: return prindirect(e1); case ADDRESS: return paddress(e1); case ST_OP: e3=caddr(e1); e1=pexpr(car(e3)); return binop0(e2,e1,pexpr(cadr(e3)),caddr(e3),cadddr(e3)); case MINUS: if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==CONST) return list2(CONST,-cadr(e3)); return list2(car(e1),e3); #if LONGLONG_CODE case LMINUS: if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==LCONST) return llist2(LCONST,-lcadr(e3)); return list2(car(e1),e3); #endif #if FLOAT_CODE case DMINUS: if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==DCONST) return dlist2(DCONST,-dcadr(e3)); if (car(e3)==FCONST) return dlist2(FCONST,-dcadr(e3)); return list2(car(e1),e3); case FMINUS: if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==DCONST) return dlist2(DCONST,-dcadr(e3)); if (car(e3)==FCONST) return dlist2(FCONST,-dcadr(e3)); return list2(car(e1),e3); #endif case CONV: return p_conv(caddr(e1),e2); case BNOT: /* ~ */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==CONST) return list2(CONST,~cadr(e3)); return list2(BNOT,e3); case LNOT: /* ! */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==CONST) return list2(CONST,!cadr(e3)); return list2(LNOT,e3); case PREINC: case UPREINC: if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==CONST) return list2(CONST,cadr(e3)+caddr(e1)); return list4(car(e1),e3,caddr(e1),cadddr(e1)); case POSTINC: case UPOSTINC: if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==CONST) return e3; return list4(car(e1),e3,caddr(e1),cadddr(e1)); #if FLOAT_CODE case DPREINC: /* ++d */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==FCONST) return dlist2(FCONST,dcadr(e3)+cadr(e2)); if (car(e3)==DCONST) return dlist2(DCONST,dcadr(e3)+cadr(e2)); return list4(car(e1),e3,caddr(e1),cadddr(e1)); case DPOSTINC: /* d++ */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==FCONST||car(e3)==DCONST) return e3; return list4(car(e1),e3,caddr(e1),cadddr(e1)); case FPREINC: /* ++f */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==FCONST) return dlist2(FCONST,dcadr(e3)+cadr(e2)); if (car(e3)==DCONST) return dlist2(DCONST,dcadr(e3)+cadr(e2)); return list4(car(e1),e3,caddr(e1),cadddr(e1)); case FPOSTINC: /* f++ */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==FCONST||car(e3)==DCONST) return e3; return list4(car(e1),e3,caddr(e1),cadddr(e1)); #endif #if LONGLONG_CODE case LPREINC: /* ++d */ case LUPREINC: /* ++d */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==LCONST) return llist2(LCONST,lcadr(e3)+cadr(e2)); return list4(car(e1),e3,caddr(e1),cadddr(e1)); case LPOSTINC: /* d++ */ case LUPOSTINC: /* d++ */ if ((e3 = pexpr(e2))==e2) return e1; if (car(e3)==LCONST) return e3; return list4(car(e1),e3,caddr(e1),cadddr(e1)); #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: #if FLOAT_CODE case DMUL: case DDIV: case DADD: case DSUB: case DCMP: case DCMPGE: case DCMPEQ: case DCMPNEQ: case FMUL: case FDIV: case FADD: case FSUB: case FCMP: case FCMPGE: case FCMPEQ: case FCMPNEQ: #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: #endif return pbinop(car(e1),e2,caddr(e1)); // relational operator case GT: case UGT: case GE: case UGE: case LT: case ULT: case LE: case ULE: case LOP+GT: case LOP+UGT: case LOP+GE: case LOP+UGE: case LOP+LT: case LOP+ULT: case LOP+LE: case LOP+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: case LOP+EQ: case LOP+NEQ: return pbinop(car(e1),e2,caddr(e1)); case LAND: return pland(car(e1),cadr(e1),caddr(e1)); case LOR: return plor(car(e1),cadr(e1),caddr(e1)); case LCOND: case DCOND: case FCOND: case COND: case UCOND: case LUCOND: e2 = pexpr(e2); if (car(e2)==CONST) return caddr(e1)? pexpr(cadr(e2)?caddr(e1):cadddr(e1)) : pexpr(cadr(e2)?e2:cadddr(e1)); // GNU extension h?:g e3=pexpr(caddr(e1)); return list4(car(e1),e2,e3,pexpr(cadddr(e1))); case STASS: return psassign(e1); case ASS: case CASS: case SASS: return passign(e1); case SASSOP: case SUASSOP: case ASSOP: case CASSOP: case CUASSOP: return passop(e1); #if FLOAT_CODE case FASS: case DASS: return pdassign(e1); case DASSOP: case FASSOP: return pdassop(e1); case BUILTIN_FABS: case BUILTIN_FABSF: case BUILTIN_FABSL: e2 = pexpr(e2); if (is_const(e2)) { if (dcadr(e2) >= 0.0 ) return e2; return pexpr(list2(car(e1)==BUILTIN_FABSF? FMINUS:DMINUS,e2)); } return list2(car(e1),e2); #endif #if LONGLONG_CODE case LASS: return plassign(e1); case LASSOP: case LUASSOP: return plassop(e1); #endif case ALLOCA: return palloc(e2); case BUILTINP: return list2(CONST,is_const(pexpr(e2))); case COMMA: return pcomma(e2,caddr(e1)); case RETURN: case ENVIRONMENT: case LCALL: return e1; #if BIT_FIELD_CODE case RBIT_FIELD: return prbit_field(e1); case BIT_FIELD: return list3(BIT_FIELD,pexpr(e2),caddr(e1)); case BASS: return pbassign(e1); case BPREINC: case BPOSTINC: case BASSOP: return pbassop(e1); #endif #if ASM_CODE case ASM: return list3(ASM,list4( car(e2),cadr(e2),caddr(e2),cadddr(e2)), caddr(e1)); #endif case CAST: if (e2==0) { // casted empty structure (struct hoge){} // I think we can skip it. It means nothing in declaration // but it make zero fill, we have to handle it later return 0; } else if (car(e2)==DECL_DATA) { // casted initialized structure (struct hoge){...} return list3(DECL_DATA,pexpr(cadr(e2)),caddr(e2)); } if (type_compatible(caddr(e1),cadddr(e1))) { return pexpr(e2); // rvalue ? } else { #if 1 e2 = pexpr(e2); // will override type type = cadddr(e1); return correct_type(e2,caddr(e1)); #else e2 = pexpr(e2); // will override type e2 = correct_type(e2,caddr(e1)); type = caddr(e1); return e2; #endif // return list4(CAST,pexpr(e2),caddr(e1),cadddr(e1)); } case DECL_DATA: return list3(DECL_DATA,pexpr(e2),caddr(e1)); case DECL_DATA_LIST: case DECL_DATA_ARRAY: return list4(car(e1),pexpr(e2),pexpr(caddr(e1)),cadddr(e1)); case DECL_DATA_FIELD: return list4n(car(e1),pexpr(e2),pexpr(caddr(e1)),ncadddr(e1)); case ST_DECL: return p_decl(e1); case ST_IF: return p_if(e1); case ST_DO: return p_do(e1); case ST_WHILE: return p_while(e1); case ST_FOR: return p_for(e1); case ST_SWITCH: return p_switch(e1); case ST_COMP: return p_comp(e1); case ST_BREAK: return p_break(e1); case ST_CONTINUE: return p_continue(e1); case ST_CASE: return p_case(e1); case ST_DEFAULT: return p_default(e1); case ST_RETURN: return p_return(e1); case ST_GOTO: return p_goto(e1); case ST_ASM: return p_asm(e1); case ST_LABEL: return p_label(e1); case ST_COMMENT: return p_comment(e1); default: error(-1); return p_bool(e1); } return VOID; } /* Prepare pvariable table */ static int replace_inline_parameter(NMTBL *anptr,int t,int e4,int narg,int evals) { int arg; if (has_attr(anptr,KONST) && !has_attr(anptr,HAS_ADDRESS)) { // replacable const variable if (is_memory(e4)) { heap[pdisp+narg]=reference(e4); return evals; } else if (is_const(e4)) { heap[pdisp+narg]=e4; return evals; } } // we need real local variable for this inline arg = heap[pdisp+narg]=list3n(LVAR,new_lvar(size(t)),anptr); inline_lvars = glist2(arg,inline_lvars); evals=list2(assign_expr0(arg,e4,anptr->ty,t),evals); return evals; } /* setup parameter replacement of inline call */ static void enter_inline(NMTBL *n, int e,int toplevel) { int e1 = attr_value(n,INLINE); int arg_disp = cadr(e1); // number of arguments int narg,e3,e4, e5, fargtype; int evals = 0; int t, replace; NMTBL *anptr; fnptr = n; // st_return see this pvartable = p_vartable(arg_disp, /* number of arg */ caddr(e1) /* number of local parameter */); replace = (is_code(fnptr)||toplevel); /* function arguments type */ fargtype = n->dsp; // we cannot do destruct reverse here /* inline function arguments */ narg = 0; if (!fargtype) { goto no_args; // wrong number of arguments } for (e3 = e5 = reverse0(caddr(e)); e3; e3 = cadr(e3)) { anptr = ncadddr(fargtype); if (!anptr) break; // should not happen? t=caddr(e3); // type e4 = car(e3); if (replace) { heap[pdisp+narg]=reference(e4); } else { evals = replace_inline_parameter(anptr,t,e4,narg,evals); } narg ++; fargtype = cadr(fargtype); } caddr(e) = reverse0(e5); // make it normal if (eval_order==NORMAL) evals = reverse0(evals); for(;evals;evals=cadr(evals)) { g_expr_u(car(evals)); } no_args: return; } /* pass local static variable list to our parents clean up and free used inline parameters */ static void leave_inline(int e1,int toplevel) { NMTBL *n; NMTBL *local_statics = ncadddr(e1); // local static list if (retcont && !toplevel) error(STERR); // inline can't handle return/environment except top level if (local_statics && local_statics != &null_nptr) { // append our local static variables to the parent list n = local_statics; while(n->next != &null_nptr) n=n->next; n->next = local_static_list; local_static_list = local_statics; ncadddr(e1) = 0; // prevent duplicate initialize } // free used local variables or registers while(inline_lvars) { int e; int l = car(inline_lvars); switch(car(l)) { case LVAR: free_lvar(cadr(l)); break; case REGISTER: case DREGISTER: case FREGISTER: case LREGISTER: free_register(cadr(l)); } e = cadr(inline_lvars); free_glist2(inline_lvars); inline_lvars = e; } } extern int gen_inline(int e, int toplevel) { // these saved value should be some struct int sretlabel; NMTBL *sfnptr; int svartable; int scslabel = cslabel; int sdisp = pdisp; int sret_register; int sret_reg_mode; int sinline_lvars; int slfree; // int slreg_count=lreg_count; NMTBL *n = (NMTBL*)ncaddr(cadr(e)); int e1 = attr_value(n,INLINE); int parse = car(e1); // inline parse tree int dots; int ret_type = function_type(cadddr(e),&dots); checkret(); checkjmp(-1); svartable = pvartable; scslabel = cslabel; sdisp = pdisp; sret_register = ret_register; sret_reg_mode = ret_reg_mode; sinline_lvars = inline_lvars; slfree=lfree; // int slreg_count=lreg_count; sretlabel = retlabel; sfnptr = fnptr; cslabel = -1; retpending = 0; inline_lvars = 0; if (!toplevel) { retlabel = fwdlabel(); } enter_inline(n,e,toplevel); if (toplevel) { ret_register = code_set_return_register(0); // fnptr required ret_reg_mode = 1; } else { ret_register = 555; ret_reg_mode = 0; } // partial evaluation of parse tree // constant propergation, etc. parse = pexpr(parse); pdisp = sdisp; pvartable = svartable; // generate code if necessary if (ret_type!=VOID) g_expr0(parse); else g_expr_u(parse); if (!toplevel) { checkret(); fwddef(retlabel); control=1; } leave_inline(e1,toplevel); fnptr = sfnptr; retlabel = sretlabel; cslabel = scslabel; ret_register = sret_register; ret_reg_mode = sret_reg_mode; inline_lvars = sinline_lvars; lfree=slfree; return ret_type; } /* end */