changeset 371:238c3704ee3d

ARM first try
author kono
date Fri, 09 Jul 2004 14:47:40 +0900
parents c6c1323be02d
children 81345636387d
files Changes mc-code-arm.c mc-code-mips.c mc-code-powerpc.c
diffstat 4 files changed, 5690 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/Changes	Thu Jul 08 12:10:34 2004 +0900
+++ b/Changes	Fri Jul 09 14:47:40 2004 +0900
@@ -5577,3 +5577,12 @@
 Thu Jul  8 02:31:03 JST 2004
 
 ARMは、どうもadd, sub は、8bit 幅で定数を持てるみたいね。
+
+table がmax-min を16bit だと仮定しているみたい。倍数を
+含んでいるときは、その限りでない。
+
+Fri Jul  9 14:45:56 JST 2004
+
+LDECL は、disp < 0
+
+const も実装しないといけないんだよな〜
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mc-code-arm.c	Fri Jul 09 14:47:40 2004 +0900
@@ -0,0 +1,5677 @@
+/* Micro-C Code Generation Part for Linux Zaurus and GameBoy Advance */
+/* $Id$ */
+
+
+#include <stdio.h>
+#include "mc.h"
+#include "mc-parse.h"
+#include "mc-code.h"
+#include "mc-codegen.h"
+
+#define Linux_Zaurus 1
+#define GameBoyAdvance 2
+
+int arc_mode = Linux_Zaurus; 
+
+char **l_include_path[];
+
+char *l_include_path_zaurus[] = {
+    "/Developer/Zaurus-X-gcc/opt/Embedix/tools/arm-linux/include",
+    0
+};
+
+char *l_include_path_gba[] = {
+    "/Developer/Zaurus-X-gcc/opt/Embedix/tools/arm-linux/include",
+    0
+};
+
+int data_alignment = 0;
+
+#define TEXT_EMIT_MODE 0
+#define DATA_EMIT_MODE 1
+#define RODATA_EMIT_MODE 2
+
+#define DOT_SIZE 1
+
+static void data_mode(char *name);
+static void text_mode(int alignment);
+static void ld_indexx(int byte, int n, int xreg,int reg,int sign);
+static void local_table(void);
+static void shift(char *op, int creg,int reg);
+static int struct_push(int e4,int t,int arg);
+static void register_usage(char *s);
+
+static int creg;
+
+static int output_mode = TEXT_EMIT_MODE;
+
+static FILE *asi;
+
+static int cprestore_label;
+static int fmask_label;
+static int fmask_offset_label;
+static int mask_label;
+static int mask_offset_label;
+static int register_save_return_label;
+static int register_save_label;
+
+
+static int r1_offset_label;
+static int lvar_offset_label;
+// static int cprestore_label;
+static int    max_func_args = 0;
+
+
+static int freg,ireg,lreg;
+static int cmpreg;
+
+int code_lassop_p = 1;
+
+#define SIZE_OF_INT  4
+#define SIZE_OF_SHORT  2
+#define SIZE_OF_FLOAT  4
+#define SIZE_OF_DOUBLE  8
+#define SIZE_OF_LONGLONG  8
+#define ENDIAN  0
+
+static int  reg_sp;   /* REGister Stack-Pointer */
+static int reg_stack[MAX_MAX];  /* 実際のレジスタの領域 */
+
+/* floating point registers */
+
+static int  freg_sp;  /* floating point REGister Stack-Pointer */
+static int freg_stack[MAX_MAX]; /* 実際のレジスタの領域 */
+
+static int  lreg_sp;  /* longlong  REGister Stack-Pointer */
+static int lreg_stack[MAX_MAX]; /* 実際のレジスタの領域 */
+
+#define REG_fp   11
+#define REG_sp   15
+#define REG_VAR_BASE 10
+#define REG_VAR_MIN  8
+#define MIN_TMP_REG 0
+#define MAX_TMP_REG 7
+
+#define PTRC_REG 3              /* mark for pointer cache */
+
+#define FREG_VAR_BASE 7
+#define FREG_VAR_MIN  4
+#define MIN_TMP_FREG 0
+#define MAX_TMP_FREG 3
+
+int MAX_REGISTER=16;             /* ARMのレジスタを10個まで使う*/
+int MAX_FREGISTER=8;
+#define  REAL_MAX_REGISTER 16    /* ARMのレジスタが32ということ*/
+#define  REAL_MAX_FREGISTER 8    /* ARMのレジスタが32ということ*/
+#define  REAL_MAX_LREGISTER 6
+
+#define FREG_OFFSET REAL_MAX_REGISTER
+#define LREG_OFFSET (REAL_MAX_REGISTER+REAL_MAX_FREGISTER)
+
+int MAX_INPUT_REGISTER_VAR = 4;
+int MAX_CODE_INPUT_REGISTER_VAR = 7-MIN_TMP_REG;
+int MAX_INPUT_DREGISTER_VAR = 0;
+int MAX_INPUT_FREGISTER_VAR = 0;
+int MAX_CODE_INPUT_DREGISTER_VAR = 3-MIN_TMP_FREG;
+int MAX_CODE_INPUT_FREGISTER_VAR = 7-MIN_TMP_FREG;
+
+#define LREG_V 3    /* mark for virtual long long/double register */
+#define REGS_MAX (REAL_MAX_REGISTER+REAL_MAX_FREGISTER+REAL_MAX_LREGISTER+LREG_V)
+static int arm_regs[REGS_MAX];
+static int regv_h0[REAL_MAX_LREGISTER+LREG_V];
+static int regv_l0[REAL_MAX_LREGISTER+LREG_V];
+#define regv_h(i)  regv_h0[(i)-LREG_OFFSET]
+#define regv_l(i)  regv_l0[(i)-LREG_OFFSET]
+
+#define RET_REGISTER 2
+#define REGISTER_OPERAND  4
+#define RET_FREGISTER FREG_OFFSET
+#define FREGISTER_OPERAND  (FREG_OFFSET +12)
+
+#define RET_LREGISTER (LREG_OFFSET+REAL_MAX_LREGISTER)
+#define LREGISTER_OPERAND  (LREG_OFFSET +REAL_MAX_LREGISTER +1)
+#define LREGISTER_OPERAND_1  (LREG_OFFSET +REAL_MAX_LREGISTER +2)
+#define RET_LREGISTER_L 2    /* low word */
+#define RET_LREGISTER_H 3    /* high word */
+#define LREGISTER_OPERAND_L  4    /* low word */
+#define LREGISTER_OPERAND_H  5    /* high word */
+#define LREGISTER_OPERAND_1_L  6    /* low word */
+#define LREGISTER_OPERAND_1_H  7    /* high word */
+
+#define RET_DREGISTER RET_LREGISTER 
+#define DREGISTER_OPERAND LREGISTER_OPERAND
+#define DREGISTER_OPERAND_1 LREGISTER_OPERAND_1
+#define RET_DREGISTER_L RET_LREGISTER_L
+#define RET_DREGISTER_H RET_LREGISTER_H
+#define DREGISTER_OPERAND_H  LREGISTER_OPERAND_H  
+#define DREGISTER_OPERAND_L  LREGISTER_OPERAND_L  
+#define DREGISTER_OPERAND_1_L  LREGISTER_OPERAND_1_L  
+#define DREGISTER_OPERAND_1_H  LREGISTER_OPERAND_1_H  
+
+static int *regs  = arm_regs;
+
+// #define CREG_REGISTER  (MAX_TMP_REG)
+#define CREG_REGISTER  REGISTER_OPERAND
+// #define FREG_FREGISTER (MAX_TMP_FREG+FREG_OFFSET)
+#define FREG_FREGISTER FREGISTER_OPERAND
+// #define LREG_LREGISTER (MAX_TMP_REG+LREG_OFFSET)
+#define LREG_LREGISTER LREGISTER_OPERAND
+#define DREG_DREGISTER LREG_LREGISTER
+#define CMP_C1T (-1)
+
+
+static int max_reg_var, max_freg_var;
+
+static char *reg_name[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 
+    "r8", "r9", "sl", "fp", "ip", "lr", "pc", "sp",
+    "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7";
+}; 
+
+#define register_name(i)  reg_name[i]
+#define fregister_name(i) reg_name[i]
+#define lregister_name_low(i) reg_name[regv_l(i)]
+#define lregister_name_high(i) reg_name[regv_h(i)]
+
+char *r(i) { return register_name(i); }
+char *f(i) { return fregister_name(i); }
+char *ll(i) { return lregister_name_low(i); }
+char *lh(i) { return lregister_name_high(i); }
+
+#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_longlong_reg(i)  (LREG_OFFSET<=i&&i<LREG_OFFSET+REAL_MAX_LREGISTER+LREG_V)
+#define is_double_reg(i)  is_longlong_reg(i)
+
+#define  use_int(reg) if (reg==USE_CREG) reg=use_int0()
+static
+int use_int0() { 
+    int i = creg;
+    if (!i||!ireg||!is_int_reg(i)) {
+	if (lreg) { if (regs[lreg]) free_register(lreg); lreg = 0; }
+	if (!ireg) ireg = get_register();
+	// else if (ireg!=i) free_register(i);
+	i = ireg;
+    }
+    if (!regs[i]) regs[i]=USING_REG;
+    creg = i;
+    return i;
+}
+
+#if LONGLONG_CODE
+#define  use_longlong(reg) if (reg==USE_CREG) reg=use_longlong0()
+
+static
+int use_longlong0() {
+    int i = creg;
+    if (!is_longlong_reg(i)) {
+	if (ireg) { free_register(ireg); ireg=0; }
+	if (!lreg||!regs[lreg]) lreg = get_lregister();
+	// else if (lreg!=i) free_register(i);
+	i = lreg;
+    }
+    if (!regv_l(i)) regv_l(i) = get_register();
+    if (!regv_h(i)) regv_h(i) = get_register();
+    if (!regs[i]) regs[i]=USING_REG;
+    if (!regs[regv_l(i)]) regs[regv_l(i)]=USING_REG;
+    if (!regs[regv_h(i)]) regs[regv_h(i)]=USING_REG;
+    creg = i;
+    return i;
+}
+
+static void lmove(int to,int from);
+#endif
+
+
+#if FLOAT_CODE
+#define  use_float(d,reg) if (reg==USE_CREG) reg=d?use_double0():use_float0()
+static
+int use_float0() { 
+    int i = creg;
+    if (!is_float_reg(i)) {
+	if (lreg) { free_register(lreg); lreg = 0; }
+	if (!freg) freg = get_dregister(0);
+	// else if (freg!=i) free_register(i);
+	i = freg;
+    }
+    if (!regs[i]) regs[i]=USING_REG;
+    creg = i;
+    return i;
+}
+
+#define USING_DREG 5
+#define INPUT_DREG 6
+
+static
+int use_double0() { 
+    int i;
+    use_longlong0();
+    i = lreg;
+    if (!regs[i]) regs[i]=USING_DREG;
+    if (!regs[regv_l(i)]) regs[regv_l(i)]=USING_REG;
+    if (!regs[regv_h(i)]) regs[regv_h(i)]=USING_REG;
+    creg = i;
+    return i;
+}
+#endif
+
+
+#if FLOAT_CODE
+
+
+static int code_d1(double d);
+static int code_d2(double d);
+static void code_double_lib(char *lib,int to,int reg,int oreg);
+static void code_double_lib_c(char *lib,int from,int to,double value);
+
+#endif
+#if LONGLONG_CODE
+static int code_l1(long long ll);
+static int code_l2(long long ll);
+#endif
+
+static void code_save_stacks();
+static void code_save_input_registers(int dots);
+static void    set_ireg(int,int);
+static void    set_dreg(int,int);
+static void    set_freg(int,int);
+static void    set_lreg(int,int);
+
+static int max_func_args;
+static int my_func_args;
+static unsigned int code_mask();
+static int code_mask_offset();
+static unsigned int code_fmask();
+static int code_fmask_offset();
+
+static void jcond(int l, char cond);
+
+#define ARG_LVAR_OFFSET 0x10000000
+
+#define round16(i)   ((i+0xf)&~0xf)
+#define round4(i)   ((i+3)&~3)
+
+/*          
+
+     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
+     r18-r24 saved register variable (input register for code segment)
+     $25    jump register
+     $31    stack pointer
+     $fp    frame pointer
+
+     $f0       return value etc.
+     $f14,$f12 input register
+     $f20-$f31 saved register variable
+
+code segment stack frame
+
+                 * gotoを呼び出した関数のr1 ! r1(goto前のr1)
+   #             *                           $fp <---r1_offset---------> $sp
+r+ +----------+--+----------+----------------+-----------+----------+----+
+    cousin arg xx  reg save !callee arg      !code local  caller arg  xx
+              ($fp)r20-r29     lvar>0         lvar<0      lvar>0x1000 000
+                   f20-f31  <-my_func_args--><--disp-----><-max_func_arg->
+                              *SIZE_OF_INT                  *SIZE_OF_INT
+                 prev $sp=$fp                 $fp                        $sp
+
+
+                      <-------r1_offset------------------------------>
+                                      <------------lvar_offset------->
+                                                              <-arg_offset->
+ r+  +-----------+----+---------------+----------+-------------+----+
+       callee arg xxx  register save   local      caller arg     xxx
+                 ($r31)($fp) reg_save   disp          max_func_args*SIZE_OF_INT
+        lvar>0                         lvar<0          lvar>0x1000 0000
+                      prev $sp=$fp                                   $sp=$fp
+ */
+
+#define arg_offset 8
+#define arg_offset1 0
+int disp_offset = 0;
+#define disp_offset  0
+
+#define func_disp_offset 8
+#define code_disp_offset 0
+#define jump_offset 0
+
+#define CODE_LVAR(l) ((l)+code_disp_offset)
+#define CODE_CALLER_ARG(l) ((l)+arg_offset1)
+#define FUNC_LVAR(l) (l+disp_offset)
+#define CALLER_ARG(l) ((l)+arg_offset1)
+#define CALLEE_ARG(l) ((l)+arg_offset1)
+
+static int
+code_offset_set(NMTBL *fnptr)
+{
+    int lvar_offsetv,r1_offsetv;
+    // int code_f = (fnptr->sc==CODE);
+
+    disp &= -SIZE_OF_INT;
+    lvar_offsetv = round16(-disp) +
+	round16((max_func_args<2?2:max_func_args)*SIZE_OF_INT) +
+	2*SIZE_OF_INT;
+    r1_offsetv = lvar_offsetv + arg_offset + SIZE_OF_INT*2 +
+	max_reg_var*SIZE_OF_INT+max_freg_var*SIZE_OF_FLOAT+2*SIZE_OF_INT ;
+    lvar_offsetv += round16(r1_offsetv)-r1_offsetv;
+    r1_offsetv = round16(r1_offsetv);
+
+#if 0
+printf("# vars= %d, regs= %d/%d, args= %d, extra= %d\n",
+	round16(-disp),
+	max_reg_var+2,
+	max_freg_var,
+	round16(max_func_args*SIZE_OF_INT),
+	0
+);
+    printf("# mask_label $L_%d=0x%x\n",mask_label,code_mask());
+    printf("# mask_offset$L_%d=%d\n",mask_offset_label,code_mask_offset());
+    printf("# fmask_label $L_%d=0x%x\n",fmask_label,code_fmask());
+    printf("# fmask_offset$L_%d=%d\n",fmask_offset_label,code_fmask_offset());
+    printf("# cprestore  $L_%d=%d\n",cprestore_label ,round16(max_func_args*SIZE_OF_INT));
+   printf("#\n");
+   printf("# callee arg top=\t%d\n",CALLEE_ARG(0)+r1_offsetv);
+   printf("# r1_offset=\t\t%d %d\n",r1_offsetv,r1_offsetv%16);
+   printf("# reg_save_top=\t\t%d\n",r1_offsetv);
+   printf("# reg_save_end=\t\t%d\n",
+	-max_reg_var*SIZE_OF_INT-max_freg_var*SIZE_OF_FLOAT-2*SIZE_OF_INT+
+	r1_offsetv);
+   printf("# lvar_offset=\t\t%d %d\n",lvar_offsetv,lvar_offsetv%16);
+   printf("# min local var=\t%d\n",FUNC_LVAR(0)+lvar_offsetv);
+   printf("# max local var=\t%d\n",FUNC_LVAR(disp)+lvar_offsetv);
+   printf("# min caller arg var=\t%d\n",
+	CALLER_ARG(round16(max_func_args*SIZE_OF_INT)));
+   printf("# max caller arg var=\t%d\n",CALLER_ARG(0));
+   printf("#\n");
+#endif
+    fprintf(asi,"$L_%d=0x%x\n",mask_label,code_mask());
+    fprintf(asi,"$L_%d=%d\n",mask_offset_label,code_mask_offset());
+    fprintf(asi,"$L_%d=0x%x\n",fmask_label,code_fmask());
+    fprintf(asi,"$L_%d=%d\n",fmask_offset_label,code_fmask_offset());
+    fprintf(asi,"$L_%d=%d\n",cprestore_label ,
+	round16((max_func_args>2?max_func_args:2)*SIZE_OF_INT));
+    fprintf(asi,"$L_%d=%d\n",r1_offset_label,r1_offsetv);
+    fprintf(asi,"$L_%d=%d\n",lvar_offset_label,lvar_offsetv);
+
+    return r1_offsetv;
+}
+
+static void
+lvar(int l)
+{
+    if (fnptr->sc==CODE) {
+        if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+            printf("%d($sp)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET));
+        } else
+            printf("%d($fp)\n",CODE_LVAR(l));
+    } else if (l<0) {  /* local variable */
+        printf("%d+$L_%d($fp)\n",FUNC_LVAR(l),lvar_offset_label);
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+        printf("%d($sp)\n",CALLER_ARG(l-ARG_LVAR_OFFSET));
+    } else { /* callee's arguments */
+        printf("%d+$L_%d($fp)\n",CALLEE_ARG(l),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,$sp,%d\n",
+		register_name(creg),CODE_CALLER_ARG(l-ARG_LVAR_OFFSET));
+        } else
+            printf("\taddu\t%s,$fp,%d\n",register_name(creg),CODE_LVAR(l));
+    } else if (l<0) {  /* local variable */
+        printf("\taddu\t%s,$fp,%d+$L_%d\n",register_name(creg),
+		FUNC_LVAR(l),lvar_offset_label);
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+        printf("\taddu\t%s,$sp,%d\n",
+		register_name(creg),CALLER_ARG(l-ARG_LVAR_OFFSET));
+    } else { /* callee's arguments */
+        printf("\taddu\t%s,$fp,%d+$L_%d\n",
+		register_name(creg),CALLEE_ARG(l),r1_offset_label);
+    }
+}
+
+
+#define lvar_intro(e)  /* do nothing */
+
+void
+code_lvar(int e2,int reg) {
+    use_int(reg);
+    lvar_address(e2,reg);
+}
+
+
+// va_start, va_arg is wrong, use va_arm.h
+
+static char *init_src0 = "\
+/* #define __builtin_va_list int */\n\
+/* #define __builtin_va_start(ap,arg) ap=(((int)(&arg))+sizeof(arg)) */\n\
+/* #define __builtin_va_arg(ap,type)  (*((type *)ap)++) */\n\
+#define __builtin_next_arg(arg)  ap=((void *)(&arg)),va_arg(ap,typeof(arg))\n\
+#define __arm__ 1\n\
+#define __LITTLE_ENDIAN__ 1\n\
+#define __inline__\n\
+#define __STDC__ 1\n\
+#define __SIZE_TYPE__ int\n\
+#define __externsion__\n\
+#define __attribute__(a)\n\
+#define __flexarr\n\
+#define __WCHAR_TYPE__ int\n\
+#define __alignof__(type) (sizeof(type)==1?1:sizeof(type)==2?2:sizeof(type)<=4?4:8)\n\
+#define __PTRDIFF_TYPE__ int\n\
+#define __GNUC__ 2\n\
+#define __const const\n\
+#define alloca __builtin_alloca\n\
+";
+
+void
+code_init(void)
+{
+    int reg;
+    /* called only once */
+
+    size_of_int = SIZE_OF_INT;
+    size_of_short = SIZE_OF_SHORT;
+    size_of_float = SIZE_OF_FLOAT;
+    size_of_double = SIZE_OF_DOUBLE;
+    size_of_longlong = SIZE_OF_LONGLONG;
+    endian = ENDIAN;
+    init_src = init_src0;
+
+    reg=RET_LREGISTER;
+    regv_l(reg) = RET_LREGISTER_L;
+    regv_h(reg) = RET_LREGISTER_H;
+    reg=LREGISTER_OPERAND;
+    regv_l(reg) = LREGISTER_OPERAND_L;
+    regv_h(reg) = LREGISTER_OPERAND_H;
+    reg=LREGISTER_OPERAND_1;
+    regv_l(reg) = LREGISTER_OPERAND_1_L;
+    regv_h(reg) = LREGISTER_OPERAND_1_H;
+}
+
+extern void
+emit_reinit()
+{
+    /* called for each file */
+    init_ptr_cache();
+}
+
+
+
+void
+gexpr_code_init(void){
+    cmpreg = CMP_C1T ;
+}
+
+void
+code_gexpr(int e){
+     if (is_int_reg(creg) && creg!=ireg) error(-1);
+// register_usage("code_gexpr");
+}
+
+
+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 i;
+    int is_code0 = is_code(fnptr);
+    int dots;
+
+    function_type(fnptr->ty,&dots);
+    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;
+            }
+        } 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);
+            }
+        } else if (type==DOUBLE) {
+            if ((reg = get_input_lregister_var(reg_var,n,is_code0))) {
+                n->sc = DREGISTER;
+                n->dsp = cadr(reg);
+                regs[i=n->dsp]= INPUT_DREG;
+                regs[regv_l(i)]= INPUT_REG;
+                regs[regv_h(i)]= INPUT_REG;
+                reg_var+=2;
+                cadddr(args)=size(type);
+            }
+        } else if (type==LONGLONG||type==ULONGLONG) {
+            if ((reg = get_input_lregister_var(reg_var,n,is_code0))) {
+                n->sc = LREGISTER;
+                n->dsp = cadr(reg);
+                regs[i=n->dsp]= INPUT_REG;
+                regs[regv_l(i)]= INPUT_REG;
+                regs[regv_h(i)]= INPUT_REG;
+                reg_var+=2;
+                cadddr(args)=size(type);
+            }
+        }
+        args = cadr(args);
+    }
+    if (is_function(fnptr))
+	code_save_input_registers(dots);
+}
+
+
+int 
+get_register(void)
+{    /* 使われていないレジスタを調べる */
+    int i,j,reg;
+    for(i=MAX_TMP_REG;i>MIN_TMP_REG;i--) {
+	if (regs[i]) continue;  /* 使われている */
+	regs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
+	return i;   /* その場所を表す番号を返す */
+    }
+    /* 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(
+                (j=new_lvar(SIZE_OF_INT)),reg,0); 
+            reg_stack[i]= j-REG_LVAR_OFFSET;
+	    return reg;
+	}
+    }
+#if LONGLONG_CODE||FLOAT_CODE
+    /* search register stack */
+    for(i=0;i<lreg_sp;i++) {
+	if ((reg=lreg_stack[i])>=0) {
+            code_lassign_lvar(
+                (j=new_lvar(SIZE_OF_LONGLONG)),reg); 
+            lreg_stack[i]= j-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+1>max_reg_var) max_reg_var=i+1;
+	    return reg;   /* その場所を表す番号を返す */
+        }
+    }
+    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
+    error(HPERR); return creg;
+}
+
+#if 0
+int 
+get_register(void)
+{
+    int i = get_register0();
+    printf("# get_register %d\n",i);
+    return i;
+}
+#endif
+
+int
+pop_register(void)
+{     /* レジスタから値を取り出す */
+    return reg_stack[--reg_sp];
+}
+
+#if FLOAT_CODE
+int 
+get_dregister(int d)
+{    /* 使われていないレジスタを調べる */
+    int i,reg;
+    if (d) {
+      i = get_lregister();
+      if (i!=-1) regs[i]=USING_DREG;
+      return i;
+    }
+    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_DOUBLE)),reg,1); 
+            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+1>max_freg_var) max_freg_var=i+1;
+	    return reg;   /* その場所を表す番号を返す */
+        }
+    }
+    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
+    error(REG_ERR); return freg;
+}
+
+#if 0
+int 
+get_dregister(int d)
+{
+    int i = get_dregister0(d);
+printf("# get_dregister %d\n",i);
+    return i;
+}
+#endif
+
+int
+pop_fregister(void)
+{     /* レジスタから値を取り出す */
+    return freg_stack[--freg_sp];
+}
+#endif
+
+int
+get_lregister0()
+{
+    int i;
+    for(i=LREG_OFFSET;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) {
+	if (regs[i]==0) {
+// printf("# get_lregister %d\n",i);
+	    return i;
+	}
+    }
+    return -1;
+}
+
+int
+get_lregister()
+{
+    int h,l,i;
+    i = get_lregister0();
+    if (i==-1) return -1;
+    h = get_register(); 
+    if (h==-1) return -1;
+    regv_h(i) = h;
+    l = get_register(); 
+    if (l==-1) { free_register(h); return -1; }
+    regv_l(i) = l;
+    regs[i]=USING_REG;
+    return i;
+}
+
+int
+get_lregister_var(NMTBL *n)
+{
+    int i,j,ll;
+    int max_reg_var_save=max_reg_var;
+    ll = get_lregister0();
+    if (ll==-1) return -1;
+    if (regs[ll]==0) {
+	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+1>max_reg_var) max_reg_var=i+1;
+		for(j=0;j<REG_VAR_BASE-REG_VAR_MIN;j++) {
+		    if (! regs[REG_VAR_BASE-j]) {       
+			/* 使われていないなら */
+			/* そのレジスタを使うことを宣言し */
+			regs[REG_VAR_BASE-j]=USING_REG; 
+			if (j+1>max_reg_var) max_reg_var=j+1;
+			/* その場所を表す番号を返す */
+			regs[ll]=USING_REG;
+			regv_l(ll) = REG_VAR_BASE-j;
+			regv_h(ll) = REG_VAR_BASE-i;
+			return list3(LREGISTER,ll,(int)n); 
+		    }
+		}
+		/* ひとつしかなかった */
+		regs[REG_VAR_BASE-i]=0; 
+		max_reg_var=max_reg_var_save;
+		goto not_found;
+	    }
+	}
+    }
+not_found:
+    return list2(LVAR,new_lvar(SIZE_OF_LONGLONG));
+}
+
+void
+emit_pop_free(int xreg)
+{
+    if (xreg>=0)
+	free_register(xreg);
+}
+
+void
+
+free_register(int i) {    /* いらなくなったレジスタを開放 */
+// printf("# free_register %d\n",i);
+    regs[i]=0;
+    if (is_longlong_reg(i)) {
+	regs[regv_l(i)]=0;
+	regs[regv_h(i)]=0;
+	//regv_l(i)=0;
+	//regv_h(i)=0;
+    }
+}
+
+extern void
+use_ptr_cache(int r)
+{
+    regs[r]=PTRC_REG;
+}
+
+int
+get_input_dregister_var(int i,NMTBL *n,int is_code,int d)
+{
+    int j;
+    if (d) {
+      // if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0;
+      j = get_input_lregister_var(i,n,is_code);
+      if (car(j)==LREGISTER) {
+	if (regs[cadr(j)]==INPUT_REG) regs[cadr(j)]=INPUT_DREG;
+	car(j) = DREGISTER;
+      }
+      return j;
+    }
+    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=12+FREG_OFFSET;
+	else if (i==1) i=14+FREG_OFFSET;
+	else if (i==2) return list3(REGISTER,6,(int)n);
+	else if (i==3) return list3(REGISTER,7,(int)n);
+	else return 0;
+    }
+    return list3(FREGISTER,i,(int)n);
+}
+
+int
+get_input_lregister_var(int i,NMTBL *n,int is_code)
+{
+    int ll;
+    ll = get_lregister0();
+    if (i!=-1) {
+	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;
+            if (i%2==1) i++;
+	}
+#if ENDIAN==0
+	regv_l(ll)=i;
+	regv_h(ll)=i+1;
+#else
+	regv_h(ll)=i;
+	regv_l(ll)=i+1;
+#endif
+    } else { error(-1); ll=LREG_OFFSET+2; }
+    return list3(LREGISTER,ll,(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;
+}
+
+#if 0
+static int
+register_full(void)
+{
+    int i;
+    for(i=0;i<MAX_REGISTER;i++) {
+	if (! regs[i]) { 
+	    return 0;  
+	}
+    }
+    return 1;    
+}
+#endif
+
+void
+free_all_register(void)
+{
+    int i;
+// printf("# free_all register\n");
+#if LONGLONG_CODE||FLOAT_CODE
+    for(i=0;i<REAL_MAX_LREGISTER;i++) {
+	regs[i+LREG_OFFSET]=0; 
+    }
+    lreg = 0;
+    // set_lreg(LREG_LREGISTER,0);
+#endif
+    for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; }
+#if FLOAT_CODE
+    for(i=0;i<MAX_FREGISTER;i++) { regs[i+FREG_OFFSET]=0; }
+    freg = get_dregister(1);
+    set_freg(FREG_FREGISTER,0);
+#endif
+    ireg = creg = get_register();
+    set_ireg(CREG_REGISTER,0);
+    return;
+}
+
+
+extern int
+code_register_overlap(int s,int t)
+{
+    switch(car(s)) {
+    case REGISTER:
+	switch(car(t)) {
+	case FREGISTER: break;
+	case REGISTER:
+	    return cadr(s)==cadr(t);
+	    break;
+	case LREGISTER: case DREGISTER: 
+	    if(cadr(s)==regv_l(cadr(t))) return 1;
+	    if(cadr(s)==regv_h(cadr(t))) return 1;
+	    break;
+	}   
+	break;
+    case FREGISTER:
+	switch(car(t)) {
+	case REGISTER: case LREGISTER: case DREGISTER: break;
+	case FREGISTER:
+	    return cadr(s)==cadr(t);
+	    break;
+	}   
+	break;
+    case DREGISTER:
+    case LREGISTER:
+	switch(car(t)) {
+	case FREGISTER: break;
+	case REGISTER:
+	    if(cadr(t)==regv_l(cadr(s))) return 1;
+	    if(cadr(t)==regv_h(cadr(s))) return 1;
+	    break;
+	case LREGISTER: case DREGISTER: 
+	    if(regv_l(cadr(t))==regv_l(cadr(s))) return 1;
+	    if(regv_l(cadr(t))==regv_h(cadr(s))) return 1;
+	    if(regv_h(cadr(t))==regv_l(cadr(s))) return 1;
+	    if(regv_h(cadr(t))==regv_h(cadr(s))) return 1;
+	    break;
+	}   
+	break;
+    }   
+    return 0;
+}
+
+
+void
+register_usage(char *s)
+{
+#if 1
+    int i,j;
+#endif
+#define USAGE_MAX 4
+    if (chk) return;
+    if (!lsrc) return;
+    printf("# %d: %s:",lineno,s);
+    if (ireg) printf(" creg=%s",register_name(ireg));
+    if (freg) printf(" freg=%s",fregister_name(freg));
+    if (lreg) printf(" lreg=%s,%s",lregister_name_high(lreg),
+	lregister_name_low(lreg));
+#if 1
+    for(j=0,i=0;i<MAX_REGISTER;i++) if (regs[i]) j++;
+    if (j>USAGE_MAX) {
+	// printf("\n# regs:01234567890123456789012");
+	printf("\n# regs:");
+	for(i=0;i<MAX_REGISTER;i++) {  printf("%d",regs[i]); }
+    }
+    if (reg_sp>0) {
+	printf(" stack ");
+	for(i=reg_sp;i>0;i--) {
+	    if(reg_stack[i-1]>=0) {
+		printf(" %s",register_name(reg_stack[i-1]));
+            } else 
+		printf(",%d",reg_stack[i-1]);
+	}
+    }
+    for(j=0,i=0;i<MAX_FREGISTER;i++) if (regs[i+FREG_OFFSET]) j++;
+    if (j>USAGE_MAX) {
+	printf("\n# freg:");
+	for(i=0;i<MAX_FREGISTER;i++) {  printf("%d",regs[i+FREG_OFFSET]); }
+    }
+    if (freg_sp>0) {
+	printf(" fstack ");
+	for(i=freg_sp;i>0;i--) {
+	    if(freg_stack[i-1]>=0) {
+		printf(" %s",fregister_name(freg_stack[i-1]));
+            } else 
+		printf(",%d",freg_stack[i-1]);
+	}
+    }
+
+    for(j=0,i=0;i<REAL_MAX_LREGISTER;i++) if (regs[i+LREG_OFFSET]) j++;
+    if (j>USAGE_MAX) {
+	printf("\n# lreg:");
+	for(i=0;i<REAL_MAX_LREGISTER;i++) {  printf("%d",regs[i+LREG_OFFSET]); }
+    }
+    if (lreg_sp>0) {
+	printf(" lstack ");
+	for(i=lreg_sp;i>0;i--) {
+	    if(lreg_stack[i-1]>=0) {
+		printf(" %s",lregister_name_high(lreg_stack[i-1]));
+		printf(",%s",lregister_name_low(lreg_stack[i-1]));
+            } else 
+		printf(",%d",lreg_stack[i-1]);
+	}
+    }
+#endif
+    printf("\n");
+}
+
+
+void
+gexpr_init(void)
+{
+    while(reg_sp > 0) {
+	error(-1);
+	free_register(reg_stack[--reg_sp]);
+    }
+    while(freg_sp > 0) {
+	error(-1);
+	free_register(freg_stack[--freg_sp]);
+    }
+    while(lreg_sp > 0) {
+	error(-1);
+	free_register(lreg_stack[--lreg_sp]);
+    }
+    use_int0();
+    text_mode(2);
+    gexpr_code_init();
+    register_usage("");
+}
+
+
+void
+
+emit_init(void)
+{
+    /* called before each declaration */
+
+    free_all_register();
+    max_reg_var=0; max_freg_var=0;
+    reg_sp = 0;
+    freg_sp = 0;
+    text_mode(3);
+}
+
+#define reg_var_num(i) (REG_VAR_BASE-i)
+
+int
+get_register_var(NMTBL *n)
+{
+    int i,j;
+    for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) {
+	j = reg_var_num(i);
+	if (! regs[j]) {       /* 使われていないなら */
+	    /* そのレジスタを使うことを宣言し */
+	    regs[j]=USING_REG; 
+	    if (i+1>=max_reg_var) max_reg_var=i+1;
+	    /* その場所を表す番号を返す */
+	    return list3(REGISTER,j,(int)n); 
+	}
+    }
+    return list2(LVAR,new_lvar(SIZE_OF_INT));
+}
+
+#define freg_var_num(i) (FREG_VAR_BASE-i+FREG_OFFSET)
+
+int
+get_dregister_var(NMTBL *n,int d)
+{
+    int i,j;
+    if (d) {
+        i = get_lregister_var(n);
+	if (car(i)==LREGISTER) {
+	    car(i) = DREGISTER;
+	    regs[cadr(i)] = USING_DREG;
+	} 
+	return i;
+    }
+	    
+    for(i=0;i<FREG_VAR_BASE-FREG_VAR_MIN;i++) {
+	j = freg_var_num(i);
+        if (! regs[j]) {       /* 使われていないなら */
+            regs[j]=USING_REG; /*そのレジスタを使うことを宣言し*/
+	    if (i+1>max_freg_var) max_freg_var=i+1;
+	    /* その場所を表す番号を返す */
+	    return list3(FREGISTER,j,(int)n); 
+        }
+    }
+    return list2(LVAR,new_lvar(SIZE_OF_DOUBLE));
+}
+
+void
+
+emit_push()
+{
+    int new_reg;
+    if (!is_int_reg(creg)) error(-1);
+    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;
+}
+
+extern void
+code_ptr_cache_def(int r, NMTBL *nptr)
+{
+    char *rrn = register_name(r);
+    printf("\tla %s,%s\n",rrn,nptr->nm);
+}
+
+static void 
+code_add(int reg,int offset,int r)
+{
+    char *crn = register_name(reg);
+    char *rrn = register_name(r);
+    if (offset==0) {
+        if(r!=reg)
+            printf("\tmove %s,%s\n",crn,rrn);
+    } else
+        printf("\taddu %s,%s,%d\n",crn,rrn,offset);
+}
+
+
+static void 
+code_ld(char *ld,int reg,int offset,int r)
+{
+    char *crn = register_name(reg);
+    char *rrn = register_name(r);
+    printf("\t%s %s,%d(%s)\n",ld,crn,offset,rrn);
+}
+
+static void 
+code_ldf(char *ld,char *crn,int offset,int r)
+{
+    char *rrn = register_name(r);
+    printf("\t%s %s,%d(%s)\n",ld,crn,offset,rrn);
+}
+
+
+static char *cload(int sz,int sign) { 
+    if (sign) {
+        return sz==1?"lb":sz==SIZE_OF_SHORT?"lh":"lw"; 
+    } else {
+        return sz==1?"lbu":sz==SIZE_OF_SHORT?"lhu":"lw"; 
+    }
+}
+
+static char *cstore(int sz) { return sz==1?"sb":sz==SIZE_OF_SHORT?"sh":"sw"; }
+
+#define cext(sign,sz,reg)  /* do nothing */
+
+
+void
+code_label(int labelno)
+{
+    clear_ptr_cache();
+    printf("$L_%d:\n",labelno);
+}
+
+void
+code_gvar(int e1,int reg) {
+    use_int(reg);
+    code_add(reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)));
+    return;
+}
+
+void
+code_rgvar(int e1,int reg) {
+    use_int(reg);
+    code_ld("lw",reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)));
+}
+
+void
+code_crgvar(int e1,int reg,int sign,int sz){
+    use_int(reg);
+    code_ld(cload(sz,sign),reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)));
+    cext(sign,sz,reg);
+}
+
+
+void
+code_register(int e2,int reg) {
+    use_int(reg);
+    if (reg!=e2)
+	printf("\tmove %s,%s\n",register_name(reg),register_name(e2));
+}
+
+
+void
+code_rlvar(int e2,int reg) {
+    use_int(reg);
+    lvar_intro(e2);
+    printf("\tlw %s,",register_name(reg));
+    lvar(e2);
+}
+
+extern void
+code_i2c(int reg)
+{
+    int reg1;
+    use_int(reg);
+    reg1 = get_register();
+    printf("sll %s,%s,24\n",register_name(reg1),register_name(reg));
+    printf("sra %s,%s,24\n",register_name(reg),register_name(reg1));
+    free_register(reg1);
+}
+
+extern void
+code_i2s(int reg)
+{
+    int reg1;
+    use_int(reg);
+    reg1 = get_register();
+    printf("sll %s,%s,16\n",register_name(reg1),register_name(reg));
+    printf("sra %s,%s,16\n",register_name(reg),register_name(reg1));
+    free_register(reg1);
+}
+
+extern void
+code_u2uc(int reg)
+{   
+    use_int(reg);
+    printf("andi %s,%s,0xff\n",register_name(reg),register_name(reg));
+}
+
+extern void
+code_u2us(int reg)
+{   
+    use_int(reg);
+    printf("andi %s,%s,0xffff\n",register_name(reg),register_name(reg));
+}
+
+void
+code_crlvar(int e2,int reg,int sign,int sz) {
+    use_int(reg);
+    lvar_intro(e2);
+    printf("\t%s %s,",cload(sz,sign),register_name(reg));
+    lvar(e2);
+    cext(sign,sz,reg);
+}
+
+void
+code_fname(NMTBL *n,int reg) {
+    int r;
+    use_int(reg);
+    r = get_ptr_cache(n);
+    if(r!=reg)
+	printf("\tmove %s,%s\n",register_name(reg),register_name(r));
+    return;
+}
+
+void
+code_label_value(int label,int reg) {
+    use_int(reg);
+    printf("\tla %s,$L_%d\n",register_name(reg),label);
+    return;
+}
+
+void
+code_const(int e2,int reg) {
+    char *crn;
+    use_int(reg);
+    crn = register_name(reg);
+    printf("\tli %s,%d\n",crn,e2);
+}
+
+void
+code_neg(int creg) {
+    use_int(creg);
+    printf("\tsubu %s,$0,%s\n", register_name(creg), register_name(creg));
+}
+
+
+void
+code_not(int creg) {
+    use_int(creg);
+    printf("\tnor %s,%s,%s\n", 
+	register_name(creg), register_name(creg),register_name(creg));
+}
+
+
+void
+code_lnot(int creg) {
+    int dreg = get_register();
+    use_int(creg);
+
+    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;
+    if (car(e2)==REGISTER) {
+	use_int(reg);
+	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(reg),register_name(cadr(e2)));
+	return;
+    } 
+    g_expr(e2);
+    if (!is_int_reg(creg)) error(-1);
+    xrn = register_name(creg);
+    if (reg==USE_CREG) {
+	reg=get_register(); if (!reg) error(-1);
+	drn = register_name(reg);
+	set_ireg(reg,0);
+    } else {
+	drn = register_name(reg);
+    }
+    printf("\t%s %s,0(%s)\n",cload(sz,sign),drn,xrn);
+    if (use) cext(sign,sz,reg);
+    printf("\taddi %s,%s,%d\n",drn,drn,dir);
+    printf("\t%s %s,0(%s)\n",cstore(sz),drn,xrn);
+}
+
+
+void
+code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) {
+    char *xrn,*crn,*nrn;
+    int nreg;
+    if (car(e2)==REGISTER) {
+	use_int(reg);
+	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);
+    if (!is_int_reg(creg)) error(-1);
+    crn = register_name(creg);
+    nreg=get_register(); if (!nreg) error(-1);
+    nrn = register_name(nreg);
+    if (reg==USE_CREG) {
+	reg=get_register(); if (!reg) error(-1);
+	xrn = register_name(reg);
+	set_ireg(reg,0);
+    } else {
+	xrn = register_name(reg);
+    }
+    printf("\t%s %s,0(%s)\n",cload(sz,sign),xrn,crn);
+    if (use) cext(sign,sz,reg);
+    printf("\taddi %s,%s,%d\n",nrn,xrn,dir);
+    printf("\t%s %s,0(%s)\n",cstore(sz),nrn,crn);
+    free_register(nreg);
+}
+
+
+void
+code_return(int creg) {
+    char *crn;
+    use_int(creg);
+    crn = register_name(creg);
+    printf("\tla %s,$L_%d\n",crn,retcont);
+}
+
+#define R1SAVE 0
+
+void
+code_environment(int creg) {
+    /* save frame pointer */
+#if R1SAVE
+    use_int(creg);
+    printf("\tlw %s,0($fp)\n",register_name(creg));
+#else
+    use_int(creg);
+    printf("\taddu %s,",register_name(creg));
+    printf("$fp,%d+$L_%d\n",FUNC_LVAR(0),lvar_offset_label);
+#endif
+}
+
+static int rexpr_bool(int e1, int reg);
+
+void
+code_bool(int e1,int reg) {
+    char *xrn;
+    int e2,e3;
+    if (rexpr_bool(e1, reg)) return;
+    b_expr(e1,1,e2=fwdlabel(),1);  /* including > < ... */
+    if (use) {
+	use_int(reg);
+	xrn = register_name(reg);
+	printf("\tli %s,0\n",xrn);
+	jmp(e3=fwdlabel());
+	fwddef(e2);
+	printf("\tli %s,1\n",xrn);
+	fwddef(e3);
+    } else {
+	fwddef(e2);
+    }
+}
+
+char *
+code_gt(int cond) {
+  return (cond?"ne":"eq");
+}
+
+char *
+code_ugt(int cond) {
+  return code_gt(cond);
+}
+
+char *
+code_ge(int cond) {
+  return code_gt(!cond);
+}
+
+char *
+code_uge(int cond) {
+  return code_gt(!cond);
+}
+
+char *
+code_eq(int cond) {
+  return cond?"":0;
+}
+
+
+void
+code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) {
+    use_int(reg);
+    code_ld(cload(sz,0),reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)));
+    cext(0,sz,r);
+    cmpreg = reg;
+    // printf("\tcmpwi cr0,%s,0\n",crn);
+    jcond(label,cond);
+}
+
+
+void
+code_cmp_crlvar(int e2,int reg, int sz,int label,int cond) {
+    char *crn;
+    use_int(reg);
+    crn = register_name(reg);
+    lvar_intro(e2);
+    printf("\t%s %s,",cload(sz,0),crn);
+    lvar(e2);
+    cext(0,sz,reg);
+    code_cmp_register(reg,label,cond);
+}
+
+
+void
+code_cmp_rgvar(int e1,int reg,int label,int cond) {
+    use_int(reg);
+    code_ld("lw",reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)));
+    code_cmp_register(reg,label,cond);
+}
+
+
+void
+code_cmp_rlvar(int e2,int reg,int label,int cond) {
+    char *crn;
+    use_int(reg);
+    crn = register_name(reg);
+    lvar_intro(e2);
+    printf("\tlw %s,",crn);
+    lvar(e2);
+    code_cmp_register(reg,label,cond);
+}
+
+
+void
+code_cmp_register(int e2,int label,int cond) {
+    use_int(e2);
+    cmpreg = e2;  // used by jcond,  beq $reg,$0,L_xx
+    jcond(label,cond);
+}
+
+
+void
+code_string(int e1,int creg)
+{
+    char *s,*crn;
+    int lb;
+
+    use_int(creg);
+    crn = register_name(creg);
+
+    s=(char *)cadr(e1);
+    lb = emit_string_label();
+    ascii(s);
+    text_mode(2);
+    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;
+    char *trn;
+    char *drn;
+    int fix = 0;
+    char *memmove = "memmove";
+    int dreg = get_register(); if (!dreg) error(-1);
+
+    drn	 = register_name(dreg);
+    use_int(from);
+    use_int(to);
+    frn =	register_name(from);
+    trn =	register_name(to);
+
+    /* 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 (length <0) {
+            if (length > -MAX_COPY_LEN) {
+                for(;length<=-4;length+=4,offset-=4)
+                    emit_copy(from,to,-4,offset-4,0,det);
+                for(;length<=-2;length+=2,offset-=2)
+                    emit_copy(from,to,-2,offset-2,0,det);
+                if(length<0)
+                    emit_copy(from,to,length,offset-1,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 $6,%d\n",length);
+	printf("\tmove $5,%s\n",frn);
+	printf("\tmove $4,%s\n",trn);
+        /* overrap must be allowed */
+	printf("\tjal %s\n",memmove);
+	extern_define(memmove,0,FUNCTION,1);
+        fix=0;
+	set_ireg(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("\taddu %s,%s,%d\n",trn,trn,fix);
+	if(creg!=to) {
+	    free_register(creg); creg=to; ireg=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);
+    if (!is_int_reg(creg)) error(-1);
+    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),dreg);
+        for(count=0;count<length;count+=SIZE_OF_INT) {
+            printf("\tlw %s,%d(%s)\n",srn,count,crn);
+            printf("\tsw %s,%d(%s)\n",srn,count,drn);
+        }
+        free_register(sreg);
+        free_register(dreg);
+        return length/SIZE_OF_INT;
+    } else {
+        code_lvar(cadr(arg),dreg);
+        /* downward direction copy */
+        emit_copy(creg,dreg,length,0,0,1);
+    }
+    free_register(dreg);
+    return length/SIZE_OF_INT;
+}
+
+static void
+set_ireg(int reg,int mode)
+{
+    if (!is_int_reg(reg)) error(-1);
+    if (reg!=creg) {
+	clear_ptr_cache_reg(reg);
+	if (ireg && reg!=ireg ) {
+	    free_register(ireg);
+	    if (mode) {
+		printf("\tmove %s,%s\n",register_name(reg),register_name(ireg));
+	    }
+	}
+	free_register(creg);
+	regs[reg]=USING_REG;
+    }
+    creg = ireg = reg;
+}
+
+static void
+set_freg(int reg,int mode)
+{
+    if (!is_float_reg(reg)) error(-1);
+    if (reg!=creg) {
+	if (freg && reg!=freg) {
+	    free_register(freg);
+	    if (mode) {
+		printf("\tmov.s %s,%s\n",fregister_name(reg),fregister_name(freg));
+	    }
+	}
+	// if (creg!=ireg) free_register(creg);
+	regs[reg]=USING_REG;
+    }
+    creg = freg = reg;
+}
+
+static void
+set_lreg0(int reg,int mode)
+{
+    if (reg!=creg) {
+	if (lreg && reg!=lreg) {
+	    if (mode) {
+		printf("\tmove %s,%s\n",
+		    lregister_name_low(reg),lregister_name_low(lreg));
+		printf("\tmove %s,%s\n",
+		    lregister_name_high(reg),lregister_name_high(lreg));
+	    }
+	    free_register(lreg);
+	}
+	if (creg!=lreg) {
+	    free_register(creg);
+	    if (creg==ireg) ireg = 0;
+	}
+	regs[reg]=USING_REG;
+	clear_ptr_cache_reg(regv_l(reg));
+	regs[regv_l(reg)]=USING_REG;
+	clear_ptr_cache_reg(regv_h(reg));
+	regs[regv_h(reg)]=USING_REG;
+    }
+    creg = lreg = reg;
+}
+
+static void
+set_lreg(int reg,int mode)
+{
+    if (!is_longlong_reg(reg)) error(-1);
+    set_lreg0(reg,mode);
+}
+
+static void
+set_dreg(int reg,int mode)
+{
+    if (reg==RET_DREGISTER) {
+	regv_l(reg) = RET_DREGISTER_L;
+	regv_h(reg) = RET_DREGISTER_H;
+    } else if (reg==DREGISTER_OPERAND) {
+	regv_l(reg) = DREGISTER_OPERAND_L;
+	regv_h(reg) = DREGISTER_OPERAND_H;
+    } else if (reg==DREGISTER_OPERAND_1) {
+	regv_l(reg) = DREGISTER_OPERAND_1_L;
+	regv_h(reg) = DREGISTER_OPERAND_1_H;
+    }
+    set_lreg0(reg,mode);
+    regs[regv_l(reg)]=USING_DREG;
+    regs[regv_h(reg)]=USING_DREG;
+}
+
+static void
+set_lreg_operand(int reg,int mode)
+{
+    // save_stack,clear_ptr_cache is assumed    
+    if (!is_longlong_reg(reg)) { error(-1); return; }
+    if (mode) {
+	lmove(LREGISTER_OPERAND,reg);
+    }
+}
+
+/*
+static void
+set_lreg_operand1(int reg,int mode)
+{
+    // save_stack,clear_ptr_cache is assumed    
+    if (!is_longlong_reg(reg)) { error(-1); return; }
+    if (mode) {
+	lmove(LREGISTER_OPERAND_1,reg);
+    }
+}
+ */
+
+static void
+set_dreg_operand(int reg,int mode)
+{
+     set_lreg_operand(reg,mode);
+}
+
+/*
+static void
+set_dreg_operand1(int reg,int mode)
+{
+     set_lreg_operand1(reg,mode);
+}
+ */
+
+void
+use_reg(int arg)
+{
+// printf("# use reg %d\n",arg);
+    if (arg<0||arg> REGS_MAX)
+	error(-1);
+    clear_ptr_cache_reg(arg);
+    regs[arg]=USING_REG;
+    if (is_longlong_reg(arg)) {
+	clear_ptr_cache_reg(regv_l(arg));
+	regs[regv_l(arg)]=USING_REG;
+	clear_ptr_cache_reg(regv_h(arg));
+	regs[regv_h(arg)]=USING_REG;
+    } else if (is_double_reg(arg)) {
+	clear_ptr_cache_reg(regv_l(arg));
+	regs[regv_l(arg)]=USING_DREG;
+	clear_ptr_cache_reg(regv_h(arg));
+	regs[regv_h(arg)]=USING_DREG;
+    }
+}
+
+void
+code_save_input_registers(int dots)
+{
+    int args;
+    NMTBL *n;
+    int reg;
+    int tag;
+    int t;
+    /* fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); */
+    int reg_offset = 0;
+    int offset = 0;
+    int reg_var = 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_var++;
+	} else if (tag==FREGISTER) {
+	    /* regs[reg]==INPUT_REG case should be considered */
+	    n->dsp = offset;
+	    t = n->ty;
+	    if(t==FLOAT) {
+		offset+=SIZE_OF_FLOAT; reg_offset+=1;
+		if (reg==6||reg==7) {   // int register case
+		    tag = REGISTER; t = INT;
+		}
+	    }
+	    // else if(t==DOUBLE) { offset+=SIZE_OF_DOUBLE; reg_offset+=2; }
+	    else error(-1);
+	    reg_var++;
+	} else if (tag==DREGISTER) {
+	    /* regs[reg]==INPUT_REG case should be considered */
+	    n->dsp = offset;
+	    t = n->ty;
+	    offset+=SIZE_OF_DOUBLE; reg_offset+=2;
+	    reg_var += 2;
+	} else if (tag==LREGISTER) {
+	    /* regs[reg]==INPUT_REG case should be considered */
+	    n->dsp = offset;
+	    t = n->ty;
+	    offset+=SIZE_OF_LONGLONG; reg_offset+=2;
+	    reg_var += 2;
+	} else {
+	    offset += size(n->ty);
+	    continue;
+	}
+	n->sc  = LVAR;
+	g_expr_u(assign_expr0(list2(LVAR,n->dsp),list3(tag,reg,(int)n),t,t));
+	if (tag==REGISTER||tag==DREGISTER||tag==FREGISTER||tag==LREGISTER) {
+	    free_register(reg);
+	}
+    }
+    if (dots) {
+        while ((reg = get_input_register_var(reg_var,0,0))) {
+            g_expr_u(assign_expr0(
+                list2(LVAR,offset),reg,INT,INT));
+            offset+=SIZE_OF_INT;
+            reg_var++;
+        }
+    }
+    my_func_args = offset;
+}
+
+static int
+not_simple_p(int e3)
+{
+    return (e3==FUNCTION||e3==CONV||e3==RSTRUCT||e3==STASS||e3==ALLOCA||
+	e3==LDIV||e3==LUDIV||e3==LMOD||e3==LUMOD||
+		e3==LLSHIFT||e3==LULSHIFT||e3==LRSHIFT||e3==LURSHIFT||
+	e3==DDIV||e3==DADD||e3==DSUB||e3==DMUL||e3==DMINUS||
+            e3== DPOSTINC || e3==DPREINC || e3==DASSOP ||
+            e3== DOP+LT || e3== DOP+LE || e3== DOP+GT ||
+            e3== DOP+GE || e3== DOP+EQ || e3== DOP+NEQ);
+}
+
+int
+simple_arg(int e3)
+{
+    return !contains_p(e3,not_simple_p);
+}
+
+int
+caller_arg_offset_v(int arg)
+{
+    return ARG_LVAR_OFFSET+arg*SIZE_OF_INT;
+}
+
+void
+use_input_reg(int reg,int mode)
+{
+    if (is_int_reg(reg)) {
+	if (ireg&&reg == ireg) {
+	    if (creg==ireg) creg = 0;
+	    ireg = 0;
+	} 
+	if (lreg) {
+	    if (regv_l(lreg)==reg) {
+		regs[lreg]=0;
+		if (regv_h(lreg)>reg&&
+		    (regs[regv_h(lreg)]==USING_REG||
+		     regs[regv_h(lreg)]==USING_DREG))
+		  {
+		    free_register(regv_h(lreg));
+		}
+		if (creg==lreg) creg = ireg;
+		lreg = 0;
+	    } else if (regv_h(lreg)==reg) {
+		regs[lreg]=0;
+		if (regv_h(lreg)>reg && (
+		    (regs[regv_l(lreg)]==USING_REG) ||
+		    (regs[regv_l(lreg)]==USING_DREG) ))
+		  {
+		    free_register(regv_l(lreg));
+		}
+		if (creg==lreg) creg = ireg;
+		lreg = 0;
+	    }
+	}
+    } else if (is_longlong_reg(reg)) {
+	use_input_reg(regv_h(reg),0);
+	use_input_reg(regv_l(reg),0);
+    } else if (is_double_reg(reg)) {
+	use_input_reg(regv_h(reg),0);
+	use_input_reg(regv_l(reg),0);
+    } else if (is_float_reg(reg)) {
+	if (freg&&reg == freg) {
+	    if (creg==freg) creg = 0;
+	    freg = 0;
+	} 
+    }
+    if (mode) use_reg(reg);
+}
+
+#define FASS_INPUT (FOP+199)
+
+static void
+code_assign_input_float_int(int e0) {
+    int e1 = cadr(e0);
+    int e2 = caddr(e0);
+    int r;
+    double value;
+    char *frn;
+    //  e2 = e3;
+    if (car(e1)!=REGISTER) { error(-1); return; }
+    frn = register_name(cadr(e1));
+    switch(car(e2)) {
+    case FCONST:
+	value = dcadr(e2);
+        printf("\tli.s %s,%12.12g\n",frn,value);
+	break;
+    case FRGVAR:
+	r = get_ptr_cache((NMTBL*)caddr(e2));
+	printf("\tlw %s,%d(%s)\n",frn,cadr(e2),register_name(r));
+	break;
+    case FRLVAR:
+	lvar_intro(cadr(e2));
+	printf("\tlw %s,",frn); lvar(cadr(e2));
+    default:
+	g_expr(e2);
+    case FREGISTER:
+	printf("\tmfc1 %s,%s\n",frn,fregister_name(freg));
+    }
+}
+
+static int
+compute_complex_arg(int e3,int reg_arg_list,int arg) {
+    int t=caddr(e3);
+    int e4 = car(e3);
+    reg_arg_list = list2(arg,reg_arg_list);
+    if (car(arg)==REGISTER||car(arg)==DREGISTER||
+	car(arg)==FREGISTER||car(arg)==LREGISTER)
+	use_input_reg(cadr(arg),1);
+    g_expr_u(assign_expr0(arg,e4,t,t));
+    car(e3) = arg;
+    return reg_arg_list;
+}
+
+static void
+increment_function_arg(int e3,int *pnargs,int *preg_arg,int *pfreg_arg) {
+    int nargs=0,reg_arg=0,freg_arg=0;
+    int t=caddr(e3);
+    if(scalar(t)) {
+	nargs ++ ; reg_arg++;
+    } else if (t==LONGLONG||t==ULONGLONG||t==DOUBLE) {
+	if (*preg_arg%2==1) reg_arg++;  // alignment
+        if (*pnargs%2==1) nargs++;  // alignment
+	nargs ++ ; reg_arg++;
+	nargs ++ ; reg_arg++;
+    } else if (t==FLOAT) {
+	reg_arg ++ ; freg_arg++;
+	nargs += size(t)/SIZE_OF_INT;
+    } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) {
+	nargs += round4(size(t))/SIZE_OF_INT;
+    } else {
+	error(TYERR);
+	nargs ++ ;
+    }
+    *pnargs += nargs;
+    *preg_arg += reg_arg;
+    *pfreg_arg += freg_arg;
+}
+
+#define AS_SAVE 1
+#define AS_ARG  0
+
+static int
+get_input_arg(int t,int mode,int nargs,int reg_arg,int freg_arg) 
+{
+    if(scalar(t)) {
+	if (mode==AS_SAVE) {
+	    return get_register_var(0);
+	} else if (reg_arg+1>MAX_INPUT_REGISTER_VAR) {
+	    return list2(LVAR,caller_arg_offset_v(nargs));
+	} else 
+	    return get_input_register_var(reg_arg,0,0);
+    } else if (t==LONGLONG||t==ULONGLONG) {
+	if (reg_arg%2==1) reg_arg++;  // alignment
+        if (nargs%2==1) nargs++;  // alignment
+	if (mode==AS_SAVE) {
+	    return get_lregister_var(0);
+	} else if (reg_arg+1>=MAX_INPUT_REGISTER_VAR)  {
+	    return list2(LVAR,caller_arg_offset_v(nargs));
+	} else
+	    return get_input_lregister_var(reg_arg,0,0);
+    } else if (t==FLOAT) {
+	if (mode==AS_SAVE) {
+	    return get_dregister_var(0,0);
+	} else if (freg_arg>=MAX_INPUT_DREGISTER_VAR) {
+	    return list2(LVAR,caller_arg_offset_v(nargs));
+	} else
+	    return get_input_dregister_var(freg_arg,0,0,0);
+    } else if (t==DOUBLE) {
+        if (reg_arg%2==1) reg_arg++;  // alignment
+        if (nargs%2==1) nargs++;  // alignment
+	if (mode==AS_SAVE) {
+	    return get_dregister_var(0,1);
+	} else if (reg_arg+1>=MAX_INPUT_DREGISTER_VAR) {
+	    return list2(LVAR,caller_arg_offset_v(nargs));
+	} else
+	    return get_input_dregister_var(reg_arg,0,0,1);
+    } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) {
+	if (mode==AS_SAVE) {
+	    return get_register_var(0);
+	} else
+	    return list2(LVAR,caller_arg_offset_v(nargs));
+    } else {
+	error(-1);
+	return get_register_var(0);
+    }
+}
+
+static void
+code_call(int e2,NMTBL *fn,int jmp)
+{
+    // char *jrn;
+    if (fnptr->sc==CODE) {
+	if (car(e2) == FNAME) {
+	    printf("\tla\t$25,%s\n",fn->nm);
+	} else {
+	    // jrn = register_name(cadr(jmp));
+	    // printf("\tmove\t$25,%s\n",jrn);
+	}
+	printf("\tjalr\t$25\n");
+	printf("\tlw\t$gp,$L_%d($sp)\n",cprestore_label);
+    } else {
+	if (car(e2) == FNAME) {
+	    printf("\tjal\t%s\n",fn->nm);
+	} else {
+	    // jrn = register_name(cadr(jmp));
+	    // printf("\tmove $25,%s\n",jrn);
+	    printf("\tjal\t$31,$25\n");
+	}
+    }
+}
+
+int
+function(int e1)
+{
+    int e2,e3,e4,e5,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;
+    int complex_;
+    int pnargs,preg_arg,pfreg_arg;
+    int stargs;
+
+    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;
+	}
+    }
+
+    arg_assign = 0;
+    e2 = cadr(e1);
+    if (car(e2) == FNAME) {	
+	fn=(NMTBL *)cadr(e2);
+    } else {	
+	if (car(e2)==INDIRECT) e2=cadr(e2); // (*func)(i) case
+	jmp = list2(REGISTER,25);
+	if (!simple_arg(e2)) {
+	    e3=get_register_var(0);
+	    g_expr_u(assign_expr0(e3,e2,INT,INT));
+	    e2=e3;
+	}
+	arg_assign = list2(assign_expr0(jmp,e2,INT,INT),arg_assign);
+    }
+    /* First we execute complex argument to avoid interaction with
+       input variables. Remain the last complex argument in complex_. */
+    stargs = 0;
+    complex_ = 0;
+    nargs = reg_arg = freg_arg = 0;
+    for (e3 = e1 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) {	
+	t=caddr(e3);
+	if ((e5= !simple_arg(car(e3)))) {
+	    if (complex_) {
+		arg = get_input_arg(caddr(complex_),AS_SAVE,
+					pnargs,preg_arg,pfreg_arg);
+		reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg);
+	    }
+	    pnargs=nargs;preg_arg=reg_arg;pfreg_arg=freg_arg;
+	    complex_ = e3;
+	}
+	if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) {
+	    // The struct should be pushed after complex arguments.
+	    if (e5) { // compute address only, complex_ is me now. Clear it.
+		complex_ = 0;
+		e4 = car(e3);
+		if (car(e4)!=RSTRUCT) error(-1);
+		if (!simple_arg(cadr(e4))) {
+		    // Calculate complex struct address here.
+		    // If simple, leave it.
+		    arg = get_register_var(0);
+		    g_expr_u(assign_expr0(arg,list2(ADDRESS,car(e3)),INT,INT));
+		    car(e3)=arg;
+		    reg_arg_list = list2(arg,reg_arg_list);
+		    if (car(arg)==REGISTER) use_input_reg(cadr(arg),1);
+		}
+	    }
+	    stargs = list4(e3,stargs,nargs,reg_arg);
+	}
+	increment_function_arg(e3,&nargs,&reg_arg,&freg_arg);
+    }
+
+    /* now all input register vars are free */
+    code_save_stacks();
+    // set_lreg(LREG_LREGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+    set_ireg(CREG_REGISTER,0);
+
+    //  Struct arguments need emit_copy. it destructs 3 input registers.
+    //  But it returns no value on a register. So calculate it here.
+    //  We cannot do this in the previous loop, because the copied struct may be
+    //  override by other complex arguments. But before this we have to check
+    //  complex_.
+
+    if (stargs) {
+	if (complex_) {
+	    arg = get_input_arg(caddr(complex_),AS_SAVE,
+				    pnargs,preg_arg,pfreg_arg);
+	    reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg);
+	}
+	for(stargs=reverse0(stargs);stargs;stargs = cadr(stargs)) {
+	    e3 = car(stargs);
+	    e4 = car(e3);
+	    t  = caddr(e3);
+	    arg = get_input_arg(t,AS_ARG,caddr(stargs),cadddr(stargs),0);
+	    struct_push(e4,t,arg);
+	    car(e3)=0;  // done
+	}
+    } else {
+	//  last complex argument can use input register
+	if (complex_) {
+	    arg = get_input_arg(caddr(complex_),AS_ARG,pnargs,preg_arg,pfreg_arg);
+	    reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg);
+	    car(complex_) = 0; // done.
+	}
+    }
+
+    nargs = reg_arg = freg_arg = 0;
+    // calc stack arguments first, it may requires extra registers,
+    // and we can still use input registers now.
+    for (e3 = e1; e3; 
+		increment_function_arg(e3,&nargs,&reg_arg,&freg_arg),
+		e3 = cadr(e3)) {	
+	if (!(e4=car(e3))) continue;
+	t=caddr(e3);
+	arg = get_input_arg(t,AS_ARG,nargs,reg_arg,freg_arg);
+	if (car(arg)!=LVAR) continue;
+	g_expr_u(assign_expr0(arg,e4,t,t));
+	car(e3)=0;  // done
+    }
+    nargs = reg_arg = freg_arg = 0;
+    for (e3 = e1; e3; 
+		increment_function_arg(e3,&nargs,&reg_arg,&freg_arg),
+		e3 = cadr(e3)) {	
+	if (!(e4=car(e3))) continue;
+	t=caddr(e3);
+	arg = get_input_arg(t,AS_ARG,nargs,reg_arg,freg_arg);
+	if(scalar(t)) {
+	    reg_arg_list = list2(arg,reg_arg_list);
+	    /* protect from input register free */
+	    if (car(arg)==REGISTER)
+		use_input_reg(cadr(arg),1);
+	    g_expr_u(assign_expr0(arg,e4,t,t));
+	} else if (t==LONGLONG||t==ULONGLONG) {
+	    if (car(arg)==LREGISTER) {
+		use_input_reg(cadr(arg),1);
+	    }
+	    reg_arg_list = list2(arg,reg_arg_list);
+	    g_expr_u(assign_expr0(arg,e4,t,t));
+	} else if (t==DOUBLE) {
+	    reg_arg_list = list2(arg,reg_arg_list);
+	    if (car(arg)==DREGISTER)
+		use_input_reg(cadr(arg),1);
+	    g_expr_u(assign_expr0(arg,e4,t,t));
+	} else if (t==FLOAT) {
+	    reg_arg_list = list2(arg,reg_arg_list);
+            if (car(arg)==FREGISTER) {
+                use_input_reg(cadr(arg),1);/* protect from input register free */
+                g_expr_u(assign_expr0(arg,e4,t,t)); /* XXX */
+            } else if (car(arg)==REGISTER) {
+		use_input_reg(cadr(arg),1);/* protect from input register free */
+                code_assign_input_float_int(list3(FASS_INPUT, arg, e4));
+            } else {
+                g_expr_u(assign_expr0(arg,e4,t,t)); /* XXX */
+            }
+	}
+	// structs are finished
+    }
+    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();
+    code_call(e2,fn,jmp);
+    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
+		||car(arg)==LREGISTER) 
+	    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);
+        use_reg(RET_DREGISTER);
+    } else if (ret_type==FLOAT) {
+        set_freg(RET_FREGISTER,0);
+    } else if (ret_type==ULONGLONG||ret_type==LONGLONG) {
+        set_lreg(RET_LREGISTER,0);
+        use_reg(RET_LREGISTER);
+    } else if (ret_type==VOID) {
+    } else {
+        set_ireg(RET_REGISTER,0);
+    }
+    return ret_type;
+}
+
+void
+code_alloca(int e1,int reg)
+{
+    char *crn,*grn;
+    int g;
+  
+    g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); 
+    use_int(reg);
+    g = get_register();
+    crn = register_name(reg);
+    grn = register_name(g);
+    printf("\tsubu $sp,$sp,%s\n",crn);
+    printf("\taddu %s,$sp,$L_%d\n",crn,cprestore_label);
+    free_register(g);
+}
+
+void
+code_frame_pointer(int e3) {
+    use_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 offset) {
+    printf("\tla $fp,");
+    printf("%d+$L_%d($sp)\n",FUNC_LVAR(0),lvar_offset_label);
+}
+
+//  MIPS $25 (=$jp) contains calling function address.
+//  It is used in cpload $25 to get global address table $gp.
+
+void
+code_jmp(char *s) {
+    // jump to continuation means use all register variable
+    max_reg_var = REG_VAR_BASE-REG_VAR_MIN;
+    max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN;
+    printf("\tla $25,%s\n",s);
+    printf("\tj\t$25\n");
+    control=0;
+}
+
+void
+code_indirect_jmp(int e2) {
+    // jump to continuation means use all register variable
+    max_reg_var = REG_VAR_BASE-REG_VAR_MIN;
+    max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN;
+    use_int(e2);
+    printf("\tmove $25,%s\n",register_name(e2));
+    printf("\tj\t$25\n");
+    control=0;
+}
+
+void
+code_rindirect(int e1, int reg,int offset, int sign,int sz)
+{
+    char *crn,*rrn;
+    g_expr(e1);
+    if (!is_int_reg(creg)) error(-1);
+    crn=register_name(creg);
+    use_int(reg);
+    rrn=register_name(reg);
+    printf("\t%s %s,%d(%s)\n",cload(sz,sign),rrn,offset,crn);
+    cext(sign,sz,reg);
+}
+
+#if FLOAT_CODE
+int
+code_drindirect(int e1, int reg,int offset, int d)
+{
+     char *crn;
+    if (d) {
+        code_lrindirect(e1,reg,offset,1);
+	use_float(d,reg);
+	// regs[reg==USE_CREG?lreg:reg]=USING_DREG;
+	return DOUBLE;
+    }
+    g_expr(e1);
+    if (!is_int_reg(creg)) error(-1);
+    crn=register_name(creg);
+    use_float(d,reg);
+    printf("\tl.s %s,%d(%s)\n",
+	fregister_name(reg),offset,crn);
+    return FLOAT;
+}
+#endif
+
+#if LONGLONG_CODE
+
+static void
+lload(int creg,int reg,int offset) 
+{
+    char *crn=register_name(creg);
+#if ENDIAN==0
+    if (creg!=regv_l(reg)) {
+	printf("\tlw %s,%d(%s)\n",lregister_name_low(reg),offset,crn);
+	printf("\tlw %s,%d(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn);
+    } else {
+	printf("\tlw %s,%d(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn);
+	printf("\tlw %s,%d(%s)\n",lregister_name_low(reg),offset,crn);
+    }
+#else
+    if (creg!=regv_l(reg)) {
+	printf("\tlw %s,%d(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn);
+	printf("\tlw %s,%d(%s)\n",lregister_name_high(reg),offset,crn);
+    } else {
+	printf("\tlw %s,%d(%s)\n",lregister_name_high(reg),offset,crn);
+	printf("\tlw %s,%d(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn);
+    }
+#endif
+}
+
+
+static void
+lmove(int to,int from)
+{
+    int l;
+    l = list3(regv_l(to),0,regv_l(from));
+    l = list3(regv_h(to),l,regv_h(from));
+    parallel_rassign(l);
+}
+
+static void
+set_operands(int r0,int r1,int r2,int r3)
+{
+    int l;
+    l = list3(DREGISTER_OPERAND_L,0,r0);
+    l = list3(DREGISTER_OPERAND_H,l,r1);
+    l = list3(DREGISTER_OPERAND_1_L,l,r2);
+    l = list3(DREGISTER_OPERAND_1_H,l,r3);
+    parallel_rassign(l);
+}
+
+
+static void
+lstore(int e2,int creg)
+{
+    char *drn = register_name(e2);
+    char *crn_h;
+    char *crn_l;
+    crn_h = lregister_name_high(creg);
+    crn_l = lregister_name_low(creg);
+#if ENDIAN==0
+    printf("\tsw %s,0(%s)\n",crn_l,drn);
+    printf("\tsw %s,%d(%s)\n",crn_h,SIZE_OF_INT,drn);
+#else
+    printf("\tsw %s,0(%s)\n",crn_h,drn);
+    printf("\tsw %s,%d(%s)\n",crn_l,SIZE_OF_INT,drn);
+#endif
+}
+
+int
+code_lrindirect(int e1, int reg, int offset, int us)
+{
+    int creg0;
+
+    g_expr(e1);
+    if (!is_int_reg(creg)) error(-1);
+    creg0=creg;
+    use_longlong(reg);
+    lload(creg0,reg,offset);
+    return us?ULONGLONG:LONGLONG;
+}
+#endif
+
+
+void
+code_assign_gvar(int e2,int creg,int byte) {
+    use_int(creg);
+    code_ldf(cstore(byte),register_name(creg),cadr(e2),
+        get_ptr_cache((NMTBL*)caddr(e2)));
+}
+
+void
+code_assign_lvar(int e2,int creg,int byte) {
+    char *crn;
+    use_int(creg);
+    crn=register_name(creg);
+    lvar_intro(e2);
+    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) {
+    use_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;
+    char *crn;
+    use_int(e2);
+    drn=register_name(e2);
+    use_int(creg);
+    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 reg, int op,int byte) {
+    //  reg <= reg(e2) op=reg
+    use_int(reg);
+    tosop(op,e2,reg);
+}
+
+void
+code_assop(int op,int creg, int byte,int sign) {
+    char *xrn,*crn,*drn;
+    int xreg;
+    int edx = get_register(); if(!edx) error(-1);
+    //  (*creg) op = pop()
+
+    use_int(creg);
+    xrn = register_name(xreg = emit_pop(0));       /* pop e3 value */
+#if 1
+    set_ireg(edx,0);
+    ld_indexx(byte,0,creg,ireg,sign);
+    tosop(op,ireg,xreg);
+    crn = register_name(ireg);
+    drn = 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);
+    }
+    free_register(edx);
+    emit_pop_free(xreg);
+#else
+    printf("# assop\n\tmove %s,%s\n",register_name(edx),register_name(creg));
+    ld_indexx(byte,0,edx,creg,sign);
+    tosop(op,creg,xreg);
+    crn = register_name(creg);
+    drn = register_name(edx);
+    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);
+    }
+    free_register(edx);
+    emit_pop_free(xreg);
+#endif
+}
+
+
+void
+tosop(int op,int creg,int oreg)
+{
+    int dx = -1;
+    int ox = -1;
+    char *orn,*crn;
+    // creg = creg op oreg
+
+    use_int(creg);
+    if(oreg==-1) {
+	error(-1);
+    } else if (oreg<= -REG_LVAR_OFFSET) {
+	ox = get_register(); if (ox<0) error(-1);
+        code_rlvar(oreg+REG_LVAR_OFFSET,ox);
+	oreg = ox;
+    }
+
+    switch(op) {
+    case LSHIFT:
+    case ULSHIFT:
+	shift("sll",creg,oreg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case RSHIFT:
+	shift("sra",creg,oreg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case URSHIFT:
+	shift("srl",creg,oreg);
+	if(ox!=-1) free_register(ox);
+	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 CMPGE:
+        printf("\tslt %s,%s,%s\n",crn,crn,orn);
+	cmpreg = creg;
+	break;
+    case CMP:
+        printf("\tslt %s,%s,%s\n",crn,orn,crn);
+	cmpreg = creg;
+	break;
+    case UCMPGE:
+        printf("\tsltu %s,%s,%s\n",crn,crn,orn);
+	cmpreg = creg;
+	break;
+    case UCMP:
+        printf("\tsltu %s,%s,%s\n",crn,orn,crn);
+	cmpreg = creg;
+	break;
+    case CMPEQ:
+        printf("\tbeq %s,%s",crn,orn);  // beq  $2,$3,L1
+	break;
+    case CMPNEQ:
+	printf("\tbne %s,%s",crn,orn);  // beq  $2,$3,L1
+	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: 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)?"mfhi":"mflo",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(dx!=-1) free_register(dx);
+    if(ox!=-1) free_register(ox);
+}
+
+int 
+code_const_op_p(int op,int v)
+{
+    if (car(v)!=CONST) return 0;
+    v = cadr(v);
+    if (op==MUL||op==UMUL) return ilog(v) ;
+    if (op==DIV||op==UDIV) return ilog(v) ;
+    if (!(op==LSHIFT|| op==ULSHIFT|| op==RSHIFT|| op==URSHIFT|| op==ADD|| op==SUB|| op==CMP|| op==BOR)) return 0;
+    return (-32766<v&&v<32767);
+}
+
+void
+oprtc(int op,int creg, int v)
+{
+    char *crn;
+    use_int(creg);
+    crn = register_name(creg);
+    v = cadr(v);
+    
+    switch(op) {
+    case LSHIFT:
+    case ULSHIFT:
+	printf("\tsll %s,%s,%d\n",crn,crn,v);
+	return;
+    case RSHIFT:
+	printf("\tsra %s,%s,%d\n",crn,crn,v);
+	return;
+    case URSHIFT:
+	printf("\tsrl %s,%s,%d\n",crn,crn,v);
+	return;
+    case ADD:
+	printf("\taddu %s,%s,%d\n",crn,crn,v);
+	break;
+    case SUB:
+	printf("\taddu %s,%s,-%d\n",crn,crn,v);
+	break;
+    case CMP:
+        printf("\tslt %s,%s,%d\n",crn,crn,v);
+        cmpreg = creg;
+	break;
+    case BOR:
+	printf("\tori %s,%s,%d\n",crn,crn,v);
+	break;
+    case MUL: case UMUL:
+	printf("\tsll %s,%s,%d\n",crn,crn,ilog(v));
+	break;
+    case UDIV:
+	printf("\tsrl %s,%s,%d\n",crn,crn,ilog(v));
+	break;
+    case DIV:
+	printf("\tsra %s,%s,%d\n",crn,crn,ilog(v));
+	break;
+    default:
+	error(-1);
+    }
+}
+
+void
+shift(char *op, int creg, int reg)
+{
+    char *crn;
+    char *rrn = register_name(reg);
+    use_int(creg);
+    crn = register_name(creg);
+    printf("\t%s %s,%s,%s\n",op,crn,crn,rrn);
+}
+
+void
+ld_indexx(int byte, int n, int xreg,int creg, int sign)
+{	
+    char *crn;
+    use_int(creg);
+    crn = register_name(creg);
+    printf("\t%s %s,%d(%s)\n",cload(byte,sign),register_name(creg),n,
+	    register_name(xreg));
+}
+
+int
+code_csvalue()
+{
+    return creg;
+}
+
+void
+code_cmpdimm(int e, int csreg,int label,int cond)
+{
+    /* used in dosiwtch() */
+    int reg=-1;
+    char *rn,*crn;
+    if(chk) return;
+    crn = register_name(csreg);
+
+    if (e<-32767||32766<e) {
+	rn = register_name(reg= get_register());
+	code_const(list2(CONST,e),reg);
+	switch(cond) {
+	case 1:
+	    printf("\tbne\t%s,%s,$L_%d\n",crn,rn,label); break;
+	case 0:
+	    printf("\tbeq\t%s,%s,$L_%d\n",crn,rn,label); break;
+	case LT:
+	    use_reg(csreg);
+	    printf("\tslt\t%s,%s,%s\n",rn,crn,rn);
+	    printf("\tbne\t%s,$0,$L_%d\n",rn,label); break;
+	default: error(-1);
+	}
+	free_register(reg);
+    }
+    switch(cond) {
+    case 1:
+	printf("\tbne\t%s,%d,$L_%d\n",crn,e,label); break;
+    case 0:
+	printf("\tbeq\t%s,%d,$L_%d\n",crn,e,label); break;
+    case LT:
+	use_reg(csreg);
+	rn = register_name(reg= get_register());
+	printf("\tslt\t%s,%s,%d\n",rn,crn,e);
+	printf("\tbne\t%s,$0,$L_%d\n",rn,label); break;
+    default: error(-1);
+    }
+    if (reg!=-1) free_register(reg);
+}
+
+void
+code_opening(char *filename)
+{
+    static int count=0;
+    char *asi_name;
+    /* this is called once per file */
+    printf("\t.file %d \"%s\"\n",count++,filename);
+    printf(".abicalls\n");
+    printf(".text\n");
+
+    if (asi) {
+        fclose(asi);
+        asi = 0;
+    }
+    asi_name = make_filename_with_extension(filename,"i");
+    if ( (asi = fopen(asi_name,"w")) == NULL ) error(FILERR);
+    if (!asi) error(-1);
+    printf(".include \"%s\"\n",asi_name);
+}
+
+// should have pcond_const
+
+#define COND_BRANCH 1
+#define COND_VALUE  2
+
+static void
+pcond(int op, int r2,int r1,int r0,int cond,int l1,int mode)
+{
+    char *slt  = "slt";
+    char *sltu = "sltu";
+    char *eq = "eq";
+    char *ne = "ne";
+    int t;
+    char *rn2;
+    char *rn1;
+    char *rn0;
+
+// printf("# pcond %d cond %d\n",op,cond);
+    switch(op+(!cond)*BNOT) {
+    case GT:  case LE+BNOT:
+		    t=r1;r1=r0;r0=t;
+    case LT:  case GE+BNOT:
+		    eq = ne;
+		    break;
+    case UGT: case ULE+BNOT:
+		    t=r1;r1=r0;r0=t;
+    case ULT: case UGE+BNOT:
+		    eq = ne; slt = sltu;
+		    break;
+    case ULE: case UGT+BNOT:
+		    t=r1;r1=r0;r0=t;
+    case UGE: case ULT+BNOT:
+		    slt = sltu;
+		    break;
+    case LE:  case GT+BNOT:
+		    t=r1;r1=r0;r0=t;
+    case GE:  case LT+BNOT:
+    case EQ:  case NEQ+BNOT:
+		    break;
+    case NEQ: case EQ+BNOT:   
+		    eq = ne;
+		    break;
+    default:        error(-1);
+    }
+    rn2 =		register_name(r2);
+    rn1 =		register_name(r1);
+    rn0 =		register_name(r0);
+
+
+    if (mode==COND_BRANCH) {
+	if (op==EQ||op==NEQ) {
+	    printf("\tb%s\t%s,%s,$L_%d\n",eq,rn0,rn1, l1);
+	} else {
+	    printf("\t%s\t%s,%s,%s\n",slt,rn2,rn1,rn0);
+	    printf("\tb%s %s,$0,$L_%d\n",eq,rn2,l1);
+	}
+    } else if (mode==COND_VALUE) {
+	if (op==EQ) {
+	    printf("\txor\t%s,%s,%s\n",rn2,rn1,rn0);
+	    printf("\tsltu\t%s,%s,1\n",rn2,rn2);
+	} else if (op==NEQ) {
+	    printf("\txor\t%s,%s,%s\n",rn2,rn1,rn0);
+	    printf("\tsltu\t%s,$0,%s\n",rn2,rn2);
+	} else {
+	    printf("\t%s\t%s,%s,%s\n",slt,rn2,rn1,rn0);
+	    if (eq==ne) {
+		printf("\txor\t%s,%s,1\n",rn2,rn2);
+	    }
+	}
+    } else error(-1);
+}
+
+int
+rexpr_bool(int e1, int reg)
+{       
+    int e2,reg0;
+    int op = car(e1);
+return 0;
+    if (!(
+	op== GT || op== LT || op== UGT || op== ULT ||
+	op== ULE || op== UGE || op== LE || op== GE ||
+	op== EQ || op== NEQ
+    )) return 0;
+    g_expr(cadr(e1));
+    emit_push();
+    g_expr(caddr(e1));
+    e2 = emit_pop(1);
+    reg0 = ireg;
+    use_int(reg);
+    pcond(op, reg,e2,reg0,1,0,COND_VALUE);
+    emit_pop_free(e2);
+    return 1;
+}
+
+void
+rexpr(int e1, int l1, int cond,int t)
+{       
+    int e2;
+    int op = car(e1);
+
+    g_expr(cadr(e1));
+    emit_push();
+    g_expr(caddr(e1));
+    e2 = emit_pop(1);
+    pcond(op, e2,e2,ireg,cond,l1,COND_BRANCH);
+    emit_pop_free(e2);
+}
+
+#define CMP_C1T (-1)
+
+static void
+jcond(int l, char cond)
+{       
+    if (chk) return;
+    if (cmpreg==CMP_C1T)  {
+      printf("\tbc1%s $L_%d\n",cond?"f":"t",l);
+    } else
+      printf("\tb%s %s,$0,$L_%d\n",cond?"ne":"eq",register_name(cmpreg),l);
+}
+
+void
+jmp(int l)
+{       
+    control=0;
+    if (chk) return;
+    printf("\tj\t$L_%d\n",l);
+}
+
+void
+gen_comment(char *s)
+{
+    if (chk) return;
+    printf("## %s",s);
+}
+
+static int
+code_mask_offset()
+{
+    /* used regsister var */
+    int i;
+    int offset=0;
+    int min = reg_var_num(max_reg_var);
+    int max = reg_var_num(0);
+    for(i=0;i<32;i++) {
+	if (i==28||i==31||(max>i&&i>=min)) {
+	    offset++;
+	}
+    }
+    if (offset>2) offset-=1;
+    return -offset*SIZE_OF_INT;
+}
+
+static unsigned int
+code_mask()
+{
+    /* used regsister var */
+    int i;
+    unsigned int mask=0;
+    int min = reg_var_num(max_reg_var);
+    int max = reg_var_num(0);
+    for(i=0;i<32;i++) {
+	if (i==28||i==31||(max>i&&i>=min)) {
+	    mask |= (1<<i);
+	}
+    }
+    return mask;
+}
+
+static int
+code_register_save(int reg_save,int freg_save,int disp)
+{
+    int i;
+    for (i=reg_var_num(0);i>reg_var_num(reg_save);i--) {
+	printf("\tsw    %s,$L_%d-%d($sp)\n",register_name(i),
+	    r1_offset_label,-disp);
+	disp -= SIZE_OF_INT;
+    }
+    for (i=freg_var_num(0);i>freg_var_num(freg_save);i--) {
+	printf("\ts.s    %s,$L_%d-%d($sp)\n",register_name(i),
+	    r1_offset_label,-disp);
+	disp -= SIZE_OF_FLOAT;
+    }
+    return disp;
+}
+
+static int
+code_register_restore(int reg_save,int freg_save,int disp)
+{
+    int i;
+    for (i=reg_var_num(0);i>reg_var_num(reg_save);i--) {
+	printf("\tlw    %s,$L_%d-%d($sp)\n",register_name(i),
+	    r1_offset_label,-disp);
+	disp -= SIZE_OF_INT;
+    }
+    for (i=freg_var_num(0);i>freg_var_num(freg_save);i--) {
+	printf("\tl.s    %s,$L_%d-%d($sp)\n",register_name(i),
+	    r1_offset_label,-disp);
+	disp -= SIZE_OF_FLOAT;
+    }
+    return disp;
+}
+
+static int
+code_fmask_offset()
+{
+    int i;
+    int offset=0;
+    int min = freg_var_num(max_reg_var);
+    int max = freg_var_num(0);
+    for(i=0;i<32;i++) {
+	if (i==28||i==31||(max>i&&i>=min)) {
+	    offset++;
+	}
+    }
+    if (offset>2) offset-=1;
+    return -offset*SIZE_OF_FLOAT;
+}
+
+static unsigned int
+code_fmask()
+{
+    int i;
+    unsigned int mask=0;
+    int min = freg_var_num(max_reg_var);
+    int max = freg_var_num(0);
+    for(i=0;i<32;i++) {
+	if (i==28||i==31||(max>i&&i>=min)) {
+	    mask |= (1<<i);
+	}
+    }
+    return mask;
+}
+
+void
+code_enter(char *name)
+{
+    if (output_mode!=TEXT_EMIT_MODE) 
+	text_mode(3);
+    else
+	printf("\t.align 3\n");
+    if (stmode!=STATIC)
+    printf("\t.globl\t%s\n",name);
+#ifdef DOT_SIZE
+    printf("\t.type\t%s,@function\n",name);
+#endif
+    printf(".ent %s\n",name);
+    printf("%s:\n",name);
+    printf("\t.frame $fp,$L_%d,$31\n",r1_offset_label=fwdlabel());
+    printf("\t.mask  $L_%d,$L_%d\n",mask_label=fwdlabel(),
+	mask_offset_label=fwdlabel());
+    printf("\t.fmask  $L_%d,$L_%d\n",fmask_label=fwdlabel(),
+	fmask_offset_label=fwdlabel());
+    printf("\t.set noreorder\n");
+    printf("\t.cpload $25\n");
+    printf("\t.set reorder\n");
+    printf("\tsubu $sp,$fp,$L_%d\n",r1_offset_label);
+    printf("\t.cprestore $L_%d\n",cprestore_label=fwdlabel());
+    // printf("\tmove  $fp,$sp\n");
+    lvar_offset_label = fwdlabel();
+    max_func_args = 0;
+}
+
+
+void
+code_enter1(int args)
+{
+    // set_lreg(LREG_LREGISTER,0);
+    set_ireg(CREG_REGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+}
+
+void
+code_leave(char *name)
+{
+    code_offset_set(fnptr);
+    local_table();
+    printf("\t.end    %s\n",name);
+}
+
+void
+enter(char *name)
+{
+    if (output_mode!=TEXT_EMIT_MODE) 
+	text_mode(3);
+    else
+	printf("\t.align 3\n");
+    
+    max_func_args = 0;
+
+    lvar_offset_label = fwdlabel();
+
+    if (stmode!=STATIC)
+	printf("\t.globl\t%s\n",name);
+    printf(".ent %s\n",name);
+    printf("%s:\n",name);
+    printf("\t.frame $fp,$L_%d,$31\n",r1_offset_label=fwdlabel());
+    printf("\t.mask  $L_%d,$L_%d\n",mask_label=fwdlabel(),
+	mask_offset_label=fwdlabel());
+    printf("\t.fmask  $L_%d,$L_%d\n",fmask_label=fwdlabel(),
+	fmask_offset_label=fwdlabel());
+    printf("\t.set noreorder\n");
+    printf("\t.cpload $25\n");
+    printf("\t.set reorder\n");
+    printf("\tsubu $sp,$sp,$L_%d\n",r1_offset_label);
+    printf("\t.cprestore $L_%d\n",cprestore_label=fwdlabel());
+    printf("\tsw      $31,$L_%d-%d($sp)\n",r1_offset_label,arg_offset);
+    printf("\tsw      $fp,$L_%d-%d($sp)\n",r1_offset_label,arg_offset+SIZE_OF_INT);
+    printf("\tj $L_%d\n",register_save_label=fwdlabel());
+    register_save_return_label = backdef();
+    printf("\tmove  $fp,$sp\n");
+}
+
+void
+enter1()
+{
+    text_mode(0);
+    // set_lreg(LREG_LREGISTER,0);
+    set_ireg(CREG_REGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+}
+
+
+void
+leave(int control, char *name)
+{
+    int retcont1=0,sz;
+    int r1_offsetv;
+
+    if (control) {
+	code_set_return_register(1);
+    } else
+	text_mode(2);
+    if (retcont) { 
+	/* return from CbC segement */
+	if (control) jmp(retlabel);
+	retcont1 = fwdlabel();
+	fwddef(retcont);
+	if (cadr(fnptr->ty)==FLOAT) {
+	    creg = freg = cadr(get_input_dregister_var(0,0,1,0));
+	    set_freg(RET_FREGISTER,1);
+	} else if (cadr(fnptr->ty)==DOUBLE) {
+	    creg = lreg = cadr(get_input_dregister_var(0,0,1,1));
+	    set_dreg(RET_DREGISTER,1);
+	} 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) {
+	    creg = ireg = cadr(get_input_register_var(0,0,1));
+	    if (creg!=RET_REGISTER)
+		set_ireg(RET_REGISTER,1);
+	}
+#if R1SAVE
+#else
+	printf("\tsubu $fp,");
+	printf("$fp,%d+$L_%d\n",FUNC_LVAR(0),lvar_offset_label);
+	// printf("\tj $L_%d\n",retcont1);
+#endif
+    }
+    fwddef(retlabel);
+    // if (retcont) {
+// 	fwddef(retcont1);
+    // }
+
+    r1_offsetv = code_offset_set(fnptr);
+
+    printf("\tmove    $sp,$fp\n");
+    printf("\tlw      $31,$L_%d-%d($sp)\n",r1_offset_label,arg_offset);
+    printf("\tlw      $fp,$L_%d-%d($sp)\n",r1_offset_label,arg_offset+SIZE_OF_INT);
+    if (max_reg_var+max_freg_var)
+	code_register_restore(max_reg_var,max_freg_var,-arg_offset-SIZE_OF_INT*2);
+    printf("\taddu    $sp,$sp,%d\n",r1_offsetv);
+    printf("\tj       $31\n");
+
+//  leave part end
+
+//  entry part  (save register)
+
+    if (max_reg_var+max_freg_var==0) {
+	fprintf(asi,"$L_%d=$L_%d\n",
+		register_save_label,register_save_return_label);
+    } else {
+	code_label(register_save_label);
+	code_register_save(max_reg_var,max_freg_var,-arg_offset-SIZE_OF_INT*2);
+	jmp(register_save_return_label);
+    }
+
+    local_table();
+    printf("\t.end    %s\n",name);
+
+    labelno++;
+    free_all_register();
+}
+
+
+void
+code_set_return_register(int mode) {
+    if (cadr(fnptr->ty)==FLOAT) {
+	set_freg(RET_FREGISTER,mode);
+    } else if (cadr(fnptr->ty)==DOUBLE) {
+	set_dreg(RET_DREGISTER,mode);
+    } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) {
+	set_lreg(RET_LREGISTER,mode);
+    } else if (cadr(fnptr->ty)==VOID) {
+    } else {
+	set_ireg(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 if (type==LONGLONG||type==ULONGLONG) {
+	set_lreg(reg,mode);
+	// use_reg(reg);
+    } else {
+	set_ireg(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
+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);
+}
+
+extern int
+emit_string_label() {
+    int lb;
+
+    lb=fwdlabel();
+    // should put on different segement
+    printf("\t.rdata\n\t.align 2\n");
+    printf("$L_%d:\n",lb);
+    output_mode = RODATA_EMIT_MODE;
+    return lb;
+}
+
+
+extern void
+emit_global(char *name,int t)
+{
+    printf(".globl\t%s\n",name);
+    data_mode(name);
+    align(t);
+    printf("%s:\n",name); 
+}
+
+extern void
+emit_space(int sp)
+{
+    data_mode(0);
+    printf("\t.space\t%d\n",sp);
+}
+
+extern void
+emit_char(int d)
+{
+    data_mode(0);
+    printf("\t.byte %d\n",d);
+}
+
+extern void
+emit_short(int d)
+{
+    data_mode(0);
+    printf("\t.short %d\n",d);
+}
+
+extern void
+emit_int(int d)
+{
+    data_mode(0);
+    printf("\t.long %d\n",d);
+}
+
+extern void
+emit_longlong(int e)
+{
+#if LONGLONG_CODE
+    long long ll = lcadr(e);
+    data_mode(0);
+#if (ENDIAN==0)
+	printf("\t.long\t0x%x,0x%x\n",code_l1(ll),code_l2(ll));
+#else
+	printf("\t.long\t0x%x,0x%x\n",code_l2(ll),code_l1(ll));
+#endif
+#endif
+}
+
+extern void
+emit_double(int e)
+{
+#if FLOAT_CODE
+    double d = dcadr(e);
+    data_mode(0);
+#if (ENDIAN==0)
+	printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d));
+#else
+	printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d));
+#endif
+#endif
+}
+
+extern void
+emit_float(int e)
+{
+#if FLOAT_CODE
+    float f = dcadr(e);
+    data_mode(0);
+    printf("\t.long\t0x%x\n",*(int *)&f);
+#endif
+}
+
+extern void
+emit_address(char *s,int offset)
+{
+    data_mode(0);
+    if (offset) 
+	printf("\t.long %s+%d\n",s,offset);
+    else
+	printf("\t.long %s\n",s);
+}
+
+extern void
+emit_label(int labelno)
+{
+    data_mode(0);
+    printf("\t.long $L_%d\n",labelno);
+}
+
+extern 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
+    }
+}
+
+
+static void
+comm(NMTBL *n)
+{
+    printf(".comm %s,%d,%d\n",n->nm,size(n->ty),
+	(n->ty==DOUBLE||n->ty==LONGLONG||n->ty==ULONGLONG)?8:4
+    );
+}
+
+void
+global_table(void)
+{
+    NMTBL *n;
+    int init;
+    init=0;
+    for(n=global_list;n;n=n->next) {
+	if ((n->sc == GVAR) && n->dsp != -1) {
+	    /* n->dsp = -1 means initialized global */
+	    if (init==0) {
+		data_mode(0);
+		init=1;
+	    }
+	    comm(n);
+	} else if ((n->sc==STATIC) && n->dsp != -1) {
+	    /* n->dsp = -1 means initialized global */
+	    if (init==0) {
+		data_mode(0);
+		init=1;
+	    }
+	    printf(".local %s\n",n->nm);
+	    comm(n);
+	}
+    }
+}
+
+void
+local_table(void)
+{
+    NMTBL *n;
+    int init;
+    init=0;
+    /* static local variables */
+    for(n=local_static_list;n;n=n->next) {
+	if (n->sc == GVAR) {
+	    if (n->dsp != -1) { /* initialized static */
+		if (init==0) {
+		    data_mode(0);
+		    init=1;
+		}
+		comm(n);
+	    }
+	}
+    }
+    text_mode(2);
+}
+
+void
+text_mode(int align)
+{
+    if (output_mode!=TEXT_EMIT_MODE) {
+	printf(".text\n");
+	if (align) printf("\t.align %d\n",align);
+	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);
+}
+
+#define lib_args(max) if (max_func_args<max) max_func_args=max
+
+static void
+extern_conv(char *conv)
+{
+     code_save_stacks();
+     clear_ptr_cache();
+     extern_define(conv,0,FUNCTION,1);
+     printf("\tjal %s\n",conv);
+     lib_args(16);
+}
+
+#if FLOAT_CODE
+
+/* floating point */
+
+#define  set_double(freg) if (regs[freg]) {regs[freg]=USING_DREG;}
+
+static void dconst(int l,int h,double value);
+
+void
+code_cmp_dregister(int e2,int d,int label,int cond)
+{
+    char *grn,*frn;
+    int greg;
+    use_float(d,e2);
+
+    if (d) {
+        code_save_stacks();
+	clear_ptr_cache();
+	set_dreg(DREGISTER_OPERAND,0);
+	dconst(DREGISTER_OPERAND_1_L,DREGISTER_OPERAND_1_H,0.0);
+        extern_conv("dpcmp");
+	set_dreg(RET_DREGISTER,0);
+	cmpreg = 2;
+    } else {
+	grn =  register_name(greg = get_dregister(d));
+	frn = register_name(e2);
+	printf("\tmtc1 $0,%s\n",grn);
+	printf("\tc.eq.s %s,%s\n",grn,frn);
+	free_register(greg);
+	cmpreg = CMP_C1T;
+    }
+    jcond(label,cond);
+    return;
+}
+
+void
+code_dregister(int e2,int freg,int d)
+{
+    use_float(d,freg);
+    if (d) {
+        code_lregister(e2,freg); set_double(freg); return;
+    }
+    if (freg!=e2) {
+        if (is_int_reg(e2)) error(-1);
+	printf("\tmov.s %s,%s\n",fregister_name(freg),fregister_name(e2));
+    }
+}
+
+void
+code_dassign_gvar(int e2,int freg,int d)
+{ 
+    if (d) {
+         code_lassign_gvar(e2,freg);  set_double(freg); return;
+    }
+    use_float(d,freg);
+    code_ldf("s.s",fregister_name(freg),cadr(e2),
+        get_ptr_cache((NMTBL*)caddr(e2)));
+}
+
+void
+code_dassign_lvar(int e2,int freg,int d)
+{ 
+    if (d) {
+        code_lassign_lvar(e2,freg); set_double(freg); return;
+    }
+    use_float(d,freg);
+    lvar_intro(e2);
+    printf("\ts.s %s,",fregister_name(freg));
+    lvar(e2);
+}
+
+void
+code_dassign(int e2,int freg,int d)
+{ 
+    if (d) {
+        code_lassign(e2,freg); set_double(freg); return;
+    }
+    use_float(d,freg);
+    printf("\ts.s %s,0(%s)\n",fregister_name(freg),register_name(e2));
+}
+
+void
+code_dassign_dregister(int e2,int d,int freg) {
+    if (d) {
+        code_lassign_lregister(e2,freg); set_double(freg); return;
+    }
+    use_float(d,freg);
+    if (e2!=freg) {
+	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;
+}
+
+static void
+dconst(int l,int h,double value)
+{
+#if ENDIAN==0
+	printf("\tli %s,0x%x\n",register_name(l),code_d1(value));
+	printf("\tli %s,0x%x\n",register_name(h),code_d2(value));
+#else
+	printf("\tli %s,0x%x\n",register_name(h),code_d1(value));
+	printf("\tli %s,0x%x\n",register_name(l),code_d2(value));
+#endif
+}
+
+void
+code_dconst(int e2,int freg,int d)
+{ 
+    double value = dcadr(e2);
+    char *frn;
+
+    use_float(d,freg);
+    if (d) {
+	dconst(regv_l(freg),regv_h(freg),value);
+    } else {
+        frn = fregister_name(freg);
+        printf("\tli.s %s,%10.10g\n",frn,value);
+    }
+}
+
+
+void
+code_dneg(int freg,int d)
+{ 
+    char *frn;
+    use_float(d,freg);
+    if (d) {
+        code_save_stacks();
+	clear_ptr_cache();
+	set_dreg(DREGISTER_OPERAND_1,1);
+        printf("\tmove $4,$0\n"); 
+        printf("\tmove $5,$0\n"); 
+	/// set_dreg_operand(oreg,1);
+        extern_conv("dpsub");
+	set_dreg(RET_DREGISTER,0);
+	return;
+    }
+    frn = fregister_name(freg);
+    printf("\tneg.s %s,%s\n",frn,frn);
+}
+
+void
+code_d2i(int reg)
+{ 
+    use_float(1,reg);
+    code_save_stacks();
+    clear_ptr_cache();
+    set_dreg(DREGISTER_OPERAND,1);
+    extern_conv("dptoli");
+    set_ireg(RET_REGISTER,0);
+    return;
+}
+
+void
+code_i2d(int reg)
+{ 
+    set_ireg(REGISTER_OPERAND,1);
+    code_save_stacks();
+    clear_ptr_cache();
+    extern_conv("litodp");
+    set_dreg(RET_DREGISTER,0);
+    use_float(1,reg);
+    return;
+}
+
+void
+code_d2u(int reg)
+{ 
+    use_float(1,reg);
+    code_save_stacks();
+    clear_ptr_cache();
+    set_dreg(DREGISTER_OPERAND,1);
+    extern_conv("dptoul");
+    set_ireg(RET_REGISTER,0);
+    return;
+}
+
+void
+code_u2d(int reg)
+{ 
+    int tmp=new_lvar(SIZE_OF_INT);
+    set_ireg(REGISTER_OPERAND,1);
+    code_assign_lvar(tmp,REGISTER_OPERAND,0);
+    code_save_stacks();
+    clear_ptr_cache();
+    extern_conv("litodp");
+    code_rlvar(tmp,REGISTER_OPERAND);
+    printf("\tbgez\t%s,1f\n",register_name(REGISTER_OPERAND));
+    code_double_lib_c("dpadd",RET_DREGISTER,RET_DREGISTER,4.29496729600000000000e9);
+    printf("1:\n");
+    set_dreg(RET_DREGISTER,0);
+    if (reg!=USE_CREG) {
+	use_float(1,reg);
+	if (reg!=RET_DREGISTER) {
+	    lmove(reg,RET_DREGISTER);
+	}
+    }
+    free_lvar(tmp);
+    return;
+}
+
+void
+code_d2f(int reg) { 
+    set_dreg(DREGISTER_OPERAND,1);
+    code_save_stacks();
+    clear_ptr_cache();
+    extern_conv("dptofp");
+    set_freg(RET_FREGISTER,0);
+    use_float(0,reg);
+    return;
+}
+
+void
+code_f2d(int reg) { 
+    set_freg(FREGISTER_OPERAND,1);
+    code_save_stacks();
+    clear_ptr_cache();
+    extern_conv("fptodp");
+    set_dreg(RET_DREGISTER,0);
+    use_float(1,reg);
+    return;
+}
+
+void
+code_f2i(int reg) {
+#if 0
+    int tmp=new_lvar(SIZE_OF_INT);
+    use_int(reg);
+    printf("\ttrunc.w.s %s,%s,%s\n",register_name(freg),
+	register_name(freg),register_name(ireg));
+    code_dassign_lvar(tmp,freg,1);
+    code_rlvar(tmp,reg);
+    free_lvar(tmp);
+#else
+    use_int(reg);
+    printf("\ttrunc.w.s %s,%s,%s\n",fregister_name(freg),
+	fregister_name(freg),register_name(ireg));
+    printf("\tmfc1    %s,%s\n",register_name(reg),fregister_name(freg));
+#endif
+}
+
+void
+code_f2u(int reg) {
+    int freg0 = freg;
+    int freg1 = get_dregister(0);
+    int freg2 = get_dregister(0);
+    int ireg1 = get_register();
+    char *fr0 = fregister_name(freg0);
+    char *fr1 = fregister_name(freg1);
+    char *fr2 = fregister_name(freg2);
+    char *r1 = register_name(ireg1);
+    char *r0;
+    int lb1,lb2;
+
+    use_int(reg);
+    r0 = register_name(ireg);
+    
+    printf("\tli.s    %s,2.14748364800000000000e9\n",fr1);
+    printf("\tc.le.s  %s,%s\n",fr1,fr0);
+    printf("\tbc1t    $L_%d\n",lb1=fwdlabel());
+    printf("\ttrunc.w.s %s,%s,%s\n",fr2,fr0,r0);
+    printf("\tmfc1    %s,%s\n",r0,fr2);
+    printf("\tj       $L_%d\n",lb2=fwdlabel());
+    printf("\t.p2align 2\n");
+    fwddef(lb1);
+    printf("\tsub.s   %s,%s,%s\n",fr0,fr0,fr1);
+    printf("\tli      %s,-2147483648                  # 0x80000000\n",
+	r0);
+    printf("\ttrunc.w.s %s,%s,%s\n",fr1,fr0,r1);
+    printf("\tmfc1    %s,%s\n",r1,fr1);
+    printf("\tor      %s,%s,%s\n",r0,r1,r0);
+    fwddef(lb2);
+    free_register(freg1);
+    free_register(freg2);
+    free_register(ireg1);
+}
+
+void
+code_i2f(int reg) {
+     int n = new_lvar(SIZE_OF_FLOAT);
+     use_int(reg);
+     code_assign_lvar(n,reg,0);
+     reg = USE_CREG;
+     use_float(0,reg);
+     code_drlvar(n,0,reg);
+     printf("\tcvt.s.w %s,%s\n",register_name(freg),register_name(freg));
+     free_lvar(n);
+}
+
+void
+code_u2f(int reg) {
+     // int n = new_lvar(SIZE_OF_FLOAT);
+     int /*reg0,*/reg1;
+     int lb1,lb2;
+     char *frn,*r0,*r1;
+     // code_assign_lvar(n,ireg,0);
+     printf("\tbltz    %s,$L_%d\n",r0=register_name(ireg),lb1=fwdlabel());
+     use_float(0,reg);
+     // code_drlvar(n,0,reg);
+     // r0= register_name(reg0 = get_register());
+     r1= register_name(reg1 = get_register());
+     frn = fregister_name(reg);
+    printf("\tmtc1     %s,%s\n",r0,frn);
+     printf("\tcvt.s.w %s,%s\n",frn,frn);
+     printf("\tj       $L_%d\n",lb2=fwdlabel());
+    printf("\t.p2align 2\n");
+    fwddef(lb1);
+    printf("\tandi    %s,%s,0x1\n",r1,r0);
+    printf("\tsrl     %s,%s,1\n",r0,r0);
+    printf("\tor      %s,%s,%s\n",r1,r1,r0);
+    printf("\tmtc1    %s,%s\n",r1,frn);
+    printf("\tcvt.s.w %s,%s\n",frn,frn);
+    printf("\tadd.s   %s,%s,%s\n",frn,frn,frn);
+    fwddef(lb2);
+    // free_register(reg0);
+    free_register(reg1);
+}
+
+void
+code_drgvar(int e2,int d,int freg)
+{ 
+    if (d) {
+         code_lrgvar(e2,freg);
+         set_double(freg);
+	 return;
+    }
+    use_float(d,freg);
+    code_ldf("l.s",fregister_name(freg),cadr(e2),
+        get_ptr_cache((NMTBL*)caddr(e2)));
+}
+
+
+void
+code_drlvar(int e2,int d,int freg)
+{ 
+    if (d) {
+         code_lrlvar(e2,freg);
+         set_double(freg);
+	 return;
+    }
+    use_float(d,freg);
+    lvar_intro(e2);
+    printf("\tl.s %s,",fregister_name(freg)); lvar(e2);
+}
+
+void
+code_cmp_drgvar(int e2,int reg,int d,int label,int cond)
+{ 
+    char *frn,*fr1;
+    int g;
+    use_float(d,reg);
+
+    if (d) {
+	code_save_stacks();
+	set_dreg(RET_DREGISTER,0);
+        code_drgvar(e2,d,RET_DREGISTER);
+	clear_ptr_cache();
+	printf("\tmove  $6,$0\n");
+	printf("\tmove  $7,$0\n");
+	extern_conv("dcmp");
+	cmpreg = 2;
+    } else {
+        code_drgvar(e2,d,USE_CREG);
+	frn = fregister_name(freg);
+	fr1=fregister_name(g = get_dregister(0));
+	printf("\tmtc1   $0,%s\n",fr1);
+        printf("\tfc.eq.s %s,%s\n",frn,fr1);
+	cmpreg = CMP_C1T;
+	free_register(g);
+    }
+    jcond(label,cond);
+}
+
+void
+code_cmp_drlvar(int e2,int reg,int d,int label,int cond)
+{ 
+    char *frn,*fr1;
+    int g;
+    use_float(d,reg);
+
+    if (d) {
+	code_save_stacks();
+	set_dreg(RET_DREGISTER,0);
+        code_drlvar(e2,d,RET_DREGISTER);
+	clear_ptr_cache();
+	printf("\tmove  $6,$0\n");
+	printf("\tmove  $7,$0\n");
+	extern_conv("dcmp");
+	cmpreg = 2;
+    } else {
+        code_drlvar(e2,d,USE_CREG);
+	frn = fregister_name(freg);
+	fr1=fregister_name(g = get_dregister(0));
+	printf("\tmtc1   $0,%s\n",fr1);
+        printf("\tfc.eq.s %s,%s\n",frn,fr1);
+	cmpreg = CMP_C1T;
+	free_register(g);
+    }
+    jcond(label,cond);
+}
+
+static void
+code_double_lib(char *lib,int to,int reg,int oreg)
+{
+    code_save_stacks();
+    clear_ptr_cache();
+    set_operands(regv_l(reg),regv_h(reg),regv_l(oreg),regv_h(oreg));
+    extern_conv(lib);
+    set_dreg(RET_DREGISTER,0);
+    if (to!=RET_DREGISTER) {
+	lmove(to,RET_DREGISTER);
+    }
+}
+
+static void
+code_double_lib_c(char *lib,int from,int to,double value)
+{
+    code_save_stacks();
+    clear_ptr_cache();
+    set_dreg_operand(from,1);
+    dconst(DREGISTER_OPERAND_1_L,DREGISTER_OPERAND_1_H,value);
+    extern_conv(lib);
+    set_dreg(RET_DREGISTER,0);
+    if (to!=RET_DREGISTER) {
+	lmove(to,RET_DREGISTER);
+    }
+}
+
+
+void
+dtosop(int op,int reg,int e1)
+{ 
+    char *opn="";
+    char *opc="";
+    char *grn,*frn;
+    int d;
+    int cmp=0;
+    int reg0=reg;
+
+    d=(op<FOP);
+    use_float(d,reg);
+    if (d) {
+	switch(op) {
+	case DADD: opc="dpadd"; break;
+	case DSUB: opc="dpsub"; break;
+	case DDIV: opc="dpdiv"; break;
+	case DMUL: opc="dpmul"; break;
+	case DCMPGE:
+	case DCMP:  opc="dpcmp"; break;
+	default:
+	    error(-1); return;
+	}
+        code_double_lib(opc,reg0==USE_CREG?RET_DREGISTER:reg,reg,e1);
+    } else {
+	switch(op) {
+	case FADD: opn="add.s"; break;
+	case FSUB: opn="sub.s"; break;
+	case FDIV: opn="div.s"; break;
+	case FMUL: opn="mul.s"; break;
+	case FCMP: opn="c.lt.s"; cmp=1; break;
+	case FCMPGE: opn="c.le.s"; cmp=1; break;
+	case FCMPEQ: opn="c.eq.s"; cmp=1; break;
+	default:
+	    error(-1); return;
+	}
+        grn = fregister_name(e1);
+        frn = fregister_name(reg);
+        if (cmp) {
+	  cmpreg=CMP_C1T;
+	  printf("\t%s %s,%s\n",opn,frn,grn);
+        } else {
+	  printf("\t%s %s,%s,%s\n",opn,frn,frn,grn);
+        }
+    }
+}
+
+void
+code_dassop(int op,int reg,int d) {
+    /* we have lvalue in creg, applied floating value is in freg */
+    //  (*creg) op = pop()
+    int  xreg;
+    char *crn;
+    char *frn;
+    int edx,edx0=-1;
+    int reg0=reg;
+
+    if (!d) {
+      xreg=emit_dpop(d);
+      crn=register_name(ireg);
+      use_float(d,reg);
+      frn  =fregister_name(reg);
+
+      printf("\tl.s %s,0(%s)\n",frn,crn);
+      dtosop(op,reg,xreg);
+      printf("\ts.s %s,0(%s)\n",frn,crn);
+      emit_dpop_free(xreg,d);
+    } else {
+      xreg = emit_lpop(0);       /* pop e3 value */
+      if (!is_int_reg(creg)) error(-1);
+      edx = ireg;
+      emit_push();
+      use_float(d,reg);
+      if (regv_l(lreg)==edx || regv_h(lreg)==edx) {
+	edx0 = get_register(); if(!edx0) error(-1);
+	printf("# dassop\n\tmove %s,%s\n",register_name(edx0),register_name(edx));
+	edx = edx0;
+      }
+      lload(edx,reg,0);
+      dtosop(op,USE_CREG,xreg);
+      if (lreg!=RET_DREGISTER) error(-1);
+      use_reg(lreg);
+      edx = emit_pop(0);
+      code_lassign(edx,RET_DREGISTER);
+      if (edx0!=-1)
+	free_register(edx0);
+      emit_pop_free(edx);
+      emit_lpop_free(xreg);
+      if (reg0!=USE_CREG && reg!=RET_DREGISTER)
+	lmove(reg,RET_DREGISTER);
+      set_double(reg);
+    }
+}
+
+void
+code_register_dassop(int reg,int op,int d) {
+    // reg op= dpop()
+    int  xreg;
+    if (!d) {
+      xreg=emit_dpop(d);
+      dtosop(op,reg,xreg);
+      emit_dpop_free(xreg,d);
+    } else {
+       xreg=emit_lpop();
+       dtosop(op,reg,xreg);
+       emit_lpop_free(xreg);
+       set_double(lreg);
+    }
+}   
+
+static int
+code_dload_1(int d)
+{
+    int g = get_dregister(d);
+    if (d)
+	error(-1);
+    else
+	printf("\tli.s %s,1.0\n",fregister_name(g));
+    return g;
+}
+
+void
+code_dpreinc(int e1,int e2,int d,int reg) {
+    char *frn;
+    char *crn;
+    int  g,xreg;
+    char *grn;
+    int dir=caddr(e1);
+
+    if (!d) {
+	if (car(e2)==FREGISTER) {
+	    crn=register_name(cadr(e2));
+	    grn=fregister_name(g=code_dload_1(d));
+	    if (reg==USE_CREG) {
+		reg=get_dregister(d); if (!reg) error(-1);
+		set_freg(reg,0);
+	    }
+	    frn=fregister_name(reg);
+	    printf("\t%s %s,%s,%s\n",dir>0?"add.s":"sub.s",crn,crn,grn);
+	    if (use && reg!=cadr(e2))
+		printf("\tmov.s %s,%s\n",frn,crn);
+	} else {
+	    g_expr(e2);
+	    if (!is_int_reg(creg)) error(-1);
+	    crn=register_name(ireg);
+	    if (reg==USE_CREG) {
+		reg=get_dregister(d); if (!reg) error(-1);
+		set_freg(reg,0);
+	    }
+	    frn=fregister_name(reg);
+	    grn = fregister_name(g = code_dload_1(d));
+	    printf("\tl.s %s,0(%s)\n",frn,crn);
+	    printf("\t%s %s,%s,%s\n",dir>0?"add.s":"sub.s",frn,frn,grn);
+	    printf("\ts.s %s,0(%s)\n",frn,crn);
+	}
+	free_register(g);
+    } else {
+	if (car(e2)==DREGISTER) {
+	    use_float(d,reg);
+	    code_save_stacks();
+	    code_double_lib_c("dpadd",cadr(e2),cadr(e2),dir);
+	    if (reg!=cadr(e2)) lmove(reg,cadr(e2));
+	    return;
+	} 
+	g_expr(e2);
+	if(!is_int_reg(creg)) error(-1);
+	xreg = ireg;
+	emit_push();
+	code_save_stacks();
+	lload(xreg,DREGISTER_OPERAND,0);
+	code_double_lib_c("dpadd",DREGISTER_OPERAND,RET_DREGISTER,dir);
+	xreg = emit_pop(0);
+	lstore(xreg,RET_DREGISTER);
+	if (use) {
+	    if (reg==USE_CREG)
+		set_dreg(RET_DREGISTER,0);
+	    else
+		lmove(reg,RET_DREGISTER);
+	}
+	emit_pop_free(xreg);
+    }
+}
+
+void
+code_dpostinc(int e1,int e2,int d,int reg) {
+    char *frn;
+    char *crn;
+    int  g,xreg;
+    char *grn;
+    int dir=caddr(e1);
+
+    if (!d) {
+	if (car(e2)==FREGISTER) {
+	    crn=register_name(cadr(e2));
+	    grn=fregister_name(g=code_dload_1(d));
+	    if (reg==USE_CREG) {
+		reg=get_dregister(d); if (!reg) error(-1);
+		set_freg(reg,0);
+	    }
+	    frn=fregister_name(reg);
+	    if (use && reg!=cadr(e2))
+		printf("\tmov.s %s,%s\n",frn,crn);
+	    printf("\t%s %s,%s,%s\n",dir>0?"add.s":"sub.s",crn,crn,grn);
+	} else {
+	    g_expr(e2);
+	    if (!is_int_reg(creg)) error(-1);
+	    crn=register_name(ireg);
+	    if (reg==USE_CREG) {
+		reg=get_dregister(d); if (!reg) error(-1);
+		set_freg(reg,0);
+	    }
+	    frn=fregister_name(reg);
+	    grn = fregister_name(g = code_dload_1(d));
+	    printf("\tl.s %s,0(%s)\n",frn,crn);
+	    printf("\t%s %s,%s,%s\n",dir>0?"add.s":"sub.s",grn,frn,grn);
+	    printf("\ts.s %s,0(%s)\n",grn,crn);
+	}
+	free_register(g);
+    } else {
+	if (car(e2)==DREGISTER) {
+	    xreg = cadr(e2);
+	    code_double_lib_c("dpadd",xreg,RET_DREGISTER,dir);
+	    //    xreg は increment する
+            //    USE_CREG だと increment する前の値を creg にセット
+	    //    reg が指定されていれば、それに前の値をセット
+	    if (reg==USE_CREG) {
+		use_float(d,reg);
+		if (reg==RET_DREGISTER) {
+		    reg = get_dregister(d);
+		}
+		set_dreg(reg,0);
+	    }
+	    g = list3(regv_l(reg),0,regv_l(xreg));
+	    g = list3(regv_h(reg),g,regv_h(xreg));
+	    g = list3(regv_l(xreg),g,regv_l(RET_DREGISTER));
+	    g = list3(regv_h(xreg),g,regv_h(RET_DREGISTER));
+	    parallel_rassign(g);
+	    return;
+	} 
+	g_expr(e2);
+	if(!is_int_reg(creg)) error(-1);
+	xreg = ireg;
+	emit_push();
+	code_save_stacks();
+	use_float(1,reg);
+	lload(xreg,DREGISTER_OPERAND,0);
+	code_double_lib_c("dpadd",DREGISTER_OPERAND,RET_DREGISTER,dir);
+	xreg = emit_pop(0);
+	emit_lpush();
+	if (use) {
+	    use_longlong(reg);
+	    lload(xreg,reg,0);
+	}
+	reg = emit_lpop();
+	lstore(xreg,reg);
+	emit_lpop_free(reg);
+	emit_pop_free(xreg);
+    }
+}
+
+void
+drexpr(int e1, int e2,int l1, int op,int cond)
+{
+    int op1;
+    if (!cond) {
+	switch(op) {
+	    case FOP+GT:
+		drexpr(e2,e1,l1,FOP+GE,1); return;
+	    case FOP+GE:
+		drexpr(e2,e1,l1,FOP+GT,1); return;
+	    case FOP+EQ:
+		op=FOP+NEQ; break;
+	    case FOP+NEQ:
+		op=FOP+EQ; break;
+	    case DOP+GT:
+		drexpr(e2,e1,l1,DOP+GE,1); return;
+	    case DOP+GE:
+		drexpr(e2,e1,l1,DOP+GT,1); return;
+	    case DOP+EQ:
+		op=DOP+NEQ; break;
+	    case DOP+NEQ:
+		op=DOP+EQ; break;
+	}
+    }
+    switch(op) {
+    case FOP+GT:  op1=FOP+CMP;   break;
+    case FOP+GE:  op1=FOP+CMPGE; break;
+    case FOP+EQ:  op1=FOP+CMPEQ; break;
+    case FOP+NEQ: op1=FOP+CMPEQ; break;
+    case DOP+GT:  op1=DOP+CMP;   break;
+    case DOP+GE:  op1=DOP+CMPGE; break;
+    case DOP+EQ:  op1=DOP+CMP;   break;
+    case DOP+NEQ: op1=DOP+CMP;   break;
+    default: error(-1);
+    }
+    g_expr(list3(op1,e2,e1));
+    switch(op) {
+	case DOP+GT:	printf("\tbltz\t$2,$L_%d\n",l1);break;
+	case DOP+GE:	printf("\tblez\t$2,$L_%d\n",l1);break;
+	case DOP+EQ:	printf("\tbeq\t$2,$0,$L_%d\n",l1);break;
+	case DOP+NEQ:	printf("\tbne\t$2,$0,$L_%d\n",l1);break;
+	case FOP+GT:	printf("\tbc1t\t$L_%d\n",l1);break;
+	case FOP+GE:	printf("\tbc1t\t$L_%d\n",l1);break;
+	case FOP+EQ:	printf("\tbc1t\t$L_%d\n",l1);break;
+        case FOP+NEQ:	printf("\tbc1f\t$L_%d\n",l1);break;
+    }
+}
+
+int emit_dpop(int d)
+{ 
+    int xreg,reg;
+    if (d) {
+	return emit_lpop(); 
+    }
+    xreg=pop_fregister();
+    if (xreg<= -REG_LVAR_OFFSET) {
+	reg = get_dregister(d);
+        code_drlvar(REG_LVAR_OFFSET+xreg,1,reg);
+	free_lvar(REG_LVAR_OFFSET+xreg);
+	xreg=reg;
+    }
+    return xreg;
+}
+
+#if 0
+static int emit_lpop_regvar();
+
+static
+int emit_dpop_regvar(int d)
+{ 
+    int xreg,reg;
+    if (d) {
+	reg =  emit_lpop_regvar();
+	regs[reg] = USING_DREG;
+	return  reg;
+    }
+    xreg=pop_fregister();
+    reg = cadr(get_dregister_var(0,d));
+    if (xreg<= -REG_LVAR_OFFSET) {
+        code_drlvar(REG_LVAR_OFFSET+xreg,1,reg);
+	free_lvar(REG_LVAR_OFFSET+xreg);
+	xreg=reg;
+    } else {
+        code_dassign_dregister(reg,d,xreg);
+    }
+    return xreg;
+}
+#endif
+
+void
+emit_dpop_free(int e1,int d)
+{ 
+    free_register(e1);
+}
+
+void
+emit_dpush(int d)
+{ 
+    int new_reg;
+    if (d) {
+	emit_lpush(); return;
+    }
+    if (!is_float_reg(creg)) error(-1);
+    if (freg_sp>MAX_MAX) error(-1);
+    new_reg = get_dregister(d);       /* 絶対に取れる */
+    freg_stack[freg_sp++] = freg;     /* push するかわりにレジスタを使う */
+    creg = freg = new_reg;
+}
+
+#endif
+
+#if LONGLONG_CODE
+
+
+/* 64bit int part */
+
+#if 0
+static int
+lcmp(int op,int cond)
+{
+    if (op==LOP+UGT||op==LOP+UGE) {
+	return UCMP;
+    } else if (op==LOP+LE||op==LOP+GE) {
+	return CMPGE;
+    } else {
+	return CMP;
+    }
+}
+#endif
+
+void
+lrexpr(int e1, int e2,int l1, int op,int cond)
+{
+    int reg,regh,regl,e3h,e3l;
+    int e3,l2,cr0=-1;
+    g_expr(e1);
+    emit_lpush();
+    g_expr(e2);
+    e3 = emit_lpop();
+    if (!is_longlong_reg(creg)) error(-1);
+    reg = lreg;
+    l2 = fwdlabel();
+    if (!(op==LOP+EQ||op==LOP+NEQ))
+	cr0 = get_register();
+    regh = regv_h(reg); regl = regv_l(reg);
+    e3h =  regv_h(e3);  e3l = regv_l(e3);
+    switch(op) {
+    case LOP+GT: case LOP+GE:
+	pcond(GT,  cr0,e3h,regh,1,cond?l1:l2,COND_BRANCH);
+	pcond(NEQ, cr0,e3h,regh,1,cond?l2:l1,COND_BRANCH);
+        break;
+    case LOP+UGT: case LOP+UGE:
+	pcond(UGT, cr0,e3h,regh,1,cond?l1:l2,COND_BRANCH);
+	pcond(NEQ, cr0,e3h,regh,1,cond?l2:l1,COND_BRANCH);
+        break;
+    case LOP+EQ:
+	pcond(EQ, cr0,regh,e3h,0,cond?l2:l1,COND_BRANCH);
+        break;
+    case LOP+NEQ:
+	pcond(EQ, cr0,regh,e3h,0,cond?l1:l2,COND_BRANCH);
+        break;
+    default:
+        error(-1);
+    }
+    pcond(op%LOP,cr0,e3l,regl,cond,l1,COND_BRANCH);
+    fwddef(l2);  
+    if (cr0!=-1) free_register(cr0);
+    emit_lpop_free(e3);
+}
+
+#if 0
+static
+int emit_lpop_regvar()
+{ 
+    int xreg,reg;
+    xreg=lreg_stack[--lreg_sp];
+    reg = cadr(get_lregister_var(0));
+    if (xreg<= -REG_LVAR_OFFSET) {
+        code_lrlvar(REG_LVAR_OFFSET+xreg,reg);
+        free_lvar(REG_LVAR_OFFSET+xreg);
+        xreg = reg;
+    } else {
+        code_lassign_lregister(reg,xreg);
+    }
+    return xreg;
+}
+#endif
+
+int
+emit_lpop()
+{
+    int xreg,reg;
+    xreg=lreg_stack[--lreg_sp];
+    if (xreg<= -REG_LVAR_OFFSET) {
+        reg = get_lregister();
+        code_lrlvar(REG_LVAR_OFFSET+xreg,reg);
+        free_lvar(REG_LVAR_OFFSET+xreg);
+        xreg = reg;
+    }
+    return xreg;
+}
+
+void
+code_lregister(int e2,int reg)
+{
+    use_longlong(reg);
+    if (reg!=e2) {
+	lmove(reg,e2);
+    }
+}
+
+void
+code_cmp_lregister(int reg,int label,int cond)
+{
+    use_longlong(reg);
+    printf("\tor %s,%s,%s\n",
+		lregister_name_low(reg),
+		lregister_name_low(reg),
+		lregister_name_high(reg));
+    code_cmp_register(regv_l(reg),label,cond);
+}
+
+void
+code_cmp_lrgvar(int e1,int creg,int label,int cond)
+{
+    use_longlong(creg);
+    code_lrgvar(e1,creg);
+    code_cmp_lregister(creg,label,cond);
+}
+
+void
+code_cmp_lrlvar(int e1,int creg,int label,int cond)
+{
+    use_longlong(creg);
+    code_lrlvar(e1,creg);
+    code_cmp_lregister(creg,label,cond);
+}
+
+void
+code_lassign(int e2,int creg)
+{
+    use_longlong(creg);
+    lstore(e2,creg);
+}
+
+void
+code_lassign_gvar(int e2,int creg)
+{
+    int r;
+    use_longlong(creg);
+    r = get_ptr_cache((NMTBL*)caddr(e2));
+#if ENDIAN==0
+    code_ldf(cstore(0),lregister_name_low(creg),cadr(e2),r);
+    code_ldf(cstore(0),lregister_name_high(creg),cadr(e2)+SIZE_OF_INT,r);
+#else
+    code_ldf(cstore(0),lregister_name_high(creg),cadr(e2),r);
+    code_ldf(cstore(0),lregister_name_low(creg),cadr(e2)+SIZE_OF_INT,r);
+#endif
+}
+
+void
+code_lassign_lvar(int e2,int creg)
+{
+    char *crn_h;
+    char *crn_l;
+
+    use_longlong(creg);
+    crn_h = lregister_name_high(creg);
+    crn_l = lregister_name_low(creg);
+    lvar_intro(e2);
+#if ENDIAN==0
+    printf("\tsw %s,",crn_l);lvar(e2);
+    printf("\tsw %s,",crn_h);lvar(e2+SIZE_OF_INT);
+#else
+    printf("\tsw %s,",crn_h);lvar(e2);
+    printf("\tsw %s,",crn_l);lvar(e2+SIZE_OF_INT);
+#endif
+}
+
+void
+code_lassign_lregister(int e2,int reg)
+{
+    use_longlong(reg);
+    if (e2!=reg) {
+	lmove(e2,reg);
+    }
+}
+
+static long long ll0 = 1LL;
+
+static int 
+code_l1(long long d)
+{
+    int *i = (int *)&ll0; int *j = (int *)&d;
+    return (i[1] == 1)?j[1]:j[0];
+}
+
+static int 
+code_l2(long long d)
+{
+    int *i = (int *)&ll0; int *j = (int *)&d;
+    return (i[1] == 1)?j[0]:j[1];
+}
+
+void
+code_lconst(int e1,int creg)
+{
+    use_longlong(creg);
+#if ENDIAN==0
+    code_const(code_l1(lcadr(e1)),regv_l(creg));
+    code_const(code_l2(lcadr(e1)),regv_h(creg));
+#else
+    code_const(code_l1(lcadr(e1)),regv_h(creg));
+    code_const(code_l2(lcadr(e1)),regv_l(creg));
+#endif
+}
+
+void
+code_lneg(int creg)
+{
+    int dreg;
+    char *rh,*rl,*dh,*dl;
+    use_longlong(creg);
+    rl=lregister_name_low(creg);
+    rh=lregister_name_high(creg);
+    dreg = get_lregister();
+    dl=lregister_name_low(dreg);
+    dh=lregister_name_high(dreg);
+    printf("\tsubu %s,$0,%s\n",dl,rl);
+    printf("\tsubu %s,$0,%s\n",dh,rh);
+    printf("\tsltu %s,$0,%s\n",rl,dl);
+    printf("\tsubu %s,%s,%s\n",dh,dh,rl);
+    free_register(lreg);
+    set_lreg(dreg,0);
+}
+
+void
+code_lrgvar(int e1,int creg)
+{
+    int r;
+    char *crn_h;
+    char *crn_l;
+    use_longlong(creg);
+    crn_h = lregister_name_high(creg);
+    crn_l = lregister_name_low(creg);
+    r = get_ptr_cache((NMTBL*)caddr(e1));
+#if ENDIAN==0
+    code_ldf("lw",crn_l,cadr(e1),r);
+    code_ldf("lw",crn_h,cadr(e1)+SIZE_OF_INT,r);
+#else
+    code_ldf("lw",crn_h,cadr(e1),r);
+    code_ldf("lw",crn_l,cadr(e1)+SIZE_OF_INT,r);
+#endif
+}
+
+void
+code_lrlvar(int e1,int creg)
+{
+    char *crn_h;
+    char *crn_l;
+    use_longlong(creg);
+    crn_h = lregister_name_high(creg);
+    crn_l = lregister_name_low(creg);
+    lvar_intro(e1);
+    printf("\tlw %s,",crn_l); lvar(e1);
+    printf("\tlw %s,",crn_h); lvar(e1+SIZE_OF_INT);
+}
+
+
+
+static void
+code_asld_lib(int reg,int oreg)
+{
+    char *ch,*cl,*oh,*ol,*dh,*dl;
+    //    5   4   7   3   2   6
+    int dreg = get_lregister();
+    ch = lregister_name_high(reg);
+    cl = lregister_name_low(reg);
+    oh = lregister_name_high(oreg);
+    ol = lregister_name_low(oreg);
+    dh = lregister_name_high(dreg);
+    dl = lregister_name_low(dreg);
+    
+    printf("\tsll     %s,%s,26\n",dh,ol);
+    printf("\tbgez    %s,1f\n",dh);
+    printf("\tsll     %s,%s,%s\n",oh,cl,ol);
+    printf("\t.set    noreorder\n");
+    printf("\tb       3f\n");
+    printf("\tmove    %s,$0\n",dl);
+    printf("\t.set    reorder\n");
+    printf("\t1:\n");
+    printf("\t.set    noreorder\n");
+    printf("\tbeq     %s,$0,2f\n",dh);
+    printf("\tsll     %s,%s,%s\n",oh,ch,ol);
+    printf("\t.set    reorder\n");
+    printf("\tsubu    %s,$0,%s\n",dh,ol);
+    printf("\tsrl     %s,%s,%s\n",dh,cl,dh);
+    printf("\tor      %s,%s,%s\n",oh,oh,dh);
+    printf("\t2:\n");
+    printf("\tsll     %s,%s,%s\n",dl,cl,ol);
+    printf("\t3:\n");
+    // printf("\tmove    %s,%s\n",cl,dl);
+    // printf("\tmove    %s,%s\n",ch,oh);
+    printf("\tmove    %s,%s\n",dh,oh);
+    set_lreg(dreg,0);
+    // free_register(dreg);
+}
+
+static void
+code_asrd_lib(int reg,int oreg) // ___ashrdi3$stub
+{
+    char *ch,*cl,*oh,*ol,*dh,*dl;
+    //    5   4   2   3   9   8
+    int dreg = get_lregister();
+    ch = lregister_name_high(creg);
+    cl = lregister_name_low(creg);
+    oh = lregister_name_high(oreg);
+    ol = lregister_name_low(oreg);
+    dh = lregister_name_high(dreg);
+    dl = lregister_name_low(dreg);
+
+    printf("\tsll     %s,%s,26\n",oh,ol);
+    printf("\tbgez    %s,1f\n",oh);
+    printf("\tsra     %s,%s,%s\n",dl,ch,ol);
+    printf("\t.set    noreorder\n");
+    printf("\tb       3f\n");
+    printf("\tsra     %s,%s,31\n",dh,ch);
+    printf("\t.set    reorder\n");
+    printf("\t1:\n");
+    printf("\t.set    noreorder\n");
+    printf("\tbeq     %s,$0,2f\n",oh);
+    printf("\tsrl     %s,%s,%s\n",dl,cl,ol);
+    printf("\t.set    reorder\n");
+    printf("\tsubu    %s,$0,%s\n",oh,ol);
+    printf("\tsll     %s,%s,%s\n",oh,ch,oh);
+    printf("\tor      %s,%s,%s\n",dl,dl,oh);
+    printf("\t2:\n");
+    printf("\tsra     %s,%s,%s\n",dh,ch,ol);
+    printf("\t3:\n");
+    // printf("\tmove    %s,%s\n",cl,dl);
+    // printf("\tmove    %s,%s\n",ch,dh);
+    set_lreg(dreg,0);
+    // free_register(dreg);
+}
+
+static void
+code_lsrd_lib(int reg,int oreg) // ___lshrdi3$stub
+{
+    char *ch,*cl,*oh,*ol,*dh,*dl;
+    //    5   4   2   3   9   8
+    int dreg = get_lregister();
+    ch = lregister_name_high(reg);
+    cl = lregister_name_low(reg);
+    oh = lregister_name_high(oreg);
+    ol = lregister_name_low(oreg);
+    dh = lregister_name_high(dreg);
+    dl = lregister_name_low(dreg);
+    
+    printf("\tsll     %s,%s,26\n",oh,ol);
+    printf("\tbgez    %s,1f\n",oh);
+    printf("\tsrl     %s,%s,%s\n",dl,ch,ol);
+    printf("\t.set    noreorder\n");
+    printf("\tb       3f\n");
+    printf("\tmove    %s,$0\n",dh);
+    printf("\t.set    reorder\n");
+    printf("\t\n");
+    printf("\t1:\n");
+    printf("\t.set    noreorder\n");
+    printf("\tbeq     %s,$0,2f\n",oh);
+    printf("\tsrl     %s,%s,%s\n",dl,cl,ol);
+    printf("\t.set    reorder\n");
+    printf("\t\n");
+    printf("\tsubu    %s,$0,%s\n",oh,ol);
+    printf("\tsll     %s,%s,%s\n",oh,ch,oh);
+    printf("\tor      %s,%s,%s\n",dl,dl,oh);
+    printf("\t2:\n");
+    printf("\tsrl     %s,%s,%s\n",dh,ch,ol);
+    printf("\t3:\n");
+    // printf("\tmove    %s,%s\n",cl,dl);
+    // printf("\tmove    %s,%s\n",ch,dh);
+    set_lreg(dreg,0);
+    // free_register(dreg);
+}
+
+static void
+code_longlong_lib(char *lib,int reg,int oreg)
+{
+    code_save_stacks();
+    clear_ptr_cache();
+    set_operands(regv_l(reg),regv_h(reg),regv_l(oreg),regv_h(oreg));
+    extern_conv(lib);
+    set_lreg(RET_LREGISTER,0);
+}
+
+#define code_ldiv_lib(reg,oreg)  code_longlong_lib("__divdi3",reg,oreg)
+#define code_ludiv_lib(reg,oreg) code_longlong_lib("__udivdi3",reg,oreg)
+#define code_lmod_lib(reg,oreg)  code_longlong_lib("__moddi3",reg,oreg)
+#define code_lumod_lib(reg,oreg) code_longlong_lib("__umoddi3",reg,oreg)
+
+#define check_lreg(reg) if (reg!=lreg) { lmove(reg,lreg); }
+
+void
+ltosop(int op,int reg,int oreg)
+{
+    int dx = -1;
+    int ox = -1;
+    char *orn_h,*crn_h,*drn_h;
+    char *orn_l,*crn_l,*drn_l;
+    char *drn;
+    // reg = reg op oreg
+
+    use_longlong(reg);
+    if(oreg==-1) {
+	error(-1);
+    } else if (oreg<= -REG_LVAR_OFFSET) {
+	ox = get_lregister(); if (ox<0) error(-1);
+	use_reg(ox);
+        code_rlvar(oreg+REG_LVAR_OFFSET,ox);
+	oreg = ox;
+    }
+
+    switch(op) {
+    case LLSHIFT:
+    case LULSHIFT:
+	code_asld_lib(reg,oreg); // ___ashldi3$stub
+	check_lreg(reg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case LRSHIFT:
+	code_asrd_lib(reg,oreg); // ___ashrdi3$stub
+	check_lreg(reg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case LURSHIFT:
+	code_lsrd_lib(reg,oreg); // ___lshrdi3$stub
+	check_lreg(reg);
+	if(ox!=-1) free_register(ox);
+	return;
+    }
+    orn_h = lregister_name_high(oreg);
+    orn_l = lregister_name_low(oreg);
+    crn_h = lregister_name_high(reg);
+    crn_l = lregister_name_low(reg);
+    switch(op) {
+    case LADD:
+        drn = register_name(dx = get_register());
+	printf("\taddu %s,%s,%s\n",crn_l,crn_l,orn_l);
+	printf("\tsltu %s,%s,%s\n",drn,crn_l,orn_l);
+	printf("\taddu %s,%s,%s\n",crn_h,crn_h,orn_h);
+	printf("\taddu %s,%s,%s\n",crn_h,crn_h,drn);
+	break;
+    case LSUB:
+        drn = register_name(dx = get_register());
+	printf("\tsltu %s,%s,%s\n",drn,crn_l,orn_l);
+	printf("\tsubu %s,%s,%s\n",crn_l,crn_l,orn_l);
+	printf("\tsubu %s,%s,%s\n",crn_h,crn_h,orn_h);
+	printf("\tsubu %s,%s,%s\n",crn_h,crn_h,drn);
+	break;
+    case LCMP:
+	error(-1);
+	break;
+    case LBAND: 
+	printf("\tand %s,%s,%s\n",crn_l,crn_l,orn_l);
+	printf("\tand %s,%s,%s\n",crn_h,crn_h,orn_h);
+	break;
+    case LEOR: 
+	printf("\txor %s,%s,%s\n",crn_l,crn_l,orn_l);
+	printf("\txor %s,%s,%s\n",crn_h,crn_h,orn_h);
+	break;
+    case LBOR:
+	printf("\tor %s,%s,%s\n",crn_l,crn_l,orn_l);
+	printf("\tor %s,%s,%s\n",crn_h,crn_h,orn_h);
+	break;
+    case LMUL:
+    case LUMUL:
+	dx=get_lregister();
+	use_reg(dx);
+	drn_l = lregister_name_low(dx);
+	drn_h = lregister_name_high(dx);
+        /*
+            drn_l 4 = l32( crn_l * orn_l);  6, 2
+            drn_h 5 = h32( crn_l * orn_l);
+            orn_l 6 = l32( crn_h * orn_l);  7, 3
+	    drn_h 5 = drn_h + orn_l;  5, 6
+            crn_l 2 = l32( crn_l * orn_h);  2, 6
+	    crn_h 5 = drn_h + crn_l;  5, 2
+	    crn_l = drn_l;
+        */
+	printf("\tsra     %s,%s,31\n",drn_l,orn_l);
+	printf("\tmultu   %s,%s\n",crn_l,orn_l);
+	printf("\tmfhi    %s\n",drn_h);
+	printf("\tmflo    %s\n",drn_l);
+	printf("\tmult    %s,%s,%s\n",orn_l,crn_h,orn_l);
+	printf("\taddu    %s,%s,%s\n",drn_h,drn_h,orn_l);
+	printf("\tmult    %s,%s,%s\n",crn_l,crn_l,orn_h);
+	printf("\taddu    %s,%s,%s\n",crn_h,drn_h,crn_l);
+	printf("\tmove    %s,%s\n",crn_l,drn_l);
+	break;
+    case LDIV:
+	code_ldiv_lib(reg,oreg)
+;  // ___divdi3$stub
+	check_lreg(reg);
+	break;
+    case LUDIV:
+	code_ludiv_lib(reg,oreg); // ___udivdi3$stub
+	check_lreg(reg);
+	break;
+    case LMOD:
+	code_lmod_lib(reg,oreg); // ___moddi3$stub
+	check_lreg(reg);
+	break;
+    case LUMOD:
+	code_lumod_lib(reg,oreg); // ___umoddi3$stub
+	check_lreg(reg);
+	break;
+    default:
+	error(-1);
+    }
+    if(ox!=-1) free_register(ox);
+    if(dx!=-1) free_register(dx);
+}
+
+int
+code_lconst_op_p(int op,int e)
+{
+    int v;
+    if (car(e)==LCONST) {
+	if (!(-32766<lcadr(e)&&lcadr(e)<32767)) return 0;
+	v = lcadr(e);
+    } else if (car(e)==CONST) {
+	if (!(-32766<cadr(e)&&cadr(e)<32767)) return 0;
+	v = cadr(e);
+    } else return 0;
+    
+    switch(op) {
+    case LLSHIFT:
+    case LULSHIFT:
+    case LRSHIFT:
+    case LURSHIFT:
+	return  (0<v&&v<31);
+    case LADD:
+    case LSUB:
+	return 1;
+    case LBOR:
+	return  (v>0);
+    default:
+	return 0;
+    }
+}
+
+void
+loprtc(int op,int creg,int e)
+{
+    char *crn_h;
+    char *crn_l;
+    char *grn,*drn;
+    int v;
+    int greg,dx=-1;
+
+    use_longlong(creg);
+    crn_h = lregister_name_high(creg);
+    crn_l = lregister_name_low(creg);
+
+    if (car(e)==LCONST) v = lcadr(e);
+    else if (car(e)==CONST) v = cadr(e);
+
+    switch(op) {
+    case LLSHIFT:
+    case LULSHIFT:
+	greg = get_register();
+	grn = register_name(greg);
+	printf("\tsll %s,%s,%d\n",crn_h,crn_h,v);
+	printf("\tsrl %s,%s,%d\n",grn,crn_l,32-v);
+	printf("\tor %s,%s,%s\n",crn_h,crn_h,grn);
+	printf("\tsll %s,%s,%d\n",crn_l,crn_l,v);
+	free_register(greg);
+	return;
+    case LRSHIFT:
+	greg = get_register();
+	grn = register_name(greg);
+	printf("\tsrl %s,%s,%d\n",crn_l,crn_l,v);
+	printf("\tsll %s,%s,%d\n",grn,crn_h,32-v);
+	printf("\tor  %s,%s,%s\n",crn_l,crn_l,grn);
+	printf("\tsra %s,%s,%d\n",crn_h,crn_h,v);
+	free_register(greg);
+	return;
+    case LURSHIFT:
+	greg = get_register();
+	grn = register_name(greg);
+	printf("\tsll %s,%s,%d\n",grn,crn_h,32-v);
+	printf("\tsrl %s,%s,%d\n",crn_l,crn_l,v);
+	printf("\tor %s,%s,%s\n",crn_l,grn,crn_l);
+	printf("\tsrl %s,%s,%d\n",crn_h,crn_h,v);
+	free_register(greg);
+	return;
+    case LSUB:
+	v = -v;
+    case LADD:
+	drn = register_name(dx = get_register());
+	if (v<0) {
+	    printf("\tsubu %s,%s,%d\n",crn_l,crn_l,-v);
+	    printf("\tsltu %s,%s,%d\n",drn,crn_l,v);
+	    printf("\tsubu %s,%s,1\n",crn_h,crn_h);
+	    printf("\taddu %s,%s,%s\n",crn_h,crn_h,drn);
+	} else {
+	    printf("\tsltu %s,%s,%d\n",drn,crn_l,v);
+	    printf("\taddu %s,%s,%d\n",crn_l,crn_l,v);
+	    printf("\taddu %s,%s,%s\n",crn_h,crn_h,drn);
+	}
+	break;
+    case LBOR:
+	printf("\tori %s,%s,%d\n",crn_l,crn_l,v);
+	break;
+    default:
+	error(-1);
+    }
+    if (dx!=-1) free_register(dx);
+}
+
+
+void
+emit_lpop_free(int xreg)
+{
+    if (xreg>=0)
+        free_register(xreg);
+}
+
+void
+emit_lpush()
+{
+    int new_reg;
+    if (!is_longlong_reg(creg)) error(-1);
+    if (lreg_sp>MAX_MAX) error(-1);
+    new_reg = get_lregister();        /* 絶対に取れる(?) */
+    lreg_stack[lreg_sp++] = creg;     /* push するかわりにレジスタを使う */
+    lreg = creg = new_reg;
+}
+
+void
+code_i2ll(int reg)
+{
+    char *crn,*crn_h,*crn_l;
+    int reg0;
+    crn = register_name(reg0 = ireg);
+    use_longlong(reg);
+    crn_h = lregister_name_high(lreg);
+    crn_l = lregister_name_low(lreg);
+    if (reg0!=regv_l(lreg))
+	printf("\tmove %s,%s\n",crn_l,crn);
+    printf("\tsra %s,%s,31\n",crn_h,crn_l);
+}
+
+void
+code_i2ull(int reg)
+{
+    code_i2ll(reg);
+}
+
+void
+code_u2ll(int reg)
+{
+    char *crn,*crn_h,*crn_l;
+    int reg0;
+    crn = register_name(reg0 = ireg);
+    use_longlong(reg);
+    crn_h = lregister_name_high(lreg);
+    crn_l = lregister_name_low(lreg);
+    if (reg0!=regv_l(lreg))
+	printf("\tmove %s,%s\n",crn_l,crn);
+    printf("\tli %s,0\n",crn_h);
+}
+
+void
+code_u2ull(int creg)
+{
+    code_u2ll(creg);
+}
+
+void
+code_ll2i(int reg)
+{
+    char *crn_l;
+    int reg0;
+    crn_l = lregister_name_low(reg0=lreg);
+    use_int(reg);
+    if (ireg!=regv_l(reg0))
+	printf("\tmove %s,%s\n",register_name(ireg),crn_l);
+}
+
+void
+code_ll2u(int creg)
+{
+    code_ll2i(creg);
+}
+
+void
+code_ull2i(int creg)
+{
+    code_ll2i(creg);
+}
+
+void
+code_ull2u(int creg)
+{
+    code_ll2i(creg);
+}
+
+#if FLOAT_CODE
+
+void
+code_d2ll(int reg)
+{
+    // fixdfdi$stub
+    set_dreg(DREGISTER_OPERAND,1);
+    extern_conv("__fixdfdi");
+    set_lreg(RET_LREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
+	use_longlong(reg);
+}
+
+void
+code_d2ull(int reg)
+{
+    set_dreg(DREGISTER_OPERAND,1);
+    extern_conv("__fixunsdfdi");
+    set_lreg(RET_LREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
+	use_longlong(reg);
+}
+
+void
+code_f2ll(int reg)
+{
+    set_freg(FREGISTER_OPERAND,1);
+    extern_conv("__fixsfdi");
+    set_lreg(RET_LREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
+	use_longlong(reg);
+}
+
+void
+code_f2ull(int reg)
+{
+    set_freg(FREGISTER_OPERAND,1);
+    extern_conv("__fixunssfdi");
+    set_lreg(RET_LREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
+	use_longlong(reg);
+}
+
+void
+code_ll2d(int reg)
+{
+    set_lreg(LREGISTER_OPERAND,1);
+    extern_conv("__floatdidf");
+    set_dreg(RET_DREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_FREGISTER)
+	use_float(1,reg);
+}
+
+
+void
+code_ll2f(int reg)
+{
+    set_lreg(LREGISTER_OPERAND,1);
+    extern_conv("__floatdisf");
+    set_freg(RET_FREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_FREGISTER)
+	use_float(0,reg);
+}
+
+void
+code_ull2d(int creg)
+{
+    code_ll2d(creg);
+}
+
+void
+code_ull2f(int creg)
+{
+    code_ll2f(creg);
+}
+
+#endif
+
+static void
+ladd(int dreg,int rreg,int v)   //   rreg = dreg + v
+{
+  int dx;
+  char *crn_l=lregister_name_low(dreg);
+  char *crn_h=lregister_name_high(dreg);
+  char *rrn_l=lregister_name_low(rreg);
+  char *rrn_h=lregister_name_high(rreg);
+  char *drn = register_name(dx = get_register());
+    if (v<0) {
+        printf("\tsubu %s,%s,%d\n",rrn_l,crn_l,-v);
+        printf("\tsltu %s,%s,%d\n",drn,rrn_l,v);
+        printf("\tsubu %s,%s,1\n",rrn_h,crn_h);
+        printf("\taddu %s,%s,%s\n",rrn_h,rrn_h,drn);
+    } else {
+        printf("\taddu %s,%s,%d\n",rrn_l,crn_l,v);
+        printf("\tsltu %s,%s,%d\n",drn,rrn_l,v);
+        printf("\taddu %s,%s,%s\n",rrn_h,crn_h,drn);
+    }
+    free_register(dx);
+}
+
+void
+code_lpreinc(int e1,int e2,int reg)
+{
+    int dreg=-1,xreg=-1;
+    int dir=caddr(e1);
+    if (car(e2)==LREGISTER) {
+        use_longlong(reg);
+	ladd(cadr(e2),cadr(e2),dir);
+        if (reg!=cadr(e2)) {
+	    lmove(reg,cadr(e2));
+	}
+        return;
+    } 
+    g_expr(e2);
+    if(!is_int_reg(creg)) error(-1);
+    emit_push();
+    if (reg==USE_CREG) {
+	dreg=get_lregister(); if (!dreg) error(-1);
+	set_lreg(dreg,0);  // free old lreg==creg
+    } else {
+        dreg = reg;
+    }
+    xreg = emit_pop(0);
+    lload(xreg,dreg,0);
+    ladd(dreg,dreg,dir);
+    code_lassign(xreg,dreg);
+    emit_pop_free(xreg);
+    if (dreg!=-1) free_register(dreg);
+}
+
+void
+code_lpostinc(int e1,int e2,int reg)
+{
+    int dreg,nreg,xreg;
+    int dir=caddr(e1);
+    if (car(e2)==LREGISTER) {
+	use_longlong(reg);
+	lmove(reg,cadr(e2));
+	ladd(cadr(e2),cadr(e2),dir);
+        return;
+    } 
+    g_expr(e2);
+    if(!is_int_reg(creg)) error(-1);
+    emit_push();
+    nreg=get_lregister(); if (!nreg) error(-1);
+    if (reg==USE_CREG) {
+	dreg=get_lregister(); if (!dreg) error(-1);
+	set_lreg(dreg,0);  // free old lreg==creg
+    } else {
+	dreg = reg;
+    }
+    xreg = emit_pop(0);
+    lload(xreg,dreg,0);
+    ladd(dreg,nreg,dir);
+    lstore(xreg,nreg);
+    emit_pop_free(xreg);
+    free_register(nreg);
+}
+
+void
+code_lassop(int op,int reg)
+{
+    int xreg;
+    int edx,edx0=-1;
+
+    // (*creg) op = pop()
+    xreg = emit_lpop(0);       /* pop e3 value */
+    if (!is_int_reg(creg)) error(-1);
+    edx = ireg;
+    emit_push();
+    use_longlong(reg);
+    if (regv_l(lreg)==edx || regv_h(lreg)==edx) {
+	edx0 = get_register(); if(!edx0) error(-1);
+	printf("# lassop\n\tmove %s,%s\n",register_name(edx0),
+	       register_name(edx));
+	edx = edx0;
+    }
+    lload(edx,reg,0);
+    // free_register(edx); don't do this, it will free pushed register
+    ltosop(op,reg,xreg);    // loprtc?
+    emit_lpop_free(xreg);
+    use_reg(reg);
+    edx = emit_pop(0);
+    code_lassign(edx,reg);
+    emit_pop_free(edx);
+    if (edx0!=-1)
+	free_register(edx0);
+}
+
+void
+code_register_lassop(int reg,int op) {
+    // reg op = pop()
+    int  xreg=emit_lpop();
+    ltosop(op,reg,xreg);
+    emit_lpop_free(xreg);
+}   
+
+
+#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;
+	    free_register(reg);
+        }
+    }
+#if FLOAT_CODE
+    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;
+	    free_register(reg);
+        }
+    }
+#endif
+#if LONGLONG_CODE
+    for(i=0;i<lreg_sp;i++) {
+        if ((reg=lreg_stack[i])>=0) {
+            code_lassign_lvar(
+                (lreg_stack[i]=new_lvar(SIZE_OF_LONGLONG)),reg); 
+            lreg_stack[i]= lreg_stack[i]-REG_LVAR_OFFSET;
+	    free_register(reg);
+        }
+    }
+#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); asi=0;
+}
+
+#if CASE_CODE
+
+int
+code_table_jump_p() { return 1; }
+
+void
+code_table_jump(int l,int csvalue,int delta,int max,int min,int dlabel)
+{
+    int t,s;
+    char *crn = register_name(csvalue);  // can be t or s
+    char *trn = register_name(t=get_register());
+    char *srn = register_name(s=get_register());
+
+    printf("\taddu\t%s,%s,%d\n",trn,crn,-min);
+    printf("\tsltu\t%s,%s,%d\n",srn,trn,max-min+1);
+    printf("\tbeq\t%s,$0,$L_%d\n",srn,dlabel);
+    switch(delta) {
+    case 1: printf("\tsll %s,%s,2\n",trn,trn); break;
+    case 2:
+	printf("\tli\t%s,1\n",srn);
+	printf("\tand\t%s,%s,%s\n",srn,trn,srn);
+	printf("\tbne\t%s,$0,$L_%d\n",srn,dlabel);
+	printf("\tsll %s,%s,1\n",trn,trn);
+	break;
+    case 4:
+	printf("\tli\t%s,3\n",srn);
+	printf("\tand\t%s,%s,%s\n",srn,trn,srn);
+	printf("\tbne\t%s,$0,$L_%d\n",srn,dlabel);
+	break;
+    default:
+	printf("\tdivu %s,%s,%d\n",trn,trn,delta);
+	printf("\tmfhi %s\n",srn);
+	printf("\tbne\t%s,$0,$L_%d\n",srn,dlabel);
+	printf("\tsll %s,%s,2\n",trn,trn); 
+    }
+    printf("\tlw\t%s,$L_%d(%s)\n",trn,l,trn);
+    printf("\t.cpadd %s\n",trn);
+    printf("\tj %s\n",trn);
+
+    free_register(s);
+    free_register(t);
+}
+
+void
+code_table_open(int l)
+{
+    output_mode = DATA_EMIT_MODE;
+    printf("\t.rdata\n");
+    printf("\t.align 4\n");
+    fwddef(l);
+}
+
+void
+code_table_value(int label,int table_top)
+{
+    printf("\t.gpword $L_%d\n",label);
+}
+
+void
+code_table_close()
+{
+    text_mode(4);
+}
+
+#endif
+
+
+#if ASM_CODE
+
+/*
+    print an operand  
+ */
+
+static void
+emit_asm_operand(int rstr)
+{
+    if (car(rstr)==REGISTER) {
+	printf("%s",register_name(cadr(rstr)));
+    } else if (car(rstr)==CONST) {
+	printf("%d",cadr(rstr));
+    } else if (car(rstr)==FNAME) {
+	printf("%s",(char*)cadr(rstr));
+    } else if (car(rstr)==STRING) {
+	printf("$L_%d",cadr(rstr));
+    } else {
+	error(-1);
+    }
+}
+
+/*
+     prepare asm operands
+
+     char *constraints string
+     int  operand expr
+     int  mode          (ASM_INPUT,ASM_OUTPUT)
+     int  replacement list
+     int  output operands count
+     int  output operands replacement list
+
+     retrun replacement list
+        list3( operands, next, clobber )
+                               0    can be shared in input/output
+                               1    can't be used in input
+ */
+
+int
+code_asm_operand(char *p,int e1,int mode,int repl,int n,int repl0)
+{
+    int r;
+    int c;
+    int val;
+    int clobber = 0;
+
+    printf("# constraint %s\n",p);
+    if (*p=='=') {
+	// output register
+	p++;
+    }
+    if (*p=='&') {
+	// earlyclobber
+	p++;
+	clobber = 1;
+    }
+    c = *p;
+    if (c=='r') {
+	if (mode==ASM_INPUT) {
+	    for(;repl0;repl0 = cadr(repl0)) {
+		if (car(car(repl0))==REGISTER && caddr(repl0)==0) {
+		    r = cadr(car(repl0));
+		    caddr(repl0) = ASM_USED;
+		    break;
+		}
+            }  
+	    r = get_register();
+	} else {
+	    r = get_register();
+	}
+	repl = list3(list2(REGISTER,r),repl,clobber);
+    } else if (c=='m') {
+	repl = list3(list2(0,0),repl,clobber);
+    } else if (c=='i') {
+	if (car(e1)==GVAR) {
+	    e1=list3(FNAME,(int)(((NMTBL *)caddr(e1))->nm),0);
+	} else if (car(e1)==FNAME) {
+	    e1=list3(FNAME,(int)(((NMTBL *)cadr(e1))->nm),0);
+	} else if (car(e1)==STRING) {
+	    val = emit_string_label();
+	    ascii((char*)cadr(e1));
+	    e1=list3(STRING,val,0);
+	} else if (car(e1)==CONST) {
+	} else error(-1);
+	repl = list3(e1,repl,clobber);
+    } else if (digit(c)) {
+	val = 0;
+	do { val = val*10 + c-'0'; } while (digit(c=*p++));
+	if (val>MAX_ASM_REG) error(-1); // too large register
+	if (n-val<0) error(-1);
+	repl = list3(car(nth(n-val-1,repl0)),repl,clobber);
+    } else error(-1);
+    return repl;
+}
+
+void
+code_free_asm_operand(int repl)
+{
+    for(;repl;repl=cadr(repl)) {
+	if (car(car(repl))==REGISTER)
+	    free_register(cadr(car(repl)));
+    }
+}
+
+
+extern void
+code_asm(char *asm_str,int repl)
+{
+    int c,i,rstr,val;
+    char *p;
+    int reg[MAX_ASM_REG];
+
+    text_mode(2);
+    c = *asm_str;
+    if (c!='\t'&&c!=' ') printf("\t");
+    for(i=0;repl && i<MAX_ASM_REG;i++) {
+	reg[i] = car(repl);
+	repl = cadr(repl);
+    }
+    p = asm_str;
+    while((c = *p++)) {
+	if (c=='%') {
+	    c = *p++;
+	    if (!c) { break;
+	    } else if (c=='%') {
+		printf("%%"); continue;
+	    } else if (!digit(c)) {
+		printf("%%%c",c); continue;
+	    }
+	    val = 0;
+	    do { val = val*10 + c-'0'; } while (digit(c=*p++)) ;
+	    p--;
+	    if (val>MAX_ASM_REG) error(-1); // too large register
+	    rstr = reg[val];
+	    emit_asm_operand(rstr);
+	} else {
+	    printf("%c",c);
+	}
+    }
+    printf("\n");
+}
+
+#endif
+
+
+#if BIT_FIELD_CODE
+
+/* bit field alignment calcuration */
+
+static void
+set_bitsz(int type,int *psign,int *pbitsz,int *palign,int *pl)
+{ 
+    int sign=0,bitsz; 
+    int align,l=0;
+    switch(cadr(type)) { 
+    case INT:		sign=1; bitsz=32; align=4;break; 
+    case UNSIGNED:		bitsz=32; align=4;break; 
+    case CHAR:          sign=1; bitsz= 8; align=1;break; 
+    case UCHAR: 		bitsz= 8; align=1;break; 
+    case SHORT:         sign=1; bitsz=16; align=2;break; 
+    case USHORT:        sign=1; bitsz=16; align=2;break; 
+    case LONGLONG:      sign=1; bitsz=64; align=8;l=1; break; 
+    case ULONGLONG:            	bitsz=64; align=8;l=1; break; 
+    default: error(-1);
+    }
+    *psign = sign;
+    *pbitsz = bitsz;
+    *palign = align;
+    *pl = l;
+}
+
+/*
+      bit field alignment calcuration
+        this is architecture depenedent
+ */
+
+extern int
+code_bit_field_disp(int type,int *poffset,int *bfd,int *sz)
+{
+    int sign,bitsz,align;
+    int i;
+    int bitpos = *bfd;
+    int offset = *poffset;
+    int l;
+    int bitsize = cadddr(type);
+    set_bitsz(type,&sign,&bitsz,&align,&l);
+
+    if (bitsize>bitsz) { error(BTERR); bitsize = i; }
+
+    /* bfd means previous bit field bit offset */
+    if (bitpos) {
+	/* previous field is bit field and spaces may remain */
+	/* calc previsous offset */
+
+	i= offset-(bitpos+7)/8;
+
+	for(l = bitpos;l>0;l -= 8,i++) {
+	    if ((i & (align-1))==0 && l+bitsize <= bitsz) {
+		/* alignment is correct and space remains */
+		*poffset=offset=i;
+		i = l+bitsize;
+		*bfd = i;
+		*sz = (i+7)/8;
+// printf("# bitpos=%d bitsize=%d bitsz=%d offset=%d\n",l,bitsize,bitsz,*poffset);
+		return l;
+	    } 
+	}
+    }
+
+    /* first bit-field */
+
+    if ((i=(offset & (align-1)))) {
+	*poffset = (offset += (align-i));
+    }
+    bitpos = 0;
+    *bfd = bitsize;
+    *sz = (bitsize+7)/8;
+
+// printf("# bitpos=%d bitsize=%d bitsz=%d offset=%d\n",bitpos,bitsize,bitsz,*poffset);
+    return bitpos;
+}
+
+/* bit field value */
+
+/* reg contains container value, result should be in reg */
+extern void
+code_bit_field(int type,int bitpos,int reg)
+{
+    int sign,bitsz,l,align;
+    int bitsize = cadddr(type);
+    int i;
+    set_bitsz(type,&sign,&bitsz,&align,&l);
+// printf("# %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz);
+    /* this implementation returns -1 for int i:1; */
+    if (l==1) {
+	use_longlong(reg);
+	/* shift left */
+	if ((i=bitsz-bitsize-bitpos)) 
+	    loprtc(LLSHIFT,reg,list2(CONST,i));
+	/* shift right */
+	if ((i=bitsz-bitsize)) 
+	    loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i));
+    } else {
+	use_int(reg);
+	/* shift left */
+	if ((i=32-bitsize-bitpos)) 
+	    oprtc(LSHIFT,reg,list2(CONST,i));
+	/* shift right */
+	if ((i=32-bitsize)) 
+	    oprtc(sign?RSHIFT:URSHIFT,reg,list2(CONST,i));
+    }
+}
+
+/* bit field replacement */
+
+static void
+make_mask_and_or(int mask,int tmp,char *trn,char *crn,char *lrn)
+{
+// printf("# mask 0x%08x ~0x%08x\n",mask,~mask);
+	code_const(~mask,tmp);
+	printf("\tor %s,%s,%s\n",trn,crn,trn);
+	/* do conjunction  */
+	printf("\tand %s,%s,%s\n",lrn,trn,lrn);
+	/* make or-mask  */
+	code_const(mask,tmp);
+	printf("\tand %s,%s,%s\n",trn,crn,trn);
+	/* do disjunction  */
+	printf("\tor %s,%s,%s\n",crn,trn,lrn);
+}
+
+extern void
+code_bit_replace(int value,int lvalue,int type,int bitpos)
+{
+    int sign,bitsz,l,align;
+    int bitsize = cadddr(type);
+    int mask = 0;
+    int tmp = -1;
+    char *crn,*lrn,*trn;
+    set_bitsz(type,&sign,&bitsz,&align,&l);
+// printf("# %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz);
+    if (l) {
+	use_longlong(value);
+	crn = lregister_name_high(value);
+	lrn = lregister_name_high(lvalue);
+	/* shift left */
+	if (bitpos) 
+	    loprtc(LLSHIFT,value,list2(CONST,bitpos));
+	trn = register_name(tmp = get_register());
+	if (bitpos+bitsize>=32) {
+	    /* make and-mask upper */
+	    mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31);
+	    make_mask_and_or(mask,tmp,trn,crn,lrn);
+	}
+	crn = lregister_name_low(value);
+	lrn = lregister_name_low(lvalue);
+	if (bitpos<32) {
+	    /* make and-mask lower */
+	    mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos);
+	    make_mask_and_or(mask,tmp,trn,crn,lrn);
+	}
+    } else {
+	use_int(value);
+	crn = register_name(value);
+	lrn = register_name(lvalue);
+	/* shift left */
+	if (bitpos) 
+	    oprtc(LSHIFT,value,list2(CONST,bitpos));
+	trn = register_name(tmp = get_register());
+	/* make and-mask */
+	mask = make_mask(32-bitpos-bitsize,31-bitpos);
+	make_mask_and_or(mask,tmp,trn,crn,lrn);
+    }
+    if (tmp!=-1) free_register(tmp);
+}
+
+
+static void
+make_mask_and_or_const(int mask,char *crn,int c)
+{
+    char *trn;
+    int tmp = -1;
+// printf("# mask 0x%08x ~0x%08x\n",mask,~mask);
+    if ((~mask|c)!=-1) {
+	trn = register_name(tmp=get_register());
+	code_const((~mask|c),tmp);
+	/* do conjunction  */
+	printf("\tand %s,%s,%s\n",crn,trn,crn);
+    }
+    /* make or-mask  */
+    c = mask&c;
+    if (c!=0) {
+	/* do disjunction  */
+	if (!((mask&c)&0xffff0000)) {
+	    printf("\tori %s,%s,%d\n",crn,crn,c);
+	} else {
+	    trn = register_name(tmp=get_register());
+	    code_const(c,tmp);
+	    printf("\tor %s,%s,%s\n",crn,trn,crn);
+	}
+    }
+    if (tmp!=-1) free_register(tmp);
+}
+
+extern void
+code_bit_replace_const(int value,int lvalue,int type,int bitpos)
+{
+    int sign,bitsz,l,align;
+    int bitsize = cadddr(type);
+    int mask = 0;
+    int c;
+#if LONGLONG_CODE
+    long long lc;
+#endif
+    char *crn;
+    set_bitsz(type,&sign,&bitsz,&align,&l);
+// printf("# %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz);
+    if (l) {
+#if LONGLONG_CODE
+	use_longlong(lvalue);
+	crn = lregister_name_high(lvalue);
+	/* shift left */
+	lc = lcadr(value);
+	lc <<= bitpos;
+	if (bitpos+bitsize>=32) {
+	    /* make and-mask upper */
+	    mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31);
+	    make_mask_and_or_const(mask,crn,(int)(lc>>32));
+	}
+	crn = lregister_name_low(lvalue);
+	if (bitpos<32) {
+	    /* make and-mask lower */
+	    mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos);
+	    make_mask_and_or_const(mask,crn,(int)lc);
+	}
+#endif
+    } else {
+	use_int(lvalue);
+	crn = register_name(lvalue);
+	/* shift left */
+	c = cadr(value);
+	c <<= bitpos;
+	/* make and-mask */
+        mask = make_mask(32-bitpos-bitsize,31-bitpos);
+	make_mask_and_or_const(mask,crn,c);
+    }
+}
+
+
+#endif
+
+/* end */
--- a/mc-code-mips.c	Thu Jul 08 12:10:34 2004 +0900
+++ b/mc-code-mips.c	Fri Jul 09 14:47:40 2004 +0900
@@ -88,10 +88,10 @@
 #define MIN_TMP_FREG 0
 #define MAX_TMP_FREG 11
 
-int MAX_REGISTER=30;             /* PowerPCのレジスタを10個まで使う*/
+int MAX_REGISTER=30;             /* MIPSのレジスタを10個まで使う*/
 int MAX_FREGISTER=31;
-#define  REAL_MAX_REGISTER 32    /* PowerPCのレジスタが32ということ*/
-#define  REAL_MAX_FREGISTER 32    /* PowerPCのレジスタが32ということ*/
+#define  REAL_MAX_REGISTER 32    /* MIPSのレジスタが32ということ*/
+#define  REAL_MAX_FREGISTER 32    /* MIPSのレジスタが32ということ*/
 #define  REAL_MAX_LREGISTER 16
 
 #define FREG_OFFSET REAL_MAX_REGISTER
--- a/mc-code-powerpc.c	Thu Jul 08 12:10:34 2004 +0900
+++ b/mc-code-powerpc.c	Fri Jul 09 14:47:40 2004 +0900
@@ -1249,6 +1249,7 @@
     char *crn;
     use_int(reg);
     crn = register_name(reg);
+    // printf("# 0x%08x\n",e2);
     if (-32768<e2&&e2<32768)
 	printf("\tli %s,%d\n",crn,e2);
     else {