changeset 661:f566ac85f2e0

*** empty log message ***
author kono
date Wed, 21 Feb 2007 20:11:23 +0900
parents 3e1dba5758d8
children c9df4e08da9b
files mc-code-spu.c
diffstat 1 files changed, 5804 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mc-code-spu.c	Wed Feb 21 20:11:23 2007 +0900
@@ -0,0 +1,5804 @@
+/* Micro-C Code Generation Part for Cell SPU */
+/* ************************************************************************
+   ** Copyright (C) 2007 Shinji Kono
+   ** 連絡先: 琉球大学情報工学科 河野 真治  
+   ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp)
+   **
+   **    このソースのいかなる複写,改変,修正も許諾します。ただし、
+   **    その際には、誰が貢献したを示すこの部分を残すこと。
+   **    再配布や雑誌の付録などの問い合わせも必要ありません。
+   **    営利利用も上記に反しない範囲で許可します。
+   **    バイナリの配布の際にはversion messageを保存することを条件とします。
+   **    このプログラムについては特に何の保証もしない、悪しからず。
+   **
+   **    Everyone is permitted to do anything on this program 
+   **    including copying, modifying, improving,
+   **    as long as you don't try to pretend that you wrote it.
+   **    i.e., the above copyright notice has to appear in all copies.  
+   **    Binary distribution requires original version messages.
+   **    You don't have to ask before copying, redistribution or publishing.
+   **    THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE.
+   ***********************************************************************/
+
+#include <stdio.h>
+#include "mc.h"
+#include "mc-parse.h"
+#include "mc-code.h"
+#include "mc-codegen.h"
+
+char *l_include_path[]={
+    "/usr/lib/gcc/spu/4.0.2/include",
+	"/usr/spu/include",
+	0};
+
+// va_start, va_arg is wrong, use va_arm.h
+
+static char *init_src0 = "\
+#define __SPU__ 1\n\
+#define __STDC_HOSTED__ 1\n\
+#define __GNUC__ 4\n\
+#define __FLT_MIN_EXP__ (-125)\n\
+#define __DBL_MIN__ 2.2250738585072014e-308\n\
+#define __NO_INLINE__ 1\n\
+#define __ELF__ 1\n\
+#define __FLT_RADIX__ 2\n\
+#define __LDBL_EPSILON__ 2.2204460492503131e-16L\n\
+#define __vector __attribute__((spu_vector))\n\
+#define __WCHAR_TYPE__ int\n\
+#define __DBL_EPSILON__ 2.2204460492503131e-16\n\
+#define __INTMAX_MAX__ 9223372036854775807LL\n\
+#define __FLT_DENORM_MIN__ 1.40129846e-45F\n\
+#define __FLT_MAX__ 6.80564693e+38F\n\
+#define __FLT_MIN_10_EXP__ (-37)\n\
+#define __INTMAX_TYPE__ long long int\n\
+#define __GNUC_MINOR__ 0\n\
+#define __DBL_MAX_10_EXP__ 308\n\
+#define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L\n\
+#define __PTRDIFF_TYPE__ long int\n\
+#define __LDBL_MIN_10_EXP__ (-307)\n\
+#define __LDBL_DIG__ 15\n\
+#define __WINT_TYPE__ unsigned int\n\
+";
+
+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 push_struct(int e4,int t,int arg);
+static void register_usage(char *s);
+static void code_add(int reg,int offset,int r);
+static void const_list_table();
+//static int search_const(int tag,int value,int *label);
+static char * cstore(int sz);
+static void code_int_lib(char *lib,int reg,int oreg); 
+static int caller_arg_offset_v(int arg);
+static void pcond(int op, int r2,int r1,int r0,int cond,int l1,int mode);
+#if FLOAT_CODE
+static int code_d1(double d);
+static int code_d2(double d);
+static void code_float_lib(char *opc,int oreg,int in_reg,int e1);
+static void code_float_lib_c(char *lib,int from,int to,double value);
+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);
+static void dconst(int l,int h,double value);
+static void code_assign_input_double_long(int e1,int e2) ;
+static void code_assign_input_float_int(int e1,int e2) ;
+#endif
+static void use_input_reg(int reg,int mode);
+static void ascii(char *s);
+
+static int creg;
+static int output_mode = TEXT_EMIT_MODE;
+static int register_save_return_label;
+
+static int r1_offset_label;
+static int lvar_offset_label;
+static int    max_func_args = 0;
+static int arg_on_register = 0;
+static int max_func_arg_label = 0;
+
+
+static int freg,ireg,lreg;
+
+int code_lassop_p = 4;
+
+#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
+#define ENDIAN_L  0
+#define ENDIAN_D  1
+
+int eval_order = NORMAL;
+
+static int  reg_sp;   /* REGister Stack-Pointer */
+static int reg_stack[MAX_MAX];  /* 実際のレジスタの領域 */
+
+
+#define REG_ip   13
+#define REG_fp   0
+#define REG_sp   1
+#define REG_VAR_BASE 3  
+#define REG_VAR_MIN  3
+#define REG_VAR_USER_MAX  127     /* at leat 6 tmp var */
+#define REG_VAR_MAX 127
+#define MIN_TMP_REG 4
+#define MAX_TMP_REG 127
+
+#define FREG_VAR_BASE 3
+#define FREG_VAR_MIN  3
+#define FREG_VAR_MAX  127
+#define MIN_TMP_FREG 3
+#define MAX_TMP_FREG 127
+
+int MAX_REGISTER=127;             /* ARMのレジスタを10個まで使う*/
+#define  REAL_MAX_REGISTER 127    /* ARMのレジスタが32ということ*/
+
+#define FREG_OFFSET 3
+#define LREG_OFFSET 3
+
+int MAX_INPUT_REGISTER_VAR = 80;
+int MAX_INPUT_DREGISTER_VAR = 80;
+int MAX_INPUT_FREGISTER_VAR = 80;
+int MAX_CODE_INPUT_REGISTER_VAR = 80;
+int MAX_CODE_INPUT_DREGISTER_VAR = 80;
+int MAX_CODE_INPUT_FREGISTER_VAR = 80;
+
+#define LREG_V 3    /* mark for virtual long long/double register */
+#define REGS_MAX (REAL_MAX_REGISTER)
+static int spu_regs[REGS_MAX];
+///   #define (i)  (i)
+// #define (i)  (i)
+
+#define RET_REGISTER 3
+#define REGISTER_OPERAND  3     //this is first register for input
+#define REGISTER_OPERAND_1  4
+#define RET_FREGISTER FREG_OFFSET
+#define FREGISTER_OPERAND  (FREG_OFFSET)
+#define FREGISTER_OPERAND_1  (FREG_OFFSET+1)
+
+#define RET_LREGISTER 3
+#define LREGISTER_OPERAND 3 
+#define LREGISTER_OPERAND_1 4 
+#define RET_LREGISTER_L 1    /* low word */
+#define RET_LREGISTER_H 2    /* high word */
+#define LREGISTER_OPERAND_L  1    /* low word */
+#define LREGISTER_OPERAND_H  2    /* high word */
+#define LREGISTER_OPERAND_1_L  3    /* low word */
+#define LREGISTER_OPERAND_1_H  4    /* 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  = spu_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;
+
+
+static char *reg_name[] = {
+	"$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", 
+	"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", 
+	"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", 
+	"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31", 
+	"$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", 
+	"$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47", 
+	"$48", "$49", "$50", "$51", "$52", "$53", "$54", "$55", 
+	"$56", "$57", "$58", "$59", "$60", "$61", "$62", "$63", 
+	"$64", "$65", "$66", "$67", "$68", "$69", "$70", "$71", 
+	"$72", "$73", "$74", "$75", "$76", "$77", "$78", "$79", 
+	"$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87", 
+	"$88", "$89", "$90", "$91", "$92", "$93", "$94", "$95", 
+	"$96", "$97", "$98", "$99", "$100", "$101", "$102", "$103", 
+	"$104", "$105", "$106", "$107", "$108", "$109", "$110", "$111", 
+	"$112", "$113", "$114", "$115", "$116", "$117", "$118", "$119", 
+	"$120", "$121", "$122", "$123", "$124", "$125", "$126", "$127"
+};
+
+#define register_name(i)  reg_name[i]
+#define lregister_name_low(i) reg_name[i]
+#define lregister_name_high(i) reg_name[i]
+
+char *rn(int i) { return register_name(i); }
+char *lln(int i) { return lregister_name_low(i); }
+char *lhn(int i) { return lregister_name_high(i); }
+int ll(int i) { return i; }
+int lh(int i) { return i; }
+
+#define is_int_reg(i)  (0<=i&&i<REAL_MAX_REGISTER)
+#define is_float_reg(i)  (is_int_reg(i))
+#define is_longlong_reg(i) (is_int_reg(i)) 
+#define is_double_reg(i) (is_int_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||FLOAT_CODE
+#define  use_longlong(reg) if (reg==USE_CREG) reg=use_int0()
+/*
+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 (!(i)) (i) = get_register();
+    if (!(i)) (i) = get_register();
+    if (!regs[i]) regs[i]=USING_REG;
+    if (!regs[(i)]) regs[(i)]=USING_REG;
+    if (!regs[(i)]) regs[(i)]=USING_REG;
+    creg = i;
+    return i;
+}
+*/
+static void lmove(int to,int from);
+#endif
+
+#define USING_DREG 5
+#define INPUT_DREG 6
+
+
+#if FLOAT_CODE
+
+#define dsuffix(d) (d?'d':'s')
+
+#define  use_float(d,reg) if (reg==USE_CREG) { reg=use_int0();}
+
+/*
+static
+int use_double0() { 
+    int i;
+    use_longlong0();
+    use_int0();
+	i = lreg;
+    if (!regs[i]) regs[i]=USING_DREG;
+    if (!regs[(i)]) regs[(i)]=USING_REG;
+    if (!regs[(i)]) regs[(i)]=USING_REG;
+    creg = i;
+    return i;
+}
+*/
+void code_lassign_lvar(int e2,int creg);
+int code_lrindirect(int e1, int reg, int offset, int us);
+void code_lregister(int e2,int reg);
+void code_lassign_gvar(int e2,int creg);
+void code_lassign(int e2,int creg);
+void code_lassign_lregister(int e2,int reg);
+void code_lrgvar(int e1,int creg);
+void code_lrlvar(int e1,int creg);
+void emit_lpop_free(int xreg);
+void emit_lpush();
+int emit_lpop();
+
+#endif
+
+
+
+#if LONGLONG_CODE
+static int code_l1(long long ll);
+static int code_l2(long long ll);
+#endif
+
+static void code_save_input_registers(int dots);
+static void    set_ireg(int,int);
+#if FLOAT_CODE
+static void    set_dreg(int,int);
+static void    set_freg(int,int);
+#endif
+#if LONGLONG_CODE
+static void    set_lreg(int,int);
+#endif
+
+static int max_func_args;
+static int my_func_args;
+
+
+
+
+
+static void jcond(int l, int cond);
+
+#define ARG_LVAR_OFFSET 0x10000000
+
+#define round16(i)   ((i+0xf)&~0xf)
+#define round4(i)   ((i+3)&~3)
+
+/*          
+
+     r0    return value etc.
+     r0,r1 return value. (dpcmp return value on $2)
+     00  special register
+     r0-r3  input register
+     r7-r9 saved register variable (input register for code segment)
+         jump register
+     sp    stack pointer
+     fp    frame pointer
+
+     f0       return value etc.
+     r0-r3    input register
+     f20-f31 saved register variable
+
+code segment stack frame
+
+register_save is done by callee
+
+                     (prev $sp)
+                            <---lvar_offset-->
+   #                       $fp <--------------------r1_offset---------> $sp
+r+ +----------+-------------+--------+-------+-----------+---------------+
+    cousin arg!  callee arg !reg_save!reg_arg!local       caller arg 
+              (arg4..)lvar>0         (arg0.3) lvar<0      lvar>0x1000 000
+               <--------------my_func_args--><--disp-----><-max_func_arg->
+                              *SIZE_OF_INT                  *SIZE_OF_INT
+                 prev $sp=$fp                 $fp                        $sp
+
+                                         (prev $sp)
+                                      <------r1_offset----------------> $sp
+                 (prev $fp)           $fp
+ r+  +-----------+--------------------+----------+-----------------------+
+       callee arg      register save   local      caller arg   
+                                        disp          max_func_args*SIZE_OF_INT
+                                       lvar<0          lvar>0x1000 0000
+                      prev $sp=$fp                                   $sp=$fp
+ */
+
+#define arg_offset (16)
+#define arg_offset1 (-64)
+int disp_offset=0;    // fore mc-codegen.c
+#define disp_offset  0
+
+#define code_disp_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_offset)
+
+static int
+code_offset_set(NMTBL *fnptr)
+{
+    int lvar_offsetv;
+    int r1_offsetv;
+    int code_f = is_code(fnptr);
+
+    disp &= -SIZE_OF_INT;
+
+    if (code_f) {
+	r1_offsetv = disp-max_func_args*SIZE_OF_INT+code_disp_offset;
+	printf("\t.set .LC%d, %d\n",r1_offset_label,r1_offsetv);
+    } else {
+	lvar_offsetv = 
+	    -12 - max_reg_var*SIZE_OF_INT-max_reg_var*SIZE_OF_DOUBLE;
+	printf("\t.set .LC%d, %d\n",lvar_offset_label,lvar_offsetv);
+    }
+    if (max_func_arg_label) {
+	printf("\t.set .LC%d, %d\n",max_func_arg_label,max_func_args*SIZE_OF_INT);
+        max_func_arg_label = 0;
+    }
+
+
+// printf("        @ args = %d, pretend = %d, frame = %d\n",
+// 	max_func_args,0,round16(-disp));
+// printf("        @ frame_needed = 1, current_function_anonymous_args = 0\n");
+
+
+#if 0
+printf("## vars= %d, regs= %d/%d, args= %d, extra= %d\n",
+	round16(-disp),
+	max_reg_var+2,
+	max_reg_var,
+	round16(max_func_args*SIZE_OF_INT),
+	0
+);
+   printf("## callee arg top=\t%d\n",CALLEE_ARG(0));
+   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_reg_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
+
+    return 0;
+}
+
+#define LARGE_OFFSET(l) (l<-511||l>511)
+
+static void lvar_address(int l,int creg);
+
+static int large_lvar;
+static void
+lvar_intro(int l)
+{
+    int large;
+    if (is_code(fnptr)) {
+        if (l>=ARG_LVAR_OFFSET) {
+	    large = LARGE_OFFSET(CODE_CALLER_ARG(l-ARG_LVAR_OFFSET));
+        } else
+	    large = LARGE_OFFSET(CODE_LVAR(l));
+    } else if (l<0) {  /* local variable */
+	    large = LARGE_OFFSET(FUNC_LVAR(l));
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	    large = LARGE_OFFSET(CALLER_ARG(l-ARG_LVAR_OFFSET));
+    } else { /* callee's arguments */
+	    large = LARGE_OFFSET(CALLEE_ARG(l));
+    }
+    if (large) {
+	large_lvar = get_register();
+	lvar_address(l,large_lvar);
+    } else {
+	large_lvar = 0;
+    }
+}
+
+static void
+lvar(int l,char *cext)
+{
+    if (large_lvar) {
+	printf("[%s, 0]%s\n",register_name(large_lvar),cext);
+	free_register(large_lvar);
+	return;
+    }
+    if (is_code(fnptr)) {
+        if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+            printf("[sp, %d]%s\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),cext);
+        } else
+            printf("[fp, %d]%s\n",CODE_LVAR(l),cext);
+    } else if (l<0) {  /* local variable */
+        //printf("[fp, #%d+.L%d]%s\n",FUNC_LVAR(l),lvar_offset_label,cext);
+        printf("%d($sp)\n",FUNC_LVAR(l));
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+        printf("[sp, %d]%s\n",CALLER_ARG(l-ARG_LVAR_OFFSET),cext);
+    } else { /* callee's arguments */
+        printf("[fp, %d]%s\n",CALLEE_ARG(l),cext);
+    }
+}
+
+static void
+lvar_address(int l,int creg)
+{
+    //int label,disp;
+    int disp;
+    int tmp = -1;
+    char *trn;
+    if (is_code(fnptr)) {
+        if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	    code_add(creg,CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),REG_sp);
+        } else
+	    code_add(creg,CODE_LVAR(l),REG_fp);
+    } else if (l<0) {  /* local variable */
+//        printf("\tsf\t%s, fp, %d\n",register_name(creg), FUNC_LVAR(l));
+	trn = register_name(tmp = get_register());
+	//disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(l)),&label);
+        printf("\tlqd\t%s, %d($sp)\n",trn,(disp*4));
+	printf("\tadd\t%s, fp, %s\n",register_name(creg),trn);
+    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
+	code_add(creg,CALLER_ARG(l-ARG_LVAR_OFFSET),REG_sp);
+    } else { /* callee's arguments */
+	code_add(creg,CALLEE_ARG(l),REG_fp);
+    }
+    if (tmp!=-1) free_register(tmp);
+}
+
+
+void
+code_lvar(int e2,int reg) {
+    use_int(reg);
+    lvar_address(e2,reg);
+}
+
+
+void
+code_init(void)
+{
+    /* 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;
+
+}
+
+extern void
+emit_reinit()
+{
+    /* called for each file */
+    init_ptr_cache();
+    output_mode = -1;
+}
+
+
+
+void
+gexpr_code_init(void){
+}
+
+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 (is_function(fnptr)) {
+		if ((reg = get_input_dregister_var(reg_var,n,is_code0,0))) {
+		    n->sc = REGISTER;
+		    n->dsp = cadr(reg);
+		    regs[n->dsp]= INPUT_REG;
+		    reg_var++;
+		    cadddr(args)=size(type);
+		}
+	    } else {
+		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_dregister_var(reg_var,n,is_code0,1))) {
+                n->sc = LREGISTER;
+                n->dsp = cadr(reg);
+                regs[i=n->dsp]= INPUT_DREG;
+                regs[i]= INPUT_REG;
+                //regs[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[i]= INPUT_REG;
+                //regs[(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;   /* その場所を表す番号を返す */
+    }
+    for(i=0;i<REG_VAR_MAX-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;   /* その場所を表す番号を返す */
+        }
+    }
+    /* 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)*4),reg,0); 
+            reg_stack[i]= j-REG_LVAR_OFFSET;
+		return reg;
+	}
+    }
+#if LONGLONG_CODE||FLOAT_CODE
+    /* search register stack */
+    for(i=0;i<reg_sp;i++) {
+	if ((reg=reg_stack[i])>0) {
+            code_lassign_lvar(
+                (j=new_lvar(SIZE_OF_LONGLONG)),reg); 
+            reg_stack[i]= j-REG_LVAR_OFFSET;
+	    free_register(reg);
+	    return get_register();
+	}
+    }
+#endif
+    /* 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;   /* その場所を表す番号を返す */
+    }
+    for(i=0;i<REG_VAR_MAX-REG_VAR_MIN;i++) {
+        reg =REG_VAR_BASE+i;
+	/* PTR_CACHE をつぶす */
+	if (regs[reg]==PTRC_REG) {
+	    clear_ptr_cache_reg(reg);
+	    regs[reg]=0;
+	    return reg;   /* その場所を表す番号を返す */
+        }
+    }
+    /* あいている場所がないなら、エラー(いったい誰が使ってるの?) */
+    error(RGERR); return creg;
+}
+
+#if 0
+int 
+get_register(void)
+{
+    int i = get_register0();
+    printf("## get_register %d\n",i);
+    //printf("hoge:%d\n",i);
+	return i;
+}
+#endif
+
+int
+pop_register(void)
+{    /* レジスタから値を取り出す */
+	return reg_stack[--reg_sp];
+}
+
+#if FLOAT_CODE
+int 
+get_dregister(int d)
+{    /* 使われていないレジスタを調べる */
+    return get_register();
+}
+
+#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 reg_stack[--reg_sp];
+}
+#endif
+
+// static int lreg_count;
+int
+get_lregister0()
+{
+	return get_register();
+}
+
+int
+get_lregister()
+{
+	return get_register();
+}
+
+int
+get_lregister_var(NMTBL *n)
+{
+	return get_register_var(n);
+}
+
+void
+emit_pop_free(int xreg)
+{
+    if (xreg>=0 && xreg!=creg)
+	free_register(xreg);
+}
+
+void
+
+free_register(int i) {    /* いらなくなったレジスタを解放 */
+// printf("## free_register %d\n",i);
+    regs[i]=0;
+ //   if (is_longlong_reg(i)) {
+// printf("## free lregister %d (%d)\n",i,lreg_count++);
+//	regs[(i)]=0;
+//	regs[(i)]=0;
+	//(i)=0;
+	//(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 (is_code) {
+	if(i>MAX_CODE_INPUT_DREGISTER_VAR) return 0;
+	i = FREG_VAR_BASE+i+FREG_OFFSET;
+	use_input_reg(i,1);
+	return list3(FREGISTER,i,(int)n);
+    }
+    if (d) {
+	j = get_input_lregister_var(i,n,is_code);
+	return j;
+    } else {
+	if (i==0) return list3(REGISTER,1,(int)n);
+	else if (i==1) return list3(REGISTER,2,(int)n);
+	else if (i==2) return list3(REGISTER,3,(int)n);
+	else if (i==3) return list3(REGISTER,4,(int)n);
+	else return 0;
+    }
+}
+
+int
+get_input_lregister_var(int i,NMTBL *n,int is_code)
+{
+	return get_input_register_var(i,n,is_code);
+}
+
+int
+get_input_register_var(int i,NMTBL *n,int is_code)
+{
+    if (is_code) {
+	if(!(i<REG_VAR_MAX-REG_VAR_MIN)) return 0;
+	i = REG_VAR_BASE+i;
+	use_input_reg(i,1);
+    } else {
+	if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0;
+	i = i+1;
+    }
+    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_REGISTER;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_REGISTER;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_REGISTER;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)==(cadr(t))) return 1;
+	    if(cadr(s)==(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)==(cadr(s))) return 1;
+	    if(cadr(t)==(cadr(s))) return 1;
+	    break;
+	case LREGISTER: case DREGISTER: 
+	    if((cadr(t))==(cadr(s))) return 1;
+	    if((cadr(t))==(cadr(s))) return 1;
+	    if((cadr(t))==(cadr(s))) return 1;
+	    if((cadr(t))==(cadr(s))) return 1;
+	    break;
+	}   
+	break;
+    }   
+    return 0;
+}
+
+
+void
+register_usage(char *s)
+{
+#if 1
+    int i,j;
+#endif
+#define USAGE_MAX 4
+    if (!lsrc) return;
+    printf("## %d: %s:",lineno,s);
+    if (ireg) printf(" creg=%s",register_name(ireg));
+    if (freg) printf(" freg=%s",register_name(freg));
+    if (lreg) printf(" lreg=%s,%s",lregister_name_high(lreg),
+	lregister_name_low(lreg));
+#if 1
+    for(j=0,i=1;i<MAX_REGISTER;i++) if (regs[i]) j++;
+    if (j>USAGE_MAX) {
+	// printf("\n# regs:01234567890123456789012");
+	printf("\n# regs:");
+	for(i=1;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_REGISTER;i++) if (regs[i+FREG_OFFSET]) j++;
+    if (j>USAGE_MAX) {
+	printf("\n# freg:");
+	for(i=0;i<MAX_REGISTER;i++) {  printf("%d",regs[i+FREG_OFFSET]); }
+    }
+    if (reg_sp>0) {
+	printf(" fstack ");
+	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<REAL_MAX_REGISTER;i++) if (regs[i+LREG_OFFSET]) j++;
+    if (j>USAGE_MAX) {
+	printf("\n# lreg:");
+	for(i=0;i<REAL_MAX_REGISTER;i++) {  printf("%d",regs[i+LREG_OFFSET]); }
+    }
+    if (reg_sp>0) {
+	printf(" lstack ");
+	for(i=reg_sp;i>0;i--) {
+	    if(reg_stack[i-1]>=0) {
+		printf(" %s",lregister_name_high(reg_stack[i-1]));
+		printf(",%s",lregister_name_low(reg_stack[i-1]));
+            } else 
+		printf(",%d",reg_stack[i-1]);
+	}
+    }
+#endif
+    printf("\n");
+}
+
+
+void
+gexpr_init(void)
+{
+    while(reg_sp > 0) {
+	error(-1);
+	free_register(reg_stack[--reg_sp]);
+    }
+    while(reg_sp > 0) {
+	error(-1);
+	free_register(reg_stack[--reg_sp]);
+    }
+    while(reg_sp > 0) {
+	error(-1);
+	free_register(reg_stack[--reg_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_reg_var=0;
+    reg_sp = 0;
+    reg_sp = 0;
+}
+
+#define reg_var_num(i) (REG_VAR_BASE+i)
+
+int
+get_register_var(NMTBL *n)
+{
+    int i,j;
+    int max = n?REG_VAR_USER_MAX-REG_VAR_BASE:REG_VAR_MAX-REG_VAR_BASE;
+    for(i=0;i<max;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 list3(LVAR,new_lvar(SIZE_OF_INT),0);
+}
+
+#define freg_var_num(i) (FREG_VAR_BASE+i+FREG_OFFSET)
+
+int
+get_dregister_var(NMTBL *n,int d)
+{
+    int i,j;
+    for(i=0;i<FREG_VAR_MAX-FREG_VAR_BASE;i++) {
+	j = freg_var_num(i);
+	if (! regs[j]) {       /* 使われていないなら */
+	    regs[j]=USING_REG; /* そのレジスタを使うことを宣言し */
+	    if (i+1>max_reg_var) max_reg_var=i+1;
+	    /* その場所を表す番号を返す */		
+	    return list3(FREGISTER,j,(int)n); 
+	}
+    }
+}
+
+int
+emit_push()
+{
+    int new_reg,old=creg;
+    if (!is_int_reg(creg)) error(-1);
+    if (reg_sp>MAX_MAX) error(-1);
+    new_reg = get_register();       /* 絶対にとれる */
+    if (new_reg==creg) error(-1);   /* who freed creg? */
+    reg_stack[reg_sp++] = creg;     /* push するかわりにレジスタを使う */
+    ireg = creg = new_reg;
+    if (!regs[creg]) regs[creg]=USING_REG;
+    return old;
+}
+
+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;
+}
+
+static int const_list;
+static int const_list_label;
+static int prev_const_list;
+static int prev_const_list_label;
+
+/*
+     constant table
+        glist3( tag, next, value )
+		LVAR       	glist2(label,offset)
+		GVAR       	nptr
+		CONST		value
+		LABEL		value
+     nth element has offset n * SIZE_OF_INT
+ */
+
+#define CONST_TBL_COUNT 100
+/*
+static int
+search_const(int tag,int value,int *label)
+{
+    int p,i,j,list,prev;
+
+    for(j=0;j<2;j++) {
+	i = 0;
+	if(j==1) {
+	    if (!const_list_label) const_list_label = fwdlabel();
+	    *label = const_list_label;
+	    if (const_list==0) {
+		const_list = glist3(tag,0,value);
+		return 0;
+	    } else {
+		prev = list = const_list;
+	    }
+	} else {
+	    prev = list = prev_const_list; *label = prev_const_list_label;
+	}
+	for(p = list; p ;prev=p,p=cadr(p),i+=SIZE_OF_INT) {
+	    if (car(p)!=tag) continue;
+	    switch(tag) {
+	    case GVAR: case CONST: case LABEL:
+		if (caddr(p)!=value) continue;
+		return i;
+	    case LVAR:
+		if (car(caddr(p))!=car(value)) continue;
+		if (cadr(caddr(p))!=cadr(value)) continue;
+		return i;
+	    }
+	}
+    }
+    cadr(prev) = glist3(tag,0,value);
+    if (i>CONST_TBL_COUNT) {
+	const_list_table();
+    }
+    return i;
+}
+*/
+#if FLOAT_CODE
+static int
+search_double_const(int tag,int value1,int value2,int *label)
+{
+    int p,i,j,list,prev;
+
+    for(j=0;j<2;j++) {
+	i = 0;
+	if(j==1) {
+	    if (!const_list_label) const_list_label = fwdlabel();
+	    *label = const_list_label;
+	    if (const_list==0) {
+		const_list = glist3(tag,glist3(tag,0,value2),value1);
+		return 0;
+	    } else {
+		prev = list = const_list;
+	    }
+	} else {
+	    prev =list = prev_const_list; *label = prev_const_list_label;
+	}
+	for(p = list; p ;prev=p,p=cadr(p),i+=SIZE_OF_INT) {
+	    if (car(p)!=tag) continue;
+	    switch(tag) {
+	    case DCONST: case LCONST:
+		if (caddr(p)!=value1) continue;
+		p = cadr(p);
+		if (!p||car(p)!=tag) error(-1);
+		if (caddr(p)!=value2) continue;
+		return i;
+	    }
+	    prev = p;
+	}
+    }
+    cadr(prev) = glist3(tag,glist3(tag,0,value2),value1);
+    if (i>CONST_TBL_COUNT) {
+	const_list_table();
+    }
+    return i;
+}
+#endif
+
+static int inst_count;
+
+static void
+const_list_table()
+{
+    int p,lb=0;
+    inst_count = 0;
+
+    if (const_list) {
+	if (control) {
+	    lb = fwdlabel();
+	    gen_jmp(lb);
+	    // printf("\t.align\t2\n");
+	}
+	fwddef(const_list_label);
+	control=0;
+	for(p = const_list; p ; p = cadr(p)) {
+	    switch(car(p)) {
+	    case GVAR:	printf("\t.word\t%s\n",((NMTBL *)caddr(p))->nm); break;
+	    case DCONST: case LCONST:
+	    case CONST:	printf("\t.word\t%d\n",caddr(p)); break;
+	    case LABEL:	printf("\t.word\t.LC%d\n",caddr(p)); break;
+	    case LVAR:	printf("\t.word\t.LC%d+%d\n",
+		car(caddr(p)),cadr(caddr(p))); break;
+	    default: error(-1);
+	    }
+	}
+	if (lb) {
+	    fwddef(lb);  // control==1 now
+	}
+	prev_const_list_label=const_list_label;
+	const_list_label = 0;
+    }
+    for(p = prev_const_list; p ; p = cadr(p)) {
+	if (car(p)==LVAR) {
+	    free_glist2(caddr(p));
+	}
+    }
+    free_glist3_a(prev_const_list);
+    prev_const_list=const_list;
+    const_list = 0;
+}
+
+
+extern void
+code_ptr_cache_def(int r, NMTBL *nptr)
+{
+    //int label,disp;
+    int disp;
+    char *rrn = register_name(r);
+    //disp = search_const(GVAR,(int)nptr,&label);
+    printf("\tlqd\t%s, %d($sp)\n",rrn,(disp*4));
+}
+
+#define mask8(d,bit)   (d & (255 << bit))
+
+/*
+     mode   CONST or other (CMP is Ok only in stage 1 result)
+     *p1    stage 1 const
+     *p2    stage 2 const
+     *p3    stage 3 const
+     return 0 ... require 4 stage
+            1 ... positive result
+           -1 ... negative result
+
+ */
+static int
+make_const(int c,int *p1,int *p2,int *p3,int mode)
+{
+    int sign,im,jm,km;
+    int min_stage = 4;
+    int msign=0,mim=0,mjm,mkm;
+    int id,jd,kd;
+    int i,j,k;
+    int d;
+    if (c == (d = mask8(c,0))) {
+	min_stage=1; min_stage=1; msign = 1;
+	    mim = d;mjm = 0;mkm = 0;
+    } else if (mode!=CONST) {
+	if (-c == (d = mask8(-c,0))) {
+	    min_stage=1; min_stage=1; msign = -1;
+		mim = d;mjm = 0;mkm = 0;
+	}
+    } else {
+	if (~c== (d = mask8(~c,0))) {
+	    min_stage=1; min_stage=1; msign = -1;
+		mim = d;mjm = 0;mkm = 0;
+	}
+    }
+    for(sign=1;sign>=-1;sign-=2) {
+	if (min_stage==1) break;
+        for(i=24;i>=0;i-=2) {
+	    jm = km = 0;
+	    if (sign>0) {
+		if (c == (d = mask8(c,i))) {
+		    min_stage=1; min_stage=1; msign = 1;
+			mim = d;mjm = 0;mkm = 0;
+		    break;
+		}
+		id = c - d;
+	    } else if (mode!=CONST) {
+		if (-c == (d = mask8(-c,i))) {
+		    min_stage=1; min_stage=1; msign = -1;
+			mim = d;mjm = 0;mkm = 0;
+		    break;
+		}
+		id = -c - d;
+	    } else {
+		if (~c== (d = mask8(~c,i))) {
+		    min_stage=1; min_stage=1; msign = -1;
+			mim = d;mjm = 0;mkm = 0;
+		    break;
+		}
+		id = ~c - d;
+	    }
+	    if (d==0) continue;
+	    im = d;
+	    if (min_stage<=2) continue;
+            for(j=i-8;j>=0;j-=2) {
+		km = 0;
+                if (!(jm=mask8(id,j))) continue;
+                jd = id - jm;
+		if (jd==0) {
+		    min_stage=2; msign = sign;
+		    mim = im;mjm = jm;mkm = km;
+		    break;
+		}
+		if (min_stage<=3) continue;
+                for(k=j-8;k>=0;k-=2) {
+                    if (!(km=mask8(jd,k))) continue;
+                    kd = jd - km;
+		    if (kd==0) { 
+			min_stage=3; msign = sign;
+			mim = im;mjm = jm;mkm = km;
+			break;
+		    }
+                }
+            }
+        }
+    }
+    if (min_stage<=3) {
+	*p1 = mim; *p2= mjm; *p3 = mkm; 
+	return msign;
+    } else return 0;
+}
+
+static int
+is_stage1_const(int c,int mode)
+{
+    int sign,p1=0,p2=0,p3=0;
+    sign = make_const(c,&p1,&p2,&p3,mode);
+    return (c==0||(p1&&!p2&&!p3))?sign:0;
+}
+
+
+static void 
+code_const0(int e2,int reg,char *opt)
+{
+    char *crn,*add,*mov;
+    int s,p1,p2,p3;
+    //int label,disp;
+    int disp;
+
+    use_int(reg);
+    crn = register_name(reg);
+    if ((s=make_const(e2,&p1,&p2,&p3,CONST))) {
+	add = s>0?"a":"sfi";
+	/************************************************************
+	 * ここでp1の値によって、命令が異なる......                 *
+	 * il命令は-32768~32767                                     *
+	 * ila命令は262143まで                                      *
+	 * それ以上はilhuとiohlを混合して使う。                     *
+	 * example:15728639                                         *
+	 *     15728639/16^4 = 239             ilhu  $4,239         *
+	 *     15728639%16^4 = 65535           iohl  $4,65535       *
+	 ***********************************************************/
+	mov = s>0?"il":"mvn";
+	printf("\t%s\t%s, %d\n",mov,crn,p1);
+	if (p2) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p2);
+	if (p3) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p3);
+    } else {
+	//disp = search_const(CONST,e2,&label);
+	printf("\tlqd\t%s, %d($sp)\n",crn,(disp*4));
+    }
+}
+
+extern void 
+code_const(int e2,int reg) {
+    code_const0(e2,reg,"");
+}
+
+static void 
+code_add(int reg,int offset,int r)
+{
+    char *crn = register_name(reg);
+    char *rrn = register_name(r);
+    char *drn;
+    int dreg;
+    int s,p1,p2,p3;
+    char *add;
+    //int label,disp;
+    int disp;
+    if (offset==0) {
+        if(r!=reg)
+            printf("\tori\t%s, %s, 0\n",crn,rrn);
+    } else if ((s=make_const(offset,&p1,&p2,&p3,0))) {
+	add = s>0?"a":"sfi";
+	printf("\t%s\t%s, %s, %d\n",add,crn,rrn,p1);
+	if (p2) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p2);
+	if (p3) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p3);
+    } else {
+	//disp = search_const(CONST,offset,&label);
+	drn = register_name(dreg = get_register());
+	printf("\tlqd\t%s, %d($sp)\n",drn,(disp*4));
+	printf("\ta\t%s, %s, %s\n",crn,drn,rrn);
+	free_register(dreg);
+    }
+}
+
+
+static void 
+code_ld(char *ld,int reg,int offset,int r,char *cext)
+{
+    char *crn = register_name(reg);
+    char *rrn = register_name(r);
+    if (-1024<offset&&offset<1024) {
+	printf("\t%s\t%s, [%s, %d]%s\n",ld,crn,rrn,offset,cext);
+    } else {
+	code_add(reg,offset,r);
+	printf("\t%s\t%s, [%s, 0]%s\n",ld,crn,crn,cext);
+    }
+}
+
+static void 
+code_ldf(char *ld,char *crn,int offset,int r,char *cext)
+{
+    //char *rrn = register_name(r);
+    char *orn;
+    int reg;
+    if (-1024<offset&&offset<1024) {
+	printf("\t%s\t%s, %d(%s)\n",ld,crn,(offset*4),cext);
+    } else {
+	orn = register_name(reg=get_register());
+	code_add(reg,offset,r);
+	//printf("\t%s\t%s, [%s, 0]%s\n",ld,crn,orn,cext);
+	printf("hoge\n");
+	free_register(reg);
+    }
+}
+
+
+#define cload(sz,sign) \
+    (sz==1?(sign?"lqx":"lqa"):sz==SIZE_OF_SHORT?(sign?"lqx":"lqa"):"lqd")
+
+
+#define cext(sign,sz,reg)
+
+static char *
+cext_at(int sz,int sign) 
+{
+    return ((sz==1&&!sign)?"  @ zero_extendqisi2":"");
+}
+
+void
+code_label(int labelno)
+{
+    clear_ptr_cache();
+    printf(".LC%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("lqd",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_at(sz,sign));
+    cext(sign,sz,reg);
+}
+
+
+void
+code_register(int e2,int reg) {
+    use_int(reg);
+    // reg = e2
+    if (reg!=e2) {
+	printf("\tori\t%s, %s, 0\n",register_name(reg),register_name(e2));
+    }
+}
+
+
+void
+code_rlvar(int e2,int reg) {
+    use_int(reg);
+    lvar_intro(e2);
+    printf("\tlqd\t%s, ",register_name(reg));
+    e2 *= 4;
+	lvar(e2,"");
+}
+
+extern void
+code_i2c(int reg)
+{
+}
+
+extern void
+code_i2s(int reg)
+{
+}
+
+extern void
+code_u2uc(int reg)
+{   
+    use_int(reg);
+    printf("and\t%s, %s, #255\n",register_name(reg),register_name(reg));
+}
+
+extern void
+code_u2us(int reg)
+{   
+    use_int(reg);
+    printf("bic\t%s, %s, #16711680\n",register_name(reg),register_name(reg));
+    printf("bic\t%s, %s, #-16777216\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\t%s, ",cload(sz,sign),register_name(reg));
+    lvar(e2,cext_at(sz,sign));
+    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("\tori\t%s, %s, 0\n",register_name(reg),register_name(r));
+    }
+    return;
+}
+
+void
+code_label_value(int label,int reg) {
+    //int lb,disp;
+    use_int(reg);
+    //disp = search_const(LABEL,label,&lb);
+    printf("\tila\t%s,.LC%d\n",register_name(reg),label);
+    return;
+}
+
+void
+code_neg(int creg) {
+    use_int(creg);
+    printf("\trsb\t%s, %s, #0\n", register_name(creg), register_name(creg));
+}
+
+
+void
+code_not(int creg) {
+    use_int(creg);
+    printf("\tmvn\t%s, %s\n", 
+	register_name(creg), register_name(creg));
+}
+
+
+void
+code_lnot(int creg) {
+    use_int(creg);
+
+    printf("\tcmp\t%s, #0\n", register_name(creg));
+    printf("\tmovne\t%s, #0\n", register_name(creg));
+    printf("\tmoveq\t%s, #1\n", register_name(creg));
+}
+
+void
+code_preinc(int e1,int e2,int dir,int sign,int sz,int reg) {
+    char *xrn,*drn;
+    int xreg;
+    if (car(e2)==REGISTER) {
+	use_int(reg);
+	code_add(cadr(e2),dir,cadr(e2));
+	if (reg!=cadr(e2))
+	    code_register(cadr(e2),reg);
+	return;
+    } 
+    g_expr(e2);
+    if (!is_int_reg(creg)) error(-1);
+    xrn = register_name(xreg = 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);
+    }
+//        ldrb    r2, [ip, #-1]!  @ zero_extendqisi2
+//        ??????offset???????????12bit!
+    code_ld(cload(sz,sign),reg,0,xreg,cext_at(sz,sign));
+    code_add(reg,dir,reg);
+    code_ldf(cstore(sz),drn,0,xreg,sz==SIZE_OF_SHORT?"  @ movhi":"");
+}
+
+
+void
+code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) {
+    char *xrn,*crn,*nrn;
+    int nreg,xreg;
+    if (car(e2)==REGISTER) {
+	use_int(reg);
+	code_register(cadr(e2),reg);
+	code_add(cadr(e2),dir,cadr(e2));
+	return;
+    } 
+    g_expr(e2);
+    if (!is_int_reg(creg)) error(-1);
+    crn = register_name(xreg=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);
+    }
+//_1:     ldrb    r4, [r0], #1            @ zero_extendqisi2 *buffer++
+    code_ld(cload(sz,sign),reg,0,xreg,cext_at(sz,sign));
+    code_add(nreg,dir,reg);
+    code_ldf(cstore(sz),nrn,0,xreg,sz==SIZE_OF_SHORT?"  @ movhi":"");
+
+    free_register(nreg);
+}
+
+
+void
+code_return(int creg) {
+    //int label,disp;
+    int disp;
+    char *crn;
+    use_int(creg);
+    crn = register_name(creg);
+
+    //disp = search_const(LABEL,retcont,&label);
+    printf("\tlqd\t%s, %d($sp)\n",crn,(disp*4));
+}
+
+void
+code_environment(int creg) {
+    /* save frame pointer */
+    if (is_code(fnptr)) {
+	use_int(creg);
+	printf("\tmov\t%s, fp\n",register_name(creg));
+    } else {
+	//int disp,label;
+	int disp;
+	char *trn = register_name(REG_ip);
+	use_int(creg);
+	//disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label);
+	printf("\tlqa\t%s, %d\n",trn,disp);
+	printf("\ta\t%s, fp, %s\n",register_name(creg),trn);
+    }
+}
+
+static int rexpr_bool(int e1, int reg);
+#if LONGLONG_CODE
+static int lrexpr_bool(int e1, int reg);
+#endif
+
+void
+code_bool(int e1,int reg) {
+    int e2,e3;
+    char *xrn;
+    if (rexpr_bool(e1, reg)) return;
+#if LONGLONG_CODE
+    if (lrexpr_bool(e1, reg)) return;
+#endif
+    b_expr(e1,1,e2=fwdlabel(),1);  /* including > < ... */
+    if (use) {
+        use_int(reg);
+        xrn = register_name(reg);
+        printf("\tmov\t%s, #0\n",xrn);
+        gen_jmp(e3=fwdlabel());
+        fwddef(e2);
+        printf("\tmov\t%s, #1\n",xrn);
+        fwddef(e3);
+    } else {
+        fwddef(e2);
+    }
+}
+
+
+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_at(sz,0));
+    cext(0,sz,r);
+    printf("\tcmp\t%s, #0\n",register_name(reg));
+    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\t%s, ",cload(sz,0),crn);
+    lvar(e2,cext_at(sz,0));
+    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("lqd",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("\tlqd\t%s, ",crn);
+    e2 *= 4;
+	lvar(e2,"");
+    code_cmp_register(reg,label,cond);
+}
+
+
+void
+code_cmp_register(int e2,int label,int cond) {
+    use_int(e2);
+    printf("\tcmp\t%s, #0\n",register_name(e2));
+    jcond(label,cond);
+}
+
+
+void
+code_string(int e1,int creg)
+{
+    char *s,*crn;
+    //int lb,label;
+    int lb;
+	printf("creg:%d\n",creg);
+	NMTBL *n = (NMTBL *)cadr(e1);
+    if ((lb=attr_value(n,LABEL))) {
+	// already defined
+	return code_label_value(lb,creg) ;
+	//return code_label_value(lb,35) ;
+    }
+
+    use_int(creg);
+    crn = register_name(creg);
+
+    s=n->nm;
+    lb = emit_string_label();
+    ascii(s);
+    text_mode(2);
+
+    //disp = search_const(LABEL,lb,&label);
+    printf("\tila\t%s, .LC%d\n",crn,lb);
+    set_attr(n,LABEL,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;
+    char *memmove = "memmove";
+    int dreg = REG_ip; 
+
+    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("\tlqd\t%s, %d(%s)\n",drn,(offset*4),trn);
+	printf("\tstqd\t%s,%d(%s)\n",drn,(offset*4),trn);
+	break;
+    case 2: case -2:
+	printf("\tlqx\t%s, [%s,#%d]\n",drn,frn,offset);
+	printf("\tstqx\t%s, [%s,#%d]\n",drn,trn,offset);
+	break;
+    case 4: case -4:
+	printf("\tlqa\t%s, [%s,#%d]\n",drn,frn,offset);
+	printf("\tstqa\t%s, [%s,#%d]\n",drn,trn,offset);
+	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();
+	parallel_rassign(list3(1,list3(2,0,from),to));
+	code_const(length>0?length:-length,3);
+        /* overlap must be allowed */
+	// offset have to be ignored */
+	printf("\thbra\t%s\n",memmove);
+	extern_define(memmove,0,FUNCTION,1);
+	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(creg!=to) {
+	    free_register(creg); creg=to; ireg=to;
+	}
+    }
+    // free_register(dreg);
+}
+
+int
+push_struct(int e4,int t,int arg)
+{
+    int length,len0,count;
+    int dreg = -1,sreg; char *drn,*crn,*srn;
+    int arg_disp = cadr(arg);
+    int on_register,arg_reg;
+    g_expr(e4);
+    if (!is_int_reg(creg)) error(-1);
+    len0=length=size(t);
+    if(length%SIZE_OF_INT) {
+        length += SIZE_OF_INT - (length%SIZE_OF_INT);
+    }
+    crn = register_name(creg);
+    on_register = 0;
+    // arg_reg = 1-CALLER_ARG(arg_disp-ARG_LVAR_OFFSET)/SIZE_OF_INT;
+    arg_reg = (arg_disp-ARG_LVAR_OFFSET)/SIZE_OF_INT + 1;
+    while (length>0 && 
+             arg_disp>=ARG_LVAR_OFFSET && 
+             CALLER_ARG(arg_disp-ARG_LVAR_OFFSET)<0) {
+	/* some part will be on registers */
+	on_register ++; 
+	length-=SIZE_OF_INT; arg_disp+= SIZE_OF_INT;
+    }
+    if (length>0) {
+	dreg = get_register(); if (!dreg) error(-1);
+	drn = register_name(dreg);
+	if (length<MAX_COPY_LEN) {
+	    sreg = get_register(); if (!sreg) error(-1);
+	    srn = register_name(sreg);
+	    code_lvar(arg_disp,dreg);
+	    for(count=0;count<length;count+=SIZE_OF_INT) {
+		printf("\tlqd\t%s, [%s, #%d]\n",srn,crn,count+on_register*SIZE_OF_INT);
+		printf("\tstr\t%s, [%s, #%d]\n",srn,drn,count);
+	    }
+	    free_register(sreg);
+	    if (on_register) {
+		if (creg<=MAX_INPUT_REGISTER_VAR) {
+		    code_register(creg,REG_ip);
+		    crn = register_name(REG_ip);
+		}
+	    }
+	} else {
+	    code_lvar(arg_disp,dreg);
+	    /* downward direction copy */
+	    if (on_register) {
+		sreg = new_lvar(SIZE_OF_INT);
+		code_assign_lvar(sreg*4,creg,0);
+		code_add(creg,on_register*SIZE_OF_INT,creg);
+		emit_copy(creg,dreg,length,0,0,1);
+		code_rlvar(sreg,REG_ip);
+		crn = register_name(REG_ip);
+		free_lvar(sreg);
+	    } else {
+		emit_copy(creg,dreg,length,0,0,1);
+	    }
+	}
+	if (dreg!=-1) free_register(dreg);
+    }
+    for (count=0,arg_reg; on_register-->0; arg_reg++,count+=SIZE_OF_INT) {
+	// len0 = (len0>2)?0:len0;
+	printf("\t%s\t%s, [%s, #%d]\n", cload(0,0),
+		register_name(arg_reg), crn,count);
+	use_input_reg(arg_reg,1);
+    }
+    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("\tori\t%s, %s, 0\n",register_name(reg),register_name(ireg));
+	    }
+	}
+	free_register(creg);
+	if (creg==lreg) lreg=0;
+	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("\t%s\t%s, %s\n",
+		    "mvfs"
+		    register_name(reg),register_name(freg));
+	    }
+	}
+	// if (creg!=ireg) free_register(creg);
+	regs[reg]=USING_REG;
+    }
+    creg = freg = reg;
+}
+
+#if LONGLONG_CODE||FLOAT_CODE
+static void
+set_lreg0(int reg,int mode)
+{
+    if (reg!=creg) {
+	if (lreg && reg!=lreg) {
+	    if (mode) {
+		lmove(reg,lreg);
+	    }
+	    free_register(lreg);
+	}
+	if (creg!=lreg) {
+	    free_register(creg);
+	    if (creg==ireg) ireg = 0;
+	}
+	regs[reg]=USING_REG;
+	clear_ptr_cache_reg(reg);
+	regs[reg]=USING_REG;
+	clear_ptr_cache_reg(reg);
+	regs[reg]=USING_REG;
+    }
+    creg = lreg = reg;
+}
+#endif
+
+#if LONGLONG_CODE
+static void
+set_lreg(int reg,int mode)
+{
+    if (!is_longlong_reg(reg)) error(-1);
+    set_lreg0(reg,mode);
+}
+#endif
+
+#if FLOAT_CODE
+static void
+set_dreg(int reg,int mode)
+{
+	return set_ireg(reg,mode);
+}
+
+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_dreg_operand(int reg,int mode)
+{
+     set_lreg_operand(reg,mode);
+}
+
+
+#endif
+
+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(arg);
+	regs[arg]=USING_REG;
+	clear_ptr_cache_reg(arg);
+	regs[arg]=USING_REG;
+    } else if (is_double_reg(arg)) {
+	clear_ptr_cache_reg(arg);
+	regs[arg]=USING_REG;
+	clear_ptr_cache_reg(arg);
+	regs[arg]=USING_REG;
+    }
+}
+
+void
+code_save_input_registers(int dots)
+{
+    int args;
+    NMTBL *n;
+    int reg;
+    int tag;
+    /* fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); */
+    int offset = 0;
+    int reg_var = 0;
+    int len;
+    arg_on_register = 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 (reg_var<MAX_INPUT_REGISTER_VAR) {
+	    n->dsp = offset;
+	    n->sc  = LVAR;
+	    len = size(n->ty); len = round4(len);
+	    for(;len>0 && reg_var<MAX_INPUT_REGISTER_VAR;len-=SIZE_OF_INT) {
+		reg_var++;
+		g_expr_u(assign_expr0(list3(LVAR,offset,0),
+			list3(REGISTER,reg_var,0),INT,INT));
+		arg_on_register += SIZE_OF_INT;
+		free_register(reg);
+		offset += SIZE_OF_INT;
+	    }
+	}
+    }
+    if (dots) {
+        while ((reg = get_input_register_var(reg_var,0,0))) {
+            g_expr_u(assign_expr0(
+                list3(LVAR,offset,0),reg,INT,INT));
+            offset+=SIZE_OF_INT;
+            reg_var++;
+	    arg_on_register += SIZE_OF_INT;
+        }
+    }
+    my_func_args = offset;
+}
+
+int
+not_simple_p(int e3)
+{
+    switch(e3) {
+	case FUNCTION: case CONV: case STASS: case ALLOCA:
+	case DIV : case UDIV : case MOD : case UMOD :
+	case LDIV: case LUDIV: case LMOD: case LUMOD:
+	case LMUL: case LUMUL:
+	case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT:
+	case DDIV: case DADD: case DSUB: case DMUL: case DMINUS:
+	case DPOSTINC : case DPREINC : case DASSOP :
+	case DOP+LT : case DOP+LE : case DOP+GT : case DOP+GE :
+	case DOP+EQ : case DOP+NEQ:
+	case RBIT_FIELD: case BASS: case BASSOP: case LCALL:
+	case INLINE:
+	return 1;
+    }
+    return 0;
+}
+
+int
+simple_arg(int e3)
+{
+    return !contains_p(e3,not_simple_p);
+}
+
+static int
+caller_arg_offset_v(int arg)
+{
+    return ARG_LVAR_OFFSET+arg*SIZE_OF_INT;
+}
+
+/* 
+     Mark argument register is used. This is too complex.
+     There must be an easy way.
+ */
+
+static 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 (lreg==reg) {
+		regs[lreg]=0;
+		if (lreg>reg&&
+		    (regs[lreg]==USING_REG||
+		     regs[lreg]==USING_DREG))
+		  {
+		    free_register(lreg);
+		}
+		if (creg==lreg) creg = ireg;
+		free_register(lreg);
+		lreg = 0;
+	    } else if (lreg==reg) {
+		regs[lreg]=0;
+		if (lreg>reg && (
+		    (regs[lreg]==USING_REG) ||
+		    (regs[lreg]==USING_DREG) ))
+		  {
+		    free_register(lreg);
+		}
+		if (creg==lreg) creg = ireg;
+		free_register(lreg);
+		lreg = 0;
+	    }
+	}
+    } else if (is_longlong_reg(reg)) {
+	use_input_reg(reg,0);
+	use_input_reg(reg,0);
+    } else if (is_double_reg(reg)) {
+	use_input_reg(reg,0);
+	use_input_reg(reg,0);
+    } else if (is_float_reg(reg)) {
+	if (freg&&reg == freg) {
+	    if (creg==freg) creg = ireg;
+	    freg = 0;
+	} 
+    }
+    if (mode) use_reg(reg);
+}
+
+static void
+code_assign_input_float_int(int e1,int e2) {
+#if FLOAT_CODE
+    int r,tmp=-1;
+    float f;
+    char *frn;
+    //  e1 = e2;
+    if (car(e1)!=REGISTER) { error(-1); return; }
+    frn = register_name(r=cadr(e1));
+    switch(car(e2)) {
+    case FCONST:
+        f = dcadr(e2);
+	code_const(*((int*)&f),r);
+        break;
+    case FRGVAR:
+	code_rgvar(e2,r);
+        break;
+    case FRLVAR:
+	code_rlvar(cadr(e2),r);
+	break;
+    default:
+        g_expr(rvalue_t(e2,FLOAT));
+    case FREGISTER:
+	tmp = new_lvar(SIZE_OF_INT);
+	code_dassign_lvar(tmp, (car(e2)==FREGISTER)?cadr(e2):freg,0);
+	code_rlvar(tmp,r);
+	if (tmp!=-1) free_lvar(tmp);
+    }
+#endif
+}
+
+static void
+code_assign_input_double_long(int e1,int e2) {
+#if FLOAT_CODE
+    int r,tmp=-1,reg=0;
+    double value;
+    //  e1 = e2;
+    if (car(e1)!=LREGISTER) { error(-1); return; }
+    r=cadr(e1);
+    switch(car(e2)) {
+    case DCONST:
+        value = dcadr(e2);
+	dconst(r,r,value);
+        break;
+    case DRGVAR:
+	code_lrgvar(e2,r);
+        break;
+    case DRLVAR:
+	code_lrlvar(cadr(e2),r);
+	break;
+    default:
+        g_expr(rvalue_t(e2,DOUBLE));
+	reg = freg;
+    case DREGISTER:
+	if (car(e2)==DREGISTER) reg = cadr(e2);
+        printf("\tstfd\t%s, [sp, #-8]!\n",register_name(reg));
+        printf("\tldmfd\tsp!, {%s, %s}\n",lregister_name_low(r),lregister_name_high(r));
+    }
+    if (tmp!=-1) free_lvar(tmp);
+#endif
+}
+
+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);
+    if (t==FLOAT&&car(arg)==REGISTER)
+	code_assign_input_float_int(arg, e4);
+    else if (t==DOUBLE&&car(arg)==LREGISTER)
+	code_assign_input_double_long(arg, e4);
+    else
+	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++; freg_arg++;
+    } else if (t==LONGLONG||t==ULONGLONG||t==DOUBLE) {
+	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 list3(LVAR,caller_arg_offset_v(nargs),0);
+	} else 
+	    return get_input_register_var(reg_arg,0,0);
+    } else if (t==LONGLONG||t==ULONGLONG) {
+	if (mode==AS_SAVE) {
+	    return get_lregister_var(0);
+	} else if (reg_arg+1>=MAX_INPUT_REGISTER_VAR)  {
+	    return list3(LVAR,caller_arg_offset_v(nargs),0);
+	} 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 list3(LVAR,caller_arg_offset_v(nargs),0);
+	} else
+	    return get_input_dregister_var(freg_arg,0,0,0);
+    } else if (t==DOUBLE) {
+	if (mode==AS_SAVE) {
+	    return get_dregister_var(0,1);
+	} else if (reg_arg+1>=MAX_INPUT_DREGISTER_VAR) {
+	    return list3(LVAR,caller_arg_offset_v(nargs),0);
+	} 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 list3(LVAR,caller_arg_offset_v(nargs),0);
+    } else {
+	error(-1);
+	return get_register_var(0);
+    }
+}
+
+static void
+code_call(int e2,NMTBL *fn,int jmp)
+{
+    if (car(e2) == FNAME) {
+	printf("\tbrsl\t$lr,%s\n",fn->nm);
+    } else {
+	printf("\tmov\tlr, pc\n");
+	printf("\tmov\tpc, %s\n",register_name(cadr(jmp)));
+    }
+}
+
+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,i;
+    int half_register = 0;
+
+    special_lvar = -1;
+    ret_type = function_type(cadddr(e1),&dots);
+    if (caddr(cadddr(e1))==0) 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 = get_register_var(0);
+	jmp = list2(REGISTER,REG_ip);
+	if (!simple_arg(e2)) {
+	    e3=get_register_var(0);
+	    reg_arg_list = list2(e3,reg_arg_list);
+	    g_expr_u(assign_expr0(e3,e2,INT,INT));
+	    e2=e3;
+	}
+	reg_arg_list = list2(jmp,reg_arg_list);
+	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;
+    pnargs = preg_arg = pfreg_arg = 0;
+    for (e3 = e1 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) {	
+	t=caddr(e3);
+	if (reg_arg==3 && (t==DOUBLE||t==LONGLONG||t==ULONGLONG)) {
+	    half_register=1;
+	}
+	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);
+	    }
+	    // memorise last complex arg parameter
+	    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);
+		    else car(e3) = rvalue_t(arg,INT);
+		}
+	    }
+	    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);
+	    push_struct(e4,t,arg);
+	    car(e3)=0;  // done
+	    if (car(arg)==REGISTER)   // wrong?
+		use_input_reg(cadr(arg),1);
+	}
+    } 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);
+	    if (car(arg)!=LVAR) use_input_reg(cadr(arg),1);
+	    car(complex_) = 0; // done.
+	    if (car(arg)==REGISTER)
+		use_input_reg(cadr(arg),1);
+	}
+    }
+
+    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
+    }
+    if (half_register) {
+	//  half register case writes *(sp-1) but it will be Ok.
+	if (max_func_args<4) max_func_args=4;
+	g_expr_u(assign_expr0(list3(REGISTER,4,0),
+		list3(LVAR,caller_arg_offset_v(3),0),INT,INT));
+	use_input_reg(4,1);
+    }
+    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)==LREGISTER) {
+		use_input_reg(cadr(arg),1);
+                code_assign_input_double_long(arg, e4);
+	    } else {
+		g_expr_u(assign_expr0(arg,e4,t,t));
+	    }
+	} else if (t==FLOAT) {
+	    reg_arg_list = list2(arg,reg_arg_list);
+            if (car(arg)==REGISTER) {
+                use_input_reg(cadr(arg),1);/* protect from input register free */
+                code_assign_input_float_int(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));
+    }
+    for(i=1;i<MAX_INPUT_REGISTER_VAR;i++) {
+	free_register(i);
+    }
+    if (ret_type==DOUBLE) {
+#if FLOAT_CODE
+        set_dreg(RET_DREGISTER,0);
+        use_reg(RET_DREGISTER);
+#endif
+    } else if (ret_type==FLOAT) {
+#if FLOAT_CODE
+        set_freg(RET_FREGISTER,0);
+#endif
+    } else if (ret_type==ULONGLONG||ret_type==LONGLONG) {
+#if LONGLONG_CODE
+        set_lreg(RET_LREGISTER,0);
+        use_reg(RET_LREGISTER);
+#endif
+    } else if (ret_type==VOID) {
+    } else {
+        set_ireg(RET_REGISTER,0);
+    }
+    return ret_type;
+}
+
+void
+code_alloca(int e1,int reg)
+{
+    char *crn;
+  
+    g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); 
+    use_int(reg);
+    crn = register_name(reg);
+    printf("\trsb\tsp, %s, sp\n",crn);
+    if (!max_func_arg_label) max_func_arg_label = fwdlabel();
+    code_label_value(max_func_arg_label ,REG_ip);
+    printf("\ta\t%s, sp, ip\n",crn);
+}
+
+void
+code_frame_pointer(int e3) {
+    use_int(e3);
+    printf("\tmov\tfp, %s\n",register_name(e3));
+}
+
+int
+code_frame_pointer_register()
+{
+    return list2(REGISTER,REG_fp);
+}
+
+void
+code_fix_frame_pointer(int env) {
+    char *trn;
+    //int disp,label;
+    //int label;
+	int disp;
+    if (is_function(fnptr) && ! env) {
+	trn = register_name(REG_ip);
+	//disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label);
+	printf("\tlqd\t%s, %d($sp)\n",trn,disp);
+	printf("\ta\tfp, fp, %s\n",trn);
+    }
+}
+
+static void
+code_unfix_frame_pointer()
+{
+    char *trn;
+    //int disp,label;
+    int disp;
+
+    trn = register_name(REG_ip);
+    //disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label);
+    printf("\tlqd\t%s, %d($sp)\n",trn,disp);
+    printf("\tsf\tfp, fp, %s\n",trn);
+}
+
+
+void
+code_jmp(char *s) {
+    // jump to continuation means use all register variable
+    max_reg_var = REG_VAR_MAX-REG_VAR_MIN;
+    max_reg_var = FREG_VAR_MAX-FREG_VAR_MIN;
+    printf("\tbr\t%s\n",s);
+    control=0;
+}
+
+void
+code_indirect_jmp(int e2) {
+    // jump to continuation means use all register variable
+    max_reg_var = REG_VAR_MAX-REG_VAR_MIN;
+    max_reg_var = FREG_VAR_MAX-FREG_VAR_MIN;
+    use_int(e2);
+    printf("\tmov\tpc, %s @ indirect jump\n",register_name(e2)); // ?!
+    control=0;
+}
+
+void
+code_rindirect(int e1, int reg,int offset, int sign,int sz)
+{
+    int lreg;
+    g_expr(e1);
+    if (!is_int_reg(creg)) error(-1);
+    lreg = creg;
+    use_int(reg);
+    code_ld(cload(sz,sign),reg,offset,lreg,cext_at(sz,sign));
+    cext(sign,sz,reg);
+}
+
+#if FLOAT_CODE
+int
+code_drindirect(int e1, int reg,int offset, int d)
+{
+    int xreg;
+    g_expr(e1);
+    if (!is_int_reg(creg)) error(-1);
+    xreg = creg;
+    use_float(d,reg);
+    code_ldf(d?"ldfd":"ldfs",register_name(reg),offset,xreg,"");
+    return d?DOUBLE:FLOAT;
+}
+#endif
+
+#if LONGLONG_CODE||FLOAT_CODE
+
+static void
+lload(int creg,int reg,int offset) 
+{
+    char *crn=register_name(creg);
+#if ENDIAN_L==0
+    if (creg!=reg) {
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset);
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset+SIZE_OF_INT);
+    } else {
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset+SIZE_OF_INT);
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset);
+    }
+#else
+    if (creg!=reg) {
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset+SIZE_OF_INT);
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset);
+    } else {
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset);
+	printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset+SIZE_OF_INT);
+    }
+#endif
+}
+
+
+static void
+lmove(int to,int from)
+{
+    int l;
+    l = list3(to,0,from);
+    l = list3(to,l,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_L==0
+    printf("\tstr\t%s, [%s, #0]\n",crn_l,drn);
+    printf("\tstr\t%s, [%s, #%d]\n",crn_h,drn,SIZE_OF_INT);
+#else
+    printf("\tstr\t%s, [%s, #0]\n",crn_h,drn);
+    printf("\tstr\t%s, [%s, #%d]\n",crn_l,drn,SIZE_OF_INT);
+#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
+
+static char *
+cstore(int sz)
+{
+    switch(sz) {
+    case 1: return "stqx";
+    case SIZE_OF_SHORT: return "stqa";
+    default: return "stqd";
+    }
+}
+
+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)),byte==SIZE_OF_SHORT?" @ movhi":"");
+}
+
+void
+code_assign_lvar(int e2,int creg,int byte) {
+    char *crn;
+    use_int(creg);
+    crn=register_name(creg);
+    lvar_intro(e2);
+    printf("\t%s\t%s,",cstore(byte),crn);
+    e2 *= 4;
+	lvar(e2,"");
+}
+
+void
+code_assign_register(int e2,int byte,int creg) {
+    use_int(creg);
+    if (e2!=creg) {
+	printf("\tori\t%s, %s, 0\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);
+
+    printf("\t%s\t%s, 0(%s)\n",cstore(byte),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_var(0);
+    if (car(edx)!=REGISTER) error(-1);
+    //  (*creg) op = pop()
+
+    drn = register_name(edx=cadr(edx));
+    use_int(creg);
+    xrn = register_name(xreg = emit_pop(0));       /* pop e3 value */
+    code_register(creg,edx);
+    ld_indexx(byte,0,edx,creg,sign);
+    tosop(op,creg,xreg);
+    crn = register_name(creg);
+    printf("\t%s\t%s, 0(%s)\n",cstore(byte),crn,drn);
+    free_register(edx);
+    free_register(creg);
+    emit_pop_free(xreg);
+}
+
+int
+tosop_operand_safe_p(int op)
+{
+    return 1;
+}
+
+void
+tosop(int op,int creg,int oreg)
+{
+    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);
+	free_lvar(oreg+REG_LVAR_OFFSET);
+	oreg = ox;
+    }
+
+    switch(op) {
+    case LSHIFT:
+    case ULSHIFT:
+	shift("asl",creg,oreg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case RSHIFT:
+	shift("asr",creg,oreg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case URSHIFT:
+	shift("lsr",creg,oreg);
+	if(ox!=-1) free_register(ox);
+	return;
+    }
+    orn = register_name(oreg);
+    crn = register_name(creg);
+    switch(op) {
+    case ADD:
+	printf("\ta\t%s, %s, %s\n",crn,crn,orn);
+	break;
+    case SUB:
+	printf("\tsf\t%s, %s, %s\n",crn,crn,orn);
+	break;
+    case CMP:
+        printf("\tcmp\t%s, %s\n",crn,orn);
+	break;
+    case BAND: 
+	printf("\tand\t%s, %s, %s\n",crn,crn,orn);
+	break;
+    case EOR: 
+	printf("\teor\t%s, %s, %s\n",crn,crn,orn);
+	break;
+    case BOR:
+	printf("\torr\t%s, %s, %s\n",crn,crn,orn);
+	break;
+    case MUL:
+    case UMUL:
+	/* target!=source */
+	printf("\tmul\t%s, %s, %s\n",crn,orn,crn);
+	break;
+    case DIV:
+	code_int_lib("__divsi3",creg,oreg); break;
+    case UDIV:
+	code_int_lib("__udivsi3",creg,oreg); break;
+    case MOD:
+	code_int_lib("__modsi3",creg,oreg); break;
+    case UMOD:
+	code_int_lib("__umodsi3",creg,oreg); break;
+    default:
+	error(-1);
+    }
+    if(ox!=-1) free_register(ox);
+}
+
+int 
+code_const_op_p(int op,int v)
+{
+    if (car(v)!=CONST) return 0;
+    v = cadr(v);
+    switch(op) {
+    case MUL: case UMUL: case DIV: case UDIV:
+	return ilog(v);
+    case ADD: case SUB:
+	return 1;
+    case LSHIFT: case ULSHIFT: case RSHIFT: case URSHIFT:
+	return 0<v&&v<=32;
+    case CMP:
+	return is_stage1_const(v,CMP);
+    case EOR: case BOR: case BAND:
+	return (is_stage1_const(v,0)>0);
+    default:
+	return 0;
+    }
+}
+
+void
+oprtc(int op,int creg, int v)
+{
+    char *crn;
+    use_int(creg);
+    crn = register_name(creg);
+    v = cadr(v);
+    
+    switch(op) {
+    case MUL: case UMUL:
+	v=ilog(v);
+    case LSHIFT:
+    case ULSHIFT:
+	printf("\tmov\t%s, %s, asl #%d\n",crn,crn,v);
+	break;
+    case DIV:
+	v=ilog(v);
+    case RSHIFT:
+	printf("\tmov\t%s, %s, asr #%d\n",crn,crn,v);
+	break;
+    case UDIV:
+	v=ilog(v);
+    case URSHIFT:
+	printf("\tmov\t%s, %s, lsr #%d\n",crn,crn,v);
+	break;
+    case ADD:
+	code_add(creg,v,creg);
+	break;
+    case SUB:
+	code_add(creg,-v,creg);
+	break;
+    case CMP: printf("\tcmp\t%s,%d\n",crn,v); break;
+    case BOR: printf("\torr\t%s, %s, #%d\n",crn,crn,v); break;
+    case EOR: printf("\teor\t%s, %s, #%d\n",crn,crn,v); break;
+    case BAND: printf("\tand\t%s, %s, #%d\n",crn,crn,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("\tmov\t%s, %s, %s  %s\n",crn,crn,op,rrn);
+}
+
+void
+ld_indexx(int byte, int n, int xreg,int creg, int sign)
+{	
+    use_int(creg);
+    code_ld(cload(byte,sign),creg,n,xreg,cext_at(byte,sign));
+}
+
+int
+code_csvalue()
+{
+    return glist2(REGISTER,creg);
+}
+
+void
+code_cmpdimm(int e, int csreg,int label,int cond)
+{
+    /* used in dosiwtch() */
+    int sign,reg=-1;
+    int regsv;
+    char *rn,*crn;
+    crn = register_name(csreg);
+
+    if (!(sign=is_stage1_const(e,CMP))) {
+	regsv = regs[csreg]; regs[csreg]=1;
+	rn = register_name(reg= get_register());
+	regs[csreg] = regsv;
+	code_const(e,reg);
+	printf("\tcmp\t%s, %s\n",crn,rn);
+    } else {
+	if (sign>0) 
+	    printf("\tcmp\t%s, #%d\n",crn,e);
+	else
+	    printf("\tcmn\t%s, #%d\n",crn,-e);
+    }
+    switch(cond) {
+    case -1: break;
+    case 1:
+	printf("\tbne\t.LC%d\n",label); break;
+    case 0:
+	printf("\tbeq\t.LC%d\n",label); break;
+    case LT:
+	printf("\tblt\t.LC%d\n",label); break;
+    case GT:
+	printf("\tbgt\t.LC%d\n",label); break;
+    default: error(-1);
+    }
+    if (reg!=-1) free_register(reg);
+}
+
+void
+code_opening(char *filename)
+{
+    /* this is called once per file */
+    //printf("@ Generated by mc for ARM/elf\n");
+    printf("\t.file \"%s\"\n",filename);
+    // printf(".text\n");
+}
+
+// should have pcond_const
+
+#define COND_BRANCH 1
+#define COND_VALUE  2
+#define COND_BRANCH_CONST 3
+#define COND_VALUE_CONST  4
+
+    /*
+            if (r1 cmp r2) goto l1   COND_BRANCH
+            r0 = (r1 cmp r2)         COND_VALUE
+     */
+static void
+pcond(int op, int r2,int r1,int r0,int cond,int l1,int mode)
+{
+    char *rn2;
+    char *rn1;
+    char *rn0;
+    char *cc=0,*ncc=0;
+
+    if (mode==COND_BRANCH_CONST||mode==COND_VALUE_CONST) {
+	rn1 =		register_name(r1);
+	if (r2>=0) 
+	    printf("\tcmp\t%s, #%d\n",rn1,r2);
+	else
+	    printf("\tcmn\t%s, #%d\n",rn1,-r2);
+    } else {
+	rn1 =		register_name(r1);
+	rn2 =		register_name(r2);
+	printf("\tcmp\t%s, %s\n",rn1,rn2);
+    }
+
+    switch(op+(!cond)*BNOT) {
+    case GT:  case LE+BNOT:	cc="gt"; ncc="le"; break;
+    case LE:  case GT+BNOT:	cc="le"; ncc="gt"; break;
+    case GE:  case LT+BNOT:	cc="ge"; ncc="lt"; break;
+    case LT:  case GE+BNOT:	cc="lt"; ncc="ge"; break;
+    case UGT: case ULE+BNOT:	cc="hi"; ncc="ls"; break;
+    case ULE: case UGT+BNOT:	cc="ls"; ncc="hi"; break;
+    case UGE: case ULT+BNOT:	cc="hs"; ncc="lo"; break;
+    case ULT: case UGE+BNOT:	cc="lo"; ncc="hs"; break;
+    case EQ:  case NEQ+BNOT:	cc="eq"; ncc="ne"; break;
+    case NEQ: case EQ+BNOT:   	cc="ne"; ncc="eq"; break;
+    default:        error(-1);
+    }
+
+    if (mode==COND_BRANCH||mode==COND_BRANCH_CONST) {
+	printf("\tb%s\t.LC%d\n",cc,l1);
+    } else if (mode==COND_VALUE||mode==COND_VALUE_CONST) {
+	rn0 =		register_name(r0);
+	printf("\tmov%s\t%s, #0\n",ncc,rn0);
+	printf("\tmov%s\t%s, #1\n",cc,rn0);
+    } else error(-1);
+}
+
+int
+rexpr_bool(int e1, int reg)
+{       
+    int e2,reg0;
+    int op = car(e1);
+    if (!(
+	op== GT || op== LT || op== UGT || op== ULT ||
+	op== ULE || op== UGE || op== LE || op== GE ||
+	op== EQ || op== NEQ
+    )) return 0;
+    if (car(caddr(e1))==CONST  && is_stage1_const(cadr(caddr(e1)),CMP)) {
+	g_expr(cadr(e1));
+	reg0 = ireg;
+	use_int(reg);
+	pcond(op, cadr(caddr(e1)),reg0,reg,1,0,COND_VALUE_CONST);
+    } else {
+	g_expr(cadr(e1));
+	emit_push();
+	g_expr(caddr(e1));
+	e2 = emit_pop(1);
+	reg0 = ireg;
+	use_int(reg);
+	pcond(op, reg0,e2,reg,1,0,COND_VALUE);
+	emit_pop_free(e2);
+    }
+    return 1;
+}
+
+int
+rexpr(int e1, int l1, int cond,int t)
+{       
+    int e2;
+    int op = car(e1);
+
+    if (car(caddr(e1))==CONST  && is_stage1_const(cadr(caddr(e1)),CMP)) {
+	g_expr(cadr(e1));
+	pcond(op, cadr(caddr(e1)),ireg,0,cond,l1,COND_BRANCH_CONST);
+    } else {
+	g_expr(cadr(e1));
+	emit_push();
+	g_expr(caddr(e1));
+	e2 = emit_pop(1);
+	pcond(op, ireg,e2,0,cond,l1,COND_BRANCH);
+	emit_pop_free(e2);
+    }
+    return l1;
+}
+
+#define CMP_C1T (-1)
+
+static void
+jcond(int l, int cond)
+{       
+    printf("\tb%s\t.LC%d\n",cond?"ne":"eq",l);
+}
+
+void
+jmp(int l)
+{       
+    printf("\tbr\t.LC%d\n",l);
+    if (inst_count>CONST_TBL_COUNT/2) {
+	const_list_table();
+    } 
+}
+
+void
+code_comment(char *s)
+{
+    printf("## %s",s);
+}
+/*
+static int
+code_register_save(int reg_save,int freg_save,int disp)
+{
+    int i;
+    printf("\tstmfd\tsp!, {");
+    for (i=reg_var_num(0);i<reg_var_num(reg_save);i++) {
+	    printf("%s, ",register_name(i));
+    }
+    printf("fp, ip, lr, pc}\n");
+    if (freg_save>0) {
+	printf("\tsfmfd\tf4, %d, [sp]!\n",freg_save);
+    }
+    return disp;
+}
+*/
+
+static int
+code_register_restore(int reg_save,int freg_save,int disp)
+{
+    int i;
+    if (freg_save>0) {  
+	i=reg_save*SIZE_OF_INT+
+		freg_save*SIZE_OF_DOUBLE + 20;
+	printf("\tlfm\tf4, %d, [fp, #%d]\n",freg_save,-i);
+    }
+    //printf("\tldmea\tfp, {");
+    for (i=reg_var_num(0);i<reg_var_num(reg_save);i++) {
+	    printf("%s, ",register_name(i));
+    }
+    //printf("fp, sp, pc}\n");
+    return disp;
+}
+
+static int entry_label;
+
+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);
+    printf("\t.type\t%s,function\n",name);
+    r1_offset_label = fwdlabel();
+    max_func_args = 0;
+    printf("%s:\n",name);
+    code_label_value(r1_offset_label,REG_ip);
+    printf("\ta\tsp, ip, fp\n");
+    clear_ptr_cache();
+}
+
+
+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.size\t%s,.LC%d-%s\n",name, backdef(),name);
+}
+
+void
+enter(char *name)
+{
+    if (output_mode!=TEXT_EMIT_MODE) 
+	text_mode(2);
+    else
+	printf("\t.align 2\n");
+    
+    max_func_args = 0;
+
+    lvar_offset_label = fwdlabel();
+    // r1_offset_label = fwdlabel();
+    printf("\t.type\t%s,function\n",name);
+    if (stmode!=STATIC)
+	printf("\t.globl\t%s\n",name);
+    printf("%s:\n",name);
+    //printf("\tmov\tip, sp\n");
+    printf("\tstqd\t$lr,16($sp)\n");
+    printf("\tstqd\t$sp,-32($sp)\n");
+    printf("\tai\t$sp,$sp,-32\n");	
+    gen_jmp(entry_label = fwdlabel());
+    register_save_return_label = backdef();
+    clear_ptr_cache();
+}
+
+void
+enter1()
+{
+    text_mode(0);
+    // set_lreg(LREG_LREGISTER,0);
+    set_ireg(CREG_REGISTER,0);
+    set_freg(FREG_FREGISTER,0);
+}
+
+void
+code_label_call(int l)
+{
+        printf("\tbl\tL_%d\n",l);
+}
+
+void
+code_ret()
+{
+	printf("\tmov\tpc, lr\n");
+	control=0;
+}
+
+void
+leave(int control0, char *name)
+{
+    int retcont1=0,sz;
+
+    if (control0) {
+	code_set_return_register(1);
+    } else
+	text_mode(2);
+    if (retcont) { 
+	/* return from CbC segement */
+	if (control0) gen_jmp(retlabel);
+	retcont1 = fwdlabel();
+	fwddef(retcont);
+	if (cadr(fnptr->ty)==FLOAT) {
+#if FLOAT_CODE
+	    creg = freg = cadr(get_input_dregister_var(0,0,1,0));
+	    set_freg(RET_FREGISTER,1);
+#endif
+	} else if (cadr(fnptr->ty)==DOUBLE) {
+#if FLOAT_CODE
+	    creg = lreg = cadr(get_input_dregister_var(0,0,1,1));
+	    set_dreg(RET_DREGISTER,1);
+#endif
+	} else if (cadr(fnptr->ty)>0&&(
+	    car(cadr(fnptr->ty))==STRUCT ||
+	    car(cadr(fnptr->ty))==UNION)) {
+	    sz = size(cadr(fnptr->ty));
+	    code_const(sz,REGISTER_OPERAND);
+	    printf("\tsf\tr1, r2, fp\n");
+	    printf("\tlqd\tr0, [fp, #%d]\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);
+	}
+	code_unfix_frame_pointer();
+    }
+    fwddef(retlabel);
+
+    code_offset_set(fnptr);
+    code_register_restore(max_reg_var,max_reg_var,0);
+
+//  leave part end
+
+//  entry part  (save register)
+
+    fwddef(entry_label);
+    if (arg_on_register>0)
+	printf("\tsfi\tsp, sp, %d\n",arg_on_register);
+    //code_register_save(max_reg_var,max_reg_var,0);
+
+    //printf("\tsf\tfp, ip, #%d\n",4+arg_on_register);
+    code_add(REG_sp,disp-max_func_args*SIZE_OF_INT,REG_sp);
+    gen_jmp(register_save_return_label);
+    local_table();
+
+    printf("\t.size\t%s,.LC%d-%s\n",name, backdef(),name);
+
+    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) {
+#if FLOAT_CODE
+	set_dreg(RET_DREGISTER,mode);
+#endif
+    } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) {
+#if LONGLONG_CODE
+	set_lreg(RET_LREGISTER,mode);
+#endif
+    } else if (cadr(fnptr->ty)==VOID) {
+    } else {
+	set_ireg(RET_REGISTER,mode);
+    }
+}
+
+int
+code_get_fixed_creg(int reg,int type) {
+    switch(type) {
+#if FLOAT_CODE
+    case DOUBLE: use_float(1,reg); break;
+    case FLOAT:  use_float(0,reg); break;
+#endif
+#if LONGLONG_CODE
+    case LONGLONG:  case ULONGLONG:  use_longlong(reg); break;
+#endif
+    default:
+        if (reg==USE_CREG) {
+            if (regs[CREG_REGISTER]==0||regs[CREG_REGISTER]==PTRC_REG) {
+		set_ireg(CREG_REGISTER,is_int_reg(creg)&&regs[creg]==USING_REG);
+                return CREG_REGISTER;
+            }
+        }
+        use_int(reg);
+        break;
+    }
+    return reg;
+}
+
+void
+code_set_fixed_creg(int reg,int mode,int type) {
+    if (type==FLOAT) {
+#if FLOAT_CODE
+	set_freg(reg,mode);
+#endif
+    } else if (type==DOUBLE) {
+#if FLOAT_CODE
+	set_dreg(reg,mode);
+#endif
+    } else if (type==LONGLONG||type==ULONGLONG) {
+#if LONGLONG_CODE
+	set_lreg(reg,mode);
+	// use_reg(reg);
+#endif
+    } else {
+	set_ireg(reg,mode);
+    }
+}
+
+void
+gen_gdecl(char *n, int gpc)
+{
+    /*
+    if (stmode!=STATIC)
+	printf(".globl %s\n",n); 
+     */
+}
+
+void
+align(int t)
+{
+    int d;
+    switch(t) {
+    case CHAR: case UCHAR: return;
+    case SHORT: case USHORT: d = data_alignment & 1; break;
+    default: d = data_alignment & 3;
+    }
+    if (d) {
+        printf("\t.align 2\n");
+	data_alignment = 0;
+    }
+}
+
+static void
+ascii(char *s)
+{
+    printf("\t.string \"");
+    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",34);
+}
+
+int
+emit_string_label() {
+    int lb;
+
+    lb=fwdlabel();
+    // should put on different segement
+    cstring_mode();
+    printf(".LC%d:\n",lb);
+    return lb;
+}
+
+extern void 
+emit_string(char *s,int t)
+{
+    t = type_value(t);
+    if (car(t)==ARRAY &&  
+            (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) {
+        ascii(s);
+    } else {
+        int l = emit_string_label();
+        ascii(s);
+        emit_label(l);
+    }
+    return;
+}
+
+void
+emit_global(NMTBL *n,int a,int e)
+{
+    int t = type_value(n->ty);
+    if (e>0 && car(e)==STRING && t>0 && car(t)==ARRAY &&  
+            (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) {
+        cstring_mode();
+    } else
+	data_mode(n->nm);
+    align(a);
+    if (n && n->sc!=STATIC)
+	printf("\t.globl\t%s\n",n->nm);
+    printf("%s:\n",n->nm); 
+}
+
+void
+emit_space(int sp)
+{
+    data_mode(0);
+    printf("\t.space\t%d\n",sp);
+}
+
+void
+emit_char(int d)
+{
+    data_mode(0);
+    printf("\t.byte %d\n",d);
+}
+
+void
+emit_short(int d)
+{
+    data_mode(0);
+    printf("\t.short %d\n",d);
+}
+
+void
+emit_int(int d)
+{
+    data_mode(0);
+    align(0);
+    printf("\t.word %d\n",d);
+}
+
+void
+emit_longlong(int e)
+{
+#if LONGLONG_CODE
+    long long ll = lcadr(e);
+    data_mode(0);
+#if (ENDIAN_L==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
+}
+
+void
+emit_double(int e)
+{
+#if FLOAT_CODE
+    double d = dcadr(e);
+    data_mode(0);
+#if (ENDIAN_D==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
+}
+
+void
+emit_float(int e)
+{
+#if FLOAT_CODE
+    float f = dcadr(e);
+    data_mode(0);
+    printf("\t.long\t0x%x\n",*(int *)&f);
+#endif
+}
+
+void
+emit_address(char *s,int offset)
+{
+    data_mode(0);
+    if (offset) 
+	printf("\t.word %s+%d\n",s,offset);
+    else
+	printf("\t.word %s\n",s);
+}
+
+void
+emit_label(int labelno)
+{
+    data_mode(0);
+    printf("\t.word .L%d\n",labelno);
+}
+
+void
+emit_data_closing(NMTBL *n)
+{
+#ifdef DOT_SIZE
+    int lb;
+#endif
+    if (mode==GDECL) {
+	data_mode(0);
+#ifdef DOT_SIZE
+	lb=fwdlabel();
+	printf(".LC%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 (is_code(n)||is_function(n)) continue;
+	    if (init==0) {
+		data_mode(0);
+		init=1;
+	    }
+	    // printf(".local %s\n",n->nm);
+	    comm(n);
+	}
+    }
+}
+
+void
+local_table(void)
+{
+    NMTBL *n;
+    int init;
+    free_glist3_a(prev_const_list); prev_const_list = 0;
+    const_list_table();
+
+    init=0;
+    /* static local variables */
+    for(n=local_static_list;n;n=n->next) {
+	if (n->sc == STATIC) {
+	    if (n->dsp != -1) { /* initialized static */
+		if (init==0) {
+		    data_mode(0);
+		    init=1;
+		}
+		comm(n);
+	    }
+	}
+    }
+    text_mode(2);
+}
+
+void
+cstring_mode(int align)
+{
+    if (output_mode!=RODATA_EMIT_MODE) {
+	printf(".section\t.rodata\n\t.align 2\n");
+	output_mode = RODATA_EMIT_MODE;
+    }
+}
+
+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
+
+#if LONGLONG_CODE||FLOAT_CODE
+static void
+extern_conv(char *conv)
+{
+     code_save_stacks();
+     clear_ptr_cache();
+     extern_define(conv,0,FUNCTION,1);
+     printf("\tbl\t%s\n",conv);
+     lib_args(16);
+}
+#endif
+
+static void
+code_int_lib(char *lib,int reg,int oreg)
+{
+    int g;
+    code_save_stacks();
+    clear_ptr_cache();
+    g = list3(REGISTER_OPERAND,0,reg);
+    g = list3(REGISTER_OPERAND_1,g,oreg);
+    parallel_rassign(g);
+    extern_define(lib,0,FUNCTION,1);
+    printf("\tbl\t%s\n",lib);
+    lib_args(16);
+    set_ireg(RET_REGISTER,0);
+    if (reg!=RET_REGISTER) {
+	code_register(RET_REGISTER,reg);
+    }
+}
+
+#if FLOAT_CODE
+
+/* floating point */
+
+#define  set_double(freg) if (regs[freg]) {regs[freg]=USING_DREG;}
+#define  set_float(freg) if (regs[freg]) {regs[freg]=USING_DREG;}
+
+void
+code_cmp_dregister(int e2,int d,int label,int cond)
+{
+    char *frn;
+    use_float(d,e2);
+
+    frn = register_name(e2);
+    printf("\tcmf\t%s, #0\n",frn);
+    jcond(label,cond);
+    return;
+}
+
+static char *
+movef(int d)
+{
+    return d?"mvfd":"mvfs";
+}
+
+static char *
+fload(int d)  { return d?"ldfd":"ldfs"; }
+
+static char *
+fstore(int d) { return d?"stfd":"stfs"; }
+
+
+void
+code_dregister(int e2,int freg,int d)
+{
+    use_float(d,freg);
+	if (freg!=e2) {
+	    if (is_int_reg(e2)) error(-1);
+	    printf("\t%s\t%s, %s\n",movef(d),
+		register_name(freg),register_name(e2));
+	}
+}
+
+void
+code_dassign_gvar(int e2,int freg,int d)
+{ 
+	use_float(d,freg);
+	code_ldf(fstore(d),register_name(freg),cadr(e2),
+	    get_ptr_cache((NMTBL*)caddr(e2))," @ float");
+}
+
+void
+code_dassign_lvar(int e2,int freg,int d)
+{ 
+	use_float(d,freg);
+	lvar_intro(e2);
+	printf("\t%s\t%s, ",fstore(d),register_name(freg));
+	lvar(e2,"@ float");
+}
+
+void
+code_dassign(int e2,int freg,int d)
+{ 
+    use_float(d,freg);
+    printf("\t%s\t%s, [%s, #0] @ float\n",fstore(d),
+	register_name(freg),register_name(e2));
+}
+
+void
+code_dassign_dregister(int e2,int d,int freg) {
+    use_float(d,freg);
+    if (e2!=freg) {
+	printf("\t%s\t%s, %s\n",movef(d),
+		register_name(e2),register_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_D==0
+    code_const(code_d1(value),l);
+    code_const(code_d2(value),h);
+#else
+    code_const(code_d1(value),h);
+    code_const(code_d2(value),l);
+#endif
+}
+
+static void
+fconst(int reg,double value)
+{
+    float f = value;
+    code_const(*((int*)&f),reg);
+}
+
+void
+code_dconst(int e2,int freg,int d)
+{ 
+    double value = dcadr(e2);
+    float f = value;
+    char *frn;
+    int label,disp;
+
+    use_float(d,freg);
+	frn = register_name(freg);
+	if (value==0 || value==1 || value==10) {
+	    printf("\t%s\t%s, #%d\n",movef(d),frn,(int)value);
+	} else if (value==-1 || value==-10) {
+	    printf("\t%s\t%s, #%d\n",d?"mnfd":"mnfs",frn,(int)-value);
+	} else if (d) {
+#if ENDIAN_D==0
+	    disp = search_double_const(DCONST,
+		code_d1(value),code_d2(value),&label);
+#else
+	    disp = search_double_const(DCONST,
+		code_d2(value),code_d1(value),&label);
+#endif
+	    printf("\tldfd\t%s, .LC%d+%d\n",frn,label,disp);
+	} else {
+	    //disp = search_const(CONST,*((int*)&f),&label);
+	    printf("\tldfs\t%s, .LC%d+%d\n",frn,label,disp);
+	}
+}
+
+
+void
+code_builtin_fabsf(int e)
+{
+}
+void
+code_builtin_fabs(int e)
+{
+}
+void
+code_builtin_inff()
+{
+}
+void
+code_builtin_inf(int op)
+{
+}
+
+void
+code_dneg(int freg,int d)
+{ 
+    char *frn;
+    use_float(d,freg);
+	frn = register_name(freg);
+	printf("\t%s\t%s, %s\n",d?"mnfd":"mnfs",frn,frn);
+}
+
+void
+code_d2i0(int reg,int d)
+{ 
+    int lreg;
+	use_float(d,reg);
+	lreg = get_register();
+	printf("\tfixz\t%s, %s\n",register_name(lreg),register_name(reg));
+	set_ireg(lreg,0);
+    return;
+}
+
+void
+code_i2d0(int reg,int d)
+{ 
+    int lreg;
+	use_int(reg);
+	lreg = get_dregister(1);
+	printf("\tflt%c\t%s, %s\n",dsuffix(d),
+		register_name(lreg),register_name(reg));
+	set_dreg(lreg,0);
+    return;
+}
+
+void
+code_d2u0(int reg,int d)
+{ 
+    int lreg,reg0;
+    char *lrn,*frn,*crn;
+	//   u = (d>2.1e9)?((int)(d-2.1e9)^2147483648):(int)d
+	use_float(1,reg);
+	frn = register_name(reg);
+        if (!d) printf("\tmvfd\t%s, %s\n",frn,frn);
+	emit_dpush(1);
+	code_dconst(dlist2(DCONST,2.147483648e9),USE_CREG,1);
+	lrn = register_name(lreg = emit_dpop(d));
+	frn = register_name(freg);
+	set_ireg(reg0=get_register(),0);
+	crn = register_name(reg0);
+        printf("\tcmfe\t%s, %s\n",lrn,frn);
+        printf("\tbge\t1f\n");
+        printf("\tfixz\t%s, %s\n",crn,lrn);
+        printf("\tb\t2f\n");
+	printf("1:\n");
+        printf("\tsufd\t%s, %s, %s\n",lrn,lrn,frn);
+        printf("\tfixz\t%s, %s\n",crn,lrn);
+        printf("\teor\t%s, %s, #-2147483648\n",crn,crn);
+	printf("2:\n");
+	emit_dpop_free(lreg,d);
+    return;
+}
+
+void
+code_u2d0(int reg,int d)
+{ 
+    int tmp,freg1;
+    char *crn,*frn,*lrn;
+	use_int(reg);
+	crn = register_name(reg);
+	set_dreg(reg=get_dregister(1),0);
+	frn = register_name(reg);
+	printf("\tfltd\t%s, %s\n",frn,crn);
+	printf("\tcmp\t%s, #0\n",crn);
+        printf("\tbge\t1f\n");
+	freg1 = get_dregister(1);
+	code_dconst(dlist2(DCONST,4.29496729600000000000e9),freg1,1);
+	frn = register_name(creg);
+	lrn = register_name(freg1);
+	printf("\tadfd\t%s, %s, %s\n",frn,frn,lrn);
+	printf("1:\n");
+	if (!d)
+	    printf("\tmvfs\t%s, %s\n",frn,frn);
+	free_register(freg1);
+    return;
+}
+
+void
+code_d2f(int reg) { 
+    char *frn;
+	frn = register_name(freg);
+	printf("\tmvfs\t%s,%s\n",frn,frn);
+    return;
+}
+
+void
+code_f2d(int reg) { 
+    char *frn;
+	frn = register_name(freg);
+	printf("\tmvfd\t%s, %s\n",frn,frn);
+    return;
+}
+
+void
+code_d2i(int reg) {
+    code_d2i0(reg,1);
+}
+
+void
+code_d2u(int reg) {
+    code_d2u0(reg,1);
+}
+
+void
+code_f2i(int reg) {
+    code_d2i0(reg,0);
+}
+
+void
+code_f2u(int reg) {
+    code_d2u0(reg,0);
+}
+
+void
+code_i2d(int reg) {
+    code_i2d0(reg,1);
+}
+
+void
+code_i2f(int reg) {
+    code_i2d0(reg,0);
+}
+
+void
+code_u2d(int reg) {
+    code_u2d0(reg,1);
+}
+
+void
+code_u2f(int reg) {
+    code_u2d0(reg,0);
+}
+
+void
+code_drgvar(int e2,int d,int freg)
+{ 
+	use_float(d,freg);
+	code_ldf(fload(d),register_name(freg),cadr(e2),
+	    get_ptr_cache((NMTBL*)caddr(e2)),"");
+}
+
+
+void
+code_drlvar(int e2,int d,int freg)
+{ 
+	use_float(d,freg);
+	lvar_intro(e2);
+	printf("\t%s\t%s, ",fload(d),register_name(freg)); 
+	lvar(e2,d?"@ double":"@ float");
+}
+
+void
+code_cmp_drgvar(int e2,int reg,int d,int label,int cond)
+{ 
+    use_float(d,reg);
+    code_drgvar(e2,d,reg);
+    code_cmp_dregister(reg,d,label,cond);
+}
+
+void
+code_cmp_drlvar(int e2,int reg,int d,int label,int cond)
+{ 
+    use_float(d,reg);
+    code_drlvar(e2,d,reg);
+    code_cmp_dregister(reg,d,label,cond);
+}
+
+static void
+code_double_lib(char *lib,int to,int reg,int oreg)
+{
+    code_save_stacks();
+    clear_ptr_cache();
+    set_operands(reg,reg,oreg,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);
+    }
+}
+
+static void
+code_float_lib(char *lib,int to,int reg,int oreg)
+{
+    code_save_stacks();
+    clear_ptr_cache();
+    if (reg!=FREGISTER_OPERAND) code_dregister(FREGISTER_OPERAND,reg,0);
+    if (to!=FREGISTER_OPERAND_1) code_dregister(FREGISTER_OPERAND_1,to,0);
+    extern_conv(lib);
+    set_freg(RET_FREGISTER,0);
+    if (to!=RET_FREGISTER) {
+	code_dregister(to,RET_FREGISTER,0);
+    }
+}
+
+static void
+code_float_lib_c(char *lib,int from,int to,double value)
+{
+    code_save_stacks();
+    clear_ptr_cache();
+    set_dreg_operand(from,1);
+    fconst(FREGISTER_OPERAND_1,value);
+    extern_conv(lib);
+    set_freg(RET_FREGISTER,0);
+    if (to!=RET_FREGISTER) {
+	code_dregister(to,RET_FREGISTER,0);
+    }
+}
+
+
+void
+dtosop(int op,int reg,int e1)
+{ 
+    char *opn="";
+
+    char *grn,*frn;
+    int d;
+    int cmp=0;
+
+
+    d=(op<FOP);
+    use_float(d,reg);
+    switch(op) {
+    case DADD: opn="adfd"; break;
+    case DSUB: opn="sufd"; break;
+    case DDIV: opn="fdvd"; break;
+    case DMUL: opn="fmld"; break;
+    case DCMPGE:
+    case DCMP:  opn="cmfe"; cmp=1; break;
+    case FADD: opn="adfs"; break;
+    case FSUB: opn="sufs"; break;
+    case FDIV: opn="fdvs"; break;
+    case FMUL: opn="fmls"; break;
+    case FCMPGE:
+    case FCMP:  opn="cmfe"; cmp=1; break;
+    default:
+	error(-1); return;
+    }
+    grn = register_name(e1);
+    frn = register_name(reg);
+    if (cmp) {
+      printf("\t%s\t%s, %s\n",opn,grn,frn);
+    } else {
+      printf("\t%s\t%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;
+
+
+
+    xreg=emit_dpop(d);
+    crn=register_name(ireg);
+    use_float(d,reg);
+    frn  =register_name(reg);
+
+    code_ldf(fload(d),register_name(freg),0,ireg,"");
+    dtosop(op,reg,xreg);
+    code_ldf(fstore(d),register_name(freg),0,ireg,"");
+    emit_dpop_free(xreg,d);
+}
+
+void
+code_register_dassop(int reg,int op,int d) {
+    // reg op= dpop()
+    int  xreg;
+	xreg=emit_dpop(d);
+	dtosop(op,reg,xreg);
+	emit_dpop_free(xreg,d);
+}   
+
+static int
+code_dload_1(int d)
+{
+    int g = get_dregister(d);
+    printf("\tmvf%c\t%s,#1\n",dsuffix(d),register_name(g));
+    return g;
+}
+
+
+void
+code_dpreinc(int e1,int e2,int d,int reg) {
+    char *frn;
+    char *crn;
+    int  g,reg0;
+    char *grn;
+    int dir=caddr(e1);
+
+    if (car(e2)==DREGISTER||car(e2)==FREGISTER) {
+	crn=register_name(cadr(e2));
+	grn=register_name(g=code_dload_1(d));
+	if (reg==USE_CREG) {
+	    reg=get_dregister(d); if (!reg) error(-1);
+	    if (d) set_dreg(reg,0); else set_freg(reg,0);
+	}
+	frn=register_name(reg);
+	printf("\t%s%c\t%s, %s, %s\n",
+	    dir>0?"adf":"suf",dsuffix(d),
+	    crn,crn,grn);
+	if (use && reg!=cadr(e2)) {
+	    printf("\tmvf%c\t%s, %s\n",dsuffix(d),frn,crn);
+	}
+    } else {
+	g_expr(e2);
+	if (!is_int_reg(creg)) error(-1);
+	reg0 = ireg;
+	if (reg==USE_CREG) {
+	    reg=get_dregister(d); if (!reg) error(-1);
+	    if (d) set_dreg(reg,0); else set_freg(reg,0);
+	}
+	grn = register_name(g = code_dload_1(d));
+	frn=register_name(reg);
+	code_ldf(fload(d),frn,0,reg0,"");
+	printf("\t%s%c\t%s, %s, %s\n",
+	    dir>0?"adf":"suf",dsuffix(d),
+	    frn,frn,grn);
+	code_ldf(fstore(d),frn,0,reg0,"");
+    }
+    free_register(g);
+}
+
+void
+code_dpostinc(int e1,int e2,int d,int reg) {
+    char *frn;
+    char *crn;
+    int  g,reg0;
+    char *grn;
+    int dir=caddr(e1);
+
+    if (car(e2)==DREGISTER||car(e2)==FREGISTER) {
+	crn=register_name(cadr(e2));
+	grn=register_name(g=code_dload_1(d));
+	if (reg==USE_CREG) {
+	    reg=get_dregister(d); if (!reg) error(-1);
+	    set_freg(reg,0);
+	}
+	frn=register_name(reg);
+	if (use && reg!=cadr(e2)) {
+	    printf("\tmvf%c\t%s, %s\n",dsuffix(d),frn,crn);
+	}
+	printf("\t%s%c\t%s,%s,%s\n",dir>0?"adf":"suf",
+	    dsuffix(d),crn,crn,grn);
+    } else {
+	g_expr(e2);
+	if (!is_int_reg(creg)) error(-1);
+	crn=register_name(reg0=ireg);
+	if (reg==USE_CREG) {
+	    reg=get_dregister(d); if (!reg) error(-1);
+	    set_freg(reg,0);
+	}
+	frn=register_name(reg);
+	grn = register_name(g = code_dload_1(d));
+	code_ldf(fload(d),frn,0,reg0,"");
+	printf("\t%s%c\t%s, %s, %s\n",
+	    dir>0?"adf":"suf",dsuffix(d),
+	    grn,frn,grn);
+	code_ldf(fstore(d),grn,0,reg0,"");
+    }
+    free_register(g);
+}
+
+
+int
+drexpr(int e1, int e2,int l1, int op,int cond)
+{
+    int op1=0;
+    char *opn=0;
+    if (!cond) {
+	switch(op) {
+	    case FOP+GT:
+		return drexpr(e2,e1,l1,FOP+GE,1);
+	    case FOP+GE:
+		return drexpr(e2,e1,l1,FOP+GT,1);
+	    case FOP+EQ:
+		op=FOP+NEQ; break;
+	    case FOP+NEQ:
+		op=FOP+EQ; break;
+	    case DOP+GT:
+		return drexpr(e2,e1,l1,DOP+GE,1);
+	    case DOP+GE:
+		return drexpr(e2,e1,l1,DOP+GT,1);
+	    case DOP+EQ:
+		op=DOP+NEQ; break;
+	    case DOP+NEQ:
+		op=DOP+EQ; break;
+	}
+    }
+    switch(op) {
+    case FOP+GT:  op1=FOP+CMP;   opn = "bgt"; break;
+    case FOP+GE:  op1=FOP+CMPGE; opn = "bge"; break;
+    case FOP+EQ:  op1=FOP+CMP;   opn = "beq"; break;
+    case FOP+NEQ: op1=FOP+CMP;   opn = "bne"; break;
+    case DOP+GT:  op1=DOP+CMP;   opn = "bgt"; break;
+    case DOP+GE:  op1=DOP+CMPGE; opn = "bge"; break;
+    case DOP+EQ:  op1=DOP+CMP;   opn = "beq"; break;
+    case DOP+NEQ: op1=DOP+CMP;   opn = "bne"; break;
+    default: error(-1);
+    }
+    g_expr(list3(op1,e2,e1));
+    printf("\t%s\t.L%d\n",opn,l1);
+    return l1;
+}
+
+int emit_dpop(int d)
+{ 
+    int xreg,reg;
+    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;
+}
+
+
+void
+emit_dpop_free(int e1,int d)
+{ 
+    free_register(e1);
+}
+
+void
+emit_dpush(int d)
+{ 
+    int new_reg;
+    if (!is_float_reg(creg)) error(-1);
+    if (reg_sp>MAX_MAX) error(-1);
+    new_reg = get_dregister(d);       /* ?????????? */
+    reg_stack[reg_sp++] = freg;     /* push ???????????????? */
+    creg = freg = new_reg;
+}
+
+#endif
+
+#if LONGLONG_CODE
+
+
+/* 64bit int part */
+
+int
+lrexpr_bool(int e1, int reg)
+{       
+    return 0;
+}
+
+int
+lrexpr(int e1, int e2,int l1, int op,int cond)
+{
+    int reg,regh,regl,e3h,e3l;
+    int e3,l2;
+    g_expr(e1);
+    emit_lpush();
+    g_expr(e2);
+    e3 = emit_lpop();
+    if (!is_longlong_reg(creg)) error(-1);
+    reg = lreg;
+    l2 = fwdlabel();
+    regh = reg; regl = reg;
+    e3h =  e3;  e3l = e3;
+    switch(op) {
+    case LOP+GT: case LOP+GE:
+	pcond(GT,  regh,e3h,0,1,cond?l1:l2,COND_BRANCH);
+	pcond(NEQ, regh,e3h,0,1,cond?l2:l1,COND_BRANCH);
+        break;
+    case LOP+UGT: case LOP+UGE:
+	pcond(UGT, regh,e3h,0,1,cond?l1:l2,COND_BRANCH);
+	pcond(NEQ, regh,e3h,0,1,cond?l2:l1,COND_BRANCH);
+        break;
+    case LOP+EQ:
+	pcond(EQ, regh,e3h,0,0,cond?l2:l1,COND_BRANCH);
+        break;
+    case LOP+NEQ:
+	pcond(EQ, regh,e3h,0,0,cond?l1:l2,COND_BRANCH);
+        break;
+    default:
+        error(-1);
+    }
+    pcond(op%LOP,regl,e3l,0,cond,l1,COND_BRANCH);
+    fwddef(l2);  
+    emit_lpop_free(e3);
+    return l1;
+}
+
+void
+code_cmp_lregister(int reg,int label,int cond)
+{
+    use_longlong(reg);
+    printf("\torr\t%s, %s, %s\n",
+		lregister_name_low(reg),
+		lregister_name_low(reg),
+		lregister_name_high(reg));
+    code_cmp_register((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);
+}
+
+#endif
+#if LONGLONG_CODE||FLOAT_CODE
+
+int
+emit_lpop()
+{
+    int xreg,reg;
+    xreg=reg_stack[--reg_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_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_L==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_L==0
+    printf("\tstr\t%s, ",crn_l);lvar(e2,"");
+    printf("\tstr\t%s, ",crn_h);lvar(e2+SIZE_OF_INT,"");
+#else
+    printf("\tstr\t%s, ",crn_h);lvar(e2,"");
+    printf("\tstr\t%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);
+    }
+}
+
+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 (reg_sp>MAX_MAX) error(-1);
+    new_reg = get_lregister();        /* ??????????(?) */
+    reg_stack[reg_sp++] = creg;     /* push ???????????????? */
+    lreg = creg = new_reg;
+}
+
+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_L==0
+    code_ldf("ldr",crn_l,cadr(e1),r,"");
+    code_ldf("ldr",crn_h,cadr(e1)+SIZE_OF_INT,r,"");
+#else
+    code_ldf("ldr",crn_h,cadr(e1),r,"");
+    code_ldf("ldr",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("\tlqd\t%s, ",crn_l); lvar(e1,"");
+    printf("\tlqd\t%s, ",crn_h); lvar(e1+SIZE_OF_INT,"");
+}
+
+#endif
+#if LONGLONG_CODE
+
+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_L==0
+    code_const(code_l1(lcadr(e1)),(creg));
+    code_const(code_l2(lcadr(e1)),(creg));
+#else
+    code_const(code_l1(lcadr(e1)),(creg));
+    code_const(code_l2(lcadr(e1)),(creg));
+#endif
+}
+
+void
+code_lneg(int creg)
+{
+
+    char *rh,*rl;
+    use_longlong(creg);
+    rl=lregister_name_low(creg);
+    rh=lregister_name_high(creg);
+    printf("\trsbs\t%s, %s, #0\n",rl,rl);
+    printf("\trsc\t%s, %s, #0\n",rh,rh);
+}
+
+static void
+code_longlong_lib(char *lib,int reg,int oreg)
+{
+    code_save_stacks();
+    clear_ptr_cache();
+    set_operands((reg),(reg),(oreg),(oreg));
+    extern_conv(lib);
+    // set_lreg(RET_LREGISTER,0);
+}
+
+#define check_lreg(reg) lmove(reg,RET_LREGISTER)
+
+void
+ltosop(int op,int reg,int oreg)
+{
+    int dx = -1;
+    int ox = -1;
+    char *orn_h,*crn_h;
+    char *orn_l,*crn_l;
+
+    // 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_longlong_lib("__ashldi3",reg,oreg);
+	check_lreg(reg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case LRSHIFT:
+	code_longlong_lib("__ashrdi3",reg,oreg);
+	check_lreg(reg);
+	if(ox!=-1) free_register(ox);
+	return;
+    case LURSHIFT:
+	code_longlong_lib("__lshrdi3",reg,oreg);
+	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:
+        printf("\tadds\t%s, %s, %s\n",crn_l,crn_l,orn_l);
+        printf("\tadc\t%s, %s, %s\n",crn_h,crn_h,orn_h);
+	break;
+    case LSUB:
+        printf("\tsubs\t%s, %s, %s\n",crn_l,crn_l,orn_l);
+        printf("\tsbc\t%s, %s, %s\n",crn_h,crn_h,orn_h);
+	break;
+    case LCMP:
+	error(-1);
+	break;
+    case LBAND: 
+	printf("\tand\t%s, %s, %s\n",crn_l,crn_l,orn_l);
+	printf("\tand\t%s, %s, %s\n",crn_h,crn_h,orn_h);
+	break;
+    case LEOR: 
+	printf("\teor\t%s, %s, %s\n",crn_l,crn_l,orn_l);
+	printf("\teor\t%s, %s, %s\n",crn_h,crn_h,orn_h);
+	break;
+    case LBOR:
+	printf("\torr\t%s, %s, %s\n",crn_l,crn_l,orn_l);
+	printf("\torr\t%s, %s, %s\n",crn_h,crn_h,orn_h);
+	break;
+    case LMUL:
+    case LUMUL:
+	code_longlong_lib("__muldi3",reg,oreg);
+	check_lreg(reg);
+	break;
+    case LDIV:
+	code_longlong_lib("__divdi3",reg,oreg);
+	check_lreg(reg);
+	break;
+    case LUDIV:
+	code_longlong_lib("__udivdi3",reg,oreg);
+	check_lreg(reg);
+	break;
+    case LMOD:
+	code_longlong_lib("__moddi3",reg,oreg);
+	check_lreg(reg);
+	break;
+    case LUMOD:
+	code_longlong_lib("__umoddi3",reg,oreg);
+	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)
+{
+    long long v;
+    if (car(e)==LCONST) {
+	v = lcadr(e);
+    } else if (car(e)==CONST) {
+	v = cadr(e);
+    } else return 0;
+    
+    switch(op) {
+    case LMUL: case LUMUL: /* case LDIV: */ case LUDIV:
+	return ilog(v);
+    case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT:
+	return 0<v&&v<=64;
+    case LADD:
+    case LSUB:
+    case LBOR:
+    case LEOR: case LBAND:
+	return (is_stage1_const(v,0)>0)
+	    && (is_stage1_const(v>>32,0)>0);
+    default:
+	return 0;
+    }
+}
+
+void
+loprtc(int op,int creg,int e)
+{
+    char *crn_h;
+    char *crn_l;
+    char *grn;
+    int v=0;
+    int vh=0;
+    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); vh = lcadr(e)>>32; }
+    else if (car(e)==CONST) {
+	v = cadr(e);
+	vh = (v<0)?-1:0;
+    }
+
+    switch(op) {
+    case LMUL: case LUMUL:
+        v=ilog(v);
+    case LLSHIFT:
+    case LULSHIFT:
+        if (v==0) return;
+        if (v==32) {
+            code_register((creg),(creg));
+            code_const(0,(creg));
+            return;
+        } else if (v>31) {
+            printf("\tmov\t%s, %s, lsl #%d\n",crn_h,crn_l,v-32);
+            code_const(0,(creg));
+            return;
+        }
+	greg = get_register();
+	grn = register_name(greg);
+	printf("\tmov\t%s, %s, lsl #%d\n",crn_h,crn_h,v);
+	printf("\tmov\t%s, %s, lsr #%d\n",grn,crn_l,32-v);
+	printf("\torr\t%s, %s,%s\n",crn_h,crn_h,grn);
+	printf("\tmov\t%s, %s, lsl #%d\n",crn_l,crn_l,v);
+	free_register(greg);
+	return;
+    case LDIV:
+        v=ilog(v);
+    case LRSHIFT:
+        if (v==0) return;
+        if (v==32) {
+            code_register((creg),(creg));
+            printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l);
+            return;
+        } else if (v>31) {
+            printf("\tmov\t%s, %s, asr #%d\n",crn_l,crn_h,v-32);
+            printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l);
+            return;
+        }
+	greg = get_register();
+	grn = register_name(greg);
+	printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_l,v);
+	printf("\tmov\t%s, %s, lsl #%d\n",grn,crn_h,32-v);
+	printf("\torr\t%s, %s,%s\n",crn_l,crn_l,grn);
+	printf("\tmov\t%s, %s, asr #%d\n",crn_h,crn_h,v);
+	free_register(greg);
+	return;
+    case LUDIV:
+        v=ilog(v);
+    case LURSHIFT:
+        if (v==0) return;
+        if (v==32) {
+            code_register((creg),(creg));
+            code_const(0,(creg));
+            return;
+        } else if (v>31) {
+            printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_h,v-32);
+            code_const(0,(creg));
+            return;
+        }
+	greg = get_register();
+	grn = register_name(greg);
+	printf("\tmov\t%s, %s, lsl #%d\n",grn,crn_h,32-v);
+	printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_l,v);
+	printf("\torr\t%s, %s,%s\n",crn_l,grn,crn_l);
+	printf("\tmov\t%s, %s, lsr #%d\n",crn_h,crn_h,v);
+	free_register(greg);
+	return;
+    case LADD:
+        printf("\tadds\t%s, %s, #%d\n",crn_l,crn_l,v);
+        printf("\tadc\t%s, %s, #%d\n",crn_h,crn_h,vh);
+	break;
+    case LSUB:
+        printf("\tsubs\t%s, %s, #%d\n",crn_l,crn_l,v);
+        printf("\tsbc\t%s, %s, #%d\n",crn_h,crn_h,vh);
+	break;
+    case LBAND: 
+	printf("\tand\t%s, %s, #%d\n",crn_l,crn_l,v);
+	printf("\tand\t%s, %s, #%d\n",crn_h,crn_h,vh);
+	break;
+    case LEOR: 
+	printf("\teor\t%s, %s, #%d\n",crn_l,crn_l,v);
+	printf("\teor\t%s, %s, #%d\n",crn_h,crn_h,vh);
+	break;
+    case LBOR:
+	printf("\torr\t%s, %s, #%d\n",crn_l,crn_l,v);
+	printf("\torr\t%s, %s, #%d\n",crn_h,crn_h,vh);
+	break;
+    default:
+	error(-1);
+    }
+    if (dx!=-1) free_register(dx);
+}
+
+
+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!=(lreg))
+	printf("\tori\t%s, %s, 0\n",crn_l,crn);
+    printf("\tmov\t%s, %s, asr #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!=(lreg))
+	printf("\tori\t%s, %s, 0\n",crn_l,crn);
+    printf("\tmov\t%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!=(reg0)) {
+	printf("\tori\t%s, %s, 0\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
+    code_assign_input_double_long(
+	list2(LREGISTER,LREGISTER_OPERAND),list2(FREGISTER,freg)) ;
+    extern_conv("__fixdfdi");
+    set_lreg(RET_LREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_LREGISTER) {
+	use_longlong(reg);
+    }
+}
+
+void
+code_d2ull(int reg)
+{
+    code_assign_input_double_long(
+	list2(LREGISTER,LREGISTER_OPERAND),list2(FREGISTER,freg)) ;
+    extern_conv("__fixunsdfdi");
+    set_lreg(RET_LREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_LREGISTER) {
+	use_longlong(reg);
+    }
+}
+
+void
+code_f2ll(int reg)
+{
+    code_assign_input_float_int(list2(REGISTER,REGISTER_OPERAND),list2(FREGISTER,freg));
+    extern_conv("__fixsfdi");
+    set_lreg(RET_LREGISTER,0);
+    if (reg!=USE_CREG&&reg!=RET_LREGISTER) {
+	use_longlong(reg);
+    }
+}
+
+void
+code_f2ull(int reg)
+{
+    code_assign_input_float_int(list2(REGISTER,REGISTER_OPERAND),list2(FREGISTER,freg));
+    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
+{
+    // v should be 8bit const with 2's shift
+    if (v>0) {
+	printf("\tadds\t%s, %s, #%d\n", 
+		lregister_name_low(rreg),lregister_name_low(dreg), v);
+	printf("\tadc\t%s, %s, #0\n", 
+		lregister_name_high(rreg),lregister_name_high(dreg));
+    } else {
+	printf("\tsubs\t%s, %s, #%d\n", 
+		lregister_name_low(rreg),lregister_name_low(dreg), -v);
+	printf("\tsbc\t%s, %s, #0\n", 
+		lregister_name_high(rreg),lregister_name_high(dreg));
+    }
+}
+
+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 ((lreg)==edx || (lreg)==edx) {
+	edx0 = get_register(); if(!edx0) error(-1);
+	printf("## lassop\n\tori\t%s, %s, 0\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);
+    if (reg!=lreg)
+	free_register(reg);
+}
+
+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)*4),reg,0); 
+            reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET;
+	    free_register(reg);
+        }
+    }
+#if FLOAT_CODE
+    for(i=0;i<reg_sp;i++) {
+        if ((reg=reg_stack[i])>=0) {
+            code_dassign_lvar(
+                (reg_stack[i]=new_lvar(SIZE_OF_DOUBLE)),reg,1); 
+            reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET;
+	    free_register(reg);
+        }
+    }
+#endif
+#if LONGLONG_CODE
+    for(i=0;i<reg_sp;i++) {
+        if ((reg=reg_stack[i])>=0) {
+            code_lassign_lvar(
+                (reg_stack[i]=new_lvar(SIZE_OF_LONGLONG)),reg); 
+            reg_stack[i]= reg_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"); */
+}
+
+#if CASE_CODE
+
+int
+code_table_jump_p(int delta) { return delta==1||delta==2||delta==4; }
+
+void
+code_table_jump(int l,int csvalue,int delta,int max,int min,int dlabel)
+{
+    int t,regsv;
+    char *trn;
+
+    regsv = regs[csvalue]; regs[csvalue] = 1;
+    trn = register_name(t=get_register());
+    regs[csvalue] = regsv;
+
+    code_add(t,-min,csvalue);
+    switch(delta) {
+    case 1: 
+	code_cmpdimm(max-min,t,dlabel,-1);
+	printf("\tldrls\tpc, [pc, %s, asl #2]\n",trn);
+	break;
+    case 2:
+	printf("\ttst\t%s, #1\n",trn);
+	printf("\tbne\t.L%d\n",dlabel);
+	code_cmpdimm(max-min,t,dlabel,-1);
+	printf("\tldrls\tpc, [pc, %s, asl #1]\n",trn); break;
+	break;
+    case 4:
+	printf("\ttst\t%s, #3\n",trn);
+	printf("\tbne\t.L%d\n",dlabel);
+	code_cmpdimm(max-min,t,dlabel,-1);
+	printf("\tldrls\tpc, [pc, %s]\n",trn); break;
+	break;
+    default:
+	error(-1);
+    }
+    printf("\tbr\t.L%d\n",dlabel);
+
+    free_register(t);
+}
+
+void
+code_table_open(int l)
+{
+    output_mode = DATA_EMIT_MODE;
+    printf("\t.align 2\n");
+    fwddef(l);
+}
+
+void
+code_table_value(int label,int table_top)
+{
+    printf("\t.word .L%d\n",label);
+}
+
+void
+code_table_close()
+{
+}
+
+#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 *pbitpos, int *pbitsize,
+	int *psign,int *pbitsz,int *palign,int *pl)
+{ 
+    int sign=0,bitsz=0; 
+    int align=0,l=0;
+    switch(cadr(type)) {   /* value type */
+    case INT:	        sign=1; break; 
+    case UNSIGNED:	break; 
+    case CHAR:          sign=1; break; 
+    case UCHAR: 	break; 
+    case SHORT:         sign=1; break; 
+    case USHORT:        sign=1; break; 
+    case LONGLONG:      sign=1; l=1; break; 
+    case ULONGLONG:     l=1; break; 
+    default: error(-1);
+    }
+    if (car(caddr(type))>0) { /* store type */
+	if (car(car(caddr(type)))==STRUCT) {
+	    bitsz=64+32; align=4; l=2;
+	} else error(-1);
+    } else {
+	switch(car(caddr(type))) { 
+	case INT:	    bitsz=32; align=4; break; 
+	case UNSIGNED:	    bitsz=32; align=4; break; 
+	case CHAR:          bitsz= 8; align=1; break; 
+	case UCHAR: 	    bitsz= 8; align=1; break; 
+	case SHORT:         bitsz=16; align=2; break; 
+	case USHORT:        bitsz=16; align=2; break; 
+	case LONGLONG:      bitsz=64; align=4; l=1; break; 
+	case ULONGLONG:     bitsz=64; align=4; l=1; break; 
+	default: error(-1);
+	}
+    }
+    *pbitpos = cadr(caddr(type));
+    *pbitsize = caddr(caddr(type));
+    *psign = sign;
+    *pbitsz = bitsz;
+    *palign = align;
+    *pl = l;
+}
+
+/*
+      bit field alignment calcuration
+        this is architecture depenedent
+ */
+
+#define NON_ALIGNED_BFD 1
+
+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,bitpos0;
+    set_bitsz(type,&bitpos0,&bitsize,&sign,&bitsz,&align,&l);
+
+    if (bitsize>bitsz) { error(BTERR); bitsize = bitsz; }
+
+    /* bfd means previous bit field bit offset */
+    if (bitpos) {
+	/* previous field is bit field and spaces may remain */
+	/* calc previsous offset */
+	offset-=(bitpos+7)/8;
+
+#ifdef NON_ALIGNED_BFD
+	/* code for non-aligned non-hole bit-field */
+
+	/* remove extra previous offset from bitpos */
+	while(bitpos>align*8) {
+	    i = ((offset+(align))&~(align-1))-offset;
+	    offset+=i; bitpos-=i*8;
+	}
+	if (bitpos+bitsize > bitsz) {
+	    int stype=UNSIGNED;
+
+	    /* rewind extra previous offset */
+	    bitpos = *bfd; offset=*poffset;
+	    offset-=(bitpos+7)/8;
+
+	    /* extend store type to allow |---===|===---| */
+	    switch(car(caddr(type))) { 
+	    case INT:	case UNSIGNED:	
+		stype=ULONGLONG; align=4; break;
+	    case CHAR:   case UCHAR: 	
+		stype=USHORT; align=2; break;
+	    case SHORT:   case USHORT:      	
+		stype=UNSIGNED; align=4; break;
+	    case ULONGLONG: case LONGLONG:   	
+		/* dummy struct type. fields are never used */
+		stype=list4(STRUCT,12,0,0);align=4;break;
+	    default: error(-1);
+	    }
+	    /* remove extra previous offset from bitpos again */
+	    while(bitpos>align*8) {
+		i = ((offset+(align))&~(align-1))-offset;
+		offset+=i; bitpos-=i*8;
+	    }
+	    bitsz = size(stype)*8;
+	    /* fix store type */
+	    car(caddr(type)) = stype;
+	}
+#endif
+
+	/* previous remaining bit space can contain this type? */
+	i= offset;
+	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==bitsz)?0:i;
+	        *sz = (i+7)/8;
+#ifdef BITPOS_DEBUG
+    printf("## %d: bitpos=%d bitsize=%d bitsz=%d offset=%d\n",lineno,bitpos,bitsize,bitsz,*poffset);
+#endif
+		return l;
+	    } 
+	}
+    }
+
+    /* first bit-field or no remaining bits */
+
+    if ((i=(offset & (align-1)))) {
+	*poffset = (offset += (align-i));
+    }
+    bitpos = 0;
+    *bfd = (bitsize==bitsz)?0:bitsize;
+    *sz = (bitsize+7)/8;
+#ifdef BITPOS_DEBUG
+    printf("## %d: bitpos=%d bitsize=%d bitsz=%d offset=%d\n",lineno,bitpos,bitsize,bitsz,*poffset);
+#endif
+    return bitpos;
+}
+
+/* bit field value */
+
+/* reg contains container value, result should be in reg */
+extern void
+code_bit_field(int type,int adr,int reg)
+{
+    int sign,bitsz,l,align;
+    int bitsize,bitpos;
+    int i,size;
+    set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l);
+    size = bitsz/8;
+// printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz);
+    /* this implementation returns -1 for int i:1; */
+    if (l==1) {
+#if LONGLONG_CODE
+	// use_int(adr);
+	use_longlong(reg);
+        lload(adr,reg,0);
+	/* 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 if (l==2) {   /* three int container */
+	int lvalue;
+	// use_int(adr);
+	use_longlong(reg);
+	lvalue = get_register(); 
+	code_register(adr,lvalue); adr = lvalue;
+   /*
+
+                        <-----bitsize--------------->
+                        hhhhhh  mmmmmmmmmmmm  lllllll
+   lllll  00000000000  mmmmmmmmmmmm  0000000  hhhhhhh 
+  |-----||-----------||------------||-------||-------|
+         <-bitpos--->
+  <----------------bitsz----------------------------->
+  <-----32----------> <---32------> <----32---------->
+      (r0:r1) <<= bitsz-bitsize-bitbos
+      rest >> =  b;
+      rest << =  a;   (b>a)   ==>    rest >> (b-a)
+                  (64+32-bitsize -bitpos - (bitsz-bitsize))
+                 = 64+32 -bitsz -bitbpos
+   */
+	/* load hhhhh */
+	code_ld(cload(0,0),(reg),SIZE_OF_INT*2,adr,cext_at(0,0));
+	/* load mmmmmm */
+	code_ld(cload(0,0),(reg),SIZE_OF_INT,adr,cext_at(0,0));
+	i = 64-(bitsize-(32-bitpos));
+	loprtc(LLSHIFT,reg,list2(CONST,i));
+	if (i<0||64<=i) error(-1);
+	/* load lllll */
+	code_ld(cload(0,0),adr,0,adr,cext_at(0,0));
+	i = (bitsize-(32-bitpos))-32;
+	oprtc(URSHIFT,adr,list2(CONST,i));
+	if (i<0||32<=i) error(-1);
+	printf("\tadd\t%s,%s,%s\n",
+			    register_name((reg)),
+			    register_name((reg)),
+			    register_name(adr));
+	i = 64-bitsize;
+	loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i));
+	if (i<0||64<=i) error(-1);
+	free_register(adr);
+#endif
+    } else {
+	// use_int(adr);
+	use_int(reg);
+	code_ld(cload(size,sign),reg,0,adr,cext_at(0,0));
+	/* 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("\torr\t%s, %s, %s\n",trn,crn,trn);
+	/* do conjunction  */
+	printf("\tand\t%s, %s, %s\n",lrn,trn,lrn);
+	/* make or-mask  */
+	code_const(mask,tmp);
+	printf("\tand\t%s, %s, %s\n",trn,crn,trn);
+	/* do disjunction  */
+	printf("\torr\t%s, %s, %s\n",crn,trn,lrn);
+}
+
+extern void
+code_bit_replace(int adr,int value,int type)
+{
+    int sign,bitsz,l,align;
+    int bitsize,bitpos;
+    int mask = 0;
+    int tmp = -1,lvalue,size;
+    char *crn,*lrn,*trn;
+    set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l);
+    size = bitsz/8;
+// printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz);
+    if (l==1) {
+#if LONGLONG_CODE
+	int tmp2;
+        // use_int(adr);
+        lvalue = get_lregister();
+	tmp2 = get_register();
+	code_register(adr,tmp2); adr = tmp2;
+        lload(adr,lvalue,0);
+	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);
+	}
+        code_lassign(adr,value);
+	free_register(lvalue);
+	free_register(adr);
+    } else if (l==2) {
+	int i;
+	int tmpvar;
+        // use_int(adr);
+	use_longlong(value);
+	lvalue = get_register();
+	code_register(adr,lvalue); adr = lvalue;
+        tmpvar=new_lvar(SIZE_OF_LONGLONG);
+	code_lassign_lvar(tmpvar,value);
+	trn = register_name(tmp = get_register());
+
+        /* make and-mask upper */
+	i=bitpos;
+	if (i) 
+	    oprtc(LSHIFT,(value),list2(CONST,i));
+	if (i<0||32<=i) error(-1);
+	crn = lregister_name_low(value);
+	code_ld(cload(0,0),(value),0,adr,cext_at(0,0));
+	lrn = lregister_name_high(value);
+        mask = make_mask(0,31-bitpos);
+	make_mask_and_or(mask,tmp,trn,crn,lrn);
+	printf("\t%s\t%s, 0(%s)\n",cstore(0),crn,register_name(adr));
+/*
+                        <-----bitsize--------------->
+                        hhhhhh  mmmmmmmmmmmm  lllllll
+   lllll  00000000000  mmmmmmmmmmmm  0000000  hhhhhhh 
+  |-----||-----------||------------||-------||-------|
+         <-bitpos--->
+  <----------------bitsz----------------------------->
+  <-----32----------> <---32------> <----32---------->
+ */
+        /* store middle */
+	code_lrlvar(tmpvar,value);
+	i=32-bitpos;
+	if (i)
+	    loprtc(LRSHIFT,value,list2(CONST,i));
+	if (i<0||64<=i) error(-1);
+	printf("\t%s\t%s, 16(%s)\n",cstore(0),crn,register_name(adr));
+
+        /* make and-mask lower */
+	code_ld(cload(0,0),(value),8,adr,cext_at(0,0));
+	if (i<0||64<=i) error(-1);
+	mask = make_mask(bitsz-bitpos-bitsize,31);
+	make_mask_and_or(mask,tmp,trn,lrn,crn);
+	printf("\t%s\t%s, 32(%s)\n",cstore(0),lrn,register_name(adr));
+	free_lvar(tmpvar);
+	free_register(adr);
+#endif
+    } else {
+	// use_int(adr);
+	use_int(value);
+        lvalue = get_register();
+	code_ld(cload(size,sign),lvalue,0,adr,cext_at(0,0));
+	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);
+        code_assign(adr,size,value);
+	free_register(lvalue);
+    }
+    if (tmp!=-1) free_register(tmp);
+    if (use) {
+       code_bit_field(type,adr,USE_CREG);
+    }
+}
+
+
+static void
+make_mask_and_or_const(int mask,char *crn,int c)
+{
+    char *trn;
+    int tmp = -1;
+    int m;
+// printf("## mask 0x%08x ~0x%08x\n",mask,~mask);
+    if ((m=(~mask|c))!=-1) {
+	if (is_stage1_const(m,0)>0) {
+	    printf("\tand\t%s, %s, #%d\n",crn,crn,m);
+	} else {
+	    trn = register_name(tmp=get_register());
+	    code_const((~mask|c),tmp);
+	    /* do conjunction  */
+	    printf("\tand\t%s, %s, %s\n",crn,trn,crn);
+	}
+    }
+    if (tmp!=-1) { free_register(tmp); tmp=-1; }
+    /* make or-mask  */
+    c = mask&c;
+    if (c!=0) {
+	/* do disjunction  */
+	if (is_stage1_const(c,0)>0) {
+	    printf("\torr\t%s, %s, #%d\n",crn,crn,c);
+	} else {
+	    trn = register_name(tmp=get_register());
+	    code_const(c,tmp);
+	    printf("\torr\t%s, %s, %s\n",crn,trn,crn);
+	}
+    }
+    if (tmp!=-1) free_register(tmp);
+}
+
+extern void
+code_bit_replace_const(int value,int adr,int type)
+{
+    int sign,bitsz,l,align;
+    int bitsize,bitpos,size;
+    int mask = 0;
+    int c;
+    int lvalue;
+#if LONGLONG_CODE
+    long long lc;
+    int tmp;
+#endif
+    char *crn;
+    set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l);
+    size = bitsz/8;
+// printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz);
+    if (l==1) {
+#if LONGLONG_CODE
+        use_int(adr);
+        lvalue = get_lregister();
+        lload(adr,lvalue,0);
+	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);
+	}
+        code_lassign(adr,lvalue);
+	free_register(adr);
+        free_register(lvalue);
+    } else if (l==2) {  // three int container
+	char *trn;
+/*
+                        hhhhhh  mmmmmmmmmmmm  lllllll
+   lllll  00000000000  mmmmmmmmmmmm  0000000  hhhhhhh 
+  |-----||-----------||------------||-------||-------|
+ */
+	use_int(adr);
+	crn = register_name(adr);
+	trn = register_name(tmp = get_register());
+	/* shift right */
+	lc = lcadr(value);
+	/* make and-mask upper */
+	code_ld(cload(0,0),tmp,0,adr,cext_at(0,0));
+	mask = make_mask(0,31-bitpos);
+	make_mask_and_or_const(mask,trn,(int)(lc<<bitpos));
+	printf("\t%s\t%s, 0(%s)\n",cstore(0),trn,crn);
+	/* store middle */
+	code_const((int)(lc>>(32-bitpos)),tmp);
+	printf("\t%s\t%s, 16(%s)\n",cstore(0),trn,crn);
+	/* make and-mask lower */
+	code_ld(cload(0,0),tmp,8,adr,cext_at(0,0));
+	mask = make_mask(bitsz-bitpos-bitsize,31);
+	make_mask_and_or_const(mask,trn,(int)(lc>>(64-bitpos)));
+	printf("\t%s\t%s, 32(%s)\n",cstore(0),trn,crn);
+	free_register(tmp);
+#endif
+    } else {
+	use_int(adr);
+	lvalue = get_register();
+	code_ld(cload(size,sign),lvalue,0,adr,cext_at(0,0));
+	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);
+        code_assign(adr,size,lvalue);
+        free_register(lvalue);
+    }
+    if (use) {
+        code_bit_field(type,adr,USE_CREG);
+    }
+}
+
+
+#endif
+
+/* end */