view mc-codegen.c @ 61:8ffb8ca3fe34

separation of architecture dependent part.
author kono
date Thu, 20 Feb 2003 03:29:15 +0900
parents
children 0b068058dd67
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  dreg;     /* temporary register */
int  reg_sp;   /* REGister Stack-Pointer */

/*
    creg   currrent virtual register
    dreg   spare virtual register

    rname[creg]   currrent real register
    rname[dreg]   spare real register

    regs[]        virtual register usage
    regv[]        value in virtual register flag

    reg_name[rname[creg]]
 */

void remove0(int *parent,int e) ;
void remove0_all(int *parent,int e) ;
int is_same_type(int e1,int e2);
void jump(int e1, int env);
void machinop(int e1);
void sassign(int e1);
void assign(int e1);
void assop(int e1);

int 
get_register(void)
{    /* 使われていないレジスタを調べる */
    int i;
    for(i=0;i<MAX_REGISTER;i++) {
	if (! regs[i]) {    /* 使われていないなら */
	    regs[i]=1;      /* そのレジスタを使うことを宣言し */
	    return i;       /* その場所を表す番号を返す */
	}
    }
    return -1;    /* 空いている場所がないなら、それを表す -1 を返す */
}

void 
free_register(int i) {    /* いらなくなったレジスタを開放 */
    regv[i]=regs[i]=0;
}

int
register_full(void)
{
    int i;
    for(i=0;i<MAX_REGISTER;i++) {
	if (! regs[i]) { 
	    return 0;  
	}
    }
    return 1;    
}

int
free_register_count(void)
{
    int i,count;
    count = 0;
    for(i=0;i<MAX_REGISTER;i++) {
	if (! regs[i] && ! regv[i]) count++;
    }
    return count;    
}

void
free_all_register(void)
{
    int i;
    for(i=0;i<MAX_REGISTER;i++) {
	regs[i]=regv[i]=0;
    }
    creg = get_register();
    dreg = get_register();
    return;
}

void
use_register_var(int i) {
    regv[i]=1;
}

int creg_regvar = -1;
static int creg_regvar_back;
static int creg_back;

void
creg_destroy() {
    creg_back = creg; creg_regvar_back = creg_regvar;
    if (creg_regvar>=0)
	creg = creg_regvar;
    creg_regvar=-1;
}

void
creg_un_destroy() {
    creg = creg_back; creg_regvar = creg_regvar_back;
}

void
register_usage(char *s)
{
    int i;
    printf("# %d: %s:",lineno,s);
    printf(" creg=%s dreg=%s ",register_name(creg,0),register_name(dreg,0));
    for(i=0;i<MAX_REGISTER;i++) {
	printf("%d",regs[i]);
    }
    printf(":");
    for(i=0;i<MAX_REGISTER;i++) {
	printf("%d",regv[i]);
    }
#if 0
    printf(" regs_stack",register_name(creg,0),register_name(dreg,0));
    for(i=reg_sp;i>=0;i--) {
	if(reg_stack[i]>=0)
	    printf(" %s",register_name(reg_stack[i],0));
    }
#endif
    printf("\n");
}

void 
gexpr_init(void)
{
    while(reg_sp > 0) {
	free_register(reg_stack[--reg_sp]);
    }
    text_mode();
    gexpr_code_init();
    register_usage("gexpr_init");
}


void 
emit_init(void)
{
    int i;
    for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; regv[i]=0;rname[i]=i;}
    free_all_register();
    reg_sp = 0;
    text_mode();
}

int
virtual(int real)
{
    int real_v,i;
    real_v = -1;
    for(i=0;i<MAX_REGISTER;i++) {
	if (rname[i]==real) {
	    real_v=i;
	    break;
	}
    }
    return real_v;
}

int 
pop_register(void)
{     /* レジスタから値を取り出す */
    return reg_stack[--reg_sp];
}

int
stack_used(void) {
    return reg_stack[--reg_sp]<0;
}

void
emit_pop_free(int xreg)
{
    if (xreg==dreg) {
	regv[dreg]=0;
    } else if (xreg!=-1) {
	free_register(xreg);
    }
}

void
gexpr(int e1)
{
    gexpr_init();
#if 0
    if(lineno==2862) {
        g_expr(e1); /*break here*/
        return;
    } 
#endif
    g_expr(e1);
}

int
csvalue()
{
    return rname[creg]; /* for switch value */
}

void
g_expr(int e1)
{
    int e2,e3/*,e4*/;
    NMTBL *n;

    if (chk) return;
    e2 = cadr(e1);
    switch (car(e1)){
    case GVAR:   
	code_gvar(e1);
	regv[creg]=1;
	return;
    case RGVAR:
	code_rgvar(e1);
	regv[creg]=1;
	return;
    case CRGVAR:
	code_crgvar(e1);
	regv[creg]=1;
	return;
    case LVAR:
	code_lvar(lvar(e2));
	regv[creg]=1;
	return;
    case REGISTER:
	/* this is of course redundant... */
	/* we can use rname for this? */
	/* or why not creg=e2? */
	code_register(e2);
	regv[creg]=1;
	return;
    case RLVAR:
	code_rlvar(lvar(e2));
	regv[creg]=1;
	return;
    case CRLVAR:
	code_crlvar(lvar(e2));
	regv[creg]=1;
	return;
    case FNAME:
	code_fname(((NMTBL *)(e2))->nm);
	regv[creg]=1;
	return;
    case CONST:  /* 代入する値が0でも特別な処理はしない */
	code_const(e2);
	regv[creg]=1;
	return;
    case STRING:
	string(e1);
	regv[creg]=1;
	return;
    case FUNCTION:
	function(e1);
	regv[creg]=1;
	return;
    case CODE:
	jump(e2,caddr(e1));
	return;
    case INDIRECT:
	g_expr(e2);
	return;
    case RINDIRECT: case CRINDIRECT:
	rindirect(e1);
	return;
    case ADDRESS:
	g_expr(e2);
	return;
    case MINUS:  /* レジスタに対し、neglを実行すれば実現可能 */
	g_expr(e2);
	code_neg();
	return;
    case BNOT:   /* ~ */
	g_expr(e2);
	code_not();
	return;
    case LNOT:   /* !  */
	g_expr(e2);
	code_lnot();
	return;
    case PREINC:
	code_preinc(e1,e2);
	return;
    case POSTINC:
	code_postinc(e1,e2);
	return;
    case CPOSTINC:
	/*   char *p; *p++ */
	code_cpostinc(e1,e2);
	return;
    case CPREINC:
	code_cpreinc(e1,e2);
	return;
    case CPOSTDEC:
	code_cpostdec(e1,e2);
	return;
    case CPREDEC:
	code_cpredec(e1,e2);
	return;
    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:
	machinop(e1);
	return;
    case COND:
	e2=fwdlabel();
	b_expr(cadr(e1),0,e2,0);
	code_set_fixed_creg(0);
	g_expr(caddr(e1));
	/* e4 = rname[creg]; this is a bad idea */
	code_set_fixed_creg(1);
	jmp(e3=fwdlabel());
	fwddef(e2);
	code_set_fixed_creg(0);
	g_expr(cadddr(e1));
	code_set_fixed_creg(1);
	fwddef(e3);
	return;
    case SASS: 
	sassign(e1);
	return;
    case ASS: case CASS:
	assign(e1);
	return;
    case ASSOP: case CASSOP:
	assop(e1);
	return;
    case RSTRUCT:
	g_expr(e2);
	return;
    case COMMA:
	g_expr(e2);
	g_expr(caddr(e1));
	return;
    case RETURN:
	n = (NMTBL *)e2;
	if (retcont==0)
	    retcont=fwdlabel();
	code_return(creg);
	regv[creg]=1;
	return;
    case ENVIRONMENT:
	code_environment(creg);
	regv[creg]=1;
	return;
    default:
	code_bool(e1);
	regv[creg]=1;
    }
}

void
bexpr(int e1, char cond, int l1)
{
    gexpr_init();
    b_expr(e1,cond,l1,0);
}

void
b_expr(int e1, char cond, int l1,int err)
{
    int e2,l2;
    if (chk) return;
    e2=cadr(e1);
    switch(car(e1)) {
    case LNOT:
	b_expr(e2,!cond,l1,0);
	return;
    case GT:
	rexpr(e1,l1,code_gt(cond));
	return;
    case UGT:
	rexpr(e1,l1,code_ugt(cond));
	return;
    case GE:
	rexpr(e1,l1,code_ge(cond));
	return;
    case UGE:
	rexpr(e1,l1,code_uge(cond));
	return;
    case LT:
	rexpr(e1,l1,code_ge(!cond));
	return;
    case ULT:
	rexpr(e1,l1,code_uge(!cond));
	return;
    case LE:
	rexpr(e1,l1,code_gt(!cond));
	return;
    case ULE:
	rexpr(e1,l1,code_ugt(!cond));
	return;
    case EQ:
	rexpr(e1,l1,code_eq(cond));
	return;
    case NEQ:
	rexpr(e1,l1,code_eq(!cond));
	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 REGISTER:
	code_cmp_register(e2);
	jcond(l1,cond);
	return;
    case CONST:
	if((cond&&e2)||(!cond&&!e2)) jmp(l1);
	return;
    default:
	if(err) {
	    error(-1); return; /* recursice g_expr/b_expr */
	}
	g_expr(e1);
	code_cmp_register(creg);
	jcond(l1,cond);
	return;
    }
}


/* 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) {
	    free_register(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) {
	*use=list3(t,*use,e1);
	e1=list2(REGISTER,e1);
	g_expr(assign_expr0(e1,s,ty,ty));
	*target = append4(*target,t,ty,e1);
    } else {
	disp-=sz;
	g_expr(assign_expr0((e1=list2(LVAR,disp)),s,ty,ty));
	*target = append4(*target,t,ty,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(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==GVAR || e1==RGVAR || e1==RLVAR || e1==CRLVAR || e1==CRGVAR
    );
}

int
is_same_type(int e1,int e2)
{
    int ce1=car(e1);
    int ce2=car(e2);
    return (   
         (ce1==LVAR && (ce2==RLVAR||ce2==CRLVAR))
      || (ce2==LVAR && (ce1==RLVAR||ce1==CRLVAR))
      || (ce1==GVAR && (ce2==RGVAR||ce2==CRGVAR))
      || (ce2==GVAR && (ce1==RGVAR||ce1==CRGVAR))
    );
}

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

void
jump(int e1, int env)
{
    int e2,e3,e4,sz,arg_size,ty,max_regs,regs;
    int t0,s0;
    NMTBL *code0;
    int target = 0;
    int source = 0;
    int processing = 0;
    int use = 0;

    /* まず、サイズを計算しながら、決まった形に落す。 */

    arg_size = 0; regs = 0; max_regs = MAX_REGISTER_VAR-1;
    for (e3 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) {	
	e2 = car(e3); sz = size(ty=caddr(e3)); 
	if (regs <= max_regs&&scalar(ty)) {
	    target=list4(list2(REGISTER,register_var(regs++)), 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 (fnptr->sc==CODE) {
	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))) {
	    disp-=sz;
	    g_expr(assign_expr0((e4=list2(LVAR,disp)),s0,ty,ty));
	    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 (code0->sc!=CODE) {
	    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) {
	free_register(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 (fnptr->sc==FUNCTION) {
	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
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(int e1)
{
    int e2,e3,e4,byte;

    byte=(car(e1) == CASS);
    /*    e2=e4 */
    e2 = cadr(e1);
    e3 = cadr(e2);
    e4 = caddr(e1);
    switch(car(e2)) {
    case GVAR:      /*   i=3 */
            g_expr(e4);
	    code_assign_gvar(e2,byte);
            return;
    case LVAR:
            g_expr(e4);
	    code_assign_lvar(lvar(cadr(e2)),byte);
            return;
    case REGISTER:
            g_expr(e4);
	    if (creg!=cadr(e2))
		code_assign_register(cadr(e2),byte);
            return;
    }
    g_expr(e2);
    emit_push();
    use_data_reg(creg,0);
    g_expr(e4);
    if (byte) use_data_reg(creg,1);
    e2 = emit_pop(0);
    code_assign(e2,byte);
    emit_pop_free(e2);
    regv[creg]=1;
    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;
}


int
fwdlabel(void)
{       
    return labelno++;
}

void
fwddef(int l)
{       
    control=1;
    printf("_%d:\n",l);
}

int
backdef(void)
{       
    control=1;
    printf("_%d:\n",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_fixed_creg(1);
    jmp(retlabel); 
}

/* end */