diff mc-code-mips.c @ 130:fea1b499d47b

fix register var save
author kono
date Fri, 04 Apr 2003 14:01:33 +0900
parents
children 09379ec2a74b
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mc-code-mips.c	Fri Apr 04 14:01:33 2003 +0900
@@ -0,0 +1,2698 @@
+/* Micro-C Code Generatation Part for Power PC (Mac OS X) */
+/* $Id$ */
+
+#define EXTERN extern
+#include "mc.h"
+#include "mc-code.h"
+#include "mc-codegen.h"
+
+#define TEXT_EMIT_MODE 0
+#define DATA_EMIT_MODE 1
+#define RODATA_EMIT_MODE 2
+
+static void data_mode(char *name);
+static void init_ptr_cache();
+static void ld_indexx(int byte, int n, int xreg);
+static void local_table(void);
+static void shift(char *op, int reg);
+static int struct_push(int e4,int t,int arg);
+
+static int output_mode = TEXT_EMIT_MODE;
+static int data_alignment = 0;
+
+static int code_disp_label;
+static int code_setup;
+static int r1_offset_label;
+static int lvar_offset_label;
+
+static int reg_save;
+static int freg_save;
+
+int size_of_int = 4;
+int size_of_float = 4;
+int size_of_double = 8;
+int size_of_longlong = 8;
+int endian = 1;
+
+
+#define REG_fp   1
+#define REG_sp   30
+#define REG_VAR_BASE 29
+#define REG_VAR_MIN  22
+#define MIN_TMP_REG 3
+#define MAX_TMP_REG 15
+
+#define PTRC_REG 3
+
+#define FREG_VAR_BASE 31
+#define FREG_VAR_MIN  24
+#define MIN_TMP_FREG 1
+#define MAX_TMP_FREG 15
+
+#define RET_REGISTER 3
+#define RET_FREGISTER 1
+
+int MAX_REGISTER=30;             /* PowerPCのレジスタを10個まで使う*/
+int MAX_FREGISTER=31;
+#define  REAL_MAX_REGISTER 32    /* PowerPCのレジスタが32ということ*/
+#define  REAL_MAX_FREGISTER 32    /* PowerPCのレジスタが32ということ*/
+
+int MAX_INPUT_REGISTER_VAR = 11-MIN_TMP_REG;
+int MAX_CODE_INPUT_REGISTER_VAR = 11-MIN_TMP_REG;
+int MAX_INPUT_DREGISTER_VAR = 14-MIN_TMP_FREG;
+int MAX_CODE_INPUT_DREGISTER_VAR = 14-MIN_TMP_FREG;
+
+#define CREG_REGISTER  MAX_TMP_REG
+#define FREG_FREGISTER MAX_TMP_FREG
+
+int powerpc_regs[REAL_MAX_REGISTER];
+int powerpc_regv[REAL_MAX_REGISTER];
+
+int *regv  = powerpc_regv;
+int *regs  = powerpc_regs;
+
+int powerpc_fregs[REAL_MAX_FREGISTER];
+int powerpc_fregv[REAL_MAX_FREGISTER];
+
+int *fregv = powerpc_fregv;
+int *fregs = powerpc_fregs;
+
+static int max_reg_var, max_freg_var;
+static int cond_reg=-1,cond_freg=-1;
+
+static char *reg_name[] = {
+    "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9",
+    "r10","r11","r12","r13","r14","r15","r16","r17","r18","r19",
+    "r20","r21","r22","r23","r24","r25","r26","r27","r28","r29",
+    "r30","r31"
+}; 
+
+static char *freg_name[] = {
+    "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9",
+    "f10","f11","f12","f13","f14","f15","f16","f17","f18","f19",
+    "f20","f21","f22","f23","f24","f25","f26","f27","f28","f29",
+    "f30","f31"
+}; 
+
+#define register_name(i)  reg_name[i]
+#define fregister_name(i) freg_name[i]
+
+static
+NMTBL float_zero = {"_float_zero",STATIC,FLOAT,0};
+static
+NMTBL float_one = {"_float_one",STATIC,FLOAT,0};
+
+
+static char * fload(int d);
+static int code_d1(double d);
+static int code_d2(double d);
+static void code_save_stacks();
+static void code_save_input_registers();
+static void clear_ptr_cache_reg(int r);
+static void    set_creg(int,int);
+static void    set_freg(int,int);
+
+int max_func_args;
+int my_func_args;
+#define ARG_LVAR_OFFSET 0x10000000
+
+/*          
+
+     r0    return value etc.
+     r3-r10  input register
+     r22-r29 saved register variable (input register for code segement)
+     r30   stack pointer
+     r31   0
+     r1    frame pointer
+
+     f0    return value etc.
+     f1-r8  input register
+     f24-f31 saved register variable
+
+function call stack frame
+                       <------r1_offset------------------------------>
+                                      <------------lvar_offset------->
+ r+  +------------+---+---------------+----------+--------------+----+    -
+      callee arg   xx   register save   local      caller arg     xx
+                          reg_save      disp       max_func_args*size_of_int
+        lvar>0                         lvar<0       lvar>0x1000 0000
+
+code segment stack frame
+
+                 * gotoを呼び出した関数のr1 ! r1(goto前のr1)
+   #             *                           r30 <---r1_offset---------> r1
+r+ +----------+--+----------+----------------+-----------+----------+----+
+    cousin arg xx  reg save !callee arg      !code local  caller arg  xx
+                   r20-r29     lvar>0         lvar<0      lvar>0x1000 000
+                   f20-f31  <-my_func_args--><--disp-----><-max_func_arg->
+                              *size_of_int                  *size_of_int
+
+ */
+int arg_offset = 24; int arg_offset1 = 24; int disp_offset = -12;
+#define func_disp_offset 60
+#define r1_offset func_disp_offset+12 
+int code_disp_offset = 0; int jump_offset = 0;
+#define CODE_LVAR l+code_disp_offset
+#define CODE_CALLER_ARG (l-ARG_LVAR_OFFSET)+arg_offset1
+#define FUNC_LVAR l+disp_offset
+#define CALLER_ARG (l-ARG_LVAR_OFFSET)+arg_offset1
+#define CALLEE_ARG l+arg_offset
+
+void
+code_offset_set()
+{
+#if 0
+    int l;
+#endif
+    int lvar_offsetv = -disp+max_func_args*size_of_int+func_disp_offset;
+    int r1_offsetv = -disp+max_func_args*size_of_int-reg_save+r1_offset;
+    printf(".set L_%d,%d\n",lvar_offset_label,lvar_offsetv);
+    printf(".set L_%d,%d\n",r1_offset_label,r1_offsetv);
+#if 0
+printf("# function %s\n",fnptr->nm);
+    l = ARG_LVAR_OFFSET;
+printf("# offset call0\t%d\n",CALLER_ARG);
+    l = ARG_LVAR_OFFSET+max_func_args*size_of_int;
+printf("# offset calln\t%d %d\n",CALLER_ARG,max_func_args*size_of_int);
+    l = disp;
+printf("# offset lvarn\t%d %d\n",FUNC_LVAR+lvar_offsetv,disp);
+    l = 0;
+printf("# offset lvar0\t%d\n",FUNC_LVAR+lvar_offsetv);
+    l = -reg_save;
+printf("# offset regs\t%d\n",FUNC_LVAR+lvar_offsetv);
+printf("# offset r1off\t%d\n",r1_offsetv);
+    l = 0;
+printf("# offset carg0\t%d\n",CALLEE_ARG+r1_offsetv);
+    l = my_func_args;
+printf("# offset cargn\t%d %d\n",CALLEE_ARG+r1_offsetv,my_func_args);
+#endif
+}
+
+
+static void
+lvar8(int l)
+{
+    if (fnptr->sc==CODE) {
+	if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	    printf("lo16(%d)(r1)\n",CODE_CALLER_ARG);
+	} else
+	    printf("lo16(%d)(r30)\n",CODE_LVAR);
+    } else if (l<0) {  /* local variable */
+	printf("lo16(%d+L_%d)(r30)\n",FUNC_LVAR,lvar_offset_label);
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	printf("lo16(%d)(r30)\n",CALLER_ARG);
+    } else { /* callee's arguments */
+	printf("lo16(%d+L_%d)(r30)\n",CALLEE_ARG,r1_offset_label);
+    }
+}
+
+/* if size of local variables / input variables is more then 64k,
+   lo16 does not work. We have to use ha16 also. But we can't know
+   the exact size in one path compile. We may safely use lvar16ha 
+   if disp or max_func_args > 32k. Of course this is reduantant for
+   smaller offset. But who cares who use very large local variables?
+ */
+
+#define LARGE_LVAR (disp<-32765||max_func_args>32765)
+
+static void
+lvar16ha(int l)
+{
+    if (fnptr->sc==CODE) {
+	if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	    printf("la r0,ha16(%d)(r1)\n",CODE_CALLER_ARG);
+	} else
+	    printf("la r0,ha16(%d)(r30)\n",CODE_LVAR);
+    } else if (l<0) {  /* local variable */
+	printf("la r0,ha16(%d+L_%d)(r30)\n",FUNC_LVAR,lvar_offset_label);
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	if (CALLER_ARG>32765)
+	    printf("la r0,ha16(%d)(r30)\n",CALLER_ARG);
+    } else { /* callee's arguments */
+	printf("la r0,ha16(%d+L_%d)(r30)\n",CALLEE_ARG,r1_offset_label);
+    }
+}
+
+static void
+lvar16lo(int l)
+{
+    if (fnptr->sc==CODE) {
+	if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	    printf("lo16(%d)(r0)\n",CODE_CALLER_ARG);
+	} else
+	    printf("lo16(%d)(r0)\n",CODE_LVAR);
+    } else if (l<0) {  /* local variable */
+	printf("lo16(%d+L_%d)(r0)\n",FUNC_LVAR,lvar_offset_label);
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	if (CALLER_ARG>32765)
+	    printf("lo16(%d)(r0)\n",CALLER_ARG);
+	else
+	    printf("lo16(%d)(r30)\n",CALLER_ARG);
+    } else { /* callee's arguments */
+	printf("lo16(%d+L_%d)(r0)\n",CALLEE_ARG,r1_offset_label);
+    }
+}
+
+#define lvar_intro(i) if (LARGE_LVAR) lvar16ha(i)
+
+#define lvar(i) if (LARGE_LVAR) lvar16lo(i); else lvar8(i)
+
+void
+code_lvar(int e2,int creg) {
+    lvar_intro(e2);
+    printf("\tla %s,",register_name(creg));
+    lvar(e2);
+    regv[creg]=1;
+}
+
+void
+code_init(void)
+{
+    init_ptr_cache();
+}
+
+void
+gexpr_code_init(void){
+    regv[creg]=0;
+    fregv[freg]=0;
+}
+
+
+void
+code_arg_register()
+{
+    if (is_function(fnptr))
+	code_save_input_registers();
+}
+
+int 
+get_register(void)
+{    /* 使われていないレジスタを調べる */
+    int i,reg;
+    for(i=MAX_TMP_REG;i>MIN_TMP_REG;i--) {
+	if (regs[i]) continue;  /* 使われている */
+	regs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
+	return i;               /* その場所を表す番号を返す */
+    }
+    /* INPUT_REG か PTR_CACHE をつぶす */
+    for(i=MAX_TMP_REG;i>MIN_TMP_REG;i--) {
+	if (regs[i]==PTRC_REG) {
+	    clear_ptr_cache_reg(i);
+	} else 
+	    continue;
+	regs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
+	return i;               /* その場所を表す番号を返す */
+    }
+    /* search register stack */
+    for(i=0;i<reg_sp;i++) {
+	if ((reg=reg_stack[i])>=0) {
+            code_assign_lvar(
+                (reg_stack[i]=new_lvar(size_of_int)),reg,0); 
+            reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET;
+	    return reg;
+	}
+    }
+    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
+    error(-1); return creg;
+}
+
+int
+pop_register(void)
+{     /* レジスタから値を取り出す */
+    return reg_stack[--reg_sp];
+}
+
+int 
+get_fregister(void)
+{    /* 使われていないレジスタを調べる */
+    int i,reg;
+    for(i=MAX_TMP_FREG;i>MIN_TMP_FREG;i--) {
+	if (fregs[i]) continue;    /* 使われている */
+	fregs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
+	return i;               /* その場所を表す番号を返す */
+    }
+    /* search register stack */
+    for(i=0;i<freg_sp;i++) {
+	if ((reg=freg_stack[i])>=0) {
+            code_dassign_lvar(
+                (freg_stack[i]=new_lvar(size_of_double)),reg,1); 
+            freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET;
+	    return reg;
+	}
+    }
+    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
+    error(REG_ERR); return freg;
+}
+
+
+int
+pop_fregister(void)
+{     /* レジスタから値を取り出す */
+    return freg_stack[--freg_sp];
+}
+
+void
+emit_pop_free(int xreg)
+{
+    if (xreg>=0)
+	free_register(xreg);
+}
+
+void 
+free_register(int i) {    /* いらなくなったレジスタを開放 */
+    if (i<0||MAX_REGISTER<i) error(-1);
+    regv[i]=regs[i]=0;
+}
+
+void 
+free_fregister(int i) {    /* いらなくなったレジスタを開放 */
+    if (i<0||MAX_FREGISTER<i) error(-1);
+    fregv[i]=fregs[i]=0;
+}
+
+int
+get_input_fregister_var(int i,NMTBL *n,int is_code)
+{
+    if (is_code) {
+	if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0;
+	i = REG_VAR_BASE-i;
+    } else {
+	if (i<0||MAX_FREGISTER<i+MIN_TMP_FREG) return 0;
+	return list3(DREGISTER,i+MIN_TMP_FREG,(int)n);
+	i = i+MIN_TMP_FREG;
+    }
+    return list3(DREGISTER,i,(int)n);
+}
+
+int
+get_input_register_var(int i,NMTBL *n,int is_code)
+{
+    if (is_code) {
+	if(!(i<FREG_VAR_BASE-FREG_VAR_MIN)) return 0;
+	i = REG_VAR_BASE-i;
+    } else {
+	if (i<0||MAX_REGISTER<i+MIN_TMP_REG) return 0;
+	i = i+MIN_TMP_REG;
+    }
+    return list3(REGISTER,i,(int)n);
+}
+
+int
+free_register_count(void)
+{
+    int i,count,fcount;
+    fcount = count = 0;
+    for(i=0;i<MAX_REGISTER;i++) {
+        if (! regs[i] && ! regv[i]) count++;
+    }
+    for(i=0;i<MAX_FREGISTER;i++) {
+        if (! fregs[i] && ! fregv[i]) fcount++;
+    }
+    fprintf(stderr,"# free reg %d freg %d\n",count,fcount);
+    return count+fcount;
+}
+
+int
+register_full(void)
+{
+    int i;
+    for(i=0;i<MAX_REGISTER;i++) {
+	if (! regs[i]) { 
+	    return 0;  
+	}
+    }
+    return 1;    
+}
+
+void
+free_all_register(void)
+{
+    int i;
+    for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; regv[i]=0; }
+    for(i=0;i<MAX_FREGISTER;i++) { fregs[i]=0; fregv[i]=0; }
+    creg = get_register();
+    freg = get_fregister();
+    set_creg(CREG_REGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+    return;
+}
+
+void
+register_usage(char *s)
+{
+#if 0
+    int i;
+#endif
+    if (chk) return;
+    if (!lsrc) return;
+    printf("# %d: %s:",lineno,s);
+    printf(" creg=%s fgreg=%s",register_name(creg),fregister_name(freg));
+#if 0
+    printf("\n# regs:");
+    for(i=0;i<MAX_REGISTER;i++) { printf("%d",regv[i]); }
+    printf(":");
+    for(i=0;i<MAX_REGISTER;i++) { printf("%d",regs[i]); }
+    printf("\n# freg:");
+    for(i=0;i<MAX_FREGISTER;i++) { printf("%d",fregs[i]); }
+    printf(" regs_stack",register_name(creg),register_name(dreg));
+    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]);
+    }
+    if (cond_freg!=-1) { 
+	if(car(cond_freg)==DREGISTER) free_fregister(cadr(cond_freg)); 
+	cond_freg=-1; 
+    }
+    if (cond_reg!=-1)  { 
+	if(car(cond_reg)==REGISTER) free_register(cadr(cond_reg)); 
+	cond_reg=-1;  
+    }
+    text_mode();
+    gexpr_code_init();
+    register_usage("gexpr_init");
+}
+
+
+void 
+emit_init(void)
+{
+    free_all_register();
+    max_reg_var=-1; max_freg_var=-1;
+    reg_sp = 0;
+    freg_sp = 0;
+    text_mode();
+}
+
+int
+register_var(int r) {
+    return r;
+}
+
+
+int
+get_register_var(NMTBL *n)
+{
+    int i;
+    for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) {
+        if (! regs[REG_VAR_BASE-i]) {       /* 使われていないなら */
+            regs[REG_VAR_BASE-i]=USING_REG; /* そのレジスタを使うことを宣言し */
+            regv[REG_VAR_BASE-i]=0;
+	    if (i>max_reg_var) max_reg_var=i;
+	    /* その場所を表す番号を返す */
+	    return list3(REGISTER,REG_VAR_BASE-i,(int)n); 
+        }
+    }
+    return list2(LVAR,new_lvar(size_of_int));
+}
+
+int
+fregister_var(int r) {
+    return r;
+}
+
+int
+get_fregister_var(NMTBL *n)
+{
+    int i;
+    for(i=0;i<FREG_VAR_BASE-REG_VAR_MIN;i++) {
+        if (! regs[FREG_VAR_BASE-i]) {       /* 使われていないなら */
+            regs[FREG_VAR_BASE-i]=USING_REG; /*そのレジスタを使うことを宣言し*/
+            regv[FREG_VAR_BASE-i]=0;
+	    if (i>max_freg_var) max_freg_var=i;
+	    /* その場所を表す番号を返す */
+	    return list3(DREGISTER,FREG_VAR_BASE-i,(int)n); 
+        }
+    }
+    return list2(LVAR,new_lvar(size_of_double));
+}
+
+void 
+emit_push()
+{
+    int new_reg;
+    if (reg_sp>MAX_MAX) error(-1);
+    new_reg = get_register();
+    reg_stack[reg_sp++] = creg;     /* push するかわりにレジスタを使う */
+    creg = new_reg;
+    regv[creg]=1;
+}
+
+int
+emit_pop(int type)
+{
+    int xreg,reg;
+    xreg=pop_register();
+    if (xreg<= -REG_LVAR_OFFSET) {
+	reg = get_register();
+        code_rlvar(REG_LVAR_OFFSET+xreg,reg);
+	free_lvar(REG_LVAR_OFFSET+xreg);
+	xreg = reg;
+	regv[xreg]=1;
+    }
+    return xreg;
+}
+
+static int code_base;
+
+#define MAX_PTR_CACHE 10
+
+int ptr_cache=0;
+
+void
+init_ptr_cache()
+{
+    int i;
+    for(i=0;i<MAX_PTR_CACHE;i++) {
+	ptr_cache=glist3(0,ptr_cache,0);
+    }
+}
+
+void
+clear_ptr_cache_reg(int r)
+{
+    int ptcptr=ptr_cache;
+    while(ptcptr) {
+	if(car(ptcptr)&&caddr(ptcptr)==r) {
+	    car(ptcptr)=0;
+	    caddr(ptcptr)=0;
+	    free_register(r);
+	    return;
+	}
+	ptcptr=cadr(ptcptr);
+    }
+}
+
+void
+clear_ptr_cache()
+{
+    int ptcptr=ptr_cache;
+    while(ptcptr) {
+	if(car(ptcptr))
+	    free_register(caddr(ptcptr));
+	car(ptcptr)=0;
+	caddr(ptcptr)=0;
+	ptcptr=cadr(ptcptr);
+    }
+}
+
+
+int
+get_ptr_cache(NMTBL *nptr)
+{
+    int r;
+    int ptcptr=ptr_cache;
+    int g = (int)nptr;
+    int p,p1;
+    char *rrn;
+
+    p1 = ptcptr; p = cadr(p1); /* unnecesary, if ptcptr is initialized */
+    while(ptcptr) {
+	if(car(ptcptr)==g) return caddr(ptcptr);
+	p1=p; p=ptcptr;
+	ptcptr=cadr(ptcptr);
+    }
+    cadr(p1)=0;            /* remove the last one */
+    cadr(p) = ptr_cache;   /* connect current queue to the last one */
+    ptr_cache = p;         /* now the last one is the top */
+    if (!caddr(p)) {
+	if((r=get_register())) {
+	    caddr(p)=r; regs[r]=PTRC_REG;
+	} else {
+	    error(-1);
+	    r=creg; /* this can't happen */
+	}
+	car(p)=g;
+    } else {
+	r = caddr(p);
+    }
+    rrn = register_name(r);
+    if (nptr->sc==STATIC) {
+	printf("\taddis %s,r31,ha16(_%s-L_%d)\n",
+		 rrn,nptr->nm,code_base);
+	printf("\tla %s,lo16(_%s-L_%d)(%s)\n",
+		 rrn,nptr->nm,code_base,rrn);
+    } else {
+	printf("\taddis %s,r31,ha16(L_%s$non_lazy_ptr-L_%d)\n",
+		 rrn,nptr->nm,code_base);
+	printf("\tlwz %s,lo16(L_%s$non_lazy_ptr-L_%d)(%s)\n",
+		 rrn,nptr->nm,code_base,rrn);
+    }
+    return r;
+}
+
+void
+code_label(int labelno)
+{
+    clear_ptr_cache();
+    printf("L_%d:\n",labelno);
+}
+
+void
+code_gvar(int e1,int creg) {
+    int r;
+    r = get_ptr_cache((NMTBL*)cadr(e1));
+    if(r!=creg)
+	printf("\tmr %s,%s\n",register_name(creg),register_name(r));
+    regv[creg]=1;
+    return;
+}
+
+void
+code_rgvar(int e1,int creg) {
+    printf("\tlwz %s,0(%s)\n",register_name(creg),
+                             register_name(get_ptr_cache((NMTBL*)cadr(e1))));
+    regv[creg]=1;
+}
+
+void
+code_crgvar(int e1,int creg){
+    char *crn = register_name(creg);
+    printf("\tlbz %s,0(%s)\n",crn,
+                             register_name(get_ptr_cache((NMTBL*)cadr(e1))));
+    printf("\textsb %s,%s\n",crn,crn);
+    regv[creg]=1;
+}
+
+
+void
+code_register(int e2,int creg) {
+    if (creg!=e2)
+	printf("\tmr %s,%s\n",register_name(creg),register_name(e2));
+    regv[creg]=1;
+}
+
+
+void
+code_rlvar(int e2,int reg) {
+    lvar_intro(e2);
+    printf("\tlwz %s,",register_name(reg));
+    lvar(e2);
+    regv[creg]=1;
+}
+
+
+void
+code_crlvar(int e2,int reg) {
+    lvar_intro(e2);
+    printf("\tlbz %s,",register_name(reg));
+    lvar(e2);
+    printf("\textsb %s,%s\n",register_name(reg),register_name(reg));
+    regv[reg]=1;
+}
+
+
+void
+code_fname(NMTBL *n,int creg) {
+    int r;
+    r = get_ptr_cache(n);
+    if(r!=creg)
+	printf("\tmr %s,%s\n",register_name(creg),register_name(r));
+    regv[creg]=1;
+    return;
+}
+
+
+void
+code_const(int e2,int creg) {
+    char *crn = register_name(creg);
+    if (-32768<e2&&e2<32768)
+	printf("\tli %s,%d\n",crn,e2);
+    else {
+	printf("\tlis %s,ha16(%d)\n",crn,e2);
+	printf("\taddi %s,%s,lo16(%d)\n",crn,crn,e2);
+    }
+    regv[creg]=1;
+}
+
+
+void
+code_neg(int creg) {
+    printf("\tneg %s,%s\n", register_name(creg), register_name(creg));
+}
+
+
+void
+code_not(int creg) {
+    printf("\tnor %s,%s,%s\n", 
+	register_name(creg), register_name(creg),register_name(creg));
+}
+
+
+void
+code_lnot(int creg) {
+    printf("\tsubfic r0,%s,0\n", register_name(creg));
+    printf("\tadde %s,r0,%s\n", register_name(creg),register_name(creg));
+}
+
+void
+code_preinc(int e1,int e2,int reg) {
+    char *xrn,*drn;
+    int i,dreg;
+    if (car(e2)==REGISTER) {
+	printf("\taddi %s,%s,%d\n", 
+		register_name(cadr(e2)),register_name(cadr(e2)), caddr(e1));
+	if (cadr(reg)!=e2)
+	    printf("\tmr %s,%s\n",register_name(cadr(reg)),register_name(e2));
+	regv[reg]=1;
+	return;
+    } 
+    g_expr(e2);
+    xrn = register_name(creg);
+    dreg=get_register(); if (!dreg) error(-1);
+    drn = register_name(dreg);
+    printf("\tlwz %s,0(%s)\n",drn,xrn);
+    printf("\taddi %s,%s,%d\n",drn,drn,caddr(e1));
+    printf("\tstw %s,0(%s)\n",drn,xrn);
+    i=creg;creg=dreg;dreg=i;
+    regv[creg]=1;
+    free_register(dreg);
+}
+
+
+void
+code_postinc(int e1,int e2,int reg) {
+    char *xrn,*crn,*nrn;
+    int dreg,nreg,i;
+    if (car(e2)==REGISTER) {
+	printf("\tmr %s,%s\n",register_name(reg),register_name(cadr(e2)));
+	printf("\taddi %s,%s,%d\n", 
+	    register_name(cadr(e2)),register_name(cadr(e2)),caddr(e1));
+	regv[reg]=1;
+	return;
+    } 
+    g_expr(e2);
+    crn = register_name(creg);
+    dreg=get_register(); if (!dreg) error(-1);
+    xrn = register_name(dreg);
+    nreg=get_register(); if (!nreg) error(-1);
+    nrn = register_name(nreg);
+    printf("\tlwz %s,0(%s)\n",xrn,crn);
+    printf("\taddi %s,%s,%d\n",nrn,xrn,caddr(e1));
+    printf("\tstw %s,0(%s)\n",nrn,crn);
+    i=creg;creg=dreg;dreg=i; 
+    free_register(nreg);
+    free_register(dreg);
+    regv[creg]=1;
+}
+
+
+void
+code_cpostinc(int e1,int e2,int reg) {
+    char *xrn,*crn,*nrn;
+    int i,nreg,dreg;
+    if (car(e2)==REGISTER) {
+	printf("\tlbz %s,0(%s)\n",register_name(reg),register_name(cadr(e2)));
+	printf("\textsb %s,%s\n",register_name(reg),register_name(reg));
+	printf("\taddi %s,%s,%d\n", 
+	    register_name(cadr(e2)),register_name(cadr(e2)),caddr(e1));
+	regv[reg]=1;
+	return;
+    } 
+    g_expr(e2);
+    crn = register_name(creg);
+    dreg=get_register(); if (!dreg) error(-1);
+    xrn = register_name(dreg);
+    nreg=get_register(); if (!nreg) error(-1);
+    nrn = register_name(nreg);
+    printf("\tlwz %s,0(%s)\n",xrn,crn);
+    printf("\tlbz %s,0(%s)\n",nrn,xrn);
+    printf("\textsb %s,%s\n",nrn,nrn);
+    printf("\taddi %s,%s,%d\n", xrn,xrn,caddr(e1));
+    printf("\tstw %s,0(%s)\n",xrn,crn);
+    i=creg;creg=nreg;nreg=i; 
+    free_register(nreg);
+    free_register(dreg);
+    regv[creg]=1;
+}
+
+
+void
+code_cpreinc(int e1,int e2,int reg) {
+    char *xrn,*crn,*nrn;
+    int i,nreg,dreg;
+    if (car(e2)==REGISTER) {
+	printf("\tlbzu %s,%d(%s)\n",register_name(reg),caddr(e1),register_name(cadr(e2)));
+	printf("\textsb %s,%s\n",register_name(reg),register_name(reg));
+	regv[reg]=1;
+	return;
+    } 
+    g_expr(e2);
+    crn = register_name(creg);
+    dreg=get_register(); if (!dreg) error(-1);
+    xrn = register_name(dreg);
+    nreg=get_register(); if (!nreg) error(-1);
+    nrn = register_name(nreg);
+    printf("\tlwz %s,0(%s)\n",xrn,crn);
+    printf("\tlbzu %s,%d(%s)\n",nrn,caddr(e1),xrn);
+    printf("\tstw %s,0(%s)\n",xrn,crn);
+    printf("\textsb %s,%s\n",nrn,nrn);
+    i=creg;creg=nreg;nreg=i; 
+    free_register(nreg);
+    free_register(dreg);
+    regv[creg]=1;
+}
+
+
+void
+code_cpostdec(int e1,int e2,int reg) {
+    char *xrn,*crn,*nrn;
+    int i,nreg,dreg;
+    if (car(e2)==REGISTER) {
+	crn=register_name(reg);
+	xrn=register_name(cadr(e2));
+	printf("\tlbz %s,0(%s)\n",crn,xrn);
+	printf("\taddi %s,%s,%d\n",xrn,xrn,caddr(e1));
+	printf("\textsb %s,%s\n",crn,crn);
+	regv[reg]=1;
+	return;
+    } 
+    g_expr(e2);
+    crn = register_name(creg);
+    dreg=get_register(); if (!dreg) error(-1);
+    xrn = register_name(dreg);
+    nreg=get_register(); if (!nreg) error(-1);
+    nrn = register_name(nreg);
+    printf("\tlwz %s,0(%s)\n",xrn,crn);
+    printf("\tlbz %s,0(%s)\n",nrn,xrn);
+    printf("\taddi %s,%s,%d\n",xrn,xrn,caddr(e1));
+    printf("\tstw %s,0(%s)\n",xrn,crn);
+    printf("\textsb %s,%s\n",nrn,nrn);
+    i=creg;creg=nreg;nreg=i; 
+    free_register(nreg);
+    free_register(dreg);
+    regv[creg]=1;
+}
+
+
+void
+code_cpredec(int e1,int e2,int reg) {
+    char *xrn,*crn,*nrn;
+    int i,nreg,dreg;
+    if (car(e2)==REGISTER) {
+	crn=register_name(reg);
+	xrn=register_name(cadr(e2));
+	printf("\tlbzu %s,%d(%s)\n",crn,caddr(e1),xrn);
+	printf("\textsb %s,%s\n",crn,crn);
+	regv[reg]=1;
+	return;
+    } 
+    g_expr(e2);
+    crn = register_name(creg);
+    dreg=get_register(); if (!dreg) error(-1);
+    xrn = register_name(dreg);
+    nreg=get_register(); if (!nreg) error(-1);
+    nrn = register_name(nreg);
+    printf("\tlwz %s,0(%s)\n",xrn,crn);
+    printf("\tlbzu %s,%d(%s)\n",nrn,caddr(e1),xrn);
+    printf("\tstw %s,0(%s)\n",xrn,crn);
+    printf("\textsb %s,%s\n",nrn,nrn);
+    i=creg;creg=nreg;nreg=i; 
+    free_register(nreg);
+    free_register(dreg);
+    regv[creg]=1;
+}
+
+
+void
+code_return(int creg) {
+    char *crn = register_name(creg);
+    printf("\taddis %s,r31,ha16(L_%d-L_%d)\n",crn,retcont,code_base);
+    printf("\tla %s,lo16(L_%d-L_%d)(%s)\n",crn,retcont,code_base,crn);
+}
+
+#define R1SAVE 1
+
+void
+code_environment(int creg) {
+    /* save frame pointer */
+#if R1SAVE
+    printf("\tlwz %s,0(r1)\n",register_name(creg));
+#else
+    int l = 0;
+    printf("\tla %s,",register_name(creg));
+    printf("lo16(%d+L_%d)(r30)\n",FUNC_LVAR,lvar_offset_label);
+#endif
+}
+
+void
+code_bool(int e1) {
+    char *xrn;
+    int e2,e3;
+    b_expr(e1,1,e2=fwdlabel(),1);  /* including > < ... */
+    xrn = register_name(creg);
+    printf("\tli %s,0\n",xrn);
+    jmp(e3=fwdlabel());
+    fwddef(e2);
+    printf("\tli %s,1\n",xrn);
+    fwddef(e3);
+}
+
+char *
+code_gt(int cond) {
+    return (cond?"gt":"le");
+}
+
+char *
+code_ugt(int cond) {
+    return (cond?"gt":"le");
+}
+
+char *
+code_ge(int cond) {
+    return (cond?"ge":"lt");
+}
+
+char *
+code_uge(int cond) {
+    return (cond?"ge":"lt");
+}
+
+char *
+code_eq(int cond) {
+    return (cond?"eq":"ne");
+}
+
+void
+code_cmp_crgvar(int e1) {
+    int r;
+    char *crn = register_name(creg);
+    r = get_ptr_cache((NMTBL*)cadr(e1));
+    printf("\tlbz %s,0(%s)\n",crn,register_name(r));
+    printf("\tcmpwi cr0,%s,0\n",crn);
+    regv[creg]=0;
+}
+
+
+void
+code_cmp_crlvar(int e2) {
+    char *crn = register_name(creg);
+    lvar_intro(e2);
+    printf("\tlbz %s,",crn);
+    lvar(e2);
+    code_cmp_register(creg);
+    regv[creg]=0;
+}
+
+
+void
+code_cmp_rgvar(int e1) {
+    int r;
+    char *crn = register_name(creg);
+    r = get_ptr_cache((NMTBL*)cadr(e1));
+    printf("\tlwz %s,0(%s)\n",crn,register_name(r));
+    code_cmp_register(creg);
+    regv[creg]=0;
+}
+
+
+void
+code_cmp_rlvar(int e2) {
+    char *crn = register_name(creg);
+    lvar_intro(e2);
+    printf("\tlwz %s,",crn);
+    lvar(e2);
+    code_cmp_register(creg);
+    regv[creg]=0;
+}
+
+
+void
+code_cmp_register(int e2) {
+    printf("\tcmpwi cr0,%s,0\n",register_name(e2));
+}
+
+
+void
+ascii(char *s)
+{
+    printf("\t.ascii \"");
+    while(*s) {
+	if (*s=='\n')
+	    printf("%cn",92);
+	else if (*s<' ')
+	    printf("%c%03o",92,*s);
+	else if (*s=='\\')
+	    printf("\\\\");
+	else if (*s==34)
+	    printf("%c%c",92,34);
+	else 
+	    printf("%c",*s);
+	s++;
+    }
+    printf("\\0%c\n\t.align 2\n",34);
+}
+
+void
+code_string(int e1,int creg)
+{
+    char *s,*crn;
+    int lb;
+    crn=register_name(creg);
+
+    s=(char *)cadr(e1);
+    printf(".data\t\n.cstring\n\t.align 2\n");
+    lb=fwdlabel();
+    printf("L_%d:\n",lb);
+    ascii(s);
+    if (output_mode==TEXT_EMIT_MODE) {
+	printf(".text\n");
+    } else {
+	text_mode();
+    }
+    printf("\taddis %s,r31,ha16(L_%d-L_%d)\n",crn,lb,code_base);
+    printf("\tla %s,lo16(L_%d-L_%d)(%s)\n",crn,lb,code_base,crn);
+}
+
+#define MAX_COPY_LEN 20
+
+void 
+emit_copy(int from,int  to,int length,int offset,int value,int det)
+{
+    char *frn =	register_name(from);
+    char *trn =	register_name(to);
+    char *drn;
+    int fix = 0;
+    char *memmove = "memmove";
+    int dreg = get_register(); if (!dreg) error(-1);
+    drn	 = register_name(dreg);
+
+    /* length <0 means upward direction copy */
+    switch (length) {
+    case 0:	break;
+    case 1: case -1:
+	printf("\tlbz %s,%d(%s)\n",drn,offset,frn);
+	printf("\tstb %s,%d(%s)\n",drn,offset,trn);
+	break;
+    case 2: case -2:
+	printf("\tlhz %s,%d(%s)\n",drn,offset,frn);
+	printf("\tsth %s,%d(%s)\n",drn,offset,trn);
+	break;
+    case 4: case -4:
+	printf("\tlwz %s,%d(%s)\n",drn,offset,frn);
+	printf("\tstw %s,%d(%s)\n",drn,offset,trn);
+	break;
+    default:
+	if (-MAX_COPY_LEN<length && length <0) {
+	    for(;length<=4;length+=4,offset-=4)
+		emit_copy(from,to,4,offset,0,det);
+	    for(;length<=2;length+=2,offset-=2)
+		emit_copy(from,to,2,offset,0,det);
+	    if(length>0)
+		emit_copy(from,to,length,offset,0,det);
+	    break;
+	} else if (length <=MAX_COPY_LEN) {
+	    for(;length>=4;length-=4,offset+=4)
+		emit_copy(from,to,4,offset,0,det);
+	    for(;length>=2;length-=2,offset+=2)
+		emit_copy(from,to,2,offset,0,det);
+	    if(length>0)
+		emit_copy(from,to,length,offset,0,det);
+	    break;
+	}
+	clear_ptr_cache();
+	code_save_stacks();
+	printf("\tli r5,%d\n",length);
+	printf("\tmr r4,%s\n",frn);
+	printf("\tmr r3,%s\n",trn);
+        /* overrap must be allowed */
+	printf("\tbl L_%s$stub\n",memmove);
+	extern_define(memmove,0,FUNCTION,1);
+        fix=0;
+	set_creg(RET_REGISTER,0);
+	if (creg!=to) {
+	    free_register(to); to = creg;
+	}
+	break;
+    }
+    if (value) {
+    /* creg must point top of the destination data */
+    /* this code is necessary for the value of assignment or function call */
+    /* otherwise we don't need this */
+	if (fix) printf("\taddi %s,%s,%d\n",trn,trn,fix);
+	if(creg!=to) {
+	    free_register(creg); creg=to;
+	}
+    }
+    free_register(dreg);
+    regv[from]=regv[to]=regv[dreg]=0;
+    regv[creg]=1;
+}
+
+int
+struct_push(int e4,int t,int arg) 
+{
+    int length,count;
+    int dreg,sreg; char *drn,*crn,*srn;
+    g_expr(e4);
+    length=size(t); 
+    if(length%size_of_int) {
+	length += size_of_int - (length%size_of_int);
+    }
+    dreg = get_register(); if (!dreg) error(-1);
+    drn = register_name(dreg);
+    crn = register_name(creg);
+    if (length<MAX_COPY_LEN) {
+	sreg = get_register(); if (!sreg) error(-1);
+	srn = register_name(sreg);
+	code_lvar(cadr(arg),sreg);
+	for(count=0;length<MAX_COPY_LEN;count++,length-=size_of_int) {
+	    if (length==0) {
+		free_register(sreg);
+		free_register(dreg);
+		return count;
+	    } else {
+		printf("\tlwz %s,%d(%s)\n",drn,length-size_of_int,crn);
+		printf("\tstwu %s,%d(%s)\n",drn,-size_of_int,srn);
+	    }
+	}
+    }
+    code_lvar(cadr(arg),dreg);
+    /* downward direction copy */
+    emit_copy(creg,dreg,length,0,0,1);
+    if (dreg) free_register(dreg);
+    return length/size_of_int;
+}
+
+void
+set_creg(int reg,int mode)
+{
+    if (reg!=creg) {
+	clear_ptr_cache_reg(reg);
+	if (mode) 
+	    printf("\tmr %s,%s\n",register_name(reg),register_name(creg));
+	free_register(creg);
+	creg = reg;
+	regs[creg]=1;
+    }
+}
+
+void
+set_freg(int reg,int mode)
+{
+    if (reg!=freg) {
+	if (mode) 
+	    printf("\tfmr %s,%s\n",fregister_name(reg),fregister_name(freg));
+	free_fregister(freg);
+	freg = reg;
+	fregs[freg]=1;
+    }
+}
+
+void
+use_var(int arg)
+{
+    if (car(arg)==REGISTER)
+	regs[cadr(arg)]=USING_REG;
+    else if (car(arg)==DREGISTER)
+	fregs[cadr(arg)]=USING_REG;
+}
+
+void
+code_save_input_registers()
+{
+#if 0
+    int args;
+    NMTBL *n;
+    int reg;
+    int tag;
+    int lvar;
+    int t;
+    /* fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); */
+    int reg_offset = 0;
+
+    for(args = fnptr->dsp;args;args = cadr(args)) {
+	n = (NMTBL *)caddr(args);
+	tag = n->sc;
+	reg = n->dsp;
+	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;
+	    reg += reg_offset; /* for duplicated floating point argument */
+	} else if (tag==DREGISTER) {
+	    /* fregs[reg]==INPUT_REG case should be considered */
+	    n->dsp = new_lvar(size_of_double);
+	    t = DOUBLE;
+	    reg_offset+=2;
+	} else 
+	    continue;
+	n->sc  = LVAR;
+	lvar = list2(LVAR,n->dsp);
+	g_expr_u(assign_expr0(list2(LVAR,n->dsp),list3(tag,reg,(int)n),n->ty,t));
+	if (tag==REGISTER) {
+	    free_register(reg);
+	} else if (tag==DREGISTER) {
+	    free_fregister(reg);
+	}
+    }
+    my_func_args = 0;
+#else
+    int args;
+    NMTBL *n;
+    int reg;
+    int tag;
+    int lvar;
+    int t;
+    /* fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); */
+    int reg_offset = 0;
+    int offset = 0;
+
+    for(args = fnptr->dsp;args;args = cadr(args)) {
+	n = (NMTBL *)caddr(args);
+	tag = n->sc;
+	reg = n->dsp;
+	if (!n||n==&null_nptr) error(REG_ERR);
+	if (tag==REGISTER) {
+	    /* regs[reg]==INPUT_REG case should be considered */
+	    n->dsp = offset;
+	    offset+=size_of_int;
+	    t = INT;
+	    reg += reg_offset; /* for duplicated floating point argument */
+	} else if (tag==DREGISTER) {
+	    /* fregs[reg]==INPUT_REG case should be considered */
+	    n->dsp = offset;
+	    t = n->ty;
+	    if(t==FLOAT) { offset+=size_of_float; reg_offset+=1; }
+	    else if(t==DOUBLE) { offset+=size_of_double; reg_offset+=2; }
+	    else error(-1);
+	} else {
+	    offset += size(n->ty);
+	    continue;
+	}
+	n->sc  = LVAR;
+	lvar = list2(LVAR,n->dsp);
+	g_expr_u(assign_expr0(list2(LVAR,n->dsp),list3(tag,reg,(int)n),n->ty,t));
+	if (tag==REGISTER) {
+	    free_register(reg);
+	} else if (tag==DREGISTER) {
+	    free_fregister(reg);
+	}
+    }
+    my_func_args = offset;
+#endif
+}
+
+int
+simple_args(int e3)
+{
+    return 
+	!contains_in_list(e3,FUNCTION) &&
+	!contains_in_list(e3,CONV) &&
+	!contains_in_list(e3,RSTRUCT) &&
+	!contains_in_list(e3,SASS)
+    ;
+}
+
+int
+caller_arg_offset_v(int arg)
+{
+    return ARG_LVAR_OFFSET+arg*size_of_int;
+}
+
+int
+function(int e1)
+{
+    int e2,e3,e4,e5,nargs,t,r0,r1;
+    int arg,reg_arg,freg_arg,arg_assign;
+    int reg_arg_list=0,ret_type,special_lvar;
+    NMTBL *fn = 0;
+    int jmp = 0;
+    char *jrn;
+
+    special_lvar = -1;
+    ret_type = cadddr(e1);
+
+    e2 = cadr(e1);
+    if (car(e2) == FNAME) {	
+	fn=(NMTBL *)cadr(e2);
+    } else {	
+	jmp = get_register_var(0);
+	if (car(jmp)!=REGISTER) error(-1);
+	reg_arg_list = list2(jmp,reg_arg_list);
+	g_expr(e2);
+	code_register(creg,cadr(jmp));
+        /* g_expr(assign_expr0(jmp,e2,INT,INT)); functions are lvalue */
+    }
+
+    /* now all input register vars are free */
+    code_save_stacks();
+    set_creg(CREG_REGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+
+    nargs = reg_arg = freg_arg = arg_assign = 0;
+    for (e3 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) {	
+	t=caddr(e3);
+	e4 = car(e3);
+	if(scalar(t)) {
+	    if (reg_arg>=MAX_INPUT_REGISTER_VAR) { 
+		arg = list2(LVAR,caller_arg_offset_v(nargs));
+	    } else if (!simple_args(e3) && cadr(e3)) {
+		arg = get_register_var(0); 
+		arg_assign = list2(
+		    assign_expr0(get_input_register_var(reg_arg,0,0),arg,t,t),
+		    arg_assign);
+	    } else {
+		arg = get_input_register_var(reg_arg,0,0); 
+	    }
+	    use_var(arg); /* protect from input register free */
+	    reg_arg_list = list2(arg,reg_arg_list);
+	    g_expr_u(assign_expr0(arg,e4,t,t));
+	    nargs ++ ; reg_arg++;
+	    continue;
+	} else if (t==DOUBLE||t==FLOAT) {
+	    if (reg_arg<MAX_INPUT_REGISTER_VAR) {
+		/* sigh... 
+                   printf requies floating value in integer registers
+                 */
+		if (car(e4)==DRLVAR) {
+		    special_lvar = cadr(e4);
+		    e5 = list2(LVAR,special_lvar);
+		} else {
+		    special_lvar = new_lvar(size_of_double);
+		    g_expr(assign_expr0(
+			(e5=list2(LVAR,special_lvar)),e4,t,t));
+		    reg_arg_list = list2(e5,reg_arg_list);
+		    e4 = list2(DREGISTER,freg);
+		    /* freg should not change until XXX */
+		}
+		r0=get_input_register_var(reg_arg,0,0);
+		r1=get_input_register_var(reg_arg+1,0,0);
+		use_var(r0); /* protect from input register free */
+		use_var(r1); /* protect from input register free */
+		reg_arg_list = list2(r0,reg_arg_list);
+		reg_arg_list = list2(r1,reg_arg_list);
+		arg_assign = list2( assign_expr0(r0,e5,INT,INT), arg_assign);
+		arg_assign = list2( assign_expr0(r1,
+			list2(LVAR,special_lvar+size_of_int),
+			INT,INT), arg_assign);
+		reg_arg += 2;
+	    }
+	    if (freg_arg>=4 && freg_arg<MAX_INPUT_DREGISTER_VAR) { 
+		/* oh my god! 
+                   it requies integer register and floating register and
+                   stack value. You are crazy.
+                 */
+		arg_assign = list2(
+		    assign_expr0(list2(LVAR,caller_arg_offset_v(nargs)),
+			    get_input_fregister_var(freg_arg,0,0),t,t),
+		    arg_assign);
+	    }
+	    if (freg_arg>=MAX_INPUT_DREGISTER_VAR) {
+		arg = list2(LVAR,caller_arg_offset_v(nargs));
+	    } else if (!simple_args(e3)) {
+		arg = get_fregister_var(0); 
+		arg_assign = list2(
+		    assign_expr0(get_input_fregister_var(freg_arg,0,0),arg,t,t),
+		    arg_assign);
+	    } else {
+		arg = get_input_fregister_var(freg_arg,0,0); 
+	    }
+	    use_var(arg); /* protect from input register free */
+	    reg_arg_list = list2(arg,reg_arg_list);
+	    g_expr_u(assign_expr0(arg,e4,t,t)); /* XXX */
+	    freg_arg++;
+	    nargs += size(t)/size_of_int;
+	    continue;
+	} else if (car(t)==STRUCT||car(t)==UNION) {
+	    arg = list2(LVAR,caller_arg_offset_v(nargs));
+	    nargs += struct_push(e4,t,arg);
+	    continue;
+	} else {
+	    error(TYERR);
+	}
+	++nargs;
+    }
+    if (max_func_args<nargs) max_func_args=nargs;
+    for(;arg_assign;arg_assign=cadr(arg_assign)) {
+	g_expr_u(car(arg_assign));
+    }
+    clear_ptr_cache();
+    if (car(e2) == FNAME) {	
+	printf("\tbl\tL_%s$stub\n",fn->nm);
+    } else {
+        jrn = register_name(cadr(jmp));
+        printf("\tmtctr %s\n",jrn);
+        printf("\tbctrl\n");
+    }
+    for(;reg_arg_list;reg_arg_list=cadr(reg_arg_list)) {
+	arg = car(reg_arg_list);
+	if (car(arg)==DREGISTER) free_fregister(cadr(arg));
+	else if (car(arg)==REGISTER) free_register(cadr(arg));
+	else if (car(arg)==LVAR&&cadr(arg)<0) free_lvar(cadr(arg));
+    }
+    if (ret_type==DOUBLE||ret_type==FLOAT) {
+	set_freg(RET_FREGISTER,0);
+        fregv[freg]=1; regv[creg]=0;
+    } else if (ret_type==VOID) {
+        fregv[freg]=0; regv[creg]=0;
+    } else {
+	set_creg(RET_REGISTER,0);
+        fregv[freg]=0; regv[creg]=1;
+    }
+    return ret_type;
+}
+
+void
+code_frame_pointer(int e3) {
+#if R1SAVE
+    printf("\tmr r1,%s\n",register_name(e3));
+#else
+    printf("\tmr r30,%s\n",register_name(e3));
+#endif
+}
+
+
+void
+code_fix_frame_pointer(int disp_offset) {
+    int l = 0;
+    printf("\tla r30,");
+    printf("lo16(%d+L_%d)(r30)\n",FUNC_LVAR,lvar_offset_label);
+}
+
+void
+code_jmp(char *s) {
+    max_reg_var = REG_VAR_BASE-REG_VAR_MIN;
+    max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN;
+    printf("\tb L_%s$stub\n",s);
+}
+
+
+void
+code_indirect_jmp(int e2) {
+    max_reg_var = REG_VAR_BASE-REG_VAR_MIN;
+    max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN;
+    printf("\tmtctr %s\n",register_name(e2));
+    printf("\tbctr\n");
+}
+
+int
+rindirect(int e1)   /* *(p +5 ) */
+{
+    char *crn;
+    int e2,e3,e4,offset;
+
+    offset=0;
+    e3 = cadr(e2 = cadr(e1));
+    if (car(e2)==ADD) {
+        e4=caddr(e2);
+	if (car(e4)==CONST) {
+	    offset=cadr(e4);
+	    e2=e3;
+	}
+    }
+    g_expr(e2);
+    crn=register_name(creg);
+    switch (car(e1)) {
+    case FRINDIRECT: case DRINDIRECT:
+	printf("\t%s %s,%d(%s)\n",fload(car(e1)==DRINDIRECT),
+	    fregister_name(freg),offset,crn);
+	regv[creg]=0; regv[freg]=1;
+	return DOUBLE;
+    case CRINDIRECT: 
+	printf("\tlbz %s,%d(%s)\n",crn,offset,crn);
+	printf("\textsb %s,%s\n",crn,crn);
+	return CHAR;
+    case RINDIRECT:
+	printf("\tlwz %s,%d(%s)\n",crn,offset,crn);
+	return INT;
+    }
+    error(-1); return INT;
+}
+
+void
+code_assign_gvar(int e2,int creg,int byte) {
+    int r;
+    char *crn,*rrn;
+    r = get_ptr_cache((NMTBL*)cadr(e2));
+    rrn=register_name(r);
+    crn=register_name(creg);
+    if (byte) {
+	printf("\tstb %s,0(%s)\n",crn,rrn);
+    } else {
+	printf("\tstw %s,0(%s)\n",crn,rrn);
+    }
+}
+
+void
+code_assign_lvar(int e2,int creg,int byte) {
+    char *crn;
+    crn=register_name(creg);
+    lvar_intro(e2);
+    if (byte) {
+	printf("\tstb %s,",crn); lvar(e2);
+    } else {
+	printf("\tstw %s,",crn); lvar(e2);
+    }
+}
+
+void
+code_assign_register(int e2,int byte,int creg) {
+    if (e2!=creg)
+	printf("\tmr %s,%s\n",register_name(e2),register_name(creg));
+}
+
+void
+code_assign(int e2,int byte,int creg) {
+    char *drn=register_name(e2);
+    char *crn=register_name(creg);
+
+    if (byte) {
+	printf("\tstb %s,0(%s)\n",crn,drn);
+    } else {
+	printf("\tstw %s,0(%s)\n",crn,drn);
+    }
+}
+
+
+void
+code_register_assop(int e2,int op,int byte) {
+    int reg;
+    int xreg = creg;
+    creg = reg = e2;
+    tosop(op,xreg);
+    creg = xreg;
+    if (creg!=reg)
+	printf("\tmr %s,%s\n",register_name(creg),register_name(reg));
+}
+
+
+void
+code_assop(int op,int byte) {
+    char *xrn,*crn,*drn;
+    int xreg;
+    int edx = get_register(); if(!edx) error(-1);
+    xrn = register_name(xreg = emit_pop(0));       /* pop e3 value */
+    regv[xreg]=regs[xreg]=1;
+    printf("# assop\n\tmr %s,%s\n",register_name(edx),register_name(creg));
+    regv[edx]=1;
+    ld_indexx(byte,0,edx);
+    tosop(op,xreg);
+    crn = register_name(creg);
+    drn = register_name(edx);
+    if (byte) {
+	printf("\tstb %s,0(%s)\n",crn,drn);
+    } else {
+	printf("\tstw %s,0(%s)\n",crn,drn);
+    }
+    free_register(edx);
+    emit_pop_free(xreg);
+}
+
+
+void
+tosop(int op,int oreg)
+{
+    int dx;
+    char *orn,*crn,*drn;
+
+    if(oreg==-1) {
+	error(-1);
+    } else if (oreg<= -REG_LVAR_OFFSET) {
+	dx = get_register(); if (dx<0) error(-1);
+        code_rlvar(oreg+REG_LVAR_OFFSET,dx);
+	oreg = dx;
+        regv[oreg]=1;
+    }
+
+    switch(op) {
+    case LSHIFT:
+    case ULSHIFT:
+	shift("slw",oreg);
+	return;
+    case RSHIFT:
+	shift("srw",oreg);
+	return;
+    case URSHIFT:
+	shift("sraw",oreg);
+	return;
+    }
+    orn = register_name(oreg);
+    crn = register_name(creg);
+    switch(op) {
+    case ADD:
+	printf("\tadd %s,%s,%s\n",crn,crn,orn);
+	break;
+    case SUB:
+	printf("\tsub %s,%s,%s\n",crn,crn,orn);
+	break;
+    case CMP:
+	printf("\tcmpw cr0,%s,%s\n",crn,orn);
+	break;
+    case BAND: 
+	printf("\tand %s,%s,%s\n",crn,crn,orn);
+	break;
+    case EOR: 
+	printf("\txor %s,%s,%s\n",crn,crn,orn);
+	break;
+    case BOR:
+	printf("\tor %s,%s,%s\n",crn,crn,orn);
+	break;
+    case MUL:
+	printf("\tmullw %s,%s,%s\n",crn,crn,orn);
+	break;
+    case UMUL:
+	printf("\tmullw %s,%s,%s\n",crn,crn,orn);
+	break;
+    case DIV:
+	printf("\tdivw %s,%s,%s\n",crn,crn,orn);
+	break;
+    case UDIV:
+	printf("\tdivwu %s,%s,%s\n",crn,crn,orn);
+	break;
+    case MOD:
+	dx=get_register();
+	drn = register_name(dx);
+	printf("\tdivw %s,%s,%s\n",drn,crn,orn);
+	printf("\tmullw %s,%s,%s\n",drn,drn,orn);
+	printf("\tsubf %s,%s,%s\n",crn,drn,crn);
+	free_register(dx);
+	break;
+    case UMOD:
+	dx=get_register();
+	drn = register_name(dx);
+	printf("\tdivwu %s,%s,%s\n",drn,crn,orn);
+	printf("\tmullw %s,%s,%s\n",drn,drn,orn);
+	printf("\tsubf %s,%s,%s\n",crn,drn,crn);
+	free_register(dx);
+	break;
+    default:
+	error(-1);
+    }
+    if(oreg!=creg) free_register(oreg);
+}
+
+
+void
+shift(char *op, int reg)
+{
+    char *crn = register_name(creg);
+    char *rrn = register_name(reg);
+    printf("\t%s %s,%s,%s\n",op,crn,rrn,crn);
+}
+
+void
+ld_indexx(int byte, int n, int xreg)
+{	
+    char *crn = register_name(creg);
+    if (byte) {
+	printf("\tlbz %s,%d(%s)\n",register_name(creg),n,
+	    register_name(xreg));
+	printf("\textsb %s,%s\n",crn,crn);
+    } else 
+	printf("\tlwz %s,%d(%s)\n",register_name(creg),n,
+	    register_name(xreg));
+}
+
+int
+code_csvalue()
+{
+    return creg;
+}
+
+void
+code_cmpdimm(int e, int csreg)
+{
+    /* used in dosiwtch() */
+    if(chk) return;
+    printf("\tcmpwi cr0,%s,%d\n",register_name(csreg),e);
+}
+
+void
+code_opening(char *filename)
+{
+    printf("\t.file \"%s\"\n",filename);
+    /* printf("\t.version\t\"01.01\"\n"); */
+    /* printf("gcc2_compiled.:\n"); */
+    printf(".text\n");
+}
+
+void
+rexpr(int e1, int l1, char *s,int t)
+{       
+    g_expr(list3(CMP,cadr(e1),caddr(e1)));
+    printf("\tb%s cr0,L_%d\n",s,l1);
+}
+
+
+void
+jcond(int l, char cond)
+{       
+    if (chk) return;
+    printf("\tb%s cr0,L_%d\n",cond?"ne":"eq",l);
+}
+
+void
+jmp(int l)
+{       
+    control=0;
+    if (chk) return;
+    printf("\tb\tL_%d\n",l);
+}
+
+void
+gen_comment(char *s)
+{
+    if (chk) return;
+    printf("## %s",s);
+}
+
+void
+code_enter(char *name)
+{
+    if (output_mode!=TEXT_EMIT_MODE) 
+	text_mode();
+    else
+	printf("\t.align 2\n");
+    if (stmode!=STATIC)
+	printf(".globl _%s\n",name);
+#ifdef DOT_SIZE
+    printf("\t.type\t%s,@function\n",name);
+#endif
+    printf("_%s:\n",name);
+    code_disp_label=fwdlabel();
+    printf("\tla r1,lo16(L_%d)(r30)\n",code_disp_label);
+    printf("\tbcl 20,31,L_%d\n",code_base = fwdlabel());
+    fwddef(code_base);
+    printf("\tmflr r31\n");
+    max_func_args = 0;
+}
+
+
+void
+code_enter1(int args)
+{
+    set_creg(CREG_REGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+}
+
+void
+code_leave(char *name)
+{
+    int r1_offsetv;
+    disp&= -size_of_int;
+    r1_offsetv = -disp+max_func_args*size_of_int+code_disp_offset;
+
+    printf(".set L_%d,%d\n",code_disp_label,-r1_offsetv);
+    local_table();
+    free_all_register();
+}
+
+void
+enter(char *name)
+{
+    if (output_mode!=TEXT_EMIT_MODE) 
+	text_mode();
+    else
+	printf("\t.align 2\n");
+    if (stmode!=STATIC)
+	printf(".globl _%s\n",name);
+/*
+    printf("\t.type\t%s,@function\n",name);
+ */
+    printf("_%s:\n",name);
+    code_setup=fwdlabel();
+    printf("\tmflr r0\n");
+    printf("\tbl L_%d\n",code_setup);
+    code_base=fwdlabel();
+    fwddef(code_base);
+    r1_offset_label = fwdlabel();
+    lvar_offset_label = fwdlabel();
+    printf("\tstwu r1,lo16(-L_%d)(r1)\n",r1_offset_label);
+    printf("\tmr r30,r1\n");
+    printf("\tmflr r31\n");
+    max_func_args = 0;
+}
+
+void
+enter1()
+{
+    set_creg(CREG_REGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+}
+
+int
+reg_save_offset()
+{
+    return -(
+	(REAL_MAX_REGISTER-(REG_VAR_BASE-max_reg_var))*size_of_int+
+	(REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*size_of_double
+	);
+}
+
+void
+leave(int control, char *name)
+{
+    int retcont1,sz;
+
+    if (max_freg_var>=0 && max_freg_var<=3) max_freg_var=3; 
+    reg_save = reg_save_offset();
+
+    if (control) {
+	code_set_return_register(1);
+    }
+    if (retcont) { 
+	if (control) jmp(retlabel);
+	retcont1 = fwdlabel();
+	fwddef(retcont);
+	if (cadr(fnptr->ty)==FLOAT||cadr(fnptr->ty)==DOUBLE) {
+	    printf("\tfmr f1,f31\n");
+	} else if (cadr(fnptr->ty)>0&&(
+	    car(cadr(fnptr->ty))==STRUCT ||
+	    car(cadr(fnptr->ty))==UNION)) {
+	    sz = size(cadr(fnptr->ty));
+	    printf("\tli r7,%d\n",sz);
+	    printf("\tsubl r6,r7,r30\n");
+	    printf("\tlwz r3,lo16(%d)(r30)\n",(my_func_args-1)*size_of_int);
+	    emit_copy(6,3,sz,0,1,1);
+	} else if (cadr(fnptr->ty)!=VOID) {
+	    printf("\tmr r3,r29\n");
+	}
+#if !R1SAVE
+	printf("\tla r1,lo16(%d)(r30)\n",
+	    -reg_save+my_func_args*size_of_int);
+#endif
+	printf("\tb L_%d\n",retcont1);
+    }
+    fwddef(retlabel);
+    printf("\tlwz r1,0(r1)\n");
+    if (retcont) {
+	fwddef(retcont1);
+    }
+    if (max_freg_var>=0) {
+	printf("\tlmw r%d,%d(r1)\n",
+			REG_VAR_BASE-max_reg_var,reg_save);
+	freg_save = 72-(REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*4;
+	printf("\tb restFP+%d ; restore f%d-f31\n",
+			freg_save,
+			FREG_VAR_BASE-max_freg_var);
+    } else {
+	printf("\tlwz r0,8(r1)\n");
+	printf("\tmtlr r0\n");
+	printf("\tlmw r%d,%d(r1)\n",
+		    REG_VAR_BASE-max_reg_var,reg_save);
+	printf("\tblr\n");
+    }
+
+    disp &= -size_of_int;
+    fwddef(code_setup);
+    printf("\tstmw r%d,%d(r1)\n",
+		    REG_VAR_BASE-max_reg_var,reg_save);
+    printf("\tstw r0,8(r1)\n");
+    if (max_freg_var>=0)
+	printf("\tb saveFP+%d ; save f%d-f31\n",
+			freg_save,
+			FREG_VAR_BASE-max_freg_var);
+    else {
+	printf("\tblr\n");
+    }
+
+    code_offset_set();
+    local_table();
+    labelno++;
+    free_all_register();
+}
+
+
+void
+code_set_return_register(int mode) {
+    if (cadr(fnptr->ty)==DOUBLE||cadr(fnptr->ty)==FLOAT) {
+	set_freg(RET_FREGISTER,mode);
+    } else {
+	set_creg(RET_REGISTER,mode);
+    }
+}
+
+void
+code_set_fixed_creg(int mode,int type) {
+    if (type==FLOAT||type==DOUBLE) {
+	if (cond_freg== -1) {
+	    cond_freg = get_fregister_var(0);
+	    if(car(cond_freg)!=DREGISTER) error(-1);
+	}
+	set_freg(cadr(cond_freg),mode);
+    } else {
+	if (cond_reg== -1) {
+	    cond_reg = get_register_var(0);
+	    if(car(cond_reg)!=REGISTER) error(-1);
+	}
+	set_creg(cadr(cond_reg),mode);
+    }
+}
+
+void
+gen_gdecl(char *n, int gpc)
+{
+    /*
+    if (stmode!=STATIC)
+	printf(".globl _%s\n",n); 
+     */
+}
+
+void 
+align(int t)
+{
+    if (t!=CHAR) {
+	if (data_alignment & 1)
+	    printf("\t.align 2\n");
+	data_alignment = 0;
+    }
+}
+
+void
+emit_data(int e, int t, NMTBL *n)
+{
+    int l;
+    double d;
+    float f;
+    char *name;
+    name = n->nm; 
+    if(mode!=GDECL)  { 
+	error(-1); return;
+    }
+    if (chk) return;
+    if (n->dsp != -1) {
+	n->dsp = -1;   /* initiallized flag */
+	printf(".globl\t_%s\n",name);
+	data_mode(name);
+	align(t);
+	printf("_%s:\n",name); 
+    } else {
+	data_mode(0);
+    }
+    if(car(e)==CONST) {       
+	if (t==CHAR) {
+	    printf("\t.byte %d\n",cadr(e));
+	    if (data_alignment>0)
+		data_alignment++;
+	    gpc += 1;
+	} else if (t==SHORT) {
+	    printf("\t.word %d\n",cadr(e));
+	    if (data_alignment>0) data_alignment++;
+	    gpc += 2;
+	} else {
+	    printf("\t.long %d\n",cadr(e));
+	    gpc += size_of_int;
+	}
+    } else if(t==DOUBLE) {       
+	d = dcadr(e);
+	printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d));
+    } else if(t==FLOAT) {       
+	f = dcadr(e);
+	printf("\t.long\t0x%x\n",*(int *)&f);
+    } else if(t!=CHAR) {       
+	gpc += size_of_int;
+	if(car(e)==ADDRESS&&car(cadr(e))==GVAR) {
+	    printf("\t.long _%s\n",((NMTBL *)cadr(cadr(e)))->nm);
+	} else if(car(e)==FNAME) {
+	    printf("\t.long _%s\n",((NMTBL *)cadr(e))->nm);
+	} else if(car(e)==GVAR) {
+	    printf("\t.long _%s\n",((NMTBL *)cadr(e))->nm);
+	} else if(car(e)==STRING) {       
+	    if (car(n->ty)!=ARRAY || cadr(n->ty)!=CHAR) {
+		l = fwdlabel();
+		printf("\t.long L_%d\n",l);
+		printf(".cstring\n\t.align 2\n");
+		printf("L_%d:\n",l);
+		output_mode = RODATA_EMIT_MODE;
+	    }
+	    ascii((char *)cadr(e));
+	} else error(TYERR);
+    }
+}
+
+void
+emit_data_closing(NMTBL *n)
+{
+#ifdef DOT_SIZE
+    int lb;
+#endif
+    if (chk) return;
+    if (mode==GDECL) {
+	data_mode(0);
+#ifdef DOT_SIZE
+	lb=fwdlabel();
+	printf("L_%d:\n",lb);
+	printf("\t.size\t%s,L_%d-%s\n",n->nm,lb,n->nm);
+#endif
+    }
+}
+
+void
+global_table(void)
+{
+    NMTBL *n;
+    int init; char *extrn;
+    init=0;
+    for(n=ntable;n < &ntable[GSYMS];n++) {
+	if ((n->sc == GVAR) && n->dsp != -1) {
+	    /* n->dsp = -1 means initialized global */
+	    if (init==0) {
+		data_mode(0);
+		init=1;
+	    }
+	    printf(".comm _%s,%d\n",n->nm,size(n->ty));
+	} else if ((n->sc==STATIC) && n->dsp != -1) {
+	    /* n->dsp = -1 means initialized global */
+	    if (init==0) {
+		data_mode(0);
+		init=1;
+	    }
+	    printf(".lcomm _%s,%d\n",n->nm,size(n->ty));
+	}
+    }
+    for(n=ntable;n < &ntable[GSYMS];n++) {
+	if (is_code(n)||is_function(n)) {
+	    extrn = n->nm;
+	    if (n->sc==EXTRN1) {
+		data_mode(0);
+printf(".picsymbol_stub\n");
+printf("L_%s$stub:\n",extrn);
+printf("\t.indirect_symbol _%s\n",extrn);
+printf("\tmflr r0\n");
+printf("\tbcl 20,31,L0$_%s\n",extrn);
+printf("L0$_%s:\n",extrn);
+printf("\tmflr r11\n");
+printf("\taddis r11,r11,ha16(L_%s$lazy_ptr-L0$_%s)\n",extrn,extrn);
+printf("\tmtlr r0\n");
+printf("\tlwz r12,lo16(L_%s$lazy_ptr-L0$_%s)(r11)\n",extrn,extrn);
+printf("\tmtctr r12\n");
+printf("\taddi r11,r11,lo16(L_%s$lazy_ptr-L0$_%s)\n",extrn,extrn);
+printf("\tbctr\n");
+printf(".data\n");
+printf(".lazy_symbol_pointer\n");
+printf("L_%s$lazy_ptr:\n",extrn);
+printf("\t.indirect_symbol _%s\n",extrn);
+printf("\t.long dyld_stub_binding_helper\n");
+	    } else if (n->sc==FUNCTION||n->sc==CODE) {
+		text_mode();
+printf("\t.set L_%s$stub,_%s\n",extrn,extrn);
+		data_mode(0);
+printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",extrn,extrn);
+	    } 
+	}
+    }
+    init=0;
+    for(n=ntable;n < &ntable[GSYMS];n++) {
+	if (n->sc == GVAR) {
+	    if (init==0) {
+		printf(".data\n");
+		init=1;
+	    }
+printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",n->nm,n->nm);
+	}
+    }
+    init = 0;
+    for(n=ntable;n < &ntable[GSYMS];n++) {
+	if (is_code(n)||is_function(n)) continue;
+	if (n->sc==EXTRN1) {
+	    if(init==0) {
+		printf(".data\n");
+printf(".non_lazy_symbol_pointer\n");
+		init=1;
+	    }
+printf("L_%s$non_lazy_ptr:\n",n->nm);
+printf("\t.indirect_symbol _%s\n",n->nm);
+printf("\t.long\t0\n");
+	}
+    }
+}
+
+void
+local_table(void)
+{
+    NMTBL *n;
+    int init;
+    init=0;
+    /* static local variables */
+    for(n=ntable+GSYMS;n < &ntable[GSYMS+LSYMS];n++) {
+	if (n->sc == GVAR) {
+	    if (init==0) {
+		data_mode(0);
+		init=1;
+	    }
+	    printf(".lcomm _%s,%d\n",n->nm,size(n->ty));
+	}
+    }
+}
+
+void
+text_mode(void)
+{
+    if (output_mode!=TEXT_EMIT_MODE) {
+	printf(".text\n");
+	printf("\t.align 2\n");
+	output_mode = TEXT_EMIT_MODE;
+    }
+}
+
+void
+data_mode(char *name)
+{
+    if (output_mode!=DATA_EMIT_MODE) {
+	printf(".data\n");
+	output_mode = DATA_EMIT_MODE;
+    }
+/*
+    if (name)
+	printf("\t.type\t%s,@object\n",name);
+ */
+}
+
+/* floating point */
+
+static int float_one_lib_used=0;
+static char *float_one_lib[] = {
+".data",
+/* ".literal8", */
+"        .align 3",
+"__float_one:",
+"        .long   1065353216",
+".text",
+/* ".set L__float_one$non_lazy_ptr,__float_one", */
+0
+};
+static int float_zero_lib_used=0;
+static char *float_zero_lib[] = {
+".data",
+/* ".literal8", */
+"        .align 3",
+"__float_zero:",
+"        .long   0",
+".text",
+/* ".set L__float_zero$non_lazy_ptr,__float_zero", */
+0
+};
+
+
+
+char *
+fstore(int d)
+{
+    return (d?"stfd":"stfs");
+}
+
+char *
+fload(int d)
+{
+    return d?"lfd":"lfs";
+}
+
+void
+code_cmp_fregister(int e2)
+{
+    char *frn,*rrn,*grn;
+    int greg,r;
+    grn =  register_name(greg = get_fregister());
+    frn = register_name(freg);
+    float_zero_lib_used=1;
+    r = get_ptr_cache(&float_zero);
+    rrn = register_name(r);
+    printf("\tlfs %s,0(%s)\n",grn,rrn);
+    printf("\tfcmpu cr0,%s,%s\n",grn,frn);
+    free_fregister(greg);
+    fregv[freg]=0;
+    return;
+}
+
+void
+code_fregister(int e2,int freg)
+{
+    if (freg!=e2)
+	printf("\tfmr %s,%s\n",fregister_name(freg),fregister_name(e2));
+    fregv[freg]=1;
+}
+
+void code_dassign_gvar(int e2,int freg,int d)
+{ 
+    int r;
+    r = get_ptr_cache((NMTBL*)cadr(e2));
+    printf("\t%s %s,0(%s)\n",fstore(d),fregister_name(freg),register_name(r));
+    fregv[freg]=1;
+}
+
+void code_dassign_lvar(int e2,int freg,int d)
+{ 
+    lvar_intro(e2);
+    printf("\t%s %s,",fstore(d),fregister_name(freg));
+    lvar(e2);
+    fregv[freg]=1;
+}
+
+void code_dassign(int e2,int freg,int d)
+{ 
+    printf("\t%s %s,0(%s)\n",fstore(d),fregister_name(freg),register_name(e2));
+    fregv[freg]=1;
+}
+
+void
+code_dassign_fregister(int e2,int d,int freg) {
+    if (e2!=freg)
+	printf("\tfmr %s,%s\n",fregister_name(e2),fregister_name(freg));
+}
+
+static double d0 = 1.0;
+
+int
+code_d1(double d)
+{
+    int *i = (int *)&d0; int *j = (int *)&d;
+    return (i[1] == 0x3ff00000)?j[0]:j[1];
+}
+
+int
+code_d2(double d)
+{
+    int *i = (int *)&d0; int *j = (int *)&d;
+    return (i[1] == 0x3ff00000)?j[1]:j[0];
+}
+
+void code_dconst(int e2,int freg)
+{ 
+    int lb;
+    double d = dcadr(e2);
+    int r;
+    char *rrn,*frn;
+    frn = fregister_name(freg);
+    if (d==0.0) {
+	float_zero_lib_used=1;
+	r = get_ptr_cache(&float_zero);
+	rrn = register_name(r);
+	printf("\tlfs %s,0(%s)\n",frn,rrn);
+	return;
+    }
+    if (d==1.0) {
+	float_one_lib_used=1;
+	r = get_ptr_cache(&float_one);
+	rrn = register_name(r);
+	printf("\tlfs %s,0(%s)\n",frn,rrn);
+	return;
+    }
+    rrn = register_name((r=get_register()));
+    printf(" \t.data\n\t.align 3\n");
+    lb=fwdlabel();
+    printf("L_%d:\n",lb);
+    printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d));
+    if (output_mode==TEXT_EMIT_MODE) {
+	printf(".text\n");
+    } else {
+	text_mode();
+    }
+    printf("\taddis %s,r31,ha16(L_%d-L_%d)\n",rrn,lb,code_base);
+    printf("\tla %s,lo16(L_%d-L_%d)(%s)\n",rrn,lb,code_base,rrn);
+    printf("\tlfd %s,0(%s)\n",frn,rrn);
+    free_register(r);
+    fregv[freg]=1;
+}
+
+void code_dneg(int freg)
+{ 
+    char *frn = fregister_name(freg);
+    printf("\tfneg %s,%s\n",frn,frn);
+}
+
+void code_d2i(int freg,int creg)
+{ 
+    char *frn = fregister_name(freg);
+    char *crn = register_name(creg);
+    int e2 = new_lvar(size_of_double);
+    free_lvar(e2);
+    printf("\tfctiwz  %s,%s\n",frn,frn);
+    lvar_intro(e2);
+    printf("\tstfd  %s,",frn); lvar(e2);
+    lvar_intro(e2+size_of_double-size_of_int);
+    printf("\tlwz %s,",crn); lvar(e2+size_of_double-size_of_int);
+    fregs[freg]=0;
+    regs[creg]=1;
+}
+
+static int i2d_lib_used=0;
+static char *i2d_lib[] = {
+".data",
+/* ".literal8", */
+"        .align 3",
+"__i2dLC0:",
+"        .long   1127219200",
+"        .long   -2147483648",
+".text",
+"        .align 2",
+"i2d_:",
+"        mflr r0",
+"        bcl 20,31,__i2dL1$pb",
+"__i2dL1$pb:",
+"        mflr r10",
+"        mtlr r0",
+"        xoris r3,r3,0x8000",
+"        stw r3,-28(r30)",
+"        lis r0,0x4330",
+"        stw r0,-32(r30)",
+"        lfd f0,-32(r30)",
+"        addis r9,r10,ha16(__i2dLC0-__i2dL1$pb)",
+"        lfd f1,lo16(__i2dLC0-__i2dL1$pb)(r9)",
+"        fsub f1,f0,f1",
+"        blr",
+0
+};
+
+void code_i2d(int creg,int freg)
+{ 
+    i2d_lib_used = 1;
+    clear_ptr_cache();
+    code_save_stacks();
+    set_creg(RET_REGISTER,1);
+    printf("\tbl i2d_\n");
+    set_freg(RET_FREGISTER,0);
+    fregs[freg]=1;
+    regs[creg]=0;
+}
+
+static int d2u_lib_used=0;
+static char *d2u_lib[] = {
+/* ".literal8", */
+"        .align 3",
+"__d2uLC0:",
+"        .long   1105199104",
+"        .long   0",
+".text",
+"        .align 2",
+"d2u_:",
+"        mflr r0",
+"        bcl 20,31,__d2uL1$pb",
+"__d2uL1$pb:",
+"        mflr r10",
+"        mtlr r0",
+"        addis r9,r10,ha16(__d2uLC0-__d2uL1$pb)",
+"        lfd f0,lo16(__d2uLC0-__d2uL1$pb)(r9)",
+"        fcmpu cr0,f1,f0",
+"        cror 2,1,2",
+"        beq- cr0,__d2uL2",
+"        fctiwz f0,f1",
+"        stfd f0,-32(r30)",
+"        lwz r3,-28(r30)",
+"        blr",
+"__d2uL2:",
+"        addis r9,r10,ha16(__d2uLC0-__d2uL1$pb)",
+"        lfd f0,lo16(__d2uLC0-__d2uL1$pb)(r9)",
+"        fsub f0,f1,f0",
+"        fctiwz f0,f0",
+"        stfd f0,-24(r30)",
+"        lwz r3,-20(r30)",
+"        xoris r3,r3,0x8000",
+"        blr",
+0
+};
+
+void code_d2u(int freg,int creg)
+{ 
+    code_save_stacks();
+    clear_ptr_cache();
+    d2u_lib_used=1;
+    set_freg(RET_FREGISTER,1);
+    printf("\tbl d2u_\n");
+    set_creg(RET_REGISTER,0);
+    fregs[freg]=1;
+    regs[creg]=0;
+}
+
+static int u2d_lib_used=0;
+static char *u2d_lib[] = {
+".data",
+/* ".literal8", */
+"        .align 3",
+"__u2dLC1:",
+"        .long   1127219200",
+"        .long   0",
+".text",
+"        .align 2",
+"u2d_:",
+"        mflr r0",
+"        bcl 20,31,__u2dL2$pb",
+"__u2dL2$pb:",
+"        mflr r10",
+"        mtlr r0",
+"        stw r3,-28(r30)",
+"        lis r0,0x4330",
+"        stw r0,-32(r30)",
+"        lfd f0,-32(r30)",
+"        addis r9,r10,ha16(__u2dLC1-__u2dL2$pb)",
+"        lfd f1,lo16(__u2dLC1-__u2dL2$pb)(r9)",
+"        fsub f1,f0,f1",
+"        blr",
+0
+};
+
+void code_u2d(int creg,int freg)
+{ 
+    char *frn;
+    char *crn;
+    u2d_lib_used = 1;
+    code_save_stacks();
+    clear_ptr_cache();
+    frn = fregister_name(freg);
+    crn = register_name(creg);
+
+    printf("\tmr r3,%s\n",crn);
+    printf("\tbl u2d_\n");
+    printf("\tfmr %s,f1\n",frn);
+    fregs[freg]=1;
+    regs[creg]=0;
+}
+
+void code_drgvar(int e2,int d,int freg)
+{ 
+    int r;
+    r = get_ptr_cache((NMTBL*)cadr(e2));
+    printf("\t%s %s,0(%s)\n",fload(d),fregister_name(freg),register_name(r));
+    fregv[freg]=1;
+}
+
+
+void code_drlvar(int e2,int d,int freg)
+{ 
+    lvar_intro(e2);
+    printf("\t%s %s,",fload(d),fregister_name(freg)); lvar(e2);
+    fregv[freg]=1;
+}
+
+void code_cmp_drgvar(int e2)
+{ 
+    int r;
+    char *frn=fregister_name(freg);
+    int g=get_fregister();
+    char *grn=fregister_name(g);
+    r = get_ptr_cache((NMTBL*)cadr(e2));
+    printf("\t%s %s,0(%s)\n",fload(1),grn,register_name(r));
+    printf("\tfcmpu cr0,%s,%s\n",frn,grn);
+    free_fregister(g);
+    fregv[freg]=0;
+}
+
+void code_cmp_drlvar(int e2)
+{ 
+    char *frn=fregister_name(freg);
+    int g=get_fregister();
+    char *grn=fregister_name(g);
+
+    lvar_intro(e2);
+    printf("\t%s %s,",fload(1),grn); lvar(e2);
+    printf("\tfcmpu cr0,%s,%s\n",frn,grn);
+    free_fregister(g);
+    fregv[freg]=0;
+}
+
+void dtosop(int op,int e1)
+{ 
+    char *opn="";
+    char *frn=fregister_name(freg);
+    char *grn=fregister_name(e1);
+    fregv[freg]=1;
+    switch(op) {
+    case DADD: opn="fadd"; break;
+    case DSUB: opn="fsub"; break;
+    case DDIV: opn="fdiv"; break;
+    case DMUL: opn="fmul"; break;
+    case DCMP: 
+	printf("\tfcmpu cr0,%s,%s\n",frn,grn);
+	free_fregister(e1);
+	return;
+    case DCMPGE: 
+	printf("\tfcmpu cr7,%s,%s\n",frn,grn);
+	free_fregister(e1);
+	return;
+    }
+    printf("\t%s %s,%s,%s\n",opn,frn,frn,grn);
+    free_fregister(e1);
+}
+
+void
+code_dassop(int op,int d) {
+    /* we have lvalue in creg, applied floating value is in freg */
+    char *frn=fregister_name(freg);
+    int  xreg=emit_dpop(0);
+    char *crn=register_name(creg);
+
+    printf("\t%s %s,0(%s)\n",fload(d),frn,crn);
+    dtosop(op,xreg);
+    printf("\t%s %s,0(%s)\n",fstore(d),frn,crn);
+    emit_dpop_free(xreg);
+    fregv[freg]=1;
+}
+
+
+void
+code_dpreinc(int e1,int e2,int d,int reg) {
+    char *frn;
+    char *crn;
+    int  g;
+    char *grn,*drn;
+    int r;
+    r = get_ptr_cache(&float_one);
+    float_one_lib_used=1;
+
+    g_expr(e2);
+
+    crn=register_name(creg);
+    frn=fregister_name(freg);
+    drn=register_name(r);
+    grn=fregister_name(g=get_fregister());
+
+    printf("\t%s %s,0(%s)\n",fload(d),frn,crn);
+    printf("\tlfs %s,0(%s)\n",grn,drn);
+    if (caddr(e1)>0)
+	printf("\tfadd %s,%s,%s\n",frn,frn,grn);
+    else
+	printf("\tfsub %s,%s,%s\n",frn,frn,grn);
+    printf("\t%s %s,0(%s)\n",fstore(d),frn,crn);
+    free_fregister(g);
+    fregv[freg]=1;
+}
+
+void
+code_dpostinc(int e1,int e2,int d,int reg) {
+    char *frn;
+    char *crn;
+    int  g;
+    char *grn,*drn;
+    int r;
+    r = get_ptr_cache(&float_one);
+    float_one_lib_used=1;
+
+    g_expr(e2);
+
+    crn=register_name(creg);
+    frn=fregister_name(freg);
+    drn=register_name(r);
+    grn=fregister_name(g=get_fregister());
+
+    printf("\t%s %s,0(%s)\n",fload(d),frn,crn);
+    printf("\tlfs %s,0(%s)\n",grn,drn);
+    if (caddr(e1)>0)
+	printf("\tfadd %s,%s,%s\n",grn,frn,grn);
+    else
+	printf("\tfsub %s,%s,%s\n",grn,frn,grn);
+    printf("\t%s %s,0(%s)\n",fstore(d),grn,crn);
+    free_fregister(g);
+    fregv[freg]=1;
+}
+
+void
+drexpr(int e1, int e2,int l1, int op)
+{       
+    g_expr(list3(((op==DOP+GE)?DCMPGE:DCMP),e1,e2));
+    switch(op) {
+	case DOP+GE:
+	    printf("\tcror 2,29,30\n");
+	    printf("\tbne\tcr0,L_%d\n",l1);
+	    break;
+	case DOP+GT:
+	    printf("\tble\tcr0,L_%d\n",l1);
+	    break;
+	case DOP+EQ:
+	    printf("\tbne\tcr0,L_%d\n",l1);
+	    break;
+	case DOP+NEQ:
+	    printf("\tbeq\tcr0,L_%d\n",l1);
+	    break;
+    }
+}
+
+int emit_dpop(int e1)
+{ 
+    int xreg,reg;
+    xreg=pop_fregister();
+    if (xreg<= -REG_LVAR_OFFSET) {
+	reg = get_fregister();
+        code_drlvar(REG_LVAR_OFFSET+xreg,1,reg);
+	free_lvar(REG_LVAR_OFFSET+xreg);
+	fregv[reg]=1; xreg=reg;
+    }
+    return xreg;
+}
+
+void emit_dpop_free(int e1)
+{ 
+    free_fregister(e1);
+}
+
+void emit_dpush()
+{ 
+    int new_reg;
+    if (freg_sp>MAX_MAX) error(-1);
+    new_reg = get_fregister();
+    freg_stack[freg_sp++] = freg;     /* push するかわりにレジスタを使う */
+    freg = new_reg;
+    fregv[freg]=1;
+}
+
+void
+code_save_stacks()
+{
+    int i,reg;
+    for(i=0;i<reg_sp;i++) {
+        if ((reg=reg_stack[i])>=0) {
+            code_assign_lvar(
+                (reg_stack[i]=new_lvar(size_of_int)),reg,0); 
+            reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET;
+        }
+    }
+    for(i=0;i<freg_sp;i++) {
+        if ((reg=freg_stack[i])>=0) {
+            code_dassign_lvar(
+                (freg_stack[i]=new_lvar(size_of_double)),reg,1); 
+            freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET;
+        }
+    }
+}
+
+void
+emit_lib(char *p[])
+{
+    while(*p) {
+	printf("%s\n",*p++);
+    }
+}
+
+void
+code_closing()
+{
+    if (d2u_lib_used) emit_lib(d2u_lib);
+    if (u2d_lib_used) emit_lib(u2d_lib);
+    if (float_one_lib_used) emit_lib(float_one_lib);
+    if (float_zero_lib_used) emit_lib(float_zero_lib);
+    if (i2d_lib_used) emit_lib(i2d_lib);
+    global_table();
+    /* printf("\t.ident \"Micro-C compiled\"\n"); */
+}
+
+/* end */
+