view mc-inline.c @ 581:ad9ef203f95b

*** empty log message ***
author kono
date Sun, 15 Jan 2006 22:40:23 +0900
parents aad312f61654
children a5b902b20300
line wrap: on
line source

/* Micro-C Partial Evaluator Part */
/* $Id$ */

#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;
	gexpr(e,1);       /* 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) def_label(cslabel,dlabel);
	else fwddef(cslabel);
    }
#else
    if (!(cst && cslist)) {
	if(dlabel) def_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)));
    } 
    g_expr(e);
    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){
    NMTBL *nptr0;
    int e1,e2,env;

    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)==CODE) {
	/*   CbC continuation */
	// conv->jump_(env);
	// should be separate function
	e2 = cadr(e1);
	env = caddr(e1);
	if (car(e2) == FNAME) {
	    nptr0=(NMTBL *)cadr(e2);
	    if (nptr0->sc==EMPTY)
		nptr0->sc = EXTRN1;
	    else if(nptr0->sc==FUNCTION)
		nptr0->sc = CODE;
	    if (nptr0->ty>0&&car(nptr0->ty)==FUNCTION)
		car(nptr0->ty)=CODE;
	}
	gexpr(list3(CODE,e1,env),0);
	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));
}

extern void
st_comment(int e1){
    glineno++;
    gen_comment((char *)caddr(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;
}

static 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)
{
    int lvar;
    int offset = caddr(e);
    if (car(lvar=cadr(e))==IVAR) {
	lvar=p_lvar(cadr(e)); // can be anything....
	switch(car(lvar)) {
	case LVAR:
	    if(offset) {
		return list3(car(e),lvar,offset);
	    }
	    return rvalue_t(lvar,cadddr(e));
	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;
	}
    }
    return list3(car(e),pexpr(cadr(e)),offset);
}

static int
pindirect(int e)
{
    //int lvar;
    //if (car(lvar=cadr(e))==IVAR)
    //	lvar=p_lvar(cadr(e)); // can be anything....
    return list3(car(e),pexpr(cadr(e)),caddr(e));
}

static int
paddress(int e)
{
    return list2(car(e),pexpr(cadr(e)));
}

static int
p_conv(int e1,int e2)
{
    int t;
    if (is_const(e2) && (t=type_of_conv(e1))) {
	return correct_type(e2,t);
    }
    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_of(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)
{
    return list2(car(e),pexpr(cadr(e)));
}

static int
pcomma(int e1,int e2)
{
    int e = pexpr(e1);
    return list3(COMMA,e,pexpr(e2));
}

static int
prbit_field(int e)
{
    return list3(car(e),pexpr(cadr(e)),caddr(e));
}

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=pexpr(caddr(e));
    return list4(car(e),pexpr(cadr(e)),e1,cadddr(e));
}

// handle local variable declaration
//    initialization is accumrated in parse tree
//    should consider  int k=some_compile_time_constant;
static int
p_decl(int e)
{
    // list4(ST_DECL,parse,(int)n,list3(mode,stmode,ctmode));
    int ctmode=cadddr(e);
    NMTBL *n=(NMTBL*)caddr(e);
    int dsp = n->dsp;
    int v=0;
    int sstmode = stmode;
    int smode = mode;
    // 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;
	stmode = sstmode;
	mode = smode;
	return pexpr(cadr(e));
//    case LLDECL:          LLDECL is mode, not stmode (bad design)
//	v = list2(FLABEL,fwdlabel()); break;
#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
    default:
	if (n->sc==FLABEL)
	    v = list3(LVAR,fwdlabel(),(int)n);
	else
	    v = list3(LVAR,new_lvar(size(n->ty)),(int)n);
    }
    if (n->sc!=FLABEL)
	inline_lvars = glist2(v,inline_lvars);
    if (heap[pdisp+dsp]) {
	fprintf(stderr,"## double p_decl %s %s\n",((NMTBL*)(caddr(heap[pdisp+dsp])))->nm,n->nm);
	error(-1);
    }
    heap[pdisp+dsp]=v;
    stmode = sstmode;
    mode = smode;
    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));
    return list3(ST_FOR,pexpr(cadr(e)), list4(p0,p1,p2,p3));
}

static int
p_switch(int e)
{
    int e2 = pexpr(caddr(e));
    int e3 = pexpr(cadddr(e));
    return list4(ST_SWITCH,pexpr(cadr(e)),e2,e3);
}

static int
p_comp(int e)
{
    int 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
    for(;clist;clist=cadr(clist))
	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 constant case value
    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(CODE,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());
	    }
	}
    }
    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++;
    return list3(ST_COMMENT,pexpr(cadr(e)),caddr(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 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 FNAME:
    case FLABEL:
	return e1;
    case RSTRUCT: 
	// list3(RSTRUCT,e,size)
	return pexpr(e2);
    case LABEL: 
	return p_label_var(e2);
    case LVAR:
    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 FUNCTION:
	return pfunction(e1);
    case CODE:
	e2=pexpr(e2);
	return list3(car(e1),e2,pexpr(cadddr(e1)));
    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 binop(e2,e1,pexpr(cadr(e3)),caddr(e3),cadddr(e3));
    case MINUS:
	if ((e3 = pexpr(e2))==e2) return e1;
	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);
#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 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;
}

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)) {
	if (is_memory(e4)) {
	    heap[pdisp+narg]=reference(e4);
	    return evals;
	} else if (is_const(e4)) {
	    heap[pdisp+narg]=e4;
	    return evals;
	} 
    }
    arg = heap[pdisp+narg]=list3(LVAR,new_lvar(size(t)),0);
    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 e1 = attr_value(n,INLINE);
    int arg_disp = cadr(e1);  // number of arguments
    int narg,e3,e4, e5, fargtype;
    int evals = 0;
    int t;
    NMTBL *anptr;

    fnptr = n;   // st_return see this
    pvartable = p_vartable(arg_disp,    /* number of arg */
			    caddr(e1)   /* number of local parameter  */);

    /* 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 = (NMTBL*)caddr(fargtype);
	if (!anptr) break; // should not happen?
        t=caddr(e3);  // type
	e4 = car(e3);
	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)
{
    NMTBL *n;
    NMTBL *local_statics = (NMTBL*)cadddr(e1);  // local static list

    if (retcont) error(STERR); // inline can't handle return/environment

    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;
	cadddr(e1) = 0;  // prevent duplicate initialize
    }
    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)
{
    // these saved value should be some struct
    int sretlabel;
    NMTBL *sfnptr;
    int svartable;
    int sretcont;
    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*)cadr(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;
    sretcont = retcont;
    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;
    retcont = 0;
    cslabel = -1;
    retpending = 0;
    ret_reg_mode = 0;
    ret_register = 5555;
    inline_lvars = 0;
    retlabel = fwdlabel();

    enter_inline(n,e);

    // 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);

    checkret();
    fwddef(retlabel);
    control=1;

    leave_inline(e1);

    fnptr = sfnptr;
    retlabel = sretlabel;
    retcont = sretcont;
    cslabel = scslabel;
    ret_register = sret_register;
    ret_reg_mode = sret_reg_mode;
    inline_lvars = sinline_lvars;
    lfree=slfree;

    return ret_type;
}

/* end */