view mc-code-powerpc.c @ 128:d497c39add36 args-works

arg.c works (?)
author kono
date Thu, 03 Apr 2003 03:04:16 +0900
parents eb4d8975926c
children 948977254fa6
line wrap: on
line source

/* 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 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) {
	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) {
	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) {
	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 */