view mc-codegen.c @ 89:917947ffeb7c

power pc version
author kono
date Thu, 06 Mar 2003 23:47:42 +0900
parents 5c8553d7f984
children 9b1aeb62e0b9
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 */

int rname[MAX_MAX];
int regs[MAX_MAX];       /* 使われているレジスタを示すフラグ */
int reg_stack[MAX_MAX];  /* 実際のレジスタの領域 */
int regv[MAX_MAX];       /* 値が入っているかどうか */

/* floating point registers */

int  freg;     /* current floating point register */
int  greg;     /* current floating point register */
int  freg_sp;  /* floating point REGister Stack-Pointer */

int frname[MAX_MAX];
int fregs[MAX_MAX];      /* 使われているレジスタを示すフラグ */
int freg_stack[MAX_MAX]; /* 実際のレジスタの領域 */
int fregv[MAX_MAX];      /* 値が入っているかどうか */

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

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

    freg    current floating point register
    fregv   calue in floating point register
 */

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);
void g_expr0(int e1);

void
gexpr(int e1,int use0)
{
    if (chk) return;
    gexpr_init();
    use = use0;
#if 0
    if(lineno==2862) {
        g_expr0(e1); /*break here*/
        return;
    } 
#endif
    g_expr0(e1);
}

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

void
g_expr_u(int e1)
{
    int suse = use; use=0;
    g_expr0(e1);
    use=suse;
}

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

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

    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 FRLVAR:
	code_drlvar(lvar(e2),0);
	fregv[freg]=1;
	return;
    case FRGVAR:
	code_drgvar(e1,0);
	fregv[freg]=1;
	return;
    case DRLVAR:
	code_drlvar(lvar(e2),1);
	fregv[freg]=1;
	return;
    case DRGVAR:
	code_drgvar(e1,1);
	fregv[freg]=1;
	return;
    case FNAME:
	code_fname(((NMTBL *)(e2))->nm);
	regv[creg]=1;
	return;
    case CONST:  /* 代入する値が0でも特別な処理はしない */
	code_const(e2);
	regv[creg]=1;
	return;
    case DCONST:
	code_dconst(e1);
	fregv[freg]=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_expr0(e2);
	return;
    case RINDIRECT:  case CRINDIRECT:
    case DRINDIRECT: case FRINDIRECT:
	rindirect(e1);
	return;
    case ADDRESS:
	g_expr0(e2);
	return;
    case MINUS:  /* レジスタに対し、neglを実行すれば実現可能 */
	g_expr0(e2); code_neg();
	return;
    case DMINUS: 
	g_expr0(e2); code_dneg();
	return;
    case I2D: 
	g_expr0(e2); code_i2d();
	return;
    case D2I: 
	g_expr0(e2); code_d2i();
	return;
    case U2D: 
	g_expr0(e2); code_u2d();
	return;
    case D2U: 
	g_expr0(e2); code_d2u();
	return;
    case BNOT:   /* ~ */
	g_expr0(e2); code_not();
	return;
    case LNOT:   /* !  */
	g_expr0(e2); code_lnot();
	return;
    case PREINC:
	code_preinc(e1,e2);
	return;
    case POSTINC:
	code_postinc(e1,e2);
	return;
    case DPREINC:
	code_dpreinc(e1,e2,1);
	return;
    case DPOSTINC:
	code_dpostinc(e1,e2,1);
	return;
    case FPREINC:
	code_dpreinc(e1,e2,0);
	return;
    case FPOSTINC:
	code_dpostinc(e1,e2,0);
	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 DMUL: case DDIV:
    case DADD: case DSUB:
    case DCMP:
	dmachinop(e1);
	return;
    case COND:
	e2=fwdlabel();
	b_expr(cadr(e1),0,e2,0);
	code_set_fixed_creg(0);
	g_expr0(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_expr0(cadddr(e1));
	code_set_fixed_creg(1);
	fwddef(e3);
	return;
    case SASS: 
	sassign(e1);
	return;
    case ASS: case CASS: 
	assign(e1);
	return;
    case FASS: case DASS: case LASS: 
	dassign(e1);
	return;
    case ASSOP: case CASSOP:
	assop(e1);
	return;
    case DASSOP: case FASSOP:
	dassop(e1);
	return;
    case RSTRUCT:
	g_expr0(e2);
	return;
    case COMMA:
	g_expr_u(e2);
	g_expr0(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)
{
    if (chk) return;
    gexpr_init();
    b_expr(e1,cond,l1,0);
}

void
b_expr(int e1, char cond, int l1,int err)
{
    int e2,l2;
    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 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 */
	} /* type ? */
	g_expr(e1);
	code_cmp_register(creg);
	jcond(l1,cond);
	return;
    }
}


void
arg_register(NMTBL *fnptr)
{
    code_arg_register(fnptr->dsp);
}

/* 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_u(assign_expr0(e1,s,ty,ty));
	*target = append4(*target,t,ty,e1);
    } else {
	disp-=sz;
	g_expr_u(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_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==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
    );
}

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&&sz==size_of_int) {
	    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_u(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
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=dpop_register()));
    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(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
dassign(int e1)
{
    int e2,e3,e4,d;

    /*    e2=e4 */
    e2 = cadr(e1);
    e3 = cadr(e2);
    e4 = caddr(e1);
    d = (car(e1)==LASS)?2:(car(e1)==DASS)?1:0;
    switch(car(e2)) {
    case GVAR:
            g_expr(e4);
	    code_dassign_gvar(e2,d);
            return;
    case LVAR:
            g_expr(e4);
	    code_dassign_lvar(lvar(cadr(e2)),d);
            return;
    }
    g_expr(e2);
    emit_push();
    g_expr(e4);
    e2 = emit_pop(0);
    code_dassign(e2,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;
}

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

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

int
backdef(void)
{       
    control=1;
    if (!chk)
	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); 
}

void
opening(char *filename)
{
    emit_init();
    if (!chk)
	code_opening(filename);
}

void
closing()
{
    if (!chk)
	code_closing();
}

/* end */