view mc-codegen.c @ 316:22d92986c7f7

asm, valued statement, local decls continue...
author kono
date Wed, 16 Jun 2004 13:15:01 +0900
parents f73b93de216a
children 183726ccd83d
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);

#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;
}

/* end */