diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mc-codegen.c	Thu Feb 20 03:29:15 2003 +0900
@@ -0,0 +1,909 @@
+/* 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 */