view mc-code-mips.c @ 239:1849e0079f08

ia32 long long continue
author kono
date Mon, 03 May 2004 19:28:35 +0900
parents 6190d24e178c
children 0dcc0ec81ed2
line wrap: on
line source

/* Micro-C Code Generatation Part for MIPS (PS2Linux) */
/* $Id$ */

#define EXTERN extern
#include "mc.h"
#include "mc-code.h"
#include "mc-codegen.h"

char *l_include_path[] = {
    "/usr/include/",
    0
};

#define TEXT_EMIT_MODE 0
#define DATA_EMIT_MODE 1
#define RODATA_EMIT_MODE 2

static void data_mode(char *name);
static void ld_indexx(int byte, int n, int xreg,int sign);
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 disp_label;
static int r1_offset_label;
static int lvar_offset_label;
static int cprestore_label;

static int reg_save;
static int freg_save;

static int freg,ireg,dreg;

/* mips requires two registers for compare */
static int cmpreg = -1;

int size_of_int = 4;
int size_of_float = 4;
int size_of_double = 8;
int size_of_longlong = 8;
int endian = 1;

int  reg_sp;   /* REGister Stack-Pointer */
int reg_stack[MAX_MAX];  /* 実際のレジスタの領域 */

/* floating point registers */

int  freg_sp;  /* floating point REGister Stack-Pointer */
int freg_stack[MAX_MAX]; /* 実際のレジスタの領域 */

/* double floating point registers */

int  dreg_sp;  /* floating point REGister Stack-Pointer */
int dreg_stack[MAX_MAX]; /* 実際のレジスタの領域 */

#define REG_fp   1
#define REG_sp   30
#define REG_VAR_BASE 29
#define REG_VAR_MIN  18
#define MIN_TMP_REG 4
#define MAX_TMP_REG 11

#define DREG_VAR_BASE 29
#define DREG_VAR_MIN  18
#define MIN_TMP_DREG 4
#define MAX_TMP_DREG 17

#define PTRC_REG 3

#define FREG_VAR_BASE 31
#define FREG_VAR_MIN  20
#define MIN_TMP_FREG 1
#define MAX_TMP_FREG 14

#define RET_REGISTER 3
#define RET_FREGISTER (1+FREG_OFFSET)
#define RET_DREGISTER (1+DREG_OFFSET)

int MAX_REGISTER=30;             /* PowerPCのレジスタを10個まで使う*/
int MAX_FREGISTER=31;
int MAX_DREGISTER=16;
#define  REAL_MAX_REGISTER 32    /* PowerPCのレジスタが32ということ*/
#define  REAL_MAX_FREGISTER 32    /* PowerPCのFレジスタが32ということ*/
#define  REAL_MAX_DREGISTER 31    /* PowerPCのDレジスタ番号が31ということ*/

#define FREG_OFFSET REAL_MAX_REGISTER
#define DREG_OFFSET (REAL_MAX_REGISTER+REAL_MAX_FREGISTER )

int MAX_INPUT_REGISTER_VAR = 7-MIN_TMP_REG;
int MAX_CODE_INPUT_REGISTER_VAR = 7-MIN_TMP_REG;
int MAX_INPUT_DREGISTER_VAR = 14-MIN_TMP_FREG;
int MAX_INPUT_FREGISTER_VAR = 14-MIN_TMP_FREG;
int MAX_CODE_INPUT_DREGISTER_VAR = 14-MIN_TMP_FREG;
int MAX_CODE_INPUT_FREGISTER_VAR = 14-MIN_TMP_FREG;

#define CREG_REGISTER  MAX_TMP_REG
#define FREG_FREGISTER (MAX_TMP_FREG+FREG_OFFSET)
#define DREG_DREGISTER (2+DREG_OFFSET)

static int powerpc_regs[REAL_MAX_REGISTER+REAL_MAX_FREGISTER+REAL_MAX_DREGISTER];

static int dreg_pair0[REAL_MAX_DREGISTER] = {
    0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
};
static int dreg_pair1[REAL_MAX_DREGISTER] = {
    1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
};

static int *regs  = powerpc_regs;

static int max_reg_var, max_freg_var;

static char *reg_name[] = {
    "$0","$1","$2","$3","$4","$5","$6","$7","$8","$9",
    "$10","$11","$12","$13","$14","$15","$16","$17","$18","$19",
    "$20","$21","$22","$23","$24","$25","$26","$27","$28","$29",
    "$30","$31",
    "$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_name0(i)
#define fregister_name(i) reg_name0(i)
#define dregister_name0(i) reg_name1(i,dreg_pair0)
#define dregister_name1(i) reg_name1(i,dreg_pair1)

static char *
reg_name0(int i)
{
    if (i<=REAL_MAX_REGISTER+REAL_MAX_FREGISTER)
	return reg_name[i];
    else {
	error(-1);
	return reg_name[0];
    }
}

static char *
reg_name1(int i,int *d)
{
    if (i<=REAL_MAX_REGISTER+REAL_MAX_FREGISTER) {
	error(-1);
	return reg_name[0];
    } else
	return reg_name[d[i-DREG_OFFSET]];
}


#define is_int_reg(i)  (0<=i&&i<REAL_MAX_REGISTER)
#define is_float_reg(i)  (REAL_MAX_REGISTER<=i&&i<REAL_MAX_FREGISTER+REAL_MAX_REGISTER)
#define is_double_reg(i)  (REAL_MAX_REGISTER+REAL_MAX_FREGISTER<=i&&i<REAL_MAX_FREGISTER+REAL_MAX_REGISTER+REAL_MAX_DREGISTER)


int use_int(int i) { 
    if (!is_int_reg(i)) i = ireg;
    if (!regs[i]) regs[i]=1;
    return i;
}

int use_float(int i) { 
    if (!is_float_reg(i)) i = freg;
    if (!regs[i]) regs[i]=1;
    return i;
}

int use_double(int i) { 
    if (!is_double_reg(i)) i = dreg;
    if (!regs[i]) regs[i]=1;
    return i;
}

int use_longlong(int i) { 
    return i;
}

#if FLOAT_CODE
static int code_d1(double d);
static int code_d2(double d);
#endif

static void code_save_stacks();
static void code_save_input_registers();
static void    set_creg(int,int);
static void    set_freg(int,int);
static void    set_dreg(int,int);

static int    mask_label;
static int    mask1_label;
static int    fmask_label;
static int    fmask1_label;

static FILE *asi;

static int max_func_args;
static int max_func_iargs;
static int my_func_args;
#define ARG_LVAR_OFFSET 0x10000000

#define DOT_SIZE 1

/*          

     Reorder is automatically done in assembler.
     delayed slot done within .set noreorder.

     r0    return value etc.
     $2,$3 return value. (dpcmp return value on $2)
     $0  special register
     $4-$7  input register
     r22-r29 saved register variable (input register for code segement)
     $31   stack pointer
     $fp    frame pointer

     $f0       return value etc.
     $f14,$f12 input register
     $f20-$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("L_%d = %d\n",lvar_offset_label,lvar_offsetv);
    printf("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
lvar(int l)
{
    if (fnptr->sc==CODE) {
        if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            printf("%d($fp)\n",CODE_CALLER_ARG);
        } else
            printf("%d($fp)\n",CODE_LVAR);
    } else if (l<0) {  /* local variable */
        printf("%d+L_%d($fp)\n",FUNC_LVAR,lvar_offset_label);
    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
        printf("%d($fp)\n",CALLER_ARG);
    } else { /* callee's arguments */
        printf("%d+L_%d($fp)\n",CALLEE_ARG,r1_offset_label);
    }
}

static void
lvar_address(int l,int creg)
{
    if (fnptr->sc==CODE) {
        if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            printf("\taddu\t%s,$fp,%d\n",register_name(creg),CODE_CALLER_ARG);
        } else
            printf("\taddu\t%s,$fp,%d\n",register_name(creg),CODE_LVAR);
    } else if (l<0) {  /* local variable */
        printf("\taddu\t%s,$fp,%d+L_%d\n",register_name(creg),FUNC_LVAR,lvar_offset_label);
    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
        printf("\taddu\t%s,$fp,%d\n",register_name(creg),CALLER_ARG);
    } else { /* callee's arguments */
        printf("\taddu\t%s,$fp,%d+L_%d\n",register_name(creg),CALLEE_ARG,r1_offset_label);
    }
}

void
code_lvar(int e2,int creg) {
    lvar_address(e2,creg);
}

void
code_init(void)
{
    /* this is called once program call */
}

void
gexpr_code_init(void){
}

void
code_gexpr(int e){
    if (is_int_reg(creg) && creg!=ireg) error(-1);
}


void
code_arg_register(NMTBL *fnptr)
{
    int args = fnptr->dsp;
    NMTBL *n;
    int reg_var = 0;
    int freg_var = 0;
    int type;
    int reg;
    int is_code0 = is_code(fnptr);

    while (args) {
        /* process in reverse order */
        n = (NMTBL*)caddr(args);
        type = n->ty;
        if (scalar(type)) {
            if ((reg = get_input_register_var(reg_var,n,is_code0))) {
                n->sc = REGISTER;
                n->dsp = cadr(reg);
                regs[n->dsp]= INPUT_REG;
                reg_var++;
                cadddr(args)=size_of_int; /* why we need this? */
            }
        } else if (type==FLOAT) {
            if ((reg = get_input_dregister_var(freg_var,n,is_code0,0))) {
                n->sc = FREGISTER;
                n->dsp = cadr(reg);
                regs[n->dsp]= INPUT_REG;
                freg_var++;
                cadddr(args)=size(type); /* why we need this? */
            }
        } else if (type==DOUBLE) {
            if ((reg = get_input_dregister_var(reg_var,n,is_code0,1))) {
                n->sc = DREGISTER;
                n->dsp = cadr(reg);
                regs[n->dsp]= INPUT_REG;
                reg_var+=2;
                cadddr(args)=size(type); /* why we need this? */
            }
        }
        args = cadr(args);
    }
    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;               /* その場所を表す番号を返す */
    }
    /* 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;
	}
    }
#if FLOAT_CODE
    /* search dregister stack */
    for(i=0;i<dreg_sp;i++) {
	if ((reg=dreg_stack[i])>=0) {
            code_dassign_lvar(
                (dreg_stack[i]=new_lvar(size_of_double)),reg,1); 
            dreg_stack[i]= dreg_stack[i]-REG_LVAR_OFFSET;
	    free_register(reg);
	    return get_register(); /* 今度は必ずある */
	}
    }
#endif
    for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) {
        reg =REG_VAR_BASE-i;
        if (! regs[reg]) {       /* 使われていないなら */
            regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */
	    if (i>max_reg_var) max_reg_var=i;
	    return reg; 
        }
    }
    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
    error(HPERR); return creg;
}

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

#if FLOAT_CODE

static int
get_dregister1() {
    int i;
    for(i=MAX_TMP_DREG+DREG_OFFSET;i>MIN_TMP_DREG+DREG_OFFSET;i--) {
	if (regs[i]) continue;  /* 使われている */
	if (regs[dreg_pair0[i-DREG_OFFSET]]) continue;
	if (regs[dreg_pair1[i-DREG_OFFSET]]) continue;
	regs[dreg_pair0[i-DREG_OFFSET]]=USING_REG;
	regs[dreg_pair1[i-DREG_OFFSET]]=USING_REG;
	regs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
	return i;               /* その場所を表す番号を返す */
    }
    return -1;
}

static int 
get_dregister0()
{
    int reg,i;
    /* とりあえず、空き int register pair を探す */
    if ((i=get_dregister1())!=-1) {
	return i;
    }
    /* search dregister stack */
    for(i=0;i<dreg_sp;i++) {
	if ((reg=dreg_stack[i])>=0) {
            code_dassign_lvar(
                (dreg_stack[i]=new_lvar(size_of_double)),reg,1); 
            dreg_stack[i]= dreg_stack[i]-REG_LVAR_OFFSET;
	    return reg;
	}
    }
    /* clear integer 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;
	    free_register(reg);
	}
    }
    if ((i=get_dregister1())!=-1) {
	return i;
    }

    error(REG_ERR); return dreg;
}

static int
get_fregister0()
{    /* 使われていないレジスタを調べる */
    int i,reg;
    for(i=MAX_TMP_FREG+FREG_OFFSET;i>MIN_TMP_FREG+FREG_OFFSET;i--) {
	if (regs[i]) continue;    /* 使われている */
	regs[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_float)),reg,0); 
            freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET;
	    return reg;
	}
    }
    for(i=0;i<FREG_VAR_BASE-REG_VAR_MIN;i++) {
        reg =FREG_VAR_BASE-i+FREG_OFFSET;
        if (! regs[reg]) {       /* 使われていないなら */
            regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */
	    if (i>max_freg_var) max_freg_var=i;
	    return reg; 
        }
    }
    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
    error(REG_ERR); return freg;
}

int 
get_dregister(int d)
{
    if (d) {
	return get_dregister0();
    } else {
	return get_fregister0();
    }
}

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

int
pop_dregister(void)
{     /* レジスタから値を取り出す */
    return dreg_stack[--dreg_sp];
}
#endif

#if LONGLONG_CODE
int
get_lregister() {
    return -1;
}

int
get_lregister_var(NMTBL *n)
{
    return list2(LVAR,new_lvar(size_of_double));
}
#endif


void
emit_pop_free(int xreg)
{
    if (xreg>=0)
	free_register(xreg);
}

void 
free_register(int i) {    /* いらなくなったレジスタを開放 */
    int i0,i1;
    if (i<0||MAX_FREGISTER+FREG_OFFSET+REAL_MAX_DREGISTER<i) error(-1);
    if (is_double_reg(i)) {
	i0 = dreg_pair0[i-DREG_OFFSET];
	regs[i0]=0;
	i1 = dreg_pair1[i-DREG_OFFSET];
	regs[i1]=0;
    }
    regs[i]=0;
}

int
get_input_dregister_var(int i,NMTBL *n,int is_code,int d)
{
    if (d) {
	if (is_code) {
	    if(!(i<DREG_VAR_BASE-DREG_VAR_MIN)) return 0;
	    i = DREG_VAR_BASE-i+DREG_OFFSET;
	} else {
	    if (i<0||i>=MAX_INPUT_DREGISTER_VAR) return 0;
	    i = i+MIN_TMP_DREG+DREG_OFFSET;
	}
	return list3(DREGISTER,i,(int)n);
    } else {
	if (is_code) {
	    if(!(i<FREG_VAR_BASE-FREG_VAR_MIN)) return 0;
	    i = FREG_VAR_BASE-i+FREG_OFFSET;
	} else {
	    if (i<0||i>=MAX_INPUT_FREGISTER_VAR) return 0;
	    i = i+MIN_TMP_FREG+FREG_OFFSET;
	}
	return list3(FREGISTER,i,(int)n);
    }
}

int
get_input_register_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||i>=MAX_INPUT_REGISTER_VAR) return 0;
	i = i+MIN_TMP_REG;
    }
    return list3(REGISTER,i,(int)n);
}

/* double register case? */

int
get_input_register_var_1(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||i>=MAX_INPUT_REGISTER_VAR+1) return 0;
	i = i+MIN_TMP_REG;
    }
    return list3(REGISTER,i,(int)n);
}

int
free_register_count(int d)
{
    int i,count,fcount;
    fcount = count = 0;
    for(i=0;i<MAX_REGISTER;i++) {
        if (! regs[i]) count++;
    }
    for(i=0;i<MAX_FREGISTER;i++) {
        if (! regs[i+FREG_OFFSET]) fcount++;
    }
    printf("# free reg %d freg %d\n",count,fcount);
    return d?fcount:count;
}

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; }
    for(i=0;i<MAX_FREGISTER;i++) { regs[i+FREG_OFFSET]=0; }
    for(i=0;i<MAX_DREGISTER;i++) { regs[i+DREG_OFFSET]=0; }
    creg = get_register();
#if FLOAT_CODE
    freg = get_dregister(0);
    dreg = DREG_DREGISTER;
#endif
    set_creg(CREG_REGISTER,0);
    set_freg(FREG_FREGISTER,0);
    set_dreg(DREG_DREGISTER,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 ireg=%s freg=%s dreg=%s",
     is_int_reg(creg)?register_name(creg):
     is_float_reg(creg)?fregister_name(creg):
     is_double_reg(creg)?dregister_name0(creg):"bad",
register_name(ireg),fregister_name(freg),dregister_name0(dreg));
#if 0
    printf("\n# regs:");
    printf(":");
    for(i=0;i<MAX_REGISTER;i++) { printf("%d",regs[i]); }
    printf("\n# freg:");
    for(i=0;i<MAX_FREGISTER;i++) { printf("%d",regs[i+FREG_OFFSET]); }
    for(i=reg_sp;i>=0;i--) {
	if(reg_stack[i]>=0)
	    printf(" %s",register_name(reg_stack[i]));
    }
#endif
    printf("\n");
}

void 
gexpr_init(void)
{
    while(reg_sp > 0) {
	free_register(reg_stack[--reg_sp]);
    }
    while(freg_sp > 0) {
	free_register(freg_stack[--freg_sp]);
    }
    while(dreg_sp > 0) {
	free_register(dreg_stack[--dreg_sp]);
    }
    cmpreg = -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;
    dreg_sp = 0;
    text_mode();
}

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; 
	    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_dregister_var(NMTBL *n,int d)
{
    int i,j;
    if (d) {
	for(i=0;i<DREG_VAR_BASE-DREG_VAR_MIN;i++) {
	    if (! regs[j=(DREG_VAR_BASE-i+DREG_OFFSET)]) {       /* 使われていないなら */
		if (regs[dreg_pair0[j]] || regs[dreg_pair1[j]]) continue;
		regs[DREG_VAR_BASE-i+DREG_OFFSET]=USING_REG; /*そのレジスタを使うことを宣言し*/
		regs[dreg_pair0[j]] = regs[dreg_pair1[j]] = USING_REG;
		if (dreg_pair1[j]>max_reg_var) max_reg_var=dreg_pair1[j];
		/* その場所を表す番号を返す */
		return list3(DREGISTER,DREG_VAR_BASE-i+DREG_OFFSET,(int)n); 
	    }
	}
	return list2(LVAR,new_lvar(size_of_double));
    } else {
	for(i=0;i<FREG_VAR_BASE-FREG_VAR_MIN;i++) {
	    if (! regs[FREG_VAR_BASE-i+FREG_OFFSET]) {       /* 使われていないなら */
		regs[FREG_VAR_BASE-i+FREG_OFFSET]=USING_REG; /*そのレジスタを使うことを宣言し*/
		if (i>max_freg_var) max_freg_var=i;
		/* その場所を表す番号を返す */
		return list3(FREGISTER,FREG_VAR_BASE-i+FREG_OFFSET,(int)n); 
	    }
	}
	return list2(LVAR,new_lvar(size_of_float));
    }
}

void 
emit_push()
{
    int new_reg;
    if (reg_sp>MAX_MAX) error(-1);
    new_reg = get_register();
    reg_stack[reg_sp++] = creg;     /* push するかわりにレジスタを使う */
    ireg = creg = new_reg;
}

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;
    }
    return xreg;
}

void
code_label(int labelno)
{
    printf("L_%d:\n",labelno);
}

void
code_gvar(int e1,int creg) {
    printf("\tla %s,%s\n",register_name(creg),((NMTBL*)cadr(e1))->nm);
}

void
code_rgvar(int e1,int creg) {
    printf("\tlw %s,%s\n",register_name(creg),((NMTBL*)cadr(e1))->nm);
}
char *cload(int sign,int sz) { return sz==1?(sign?"lbu":"lb"):(sz==size_of_short?(sign?"lhu":"lh"):"lw");}
char *cstore(int sz) { return sz==1?"sb":(sz==size_of_short)?"sh":"sw";}
void
code_crgvar(int e1,int creg,int sign,int sz){
    printf("\t%s %s,%s\n",cload(sign,sz),register_name(creg),((NMTBL*)cadr(e1))->nm);
}


void
code_register(int e2,int creg) {
    if (creg!=e2)
        printf("\tmove %s,%s\n",register_name(creg),register_name(e2));
}


void
code_rlvar(int e2,int reg) {
    printf("\tlw %s,",register_name(reg));
    lvar(e2);
}


void
code_crlvar(int e2,int reg,int sign,int sz) {
    printf("\t%s %s,",cload(sign,sz),register_name(reg));
    lvar(e2);
}


void
code_fname(NMTBL *n,int creg) {
    printf("\tla %s,%s\n",register_name(creg),n->nm);
}


void
code_const(int e2,int creg) {
    printf("\tli %s,%d\n",register_name(creg),e2);
}


void
code_neg(int creg) {
    printf("\tsubu %s,$0,%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) {
    /* if non zero 1 else 0 */
    int dreg = get_register();
    printf("\txori %s,%s,0x0\n", 
        register_name(dreg),register_name(creg));
    printf("\tsltu %s,%s,1\n", 
        register_name(creg),register_name(dreg));
    free_register(dreg);
}

void
code_preinc(int e1,int e2,int dir,int sign,int sz,int reg) {
    char *xrn,*drn;
    int i,dreg;
    if (car(e2)==REGISTER) {
        printf("\taddu %s,%s,%d\n", 
                register_name(cadr(e2)),register_name(cadr(e2)), dir);
        if (cadr(reg)!=e2)
            printf("\tmove %s,%s\n",register_name(cadr(reg)),register_name(e2));
        return;
    } 
    g_expr(e2);
    xrn = register_name(creg);
    dreg=get_register(); if (!dreg) error(-1);
    drn = register_name(dreg);
    printf("\t%s %s,0(%s)\n",cload(sign,sz),drn,xrn);
    printf("\taddu %s,%s,%d\n",drn,drn,dir);
    printf("\t%s %s,0(%s)\n",cstore(sz),drn,xrn);
    i=creg;creg=dreg;dreg=i;
    ireg=creg;
    free_register(dreg);
}


void
code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) {
    char *xrn,*crn,*nrn;
    int dreg,nreg,i;
    if (car(e2)==REGISTER) {
        printf("\tmove %s,%s\n",register_name(reg),register_name(cadr(e2)));
        printf("\taddu %s,%s,%d\n", 
            register_name(cadr(e2)),register_name(cadr(e2)),dir);
        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("\t%s %s,0(%s)\n",cload(sign,sz),xrn,crn);
    printf("\taddu %s,%s,%d\n",nrn,xrn,dir);
    printf("\t%s %s,0(%s)\n",cstore(sz),nrn,crn);
    i=creg;creg=dreg;dreg=i; 
    free_register(nreg);
    free_register(dreg);
    ireg=creg;
}



void
code_return(int creg) {
    char *crn = register_name(creg);
    printf("\tla %s,L_%d\n",crn,retcont);
}

#define R1SAVE 1

void
code_environment(int creg) {
    /* save frame pointer */
#if R1SAVE
    printf("\tlw %s,0($fp)\n",register_name(creg));
#else
    int l = 0;
    printf("\taddu %s,",register_name(creg));
    printf("$fp,%d+L_%d\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 > < ... */
    creg = use_int(creg);
    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?"\tslt  %s,%s,%s\n\tbeq %s,$0,L_%d\n":
                 "\tslt  %s,%s,%s\n\tbne %s,$0,L_%d\n");
}

char *
code_ugt(int cond) {
    return (cond?"\tsltu %s,%s,%s\n\tbeq %s,$0,L_%d\n":
                 "\tsltu %s,%s,%s\n\tbne %s,$0,L_%d\n");
}

char *
code_ge(int cond) {
    return (cond?"\tslt  %s,%s,%s\n\txori %s,%s,0x1\n\tbeq %s,$0,L_%d\n":
                 "\tslt  %s,%s,%s\n\txori %s,%s,0x1\n\tbne %s,$0,L_%d\n");
}

char *
code_uge(int cond) {
    return (cond?"\tsltu %s,%s,%s\n\txori %s,%s,0x1\n\tbeq %s,$0,L_%d\n":
                 "\tsltu %s,%s,%s\n\txori %s,%s,0x1\n\tbne %s,$0,L_%d\n");
}

char *
code_eq(int cond) {
    return (cond?"\tbeq %s,%s,L_%d\n":"\tbne %s,%s,L_%d\n");
}

void
code_cmp_crgvar(int e1,int sz) {
    if (cmpreg==-1) cmpreg = get_register();
    code_crgvar(cadr(e1),cmpreg,1,sz);
}


void
code_cmp_crlvar(int e2,int sz) {
    if (cmpreg==-1) cmpreg = get_register();
    code_crlvar(e2,cmpreg,1,sz);
}


void
code_cmp_rgvar(int e1) {
    if (cmpreg==-1) cmpreg = get_register();
    code_rgvar(e1,cmpreg);
}


void
code_cmp_rlvar(int e2) {
    if (cmpreg==-1) cmpreg = get_register();
    code_rlvar(e2,cmpreg);
}


void
code_cmp_register(int e2) {
    cmpreg = e2;
    /* prevent cmpreg freeing */
}


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("\t.rdata\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("\tla %s,L_%d\n",crn,lb);
}

#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("\tlb %s,%d(%s)\n",drn,offset,frn);
        printf("\tsb %s,%d(%s)\n",drn,offset,trn);
        break;
    case 2: case -2:
        printf("\tlh %s,%d(%s)\n",drn,offset,frn);
        printf("\tsh %s,%d(%s)\n",drn,offset,trn);
        break;
    case 4: case -4:
        printf("\tlw %s,%d(%s)\n",drn,offset,frn);
        printf("\tsw %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;
        }
        code_save_stacks();
        printf("\tli $6,%d\n",length);
        printf("\tmr $5,%s\n",frn);
        printf("\tmr $4,%s\n",trn);
        /* overrap must be allowed */
        printf("\tbl L_%s$stub\n",memmove);
        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);
}

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("\tlw %s,%d(%s)\n",drn,length-size_of_int,crn);
                printf("\tsw %s,%d(%s)\n",drn,length-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 (!is_int_reg(reg)) error(-1);
    if (reg!=creg) {
	if (reg!=ireg && mode) 
            printf("\tmove %s,%s\n",register_name(reg),register_name(ireg));
	free_register(creg);
	creg = ireg = reg;
	regs[creg]=1;
    }
}

void
set_freg(int reg,int mode)
{
    if (!is_float_reg(reg)) error(-1);
    if (reg!=creg) {
	if (reg!=freg && mode) {
            printf("\tfmove %s,%s\n",fregister_name(reg),fregister_name(freg));
	}
	free_register(creg);
	creg = freg = reg;
	regs[freg]=1;
    }
}

static void
move_dreg(int reg,int dreg)
{
    if (reg!=dreg) {
	printf("\tmove %s,%s\n",dregister_name0(reg),
				dregister_name0(dreg));
	printf("\tmove %s,%s\n",dregister_name1(reg),
				dregister_name1(dreg));
    }
}

void
set_dreg(int reg,int mode)
{
    if (!is_double_reg(reg)) error(-1);
    if (reg!=creg) {
	if (mode) {
	    move_dreg(reg,dreg);
	}
	free_register(creg);
	creg = dreg = reg;
	regs[dreg]=1;
	regs[dreg_pair0[dreg-DREG_OFFSET]]=1;
	regs[dreg_pair1[dreg-DREG_OFFSET]]=1;
    }
}


void
use_var(int arg)
{
    if (car(arg)==REGISTER)
	regs[cadr(arg)]=USING_REG;
    else if (car(arg)==FREGISTER)
	regs[cadr(arg)]=USING_REG;
    else if (car(arg)==DREGISTER)
	regs[cadr(arg)]=USING_REG;
}

void
code_save_input_registers()
{
    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==FREGISTER) {
            /* 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 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||tag==DREGISTER||tag==FREGISTER) {
	    free_register(reg);
	}
    }
    my_func_args = offset;
}

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,STASS)
    ;
}

int
caller_arg_offset_v(int arg)
{
    return ARG_LVAR_OFFSET+arg*size_of_int;
}

int
function(int e1)
{
    int e2,e3,e4,nargs,t;
    int arg,reg_arg,freg_arg,arg_assign;
    int dots;
    int reg_arg_list=0,ret_type,special_lvar;
    NMTBL *fn = 0;
    int jmp = 0;
    char *jrn;
    int iargs=0;

    special_lvar = -1;
    ret_type = cadr(cadddr(e1));
    if (ret_type==CHAR) ret_type=INT;

    /* check argments type is DOTS? */
    t = caddr(cadddr(e1));
    if (t==0 || t==DOTS) dots = 1;
    else {
	dots = 0;
	for(t = caddr(cadddr(e1));t;t = cadr(t)) {
	    if (car(t)==DOTS) dots = 1;
	}
    }

    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);
    set_dreg(DREG_DREGISTER,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++; iargs += size_of_int;
	    continue;
	} else if (t==DOUBLE||t==FLOAT) {
	    if (freg_arg>=MAX_INPUT_DREGISTER_VAR) {
		arg = list2(LVAR,caller_arg_offset_v(nargs));
	    } else if (!simple_args(e3) && cadr(e3)) {
		arg = get_dregister_var(0,1); 
		arg_assign = list2(
		    assign_expr0(get_input_dregister_var(freg_arg,0,0,1),
			arg,t,t),
		    arg_assign);
	    } else {
		arg = get_input_dregister_var(freg_arg,0,0,1); 
	    }
	    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;
	    if (t==DOUBLE) iargs += size(t);
	    continue;
	} else if (car(t)==STRUCT||car(t)==UNION) {
	    arg = list2(LVAR,caller_arg_offset_v(nargs));
	    nargs += struct_push(e4,t,arg);
	    iargs += ((size(t)+3)/size_of_int)*size_of_int;
	    continue;
	} else {
	    error(TYERR);
	}
	++nargs;
    }
    if (max_func_args<nargs) max_func_args=nargs;
    if (max_func_iargs<iargs) max_func_iargs=iargs;
    for(;arg_assign;arg_assign=cadr(arg_assign)) {
	g_expr_u(car(arg_assign));
    }
    if (car(e2) == FNAME) {	
	printf("\tbl\tL_%s$stub\n",fn->nm);
    } else {
        jrn = register_name(cadr(jmp));
        printf("\tj %s\n",jrn);
    }
    for(;reg_arg_list;reg_arg_list=cadr(reg_arg_list)) {
	arg = car(reg_arg_list);
	if (car(arg)==REGISTER||car(arg)==DREGISTER||car(arg)==FREGISTER) 
	    free_register(cadr(arg));
	else if (car(arg)==LVAR&&cadr(arg)<0) free_lvar(cadr(arg));
    }
    if (ret_type==DOUBLE) {
	set_dreg(RET_DREGISTER,0);
    } else if (ret_type==FLOAT) {
	set_freg(RET_FREGISTER,0);
    } else if (ret_type==VOID) {
    } else {
	set_creg(RET_REGISTER,0);
    }
    return ret_type;
}

void
code_frame_pointer(int e3) {
#if R1SAVE
    printf("\tmove $fp,%s\n",register_name(e3));
#else
    printf("\tmove $fp,%s\n",register_name(e3));
#endif
}


void
code_fix_frame_pointer(int disp_offset) {
    int l = 0;
    printf("\tla $fp,");
    printf("%d+L_%d($sp)\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("\tj L_%s\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("\tj %s\n",register_name(e2));
}

int
code_rindirect(int e1, int offset, int us)
{
    char *crn;
    g_expr(e1);
    crn=register_name(creg);
    printf("\tlw %s,%d(%s)\n",crn,offset,crn);
    return INT;
}

int
code_crindirect(int e1, int offset, int us)
{
    char *crn;
    g_expr(e1);
    crn=register_name(creg);
    if (us) {
        printf("\tlbu %s,%d(%s)\n",crn,offset,crn);
        return UCHAR;
    } else {
        printf("\tlb %s,%d(%s)\n",crn,offset,crn);
        return CHAR;
    }
}

int
code_srindirect(int e1, int offset, int us)
{
    char *crn;
    g_expr(e1);
    crn=register_name(creg);
    if (us) {
        printf("\tlhu %s,%d(%s)\n",crn,offset,crn);
        return USHORT;
    } else {
        printf("\tlh %s,%d(%s)\n",crn,offset,crn);
        return SHORT;
    }
}

#if FLOAT_CODE
int
code_drindirect(int e1, int offset, int d)
{
    char *crn;
    g_expr(e1);
    crn=register_name(creg);
    if (d) {
        printf("\tlw %s,%d(%s)\n",
            dregister_name0(dreg),offset,crn);
        printf("\tlw %s,%d(%s)\n",
            dregister_name1(dreg),offset+size_of_int,crn);
	creg = dreg;
        return DOUBLE;
    } else {
        printf("\tl.s %s,%d(%s)\n", fregister_name(freg),offset,crn);
	creg = freg;
        return FLOAT;
    }
}
#endif

#if LONGLONG_CODE
int
code_lrindirect(int e1, int offset, int us)
{
    char *crn;
    g_expr(e1);
    crn=register_name(creg);
    return LONGLONG;
}
#endif

void
code_assign_gvar(int e2,int creg,int byte) {
    char *crn,*name;

    name = ((NMTBL*)cadr(e2))->nm;
    crn=register_name(creg);
    if (byte==1) {
        printf("\tsb %s,%s\n",crn,name);
    } if (byte==size_of_short) {
        printf("\tsh %s,%s\n",crn,name);
    } else {
        printf("\tsw %s,%s\n",crn,name);
    }
}

void
code_assign_lvar(int e2,int creg,int byte) {
    char *crn;
    crn=register_name(creg);
    if (byte==1) {
        printf("\tsb %s,",crn);
    } else if (byte==size_of_short) {
        printf("\tsh %s,",crn);
    } else {
        printf("\tsw %s,",crn); 
    }
    lvar(e2);
}

void
code_assign_register(int e2,int byte,int creg) {
    if (e2!=creg)
        printf("\tmove %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==1) {
        printf("\tsb %s,0(%s)\n",crn,drn);
    } else if (byte==size_of_short) {
        printf("\tsh %s,0(%s)\n",crn,drn);
    } else {
        printf("\tsw %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("\tmove %s,%s\n",register_name(creg),register_name(reg));
}


void
code_assop(int op,int byte,int sign) {
    char *xrn,*crn,*drn;
    int xreg;
    int edx = get_register(); if(!edx) error(-1);
    xrn = register_name(xreg = emit_pop(0));       /* pop e3 value */
    regs[xreg]=1;
    printf("# assop\n\tmr %s,%s\n",register_name(edx),register_name(creg));
    ld_indexx(byte,0,edx,sign);
    tosop(op,xreg);
    crn = register_name(creg);
    drn = register_name(edx);
    printf("\t%s %s,0(%s)\n",cstore(byte),crn,drn);
    free_register(edx);
    emit_pop_free(xreg);
}


void
tosop(int op,int oreg)
{
    int dx;
    char *orn,*crn;

    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;
    }

    switch(op) {
    case LSHIFT:
    case ULSHIFT:
	shift("sll",oreg);
	return;
    case RSHIFT:
	shift("srl",oreg);
	return;
    case URSHIFT:
	shift("sra",oreg);
	return;
    }
    orn = register_name(oreg);
    crn = register_name(creg);
    switch(op) {
    case ADD:
	printf("\taddu %s,%s,%s\n",crn,crn,orn);
	break;
    case SUB:
	printf("\tsubu %s,%s,%s\n",crn,crn,orn);
	break;
    case CMP:
	printf("\tslt %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("\tmult %s,%s,%s\n",crn,crn,orn);
	break;
    case UMUL:
	printf("\tmultu %s,%s,%s\n",crn,crn,orn);
	break;
    case DIV:
	printf("\tdivw %s,%s,%s\n",crn,crn,orn);
	break;
    case UDIV: case MOD: case UMOD:
        printf("\t%s $0,%s,%s\n",(op==UDIV||op==UMOD)?"divu":"div",crn,orn);
        printf("\t%s %s\n",(op==MOD||op==UMOD)?"mflo":"mfhi",crn);
        printf("\t.set    noreorder\n");
        printf("\tbeql    %s,$0,1f\n",orn);
        printf("\tbreak   7\n");
        printf("1:\n");
        printf("\t.set    reorder\n");
        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);
}

int 
code_const_op_p(int op,int v)
{
    if (op==BAND||op==DIV||op==UDIV||op==MOD||op==UMOD) return 0;
    return 0;
}

void 
oprtc(int op,int v)
{
}


void
ld_indexx(int byte, int n, int xreg,int sign)
{	
    char *crn = register_name(creg);
    printf("\t%s %s,%d(%s)\n",cload(sign,byte),crn,n,
	register_name(xreg));
}

int
code_csvalue()
{
    return creg;
}

void
code_cmpdimm(int e, int csreg)
{
    /* used in dosiwtch() */
    if(chk) return;
    creg = use_int(creg);
    printf("\tli %s,%d\n",register_name(creg),e);
    cmpreg = csreg;
}

void
code_opening(char *s)
{
    /* this is called once per month */
    char *p=cheapp;

    printf("\t.file \"%s\"\n",s);
    /* printf("\t.version\t\"01.01\"\n"); */
    /* printf("gcc2_compiled.:\n"); */
    printf("\t.abicalls\n");
    printf("\t.text\n");

    if (asi) {
        fclose(asi);
        asi = 0;
    }
    while ((*cheapp++ = *s++)) {
        if (*s=='.') {
            *cheapp++=*s++; *cheapp++='i';
            *cheapp++=0;
            break;
        }
    }
    asi = fopen(p,"w");
    printf(".include \"%s\"\n",p);
    if (!asi) error(-1);
}

void
rexpr(int e1, int l1, char *s,int t)
{       
    char *crn,*drn;
    if (cmpreg>=0) { free_register(cmpreg); cmpreg = -1; }

    g_expr(cadr(e1));
    emit_push();
    g_expr(caddr(e1));
    cmpreg = emit_pop(0);
    crn = register_name(creg);
    drn = register_name(cmpreg);

    if (s[1] == 's') {
        if (s[16]=='x') {
            /* slt $2,$2,$3; xroi $2,$2,0x1; beq $2,$0,L1 */
            printf(s,crn,drn,drn,crn,crn,crn,l1);
        } else {
            /* slt $2,$2,$3; beq $2,$0,L1 */
            printf(s,crn,drn,drn,crn,l1);
        }
    } else {
        /* beq $2,$3,L1 */
        printf(s,crn,drn,l1);
    }
    free_register(cmpreg) ; cmpreg = -1;
}

void
jcond(int l, char cond)
{
    if (chk) return;
    if (cmpreg==-1) error(-1);
    printf("\tb%s %s,%s,L_%d\n",
        cond?"ne":"eq",
	register_name(creg),register_name(cmpreg),
	l);
    free_register(cmpreg); cmpreg = -1;
}

void
jmp(int l)
{       
    control=0;
    if (chk) return;
    printf("\tj\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 3\n");
    /* if (stmode!=STATIC)
	printf(".globl _%s\n",name); */
    printf(".ent %s\n",name);
    printf("_%s:\n",name);
    code_disp_label=fwdlabel();

    printf("\t.set noreorder\n");
    printf("\t.cpload $25\n");
    printf("\t.set reorder\n");
    printf("\tsubu $sp,$sp,L_%d\n",code_disp_label);
    printf("\t.cprestore L_%d\n",cprestore_label);

    max_func_args = 0;
    max_func_iargs = 0;
}


void
code_enter1(int args)
{
    set_creg(CREG_REGISTER,0);
    set_freg(FREG_FREGISTER,0);
    set_dreg(DREG_DREGISTER,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;

    fprintf(asi,"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(".ent %s\n",name);
    printf("_%s:\n",name);

    r1_offset_label = fwdlabel();
    lvar_offset_label = fwdlabel();
    disp_label = fwdlabel();
    mask_label = fwdlabel();
    mask1_label = fwdlabel();
    fmask_label = fwdlabel();
    fmask1_label = fwdlabel();
    cprestore_label = fwdlabel();

    printf("\t.frame $fp,L_%d,$31\n",r1_offset_label);
    printf("\t.mask L_%d,L_%d\n",mask_label,mask1_label);
    printf("\t.fmask L_%d,L_%d\n",fmask_label,fmask1_label);

    printf("\t.set noreorder\n");
    printf("\t.cpload $25\n");
    printf("\t.set reorder\n");
    printf("\tsubu $sp,$sp,L_%d\n",disp_label);
    printf("\t.cprestore L_%d\n",cprestore_label);
    max_func_args = 0;
    max_func_iargs = 0;

}

void
enter1()
{
    set_creg(CREG_REGISTER,0);
    set_freg(FREG_FREGISTER,0);
    set_dreg(DREG_DREGISTER,0);
}

static unsigned int
code_mask_label()
{
    int i;
    unsigned int mask=0;
    for(i=0;i<32;i++) {
	if (i==28||i==31||(REG_VAR_MIN<=i&&i<=REG_VAR_MIN+max_reg_var)) {
	    mask |= (1<<i);
	}
    }
    return mask;
}

static unsigned int
code_fmask_label()
{
    int i;
    unsigned int mask=0;
    for(i=0;i<32;i++) {
	if (FREG_VAR_MIN<=i&&i<=FREG_VAR_MIN+max_freg_var) {
	    mask |= (1<<i);
	}
    }
    return mask;
}


void
leave(int control, char *name)
{
    int retcont1=0,sz;
    int r1_offsetv;

    if (max_freg_var>=0 && max_freg_var<=3) max_freg_var=3; 
    reg_save = 
	(REAL_MAX_REGISTER-(REG_VAR_BASE-max_reg_var))*size_of_int;
    freg_save = 
	(REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*size_of_float;

    if (control) {
	code_set_return_register(1);
    }
    if (retcont) { 
	/* return from CbC segement */
	if (control) jmp(retlabel);
	retcont1 = fwdlabel();
	fwddef(retcont);
	if (cadr(fnptr->ty)==FLOAT) {
	    if (freg!=RET_FREGISTER)
		printf("\tmov.s %s,%s\n",register_name(RET_FREGISTER),
			register_name(freg));
	} else if (cadr(fnptr->ty)==DOUBLE) {
	    move_dreg(RET_DREGISTER,dreg);
	} else if (cadr(fnptr->ty)>0&&(
	    car(cadr(fnptr->ty))==STRUCT ||
	    car(cadr(fnptr->ty))==UNION)) {
	    sz = size(cadr(fnptr->ty));
	    printf("\tli $4,%d\n",sz);
	    printf("\tsubl $5,$4,$fp\n");
	    printf("\tlw $3,(%d)($fp)\n",(my_func_args-1)*size_of_int);
	    emit_copy(6,3,sz,0,1,1);
	} else if (cadr(fnptr->ty)!=VOID) {
	    if (creg!=RET_REGISTER)
		printf("\tmove $3,%s\n",register_name(creg));
	}
	printf("\tj L_%d\n",retcont1);
    }
    fwddef(retlabel);
    if (retcont) {
	fwddef(retcont1);
    }
    if (max_freg_var>=0) {
    } else {
    }
    fprintf(asi,"L_%d=%d\n",r1_offset_label,0);
    fprintf(asi,"L_%d=%d\n",lvar_offset_label,0);
    fprintf(asi,"L_%d=0x%x\n",mask_label,code_mask_label());
    fprintf(asi,"L_%d=%d\n",mask1_label,0);
    fprintf(asi,"L_%d=0x%x\n",fmask_label ,code_fmask_label());
    fprintf(asi,"L_%d=%d\n",fmask1_label,0);
    fprintf(asi,"L_%d=%d\n",cprestore_label ,max_func_iargs);

    disp &= -size_of_int;
    r1_offsetv = 0;

    printf("\tmove    $sp,$fp\n");
    printf("\tlw      $31,%d($sp)\n",-disp);
    printf("\tlw      $fp,%d($sp)\n",-disp-4);
    printf("\taddu    $sp,$sp,%d\n",r1_offsetv);
    printf("\tj       $31\n");
    printf("\t.end    print\n");

    fprintf(asi,"L_%d=%d\n",disp_label,-r1_offsetv);

    code_offset_set();
    local_table();
    labelno++;
    free_all_register();
}


void
code_set_return_register(int mode) {
    if (cadr(fnptr->ty)==DOUBLE) {
	set_dreg(RET_DREGISTER,mode);
    } else if (cadr(fnptr->ty)==FLOAT) {
	set_freg(RET_FREGISTER,mode);
    } else if (cadr(fnptr->ty)==VOID) {
    } else {
	set_creg(RET_REGISTER,mode);
    }
}

int
code_get_fixed_creg(int reg,int type) {
    return creg;
}

void
code_set_fixed_creg(int reg,int mode,int type) {
    if (type==FLOAT) {
        set_freg(reg,mode);
    } else if (type==DOUBLE) {
        set_dreg(reg,mode);
    } else {
        set_creg(reg,mode);
    }
}


void
gen_gdecl(char *n, int gpc)
{
    if (stmode!=STATIC)
	printf("\t.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;
#if FLOAT_CODE
    double d;
    float f;
#endif
    char *name;
    name = n->nm; 
    if(mode!=GDECL&&mode!=STADECL)  { 
	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||t==UCHAR) {
	    printf("\t.byte %d\n",cadr(e));
	    if (data_alignment>0)
		data_alignment++;
	    gpc += 1;
	} else if (t==SHORT||t==USHORT) {
	    printf("\t.short %d\n",cadr(e));
	    if (data_alignment>0) data_alignment++;
	    gpc += 2;
	} else {
	    printf("\t.word %d\n",cadr(e));
	    gpc += size_of_int;
	}
#if FLOAT_CODE
    } else if(t==DOUBLE) {       
        d = dcadr(e);
        printf("\t.word\t0x%x\n\t.word\t0x%x\n",code_d1(d),code_d2(d));
    } else if(t==FLOAT) {       
        f = dcadr(e);
        printf("\t.word\t0x%x\n",*(int *)&f);
#endif
    } else if(t!=CHAR) {       
	gpc += size_of_int;
        if(car(e)==ADDRESS&&car(cadr(e))==GVAR) {
            printf("\t.word _%s\n",((NMTBL *)cadr(cadr(e)))->nm);
        } else if(car(e)==FNAME) {
            printf("\t.word _%s\n",((NMTBL *)cadr(e))->nm);
        } else if(car(e)==GVAR) {
            printf("\t.word _%s\n",((NMTBL *)cadr(e))->nm);
        } else if(car(e)==STRING) {       
            if (car(n->ty)!=ARRAY || cadr(n->ty)!=CHAR) {
                l = fwdlabel();
                printf("\t.word L_%d\n",l);
                printf(".rdata\n\t.align 2\n");
                printf("L_%d:\n",l);
                output_mode = RODATA_EMIT_MODE;
            }
            ascii((char *)cadr(e));
	} else error(TYERR);
    } 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; 
    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));
        }
    }
}

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;
	    }
	    if (n->dsp!=-1) /* n->dsp = -1 means initialized global */
	    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);
}

#if FLOAT_CODE

char *
fstore(int d)
{
    return (d?"stfd":"stfs");
}

char *
fload(int d)
{
    return d?"lfd":"lfs";
}

static
void code_dpfunc(char *f)
{
    if (max_func_iargs<16) max_func_iargs=16;
    printf("\tjal %s\n",f);
}

void
code_cmp_dregister(int e2,int d)
{
    char *frn,*grn;
    int greg;

    if (d) {
	printf("\tli.d $6,%g\n",0.0);
        code_save_stacks();
	move_dreg(4+DREG_OFFSET,freg);
	code_dpfunc("dpcmp");
        if (max_func_iargs<16) max_func_iargs=16;
        set_dreg(RET_DREGISTER,0);
	return;
    } else {
	grn =  register_name(greg = get_dregister(d));
	frn = register_name(e2);
	printf("\tli.s %s,%g\n",grn,0.0);
	printf("\tc.eq.s %s,%s\n",grn,frn);
	free_register(greg);
	return;
    }
}

void
code_dregister(int e2,int freg,int d)
{
    if (freg!=e2) {
	if (d) {
	    if (!is_double_reg(e2)) error(-1);
	    move_dreg(freg,e2);
	} else {
	    if (!is_float_reg(e2)) error(-1);
	    printf("\tfmr %s,%s\n",fregister_name(freg),fregister_name(e2));
	}
    }
}

void code_dassign_gvar(int e2,int freg,int d)
{ 
    NMTBL *n = (NMTBL*)cadr(e2);
    if (d) {
	if (!is_double_reg(freg)) error(-1);
        printf("\tsw %s,0(%s)\n",dregister_name0(freg),n->nm);
        printf("\tsw %s,0(%s)\n",dregister_name1(freg),n->nm);
    } else {
        printf("\ts.s %s,0(%s)\n",fregister_name(freg),n->nm);
    }
}

void code_dassign_lvar(int e2,int freg,int d)
{ 
    if (d) {
	if (!is_double_reg(freg)) error(-1);
        printf("\tsw %s,",dregister_name0(freg));
        lvar(e2);
        printf("\tsw %s,",dregister_name1(freg));
        e2 += size_of_double/2;
    } else {
        printf("\ts.s %s,",fregister_name(freg));
    }
    lvar(e2);
}

void code_dassign(int e2,int freg,int d)
{ 
    if (d) {
	if (!is_double_reg(freg)) error(-1);
        printf("\tsw %s,0(%s)\n",dregister_name0(freg),register_name(e2));
        printf("\tsw %s,4(%s)\n",dregister_name1(freg),register_name(e2));
    } else {
        printf("\ts.s %s,0(%s)\n",fregister_name(freg),register_name(e2));
    }
}

void
code_dassign_dregister(int e2,int d,int freg) {
    /* これってさ、code_dregister と同じ? */
    if (e2!=freg) {
        if (d) {
	    if (!is_double_reg(freg)) error(-1);
	    move_dreg(freg,e2);
        } else {
            printf("\tmov.s %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];
}

int
code_f(double d)
{
    float f = d;
    int *j = (int *)&f;
    return *j;
}

void 
code_dconst(int e2,int freg,int d)
{ 
    double value = dcadr(e2);
    char *frn;
    if (d) {
        printf("\tli.d %s,%g\n",dregister_name0(freg),value);
    } else {
        frn = fregister_name(freg);
        printf("\tli.s %s,%g\n",frn,value);
    }
}


void code_dneg(int freg,int d)
{ 
    char *frn;
    if (d) {
        code_save_stacks();
	move_dreg(4+DREG_OFFSET,freg);
	code_dpfunc("dpneg");
        set_dreg(RET_DREGISTER,0);
    } else {
        frn = fregister_name(freg);
        printf("\tfneg %s,%s\n",frn,frn);
    }
}

void code_d2i(int freg0)
{ 
    code_save_stacks();
    set_dreg(RET_DREGISTER,1);
    code_dpfunc("dptoli");
    set_creg(RET_REGISTER,0);
}

void code_i2d(int creg0)
{ 
    code_save_stacks();
    set_creg(RET_REGISTER,1);
    code_dpfunc("litodp");
    set_dreg(RET_DREGISTER,0);
}

void code_d2u(int freg0)
{ 
    code_save_stacks();
    set_dreg(RET_DREGISTER,1);
    code_dpfunc("dptoul");
    set_creg(RET_REGISTER,0);
}

void code_u2d(int creg0)
{ 
    code_save_stacks();
    set_creg(RET_REGISTER,1);
    code_dpfunc("ultodp");
    set_dreg(RET_DREGISTER,0);
}

void code_d2f(int freg) {
    code_save_stacks();
    set_dreg(RET_DREGISTER,1);
    code_dpfunc("dptofp");
    set_freg(RET_FREGISTER,0);
}

void code_f2d(int freg) {
    code_save_stacks();
    set_freg(RET_FREGISTER,1);
    code_dpfunc("fptodp");
    set_dreg(RET_DREGISTER,0);
}

void code_f2i(int freg) {
    printf("\ttrunc.w.s %s,%s,%s\n",register_name(freg),
	register_name(freg),register_name(ireg));
    creg = ireg;
}

void code_f2u(int freg) {
    printf("\ttrunc.w.s %s,%s,%s\n",register_name(freg),
	register_name(freg),register_name(ireg));
    creg = ireg;
}

void code_i2f(int creg0) {
    printf("\tcvt.s.w %s,%s\n",register_name(freg),register_name(freg));
    creg = freg;
}

void code_u2f(int creg0) {
    printf("\tcvt.s.w %s,%s\n",register_name(freg),register_name(freg));
    creg = freg;
}

void code_drgvar(int e2,int d,int freg)
{ 
    char *name = ((NMTBL*)cadr(e2))->nm;
    if (d) {
        printf("\tlw %s,%s\n",dregister_name0(freg),name);
        printf("\tlw %s,%s\n",dregister_name1(freg),name);
    } else {
        printf("\tl.s %s,%s\n",fregister_name(freg),name);
    }
}


void code_drlvar(int e2,int d,int freg)
{ 
    if (d) {
        printf("\tlw %s,",dregister_name0(freg)); lvar(e2);
        printf("\tlw %s,",dregister_name1(freg)); lvar(e2+size_of_double/2);
    } else {
        printf("\tl.s %s,",fregister_name(freg)); lvar(e2);
    }
}

void code_cmp_drgvar(int e2,int d)
{ 
    char *frn;
    int g;
    if (d) {
	code_save_stacks();
	set_dreg(RET_DREGISTER,1);
        code_drgvar(e2,d,RET_DREGISTER+2);
	code_dpfunc("dcmp");
    } else {
	frn=fregister_name(freg);
        g=get_dregister(d);
        code_drgvar(e2,d,g);
        printf("\tfc.eq.s %s,%s\n",frn,fregister_name(g));
	free_register(g);
    }
}

void code_cmp_drlvar(int e2,int d)
{ 
    char *frn=fregister_name(freg);
    int g;
    if (d) {
	code_save_stacks();
	set_dreg(RET_DREGISTER,1);
        code_drgvar(e2,d,RET_DREGISTER+2);
	code_dpfunc("dcmp");
    } else {
        g=get_dregister(d);
        code_drlvar(e2,d,g);
        printf("\tc.eq.s %s,%s\n",frn,fregister_name(g));
	free_register(g);
    }
}

static void
dtosop0(char *opn,int e1,int d,int cmp)
{
    char *frn;
    char *grn;
    if (d) {
	code_save_stacks();
	set_dreg(RET_DREGISTER,1);
	move_dreg(RET_DREGISTER+2,e1);
	code_dpfunc(opn);
    } else {
        frn=fregister_name(freg);
        grn=fregister_name(e1);
        if (cmp) {
            printf("\t%s %s,%s\n",opn,frn,grn);
        } else {
            printf("\t%s %s,%s,%s\n",opn,frn,frn,grn);
        }
    }
    free_register(e1);
}


void dtosop(int op,int e1)
{ 
    switch(op) {
    case FADD: dtosop0("fadd",e1,0,0); return;
    case DADD: dtosop0("dpadd",e1,1,0); return;
    case FSUB: dtosop0("fadd",e1,0,0); return;
    case DSUB: dtosop0("dpsub",e1,1,0); return;
    case FDIV: dtosop0("fadd",e1,0,0); return;
    case DDIV: dtosop0("dpdiv",e1,1,0); return;
    case FMUL: dtosop0("fadd",e1,0,0); return;
    case DMUL: dtosop0("dpmul",e1,1,0); return;
    case DCMPGE: 
    case DCMP:  dtosop0("dpcmp",e1,1,1); return;
    case FCMPGE: dtosop0("c.le.s",e1,0,1); return;
    case FCMP: dtosop0("c.eq.s",e1,0,1); return;
    default:
        error(-1); return;
    }
}

void
code_dassop(int op,int d) {
    /* we have lvalue in creg, applied floating value is in freg */
    char *frn;
    int  xreg;
    char *crn=register_name(creg);

    if (d) {
        xreg=emit_dpop(d);
        printf("\tlw %s,0(%s)\n",dregister_name0(freg),crn);
        printf("\tlw %s,%d(%s)\n",dregister_name1(freg),size_of_int,crn);
        dtosop(op,xreg);
        printf("\tsw %s,0(%s)\n",dregister_name0(freg),crn);
        printf("\tsw %s,%d(%s)\n",dregister_name1(freg),size_of_int,crn);
        emit_dpop_free(xreg,d);
	creg = dreg;
    } else {
        xreg=emit_dpop(d);
        frn=fregister_name(freg);
        crn=register_name(creg);

        printf("\tl.s %s,0(%s)\n",frn,crn);
        dtosop(op,xreg);
        printf("\ts.s %s,0(%s)\n",frn,crn);
        emit_dpop_free(xreg,d);
	creg = freg;
    }
}

void
code_register_dassop(int reg,int op,int d) {
    error(-1);
}   


void
code_dpreinc(int e1,int e2,int d,int reg) {
    char *frn;
    char *crn;
    int  g;
    char *grn;

    g_expr(e2);

    if (d) {
        crn=register_name(creg);
        frn=fregister_name(freg);

	code_save_stacks();
        set_dreg(RET_DREGISTER,0);
        printf("\tlw $4,0(%s)\n",crn);
        printf("\tlw $5,%d(%s)\n",size_of_int,crn);
        printf("\tli.d $6,1.0\n");
        if (caddr(e1)>0)
	    code_dpfunc("dpadd");
        else
	    code_dpfunc("dpsub");
        printf("\tsw $2,0(%s)\n",crn);
        printf("\tsw $3,%d(%s)\n",size_of_int,crn);
	creg = dreg;
    } else {
        crn=register_name(creg);
        frn=fregister_name(freg);
        grn=fregister_name(g=get_dregister(d));

        printf("\tl.s %s,0(%s)\n",frn,crn);
        printf("\tli.s %s,1.0\n",grn);
        if (caddr(e1)>0)
            printf("\tfadd %s,%s,%s\n",frn,frn,grn);
        else
            printf("\tfsub %s,%s,%s\n",frn,frn,grn);
        printf("\ts.s %s,0(%s)\n",frn,crn);
        free_register(g);
	creg = freg;
    }
}

void
code_dpostinc(int e1,int e2,int d,int reg) {
    char *frn;
    char *crn;
    int  g;
    char *grn;

    g_expr(e2);

    if (d) {
        crn=register_name(creg);
	g = get_dregister(d);
        set_dreg(RET_DREGISTER,0);
        printf("\tlw $4,0(%s)\n",crn);
        printf("\tlw $5,%d(%s)\n",size_of_int,crn);
	move_dreg(g,4+DREG_OFFSET);
        printf("\tli.d $6,1.0\n");
        if (caddr(e1)>0)
	    code_dpfunc("dpadd");
        else
	    code_dpfunc("dpsub");
        set_dreg(RET_DREGISTER,0);
        printf("\tsw $2,0(%s)\n",crn);
        printf("\tsw $3,%d(%s)\n",size_of_int,crn);
        free_register(dreg);
        set_dreg(g,0);
	creg = g;
    } else {
        crn=register_name(creg);
        frn=fregister_name(freg);
        grn=fregister_name(g=get_dregister(d));

        printf("\tl.s %s,0(%s)\n",frn,crn);
        printf("\tli.s %s,1.0\n",grn);
        if (caddr(e1)>0)
            printf("\tfadd %s,%s,%s\n",frn,frn,grn);
        else
            printf("\tfsub %s,%s,%s\n",frn,frn,grn);
        printf("\ts.s %s,0(%s)\n",grn,crn);
        free_register(g);
	creg = freg;
    }

}

void
drexpr(int e1, int e2,int l1, int op)
{       
    g_expr(list3(((op==FOP+EQ||op==FOP+NEQ)?DCMP:FCMPGE),e1,e2));
    switch(op) {
        case DOP+GE:
            printf("\tbgez\tL_%d\n",l1);
            break;
        case DOP+GT:
            printf("\tbltz\tL_%d\n",l1);
            break;
        case DOP+EQ:
            printf("\tbeq\tL_%d\n",l1);
            break;
        case DOP+NEQ:
            printf("\tbne\tL_%d\n",l1);
            break;
        case FOP+GE:
            printf("\tbc1tl\tL_%d\n",l1);
            break;
        case FOP+GT:
            printf("\tbc1tl\tL_%d\n",l1);
            break;
        case FOP+EQ:
            printf("\tbc1f\tL_%d\n",l1);
            break;
        case FOP+NEQ:
            printf("\tbc1f\tL_%d\n",l1);
            break;
    }
}

int emit_dpop(int d)
{ 
    int xreg,reg;
    if (d)
	xreg=pop_dregister();
    else
	xreg=pop_fregister();
    if (xreg<= -REG_LVAR_OFFSET) {
	reg = get_dregister(d);
        code_drlvar(REG_LVAR_OFFSET+xreg,d,reg);
	free_lvar(REG_LVAR_OFFSET+xreg);
	xreg=reg;
    }
    return xreg;
}

void emit_dpop_free(int e1,int d)
{ 
    free_register(e1);
}

void emit_dpush(int d)
{ 
    int new_reg;
    if (freg_sp>MAX_MAX) error(-1);
    new_reg = get_dregister(d);
    if (d) {
	dreg_stack[dreg_sp++] = dreg;     /* push するかわりにレジスタを使う */
	creg = dreg = new_reg;
    } else {
	freg_stack[freg_sp++] = freg;     /* push するかわりにレジスタを使う */
	creg = freg = new_reg;
    }
}

#endif

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;
        }
    }
#if FLOAT_CODE
    for(i=0;i<dreg_sp;i++) {
        if ((reg=dreg_stack[i])>=0) {
            code_dassign_lvar(
                (dreg_stack[i]=new_lvar(size_of_double)),reg,1); 
            dreg_stack[i]= dreg_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_float)),reg,0); 
            freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET;
        }
    }
#endif
}

void
emit_lib(char *p[])
{
    while(*p) {
	printf("%s\n",*p++);
    }
}

void
code_closing()
{
    global_table();
    /* printf("\t.ident \"Micro-C compiled\"\n"); */
    fclose(asi);
}


#if LONGLONG_CODE


/* 64bit int part */

void lrexpr(int e1, int e2,int l1, int op)
{
}

int lpop_register()
{
	return 0;
}

int emit_lpop()
{
	return 0;
}

void code_lregister(int e2,int reg)
{

}

void code_cmp_lregister(int reg)
{

}

void code_cmp_lrgvar(int e1,int e2)
{

}

void code_cmp_lrlvar(int e1,int e2)
{

}

void code_lassign(int e1,int e2)
{

}

void code_lassign_gvar(int e1,int e2)
{

}

void code_lassign_lvar(int e1,int e2)
{

}

void code_lassign_lregister(int e2,int reg)
{

}

void code_lconst(int e1,int e2)
{

}

void code_lneg(int e1)
{

}

void code_lrgvar(int e1,int e2)
{

}

void code_lrlvar(int e1,int e2)
{

}

void ltosop(int e1,int e2)
{

}

int code_lconst_op_p(int op,int e) {return 0;}
void loprtc(int op,int e) {}

void emit_lpop_free(int e1)
{

}

void emit_lpush()
{

}

void code_i2ll(int creg)
{

}

void code_i2ull(int creg)
{

}

void code_u2ll(int creg)
{

}

void code_u2ull(int creg)
{

}

void code_ll2i(int creg)
{

}

void code_ll2u(int creg)
{

}

void code_ull2i(int creg)
{

}

void code_ull2u(int creg)
{

}

#if FLOAT_CODE
void code_d2ll(int creg)
{

}

void code_d2ull(int creg)
{

}

void code_f2ll(int creg)
{

}

void code_f2ull(int creg)
{

}

void code_ll2d(int creg)
{

}

void code_ll2f(int creg)
{

}

void code_ull2d(int creg)
{

}

void code_ull2f(int creg)
{

}

void code_ull2ll(int creg)
{

}

void code_ull2ull(int creg)
{

}

#endif


void code_lpreinc(int e1,int e2,int reg)
{

}

void code_lpostinc(int e1,int e2,int reg)
{

}

void code_lassop(int op)
{

}

void
code_register_lassop(int reg,int op) {
}



#endif

/* end */