view mc-codegen.c @ 118:07b91b625f84 assignment-opt

assignment optimization
author kono
date Fri, 21 Mar 2003 18:35:13 +0900
parents 2d5a203cc3a6
children b815fcd57b9d
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  creg;     /* current register */
int  reg_sp;   /* REGister Stack-Pointer */
int reg_stack[MAX_MAX];  /* 実際のレジスタの領域 */

/* floating point registers */

int  freg;     /* current floating point register */
int  freg_sp;  /* floating point REGister Stack-Pointer */
int freg_stack[MAX_MAX]; /* 実際のレジスタの領域 */

int use;       /* generated value will be used */

/*
    creg   currrent virtual register
    regs[]        virtual register usage
    regv[]        value in virtual register flag
    freg    current floating point register
    fregv   calue in floating point register
 */

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

void
codegen_init()
{
    code_init();
}

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);
    use=suse;
    return t;
}

int
g_expr(int e1)
{
    int t;
    int suse = use; use=1;
    t=g_expr0(e1);
    use=suse;
    return t;
}

int
g_expr0(int e1)
{
    int e2,e3,t;
    NMTBL *n;

    e2 = cadr(e1);
    switch (car(e1)){
    case GVAR:   
	code_gvar(e1,creg);
	return ADDRESS;
    case RGVAR:
	code_rgvar(e1,creg);
	return INT;
    case CRGVAR:
	code_crgvar(e1,creg);
	return CHAR;
    case LVAR:
	code_lvar(lvar(e2),creg);
	return ADDRESS;
    case REGISTER:
	code_register(e2,creg);
	return INT;
    case DREGISTER:
	code_fregister(e2,freg);
	return DOUBLE;
    case RLVAR:
	code_rlvar(lvar(e2),creg);
	return INT;
    case CRLVAR:
	code_crlvar(lvar(e2),creg);
	return CHAR;
    case FRLVAR:
	code_drlvar(lvar(e2),0,freg);
	return FLOAT;
    case FRGVAR:
	code_drgvar(e1,0,freg);
	return FLOAT;
    case DRLVAR:
	code_drlvar(lvar(e2),1,freg);
	return DOUBLE;
    case DRGVAR:
	code_drgvar(e1,1,freg);
	return DOUBLE;
    case FNAME:
	code_fname((NMTBL *)(e2),creg);
	return ADDRESS;
    case CONST:  /* 代入する値が0でも特別な処理はしない */
	code_const(e2,creg);
	return INT;
    case DCONST:
	code_dconst(e1,freg);
	return DOUBLE;
    case STRING:
	code_string(e1,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:  case CRINDIRECT:
    case DRINDIRECT: case FRINDIRECT:
	return rindirect(e1);
    case ADDRESS:
	if (car(e2)==REGISTER||car(e2)==DREGISTER)
	    return register_to_lvar(e2);
	else
	    return g_expr0(e2);
    case MINUS:  /* レジスタに対し、neglを実行すれば実現可能 */
	g_expr0(e2); code_neg(creg);
	return INT;
    case DMINUS: 
	g_expr0(e2); code_dneg(freg);
	return DOUBLE;
    case CONV: 
	g_expr0(e2); 
	switch(caddr(e1)) {
	case I2D: 
	    code_i2d(creg,freg);
	    return DOUBLE;
	case D2I: 
	    code_d2i(freg,creg);
	    return INT;
	case U2D: 
	    code_u2d(creg,freg);
	    return DOUBLE;
	case D2U: 
	    code_d2u(freg,creg);
	    return UNSIGNED;
	default:
	    error(-1); return INT;
	}
    case BNOT:   /* ~ */
	g_expr0(e2); code_not(creg);
	return INT;
    case LNOT:   /* !  */
	g_expr0(e2); code_lnot(creg);
	return INT;
    case PREINC:
	code_preinc(e1,e2,creg);
	return INT;
    case POSTINC:
	code_postinc(e1,e2,creg);
	return INT;
    case DPREINC:
	code_dpreinc(e1,e2,1,freg);
	return DOUBLE;
    case DPOSTINC:
	code_dpostinc(e1,e2,1,freg);
	return DOUBLE;
    case FPREINC:
	code_dpreinc(e1,e2,0,freg);
	return FLOAT;
    case FPOSTINC:
	code_dpostinc(e1,e2,0,freg);
	return FLOAT;
    case CPOSTINC:
	/*   char *p; *p++ */
	code_cpostinc(e1,e2,creg);
	return CHAR;
    case CPREINC:
	code_cpreinc(e1,e2,creg);
	return CHAR;
    case CPOSTDEC:
	code_cpostdec(e1,e2,creg);
	return CHAR;
    case CPREDEC:
	code_cpredec(e1,e2,creg);
	return CHAR;
    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:
	machinop(e1);
	return INT;
    case DMUL: case DDIV:
    case DADD: case DSUB:
    case DCMP: case DCMPGE:
	dmachinop(e1);
	return DOUBLE;
    case COND:
	e2=fwdlabel();
	b_expr(cadr(e1),0,e2,0);
	code_set_fixed_creg(0,INT);
	t = g_expr0(caddr(e1));
	code_set_fixed_creg(1,t);
	jmp(e3=fwdlabel());
	fwddef(e2);
	code_set_fixed_creg(0,INT);
	t = g_expr0(cadddr(e1));
	code_set_fixed_creg(1,t);
	fwddef(e3);
	return t;
    case DCOND:
	e2=fwdlabel();
	b_expr(cadr(e1),0,e2,0);
	code_set_fixed_creg(0,DOUBLE);
	t = g_expr0(caddr(e1));
	code_set_fixed_creg(1,t);
	jmp(e3=fwdlabel());
	fwddef(e2);
	code_set_fixed_creg(0,DOUBLE);
	t = g_expr0(cadddr(e1));
	code_set_fixed_creg(1,t);
	fwddef(e3);
	return t;
    case SASS: 
	sassign(e1);
	return RSTRUCT;
    case ASS: case CASS: 
	assign(e1);
	return INT;
    case FASS: case DASS: case LASS: 
	dassign(e1);
	return DOUBLE;
    case ASSOP: case CASSOP:
	assop(e1);
	return INT;
    case DASSOP: case FASSOP:
	dassop(e1);
	return DOUBLE;
    case RSTRUCT:
	g_expr0(e2);
	return RSTRUCT;
    case COMMA:
	g_expr_u(e2);
	return g_expr0(caddr(e1));
    case RETURN:
	n = (NMTBL *)e2;
	if (retcont==0)
	    retcont=fwdlabel();
	code_return(creg);
	return VOID;
    case ENVIRONMENT:
	code_environment(creg);
	return ADDRESS;
    default:
	code_bool(e1); /* 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==EQ|| op==NEQ|| op==DOP+EQ|| op==DOP+NEQ)

int
rop_dual(op)
{
    if (op==GT) return LT;
    if (op==UGT) return ULT;
    if (op==GE) return LE;
    if (op==UGE) return ULE;
    if (op==LT) return GT;
    if (op==ULT) return UGT;
    if (op==LE) return GE;
    if (op==ULE) return UGE;
    if (op==DOP+GT) return DOP+LT;
    if (op==DOP+GE) return DOP+LE;
    if (op==DOP+LT) return DOP+GT;
    if (op==DOP+LE) return DOP+GE;
    return op;
}

void
bexpr(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
b_expr(int e1, char cond, int l1,int err)
{
    int e2,l2,t;
    e2=cadr(e1);
    switch(car(e1)) {
    case LNOT:
	b_expr(e2,!cond,l1,0);
	return;
    case GT:
	rexpr(e1,l1,code_gt(cond),INT);
	return;
    case UGT:
	rexpr(e1,l1,code_ugt(cond),UNSIGNED);
	return;
    case GE:
	rexpr(e1,l1,code_ge(cond),INT);
	return;
    case UGE:
	rexpr(e1,l1,code_uge(cond),UNSIGNED);
	return;
    case LT:
	rexpr(e1,l1,code_ge(!cond),INT);
	return;
    case ULT:
	rexpr(e1,l1,code_uge(!cond),UNSIGNED);
	return;
    case LE:
	rexpr(e1,l1,code_gt(!cond),INT);
	return;
    case ULE:
	rexpr(e1,l1,code_ugt(!cond),UNSIGNED);
	return;
    case EQ:
	rexpr(e1,l1,code_eq(cond),INT);
	return;
    case NEQ:
	rexpr(e1,l1,code_eq(!cond),INT);
	return;

    case DOP+GT:
	drexpr(cadr(e1),caddr(e1),l1,DOP+GT);
	return;
    case DOP+GE:
	drexpr(cadr(e1),caddr(e1),l1,DOP+GE);
	return;
    case DOP+LT:
	drexpr(caddr(e1),cadr(e1),l1,DOP+GT);
	return;
    case DOP+LE:
	drexpr(caddr(e1),cadr(e1),l1,DOP+GE);
	return;
    case DOP+EQ:
	drexpr(cadr(e1),caddr(e1),l1,DOP+EQ);
	return;
    case DOP+NEQ:
	drexpr(cadr(e1),caddr(e1),l1,DOP+NEQ);
	return;

    case LAND:
	b_expr(e2,0,cond?(l2=fwdlabel()):l1,0);
	b_expr(caddr(e1),cond,l1,0);
	if(cond) fwddef(l2);
	return;
    case LOR:
	b_expr(e2,1,cond?l1:(l2=fwdlabel()),0);
	b_expr(caddr(e1),cond,l1,0);
	if(!cond) fwddef(l2);
	return;
    case CRGVAR:
	code_cmp_crgvar(e1);
	jcond(l1,cond);
	return;
    case CRLVAR:
	code_cmp_crlvar(lvar(e2));
	jcond(l1,cond);
	return;
    case RGVAR:
	code_cmp_rgvar(e1);
	jcond(l1,cond);
	return;
    case RLVAR:
	code_cmp_rlvar(lvar(e2));
	jcond(l1,cond);
	return;
    case DRLVAR:
	code_cmp_drlvar(lvar(e2));
	jcond(l1,cond);
	return;
    case DRGVAR:
	code_cmp_drgvar(lvar(e2));
	jcond(l1,cond);
	return;
    case REGISTER:
	code_cmp_register(e2);
	jcond(l1,cond);
	return;
    case DREGISTER:
	code_cmp_fregister(e2);
	jcond(l1,cond);
	return;
    case CONST:
	if((cond&&e2)||(!cond&&!e2)) jmp(l1);
	return;
    case DCONST:
	if((dcadr(e2)!=0.0)^cond) jmp(l1);
	return;
    default:
	if(err) {
	    error(-1); return; /* recursive g_expr/b_expr */
	}
	t=g_expr(e1);
	if(t==FLOAT||t==DOUBLE)
	    code_cmp_fregister(freg);
	else
	    code_cmp_register(creg);
	jcond(l1,cond);
	return;
    }
}


void
arg_register(NMTBL *fnptr)
{
    int args = fnptr->dsp;
    NMTBL *n;
    int reg_var = 0;
    int freg_var = 0;
    int type;
    int max_input_register_var;
    int max_input_fregister_var;

    if (is_function(fnptr)) {
	max_input_register_var = MAX_INPUT_REGISTER_VAR;
	max_input_fregister_var = MAX_INPUT_DREGISTER_VAR;
    } else {
	max_input_register_var = MAX_CODE_INPUT_REGISTER_VAR;
	max_input_fregister_var = MAX_CODE_INPUT_DREGISTER_VAR;
    }

    while (args) {
	/* process in reverse order */
        n = (NMTBL*)caddr(args);
	type = n->ty;
        if (scalar(type)) {
            if(reg_var<max_input_register_var) {
                n->sc = REGISTER;
		n->dsp = cadr(get_input_register_var(reg_var,n));
		regv[n->dsp]= 1;
		regs[n->dsp]= INPUT_REG;
                reg_var++;
                cadddr(args)=size_of_int; /* why we need this? */
            }
        } else if (type==FLOAT||type==DOUBLE) {
            if(freg_var<max_input_fregister_var) {
                n->sc = DREGISTER;
		n->dsp = cadr(get_input_fregister_var(freg_var,n));
		fregv[n->dsp]= 1;
		fregs[n->dsp]= INPUT_REG;
                freg_var++;
                cadddr(args)=size_of_double; /* why we need this? */
            }
        }
	args = cadr(args);
    }
    code_arg_register();
}

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) {
	/* regs[reg]==INPUT_REG case should be considered */
	n->dsp = new_lvar(size_of_int);
        t = INT;
    } else if (tag==DREGISTER) {
	/* fregs[reg]==INPUT_REG case should be considered */
	n->dsp = new_lvar(size_of_double);
        t = DOUBLE;
    } 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) {
	free_register(reg);
    } else if (tag==DREGISTER) {
	free_fregister(reg);
    }
    return g_expr0(lvar);
#endif
}

/* 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 1

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;
    while(use0) {
	if (car(use0)==t) {
	    if (car(caddr(use0))==REGISTER)
		free_register(cadr(caddr(use0)));
	    else if (car(caddr(use0))==DREGISTER)
		free_fregister(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);
    } else if (sz==size_of_double && (e1=get_fregister())!=-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 {
	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==GVAR || e1==RGVAR || e1==RLVAR || e1==CRLVAR || e1==CRGVAR ||
	e1==DRLVAR || e1==FRLVAR 
    );
}

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))
      || (ce2==LVAR && (ce1==RLVAR||ce1==CRLVAR||ce1==FRLVAR||ce1==DRLVAR))
      || (ce1==GVAR && (ce2==RGVAR||ce2==CRGVAR||ce2==FRGVAR||ce2==DRGVAR))
      || (ce2==GVAR && (ce1==RGVAR||ce1==CRGVAR||ce1==FRGVAR||ce1==DRGVAR))
    );
}

int
is_memory(int e1)
{
    int ce1=car(e1);
    return (   
         ce1==LVAR ||ce1==RLVAR||ce1==CRLVAR || ce1==DRLVAR ||
         ce1==GVAR ||ce1==RGVAR||ce1==CRGVAR || ce1==DRGVAR ||
         ce1==REGISTER|| ce1==DREGISTER
    );
}

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


void
jump(int e1, int env)
{
    int e2,e3,e4,sz,arg_size,ty,regs,fregs;
    int t0,s0;
    NMTBL *code0;
    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) && 
		regs < MAX_CODE_INPUT_REGISTER_VAR) {
	    target=list4(get_input_register_var(regs++,0), 
		    target,ty,e2);
	} else if ((ty==DOUBLE||ty==FLOAT) && 
		fregs < MAX_CODE_INPUT_DREGISTER_VAR) {
	    target=list4(get_input_fregister_var(fregs++,0), 
		    target,ty,e2);
	} else {
	    target=list4(list2(LVAR,0), target,ty,e2);
	    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) {
	if (car(caddr(use))==REGISTER)
	    free_register(cadr(caddr(use)));
	else if (car(caddr(use))==DREGISTER)
	    free_fregister(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)) {
	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);
    g_expr(e3);
    emit_push();
    g_expr(e2);
    tosop(car(e1),(e2=pop_register()));
    emit_pop_free(e2);
    regv[creg]=1;
    return;
}

void
dmachinop(int e1)
{
    int e2,e3,op;

    e2 = cadr(e1);
    op = car(e1);
    e3 = caddr(e1);
    g_expr(e3);
    emit_dpush();
    g_expr(e2);
    dtosop(car(e1),(e2=emit_dpop(1)));
    emit_dpop_free(e2);
    fregv[freg]=1;
    return;
}


void
sassign(int e1)
{
    int e2,e3,e4,sz,xreg,det;

    /* 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 */
    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)) sz=-sz;
	det=1;
    } else {
	det = 0;
    }
    emit_copy(xreg,creg,sz,0,1,det);
    emit_pop_free(xreg);
    return;
}

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(lvar(cadr(e2)),reg,byte); return;
	case REGISTER: code_assign_register(cadr(e2),byte,reg); return;
	}
	g_expr(e2);
	code_assign(e2,byte,reg);
	return;
    }
    /* e2 is register now */
    if (car(e2)!=REGISTER) error(-1);
    reg = cadr(e2);
    switch(e5) {
    case CRGVAR:  code_crgvar(e4,reg); return;
    case RGVAR:   code_rgvar(e4,reg);  return;
    case CRLVAR:  code_crlvar(lvar(cadr(e4)),reg); return;
    case RLVAR:   code_rlvar(lvar(cadr(e4)),reg);  return;
    case GVAR:    code_gvar(e4,reg);   return;
    case LVAR:    code_lvar(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;
    case DEFAULT: error(-1);
    }
}

void
assign(int e1)
{
    int e2,e4,byte,e5;

    byte=(car(e1) == CASS);
    /*    e2=e4 */
    e2 = cadr(e1);
    e4 = caddr(e1);e5=car(e4);
    if (!use && (
	    (e5==REGISTER) ||
	    (car(e2)==REGISTER&&(
		e5== CRGVAR || e5== CRLVAR || e5== RGVAR || e5== RLVAR ||
		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,creg,byte);
            return;
    case LVAR:
            g_expr(e4);
	    code_assign_lvar(lvar(cadr(e2)),creg,byte);
            return;
    case REGISTER:
            g_expr(e4);
	    if (creg!=cadr(e2))
		code_assign_register(cadr(e2),byte,creg);
            return;
    }
    g_expr(e2);
    emit_push();
    g_expr(e4);
    e2 = emit_pop(0);
    code_assign(e2,byte,creg);
    emit_pop_free(e2);
    regv[creg]=1;
    return;
}

void
dassign_opt(int e5,int e2,int e4,int d)
{
    int reg;
    /*    e2=e4 */
    if (e5==DREGISTER) {
	reg = cadr(e4);
	switch(car(e2)) {
	case GVAR:      /*   i=3 */
		code_dassign_gvar(e2,reg,d);
		return;
	case LVAR:
		code_dassign_lvar(lvar(cadr(e2)),reg,d);
		return;
	case DREGISTER:
		if (reg!=cadr(e2))
		    code_dassign_fregister(cadr(e2),d,reg);
		return;
	}
	g_expr(e2);
	code_dassign(e2,reg,d);
	return;
    }
    /* e2 is register now */
    if (car(e2)!=DREGISTER) error(-1);
    reg = cadr(e2);
    switch(e5) {
    case DRGVAR: code_drgvar(e4,d,reg); return;
    case DRLVAR: code_drlvar(lvar(cadr(e4)),d,reg); return;
    case DCONST: code_dconst(e4,reg); return;
    case 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);
    d = (car(e1)==LASS)?2:(car(e1)==DASS)?1:0;
    if (!use && (
	    (e5==DREGISTER) ||
	    (car(e2)==DREGISTER&&(e5==DRGVAR||e5==DRLVAR||e5==DCONST))
	)) {
	dassign_opt(e5,e2,e4,d);
	return;
    }
    switch(car(e2)) {
    case GVAR:
            g_expr(e4);
	    code_dassign_gvar(e2,freg,d);
            return;
    case LVAR:
            g_expr(e4);
	    code_dassign_lvar(lvar(cadr(e2)),freg,d);
            return;
    case DREGISTER:
            g_expr(e4);
	    if (freg!=cadr(e2))
		code_dassign_fregister(cadr(e2),d,freg);
            return;
    }
    g_expr(e2);
    emit_push();
    g_expr(e4);
    e2 = emit_pop(0);
    code_dassign(e2,freg,d);
    emit_pop_free(e2);
    return;
}

void
assop(int e1)
{
    int e2,e3,byte,op;

    /*   e2 op= e3 */
    byte = (car(e1) == CASSOP);
    e2 = cadr(e1);
    if (car(e2)==INDIRECT) e2=cadr(e2);
    e3 = caddr(e1);
    op = cadddr(e1);

    g_expr(e3);
    if (car(e2)==REGISTER) {
	code_register_assop(cadr(e2),op,byte);
	regv[creg]=1;
	return;
    }
    emit_push();
    g_expr(e2);
    code_assop(op,byte);
    regv[creg]=1;
    return;
}

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);
    emit_dpush();
    g_expr(e2);
    code_dassop(op,d);
    regv[creg]=1;
    return;
}

void 
cmpdimm(int e, int csreg)
{
    code_cmpdimm(e, csreg);
}

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;
	switch (car(e)){
        /* list arguments */
	case FUNCTION: case CODE:
	    return contains_in_list(caddr(e),type);
        /* unary operators */
	case INDIRECT: case RINDIRECT:  case CRINDIRECT:
	case DRINDIRECT: case FRINDIRECT: case ADDRESS: case MINUS: case DMINUS: 
	case I2D: case D2I: case U2D: case D2U: case BNOT: case LNOT:
	case PREINC: case POSTINC: case DPREINC: case DPOSTINC:
	case FPREINC: case FPOSTINC: case CPOSTINC:
	case CPREINC: case CPOSTDEC: case CPREDEC:
	case RSTRUCT:
	    e = cadr(e);
	    continue;
        /* biary operators */
	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 DMUL: case DDIV: case DADD: case DSUB: case DCMP: case DCMPGE:
	case SASS: case ASS: case CASS: case FASS: case DASS: case LASS: 
	case ASSOP: case CASSOP: case DASSOP: case FASSOP: case COMMA:
	    if (contains(cadr(e),type)) return 1;
	    e = caddr(e);
	    continue;
        /* tarary operators */
	case COND:
	    if (contains(cadr(e), type)) return 1;
	    if (contains(caddr(e),type)) return 1;
	    e = cadddr(e);
	    continue;
	default:
        /* nullary operators 
	case GVAR:   case RGVAR: case CRGVAR: case LVAR:
	case REGISTER: case DREGISTER:
	case RLVAR: case CRLVAR: case FRLVAR: case FRGVAR:
	case DRLVAR: case DRGVAR:
	case FNAME: case CONST:  case DCONST: case STRING:
	case RETURN: case ENVIRONMENT: */
	    return 0;
	}
    }
    return 0;
}

/* end */