view mc-code-powerpc.c @ 935:7672a37e7545 default tip

Raspbery PI ARM support begin
author kono
date Sat, 24 Dec 2016 03:02:57 +0000
parents 35b339b36c88
children
line wrap: on
line source

/* Micro-C Code Generation Part for Power PC (Mac OS X) */

/*
************************************************************************
** Copyright (C) 2006 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"

#include "mc-include.c"

// #undef __APPLE__

static
char *init_src0 = 
#ifdef __APPLE__
"\
#define __ppc__ 1\n\
#define __BIG_ENDIAN__ 1\n\
#define __STDC__ 1\n\
#define __GNUC__ 1\n\
#define __inline inline\n\
#define __inline__ inline\n\
#define __builtin_va_list int\n\
#define __builtin_va_start(ap,arg) ap=(((int)(&arg))+sizeof(arg))\n\
#define __builtin_va_arg(ap,type)  (*((type *)ap)++)\n\
#define alloca __builtin_alloca\n\
#define    __FLT_MIN__  1.17549435e-38F\n\
#define    __DBL_MIN__ 2.2250738585072014e-308\n\
#define    __LDBL_MIN__ 2.00416836000897277799610805135016e-292L\n\
"
#else 
"\
#define __inline inline\n\
#define __extension__\n\
#define __const const\n\
#define __inline__ inline\n\
typedef struct __builtin_va_list { \\\n\
    long long_last; \\\n\
    long float_first; \\\n\
    long float_last; \\\n\
    long stack_top; \\\n\
    long arg; \\\n\
    long top; \\\n\
} __builtin_va_list; \\\n\
 \\\n\
#define __builtin_va_start(__ap0,v) \\\n\
{ \\\n\
    __builtin_va_list *__ap = &__ap0; \\\n\
    long __top = __ap->top = (long)&__my_va_list; \\\n\
    __ap->long_last = __top +32; \\\n\
    __ap->float_first = __ap->long_last; \\\n\
    __ap->stack_top = __top+32+64+8; \\\n\
    long __adr = (long)(&v) + sizeof(v); \\\n\
    if (__adr >= __ap->stack_top) __ap->arg = __ap->float_first = __adr; \\\n\
    if (__builtin_types_compatible_p(typeof(v),double))  \\\n\
        __ap->float_first = __adr; \\\n\
    __ap->arg = __adr; \\\n\
} \\\n\
\n\
#define __builtin_va_arg(__ap0,type) ({ \\\n\
    __builtin_va_list *__ap = &__ap0; \\\n\
    long __arg; \\\n\
    if (__builtin_types_compatible_p(type,double)  \\\n\
            && __ap->float_first < __ap->stack_top) { \\\n\
        __arg = __ap->float_first; \\\n\
        __ap->float_first = __ap->float_first+8; \\\n\
        if (__ap->float_first==__ap->float_last) \\\n\
            __ap->float_first = __ap->stack_top;\\\n\
    } else { \\\n\
        if (__builtin_types_compatible_p(type,long long)) {  \\\n\
            if (__ap->arg==__ap->top+4) __ap->arg += 4; \\\n\
            __arg = __ap->arg; \\\n\
            __ap->arg += 8; \\\n\
            if (__ap->arg==__ap->top+16+16) \\\n\
                __ap->arg = __ap->stack_top; \\\n\
        } else { \\\n\
            __arg = __ap->arg; \\\n\
            __ap->arg = __ap->arg+sizeof(type); \\\n\
            if (__ap->arg==__ap->long_last) \\\n\
                __ap->arg = __ap->stack_top; \\\n\
        } \\\n\
    } \\\n\
    *((type *)(__arg)); \\\n\
}) \\\n\
\n"

"// #define __builtin_va_arg(ap,type)  (*((type *)__builtin_va_next((type),&ap)))\n\
#define alloca __builtin_alloca\n\
#define __DBL_MIN_EXP__ (-1021)\n\
#define __FLT_MIN__ 1.17549435e-38F\n\
#define __CHAR_BIT__ 8\n\
#define __WCHAR_MAX__ 2147483647\n\
#define __DBL_DENORM_MIN__ 4.9406564584124654e-324\n\
#define __FLT_EVAL_METHOD__ 0\n\
#define __DBL_MIN_10_EXP__ (-307)\n\
#define __FINITE_MATH_ONLY__ 0\n\
#define __GNUC_PATCHLEVEL__ 0\n\
#define __SHRT_MAX__ 32767\n\
#define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L\n\
#define __UINTMAX_TYPE__ long long unsigned int\n\
#define __linux 1\n\
#define __CHAR_UNSIGNED__ 1\n\
#define __LDBL_MAX_EXP__ 1024\n\
#define __linux__ 1\n\
#define __SCHAR_MAX__ 127\n\
#define __USER_LABEL_PREFIX__ \n\
#define __STDC_HOSTED__ 1\n\
#define __LDBL_HAS_INFINITY__ 1\n\
#define __DBL_DIG__ 15\n\
#define __FLT_EPSILON__ 1.19209290e-7F\n\
#define _CALL_SYSV 1\n\
#define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L\n\
#define __unix__ 1\n\
#define __DECIMAL_DIG__ 33\n\
#define __gnu_linux__ 1\n\
#define __LDBL_HAS_QUIET_NAN__ 1\n\
#define __GNUC__ 4\n\
#define __DBL_MAX__ 1.7976931348623157e+308\n\
#define __DBL_HAS_INFINITY__ 1\n\
#define __DBL_MAX_EXP__ 1024\n\
#define __LONG_LONG_MAX__ 9223372036854775807LL\n\
#define __PPC__ 1\n\
#define __GXX_ABI_VERSION 1002\n\
#define __FLT_MIN_EXP__ (-125)\n\
#define __DBL_MIN__ 2.2250738585072014e-308\n\
#define __DBL_HAS_QUIET_NAN__ 1\n\
#define __REGISTER_PREFIX__ \n\
#define __NO_INLINE__ 1\n\
#define _ARCH_PPC 1\n\
#define __FLT_MANT_DIG__ 24\n\
#define __VERSION__ \"mc-powerpc\"\n\
#define __BIG_ENDIAN__ 1\n\
#define __powerpc__ 1\n\
#define unix 1\n\
#define __SIZE_TYPE__ unsigned int\n\
#define __ELF__ 1\n\
#define __FLT_RADIX__ 2\n\
#define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L\n\
#define __GNUC_RH_RELEASE__ 3\n\
#define __LDBL_DIG__ 31\n\
#define __FLT_HAS_QUIET_NAN__ 1\n\
#define __FLT_MAX_10_EXP__ 38\n\
#define __LONG_MAX__ 2147483647L\n\
#define __FLT_HAS_INFINITY__ 1\n\
#define __unix 1\n\
#define _BIG_ENDIAN 1\n\
#define linux 1\n\
#define __PPC 1\n\
#define __LDBL_MANT_DIG__ 106\n\
#define __WCHAR_TYPE__ long int\n\
#define __FLT_DIG__ 6\n\
#define __powerpc 1\n\
#define __INT_MAX__ 2147483647\n\
#define __LONG_DOUBLE_128__ 1\n\
#define __FLT_MAX_EXP__ 128\n\
#define __DBL_MANT_DIG__ 53\n\
#define __WINT_TYPE__ unsigned int\n\
#define __LDBL_MIN_EXP__ (-968)\n\
#define __LDBL_MAX_10_EXP__ 308\n\
#define __DBL_EPSILON__ 2.2204460492503131e-16\n\
#define PPC 1\n\
#define powerpc 1\n\
#define __INTMAX_MAX__ 9223372036854775807LL\n\
#define __FLT_DENORM_MIN__ 1.40129846e-45F\n\
#define __FLT_MAX__ 3.40282347e+38F\n\
#define __FLT_MIN_10_EXP__ (-37)\n\
#define __INTMAX_TYPE__ long long int\n\
#define __GNUC_MINOR__ 1\n\
#define __DBL_MAX_10_EXP__ 308\n\
#define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L\n\
#define __STDC__ 1\n\
#define __PTRDIFF_TYPE__ int\n\
#define __LDBL_MIN_10_EXP__ (-291)\n\
"
#endif
#ifdef __APPLE__
"#define __APPLE__ 1\n"
#endif
;

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

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 ascii(char *s,int len);

#ifdef __APPLE__
static char lpfx[] = "L_";
static char npfx[] = "_";
#else
static char lpfx[] = ".LC";
static char npfx[] = "";
#endif

int eval_order = NORMAL;

static int creg;

static int output_mode = TEXT_EMIT_MODE;
int data_alignment = 0;

static int code_disp_label;
static int code_setup;
static int r1_offset_label;
static int lvar_offset_label;
static int max_func_arg_label;
#ifndef __APPLE__
static int arg_offset_label;
#endif
static int arg_offset_v = 0;

static int reg_save;
static int freg_save;

static int freg,ireg,lreg;

int code_lassop_p = 1;

#define SIZE_OF_INT  4
#define SIZE_OF_SHORT  2
#define SIZE_OF_FLOAT  4
#define SIZE_OF_DOUBLE  8
#define SIZE_OF_LONGLONG  8
#define ENDIAN  1
#define ENDIAN_L  1
#define ENDIAN_D  1

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

/* floating point registers */

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

static int  lreg_sp;  /* longlong  REGister Stack-Pointer */
static int lreg_stack[MAX_MAX]; /* 実際のレジスタの領域 */

#ifdef __APPLE__
#define REG_sp   1
#define REG_fp   30
#define REG_VAR_BASE 29
#define REG_VAR_MIN  18
#define MIN_TMP_REG 3
#define MAX_TMP_REG 11

#define FREG_VAR_BASE 31
#define FREG_VAR_MIN  20
#define MIN_TMP_FREG 1
#define MAX_TMP_FREG 14
#else
#define REG_sp   1
#define REG_fp   31
#define REG_VAR_BASE 29
#define REG_VAR_MIN  18
#define MIN_TMP_REG 3
#define MAX_TMP_REG 11

#define FREG_VAR_BASE 31
#define FREG_VAR_MIN  20
#define MIN_TMP_FREG 1
#define MAX_TMP_FREG 9
#endif

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

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

#define RET_REGISTER 3
#define RET_FREGISTER (1+FREG_OFFSET)
#define RET_LREGISTER_H 3    /* high word */
#define RET_LREGISTER_L 4    /* low word */
#define RET_LREGISTER LREG_OFFSET

int MAX_INPUT_REGISTER_VAR = 11-MIN_TMP_REG;
int MAX_CODE_INPUT_REGISTER_VAR = 11-MIN_TMP_REG;
int MAX_INPUT_DREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG;
int MAX_INPUT_FREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG;
int MAX_CODE_INPUT_DREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG;
int MAX_CODE_INPUT_FREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG;

static int powerpc_regs[REAL_MAX_REGISTER+REAL_MAX_FREGISTER+
   REAL_MAX_LREGISTER];
static int regv_h0[REAL_MAX_LREGISTER];
static int regv_l0[REAL_MAX_LREGISTER];
#define regv_h(i)  regv_h0[(i)-LREG_OFFSET]
#define regv_l(i)  regv_l0[(i)-LREG_OFFSET]

static int *regs  = powerpc_regs;

#define CREG_REGISTER  (MAX_TMP_REG)
#define FREG_FREGISTER (MAX_TMP_FREG+FREG_OFFSET)
#define LREG_LREGISTER (MAX_TMP_REG+LREG_OFFSET)


static int max_reg_var, max_freg_var;

#ifdef __APPLE__
static char *reg_name[] = {
    "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9",
    "r10","r11","r12","r13","r14","r15","r16","r17","r18","r19",
    "r20","r21","r22","r23","r24","r25","r26","r27","r28","r29",
    "r30","r31",
    "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9",
    "f10","f11","f12","f13","f14","f15","f16","f17","f18","f19",
    "f20","f21","f22","f23","f24","f25","f26","f27","f28","f29",
    "f30","f31"
}; 
#else
// PS3 (PowerPC Fedora Core)
static char *reg_name[] = {
    "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9",
    "r10","r11","r12","r13","r14","r15","r16","r17","r18","r19",
    "r20","r21","r22","r23","r24","r25","r26","r27","r28","r29",
    "r30","r31",
    "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"
}; 
#endif

#define round4(i)   align(i,4)
#define round16(i)   align(i,16)

#define register_name(i)  reg_name[i]
#define fregister_name(i) reg_name[i]
#define lregister_name_low(i) reg_name[regv_l(i)]
#define lregister_name_high(i) reg_name[regv_h(i)]

#define DEBUG_REG 1
#if DEBUG_REG
char *rn(int i) { return register_name(i); }
char *fn(int i) { return fregister_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 regv_l(i); }
int lh(int i) { return regv_h(i); }
#endif

#define is_int_reg(i)  (0<=i&&i<REAL_MAX_REGISTER)
#define is_float_reg(i)  (REAL_MAX_REGISTER<=i&&i<REAL_MAX_FREGISTER+REAL_MAX_REGISTER)
#define is_longlong_reg(i)  (LREG_OFFSET<=i&&i<LREG_OFFSET+REAL_MAX_LREGISTER)

#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]!=REG_VAR) free_register(lreg); lreg = 0; }
        if (!ireg) ireg = get_register();
        // else if (ireg!=i) free_register(i);
        i = ireg;
    }
    if (!regs[i]) regs[i]=USING_REG;
    creg = i;
    return i;
}

#if LONGLONG_CODE
#define  use_longlong(reg) if (reg==USE_CREG) reg=use_longlong0()

static
int use_longlong0() {
    int i = creg;
    if (!is_longlong_reg(i)) {
        if (ireg) { if (regs[ireg]!=REG_VAR) free_register(ireg); ireg=0; }
        if (!lreg||!regs[lreg]) lreg = get_lregister();
        // else if (lreg!=i) free_register(i);
        i = lreg;
    }
    if (!regv_l(i)) regv_l(i) = get_register();
    if (!regv_h(i)) regv_h(i) = get_register();
    if (!regs[i]) regs[i]=USING_REG;
    if (!regs[regv_l(i)]) regs[regv_l(i)]=USING_REG;
    if (!regs[regv_h(i)]) regs[regv_h(i)]=USING_REG;
    creg = i;
    return i;
}
#endif


#if FLOAT_CODE
#define  use_float(d,reg) if (reg==USE_CREG) reg=d?use_double0():use_float0()
static
int use_float0() { 
    int i = creg;
    if (!is_float_reg(i)) {
        if (lreg) { if (regs[lreg]!=REG_VAR) free_register(lreg); lreg = 0; }
        if (!freg) freg = get_dregister(0);
        else if (freg!=i) if (regs[i]!=REG_VAR) free_register(i);
        i = freg;
    }
    if (!regs[i]) regs[i]=USING_REG;
    creg = i;
    return i;
}
static
int use_double0() { 
    int i = creg;
    if (!is_float_reg(i)) {
        if (lreg) { if (regs[lreg]!=REG_VAR) free_register(lreg); lreg = 0; }
        if (!freg) freg = get_dregister(1);
        else if (freg!=i) if (regs[i]!=REG_VAR) free_register(i);
        i = freg;
    }
    if (!regs[i]) regs[i]=USING_REG;
    creg = i;
    return i;
}
#endif


#if FLOAT_CODE
#ifdef __APPLE__
static
NMTBL float_zero = {"_float_zero",0,STATIC,FLOAT,0};
static
NMTBL float_one = {"_float_one",0,STATIC,FLOAT,0};
#else
static
NMTBL float_zero = {"__float_zero",0,STATIC,FLOAT,0};
static
NMTBL float_one = {"__float_one",0,STATIC,FLOAT,0};
#endif


static char * fload(int d);
static int code_d1(double d);
static int code_d2(double d);
#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);
static void    set_freg(int,int);
static void    set_lreg(int,int);
static void jcond(int l, char cond);
static void register_usage(char *s);


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

/*          

     r0    return value etc.
     r3-r10  input register
     r22-r29 saved register variable (input register for code segment)
     r30   stack pointer
     r31   0
     r1    frame pointer

     f0    return value etc.
     f1-r8  input register
     f24-f31 saved register variable

 function call stack frame (Mac OS X)
                      <-------r1_offset------------------------------>
                                     r30
                                      <------------lvar_offset0------>
                      <--lvar_offset-->                              r1
 r+  +------------+---+---------------+----------+--------------+----+    -
      callee arg   xx   register save   local      caller arg     xx
                          reg_save      disp       max_func_args*SIZE_OF_INT
        lvar>0                         lvar<0       lvar>0x1000 0000

 function call stack frame (PS3)
                <---------------r1_offset------------------------------>
                                        r30-->
                         <--arg_offset-->
             xxx<----------lvar_offset-->                         <----r1
 r+  +------+---+------+---------------+----------+--------------+----+    -
  callee arg   reg arg register save   local      caller arg     xx
                          reg_save      disp       max_func_args*SIZE_OF_INT
        lvar>0                         lvar<0       lvar>0x1000 0000


code segment stack frame

                 * gotoを呼び出した関数のr1 ! r1(goto前のr1)
   #             *                           r30 <---r1_offset---------> r1
r+ +----------+--+----------+----------------+-----------+----------+----+
    cousin arg xx  reg save !callee arg      !code local  caller arg  xx
                   r20-r29     lvar>0         lvar<0      lvar>0x1000 000
                   f20-f31  <-my_func_args--><--disp-----><-max_func_arg->
                              *SIZE_OF_INT                  *SIZE_OF_INT

 */


#ifdef __APPLE__

#define arg_offset  24
#define arg_offset1  24

#define func_disp_offset 68
#define func_disp_offset1 16
#define code_disp_offset0 (-4)

#else

#define arg_offset  (8)
#define arg_offset0  (8)
#define arg_offset1  (8)

#define func_disp_offset (12)
#define code_disp_offset0 (-4)

#endif

int disp_offset = -4;

#define CODE_LVAR(l) ((l)+code_disp_offset0)
#define CODE_CALLER_ARG(l) ((l)+arg_offset1)
#define FUNC_LVAR(l) ((l)+disp_offset)
#ifdef __APPLE__
#define CALLEE_ARG(l) ((l)+arg_offset)
#else
#define CALLEE_ARG(l) ((l)+arg_offset+((l>=arg_offset_v)?arg_offset0:0))
#endif
#define CALLER_ARG(l) ((l)+arg_offset1)


void
code_offset_set()
{
#if 0
    int l;
#endif
    int lvar_offsetv = 
        round16(-disp+max_func_args*SIZE_OF_INT)+func_disp_offset;
    int r1_offsetv = round16(lvar_offsetv-reg_save);

    printf(".set %s%d,%d\n",lpfx,lvar_offset_label,r1_offsetv-lvar_offsetv);
    if (r1_offsetv-lvar_offsetv > 65000) error(-1);
        // too large function arguments?
    printf(".set %s%d,%d\n",lpfx,r1_offset_label,r1_offsetv);
    if (max_func_arg_label) {
        printf(".set %s%d,%d\n",lpfx,max_func_arg_label,
            round16(max_func_args*SIZE_OF_INT)+24);
        max_func_arg_label = 0;
    }

#if 0
printf("## reg_save %d\n",reg_save);
printf("## function %s\n",fnptr->nm);
    l = ARG_LVAR_OFFSET;
printf("## offset call0\t%d\n",CALLER_ARG);
    l = ARG_LVAR_OFFSET+max_func_args*SIZE_OF_INT;
printf("## offset calln\t%d %d\n",CALLER_ARG,max_func_args*SIZE_OF_INT);
    l = disp;
printf("## offset lvarn\t%d %d\n",FUNC_LVAR+lvar_offsetv,disp);
    l = 0;
printf("## offset lvar0\t%d\n",FUNC_LVAR+lvar_offsetv);
    l = -reg_save;
printf("## offset regs\t%d\n",FUNC_LVAR+lvar_offsetv);
printf("## offset r1off\t%d\n",r1_offsetv);
    l = 0;
printf("## offset carg0\t%d\n",CALLEE_ARG+r1_offsetv);
    l = my_func_args;
printf("## offset cargn\t%d %d\n",CALLEE_ARG+r1_offsetv,my_func_args);
#endif
}

static int large_offset_reg;

#ifdef __APPLE__

static void
lvar(int l)
{
    char *rn;
    if (!large_offset_reg) {
        if (is_code(fnptr)) {
            if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
                printf("lo16(%d)(r1)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET));
            } else
                printf("lo16(%d)(r30)\n",CODE_LVAR(l));
        } else if (l<0) {  /* local variable */
            printf("lo16(%d)(r30)\n",FUNC_LVAR(l));
        } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            printf("lo16(%d)(r1)\n",CALLER_ARG(l-ARG_LVAR_OFFSET));
        } else { /* callee's arguments */
            printf("lo16(%d+%s%d)(r30)\n",CALLEE_ARG(l),lpfx,lvar_offset_label);
        }
    } else {
        rn = register_name(large_offset_reg);
        if (is_code(fnptr)) {
            if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
                printf("lo16(%d)(%s)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),rn);
            } else
                printf("lo16(%d)(%s)\n",CODE_LVAR(l),rn);
        } else if (l<0) {  /* local variable */
            printf("lo16(%d)(%s)\n",FUNC_LVAR(l),rn);
        } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            printf("lo16(%d)(%s)\n",CALLER_ARG(l-ARG_LVAR_OFFSET),rn);
        } else { /* callee's arguments */
            printf("lo16(%d+%s%d)(%s)\n",CALLEE_ARG(l),lpfx,lvar_offset_label,rn);
        }
        free_register(large_offset_reg);
    }
}

/* if size of local variables / input variables is more then 64k,
   lo16 does not work. We have to use ha16 also. But we can't know
   the exact size in one path compile. We may safely use lvar16ha 
   if disp or max_func_args > 32k. Of course this is redundant for
   smaller offset. But who cares who use very large local variables?
 */

#define LARGE_OFFSET(l) (l<-32000||l>32000)

static void
lvar_intro(int l)
{
    char *rn;
    large_offset_reg=0;
    if (is_code(fnptr)) {
        if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            if (LARGE_OFFSET(CODE_CALLER_ARG(l-ARG_LVAR_OFFSET))) {
                rn=register_name(large_offset_reg=get_register());
                printf("\taddis %s,r1,ha16(%d)\n",rn,
                    CODE_CALLER_ARG(l-ARG_LVAR_OFFSET));
            }
        } else {
            if (LARGE_OFFSET(CODE_LVAR(l))) {
                rn=register_name(large_offset_reg=get_register());
                printf("\taddis %s,r30,ha16(%d)\n",rn,CODE_LVAR(l));
            }
        }
    } else if (l<0) {  /* local variable */
        if (LARGE_OFFSET(FUNC_LVAR(l))) {
            rn=register_name(large_offset_reg=get_register());
            printf("\taddis %s,r30,ha16(%d)\n",rn,FUNC_LVAR(l));
        }
    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
        if (LARGE_OFFSET(CALLER_ARG(l-ARG_LVAR_OFFSET))) {
            rn=register_name(large_offset_reg=get_register());
            printf("\taddis %s,r1,ha16(%d)\n",rn,CALLER_ARG(l-ARG_LVAR_OFFSET));
        }
    } else { /* callee's arguments */
        if (LARGE_OFFSET(CALLEE_ARG(l))) {
            rn=register_name(large_offset_reg=get_register());
            printf("\taddis %s,r30,ha16(%d+%s%d)\n",
                rn,CALLEE_ARG(l),lpfx,lvar_offset_label);
        }
    }
}

#else /* PS3 */

static void
lvar(int l)
{
    char *rn;
    if (!large_offset_reg) {
        if (is_code(fnptr)) {
            if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
                printf("%d@l(1)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET));
            } else
                printf("%d@l(%d)\n",CODE_LVAR(l),REG_fp);
        } else if (l<0) {  /* local variable */
            printf("%d@l(%d)\n",FUNC_LVAR(l),REG_fp);
        } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            printf("%d@l(1)\n",CALLER_ARG(l-ARG_LVAR_OFFSET));
        } else { /* callee's arguments */
            printf("%d+%s%d@l(%d)\n",CALLEE_ARG(l),lpfx,lvar_offset_label,REG_fp) ;
        }
    } else {
        rn = register_name(large_offset_reg);
        if (is_code(fnptr)) {
            if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
                printf("%d@l(%s)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),rn);
            } else
                printf("%d@l(%s)\n",CODE_LVAR(l),rn);
        } else if (l<0) {  /* local variable */
            printf("%d@l(%s)\n",FUNC_LVAR(l),rn);
        } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            printf("%d@l(%s)\n",CALLER_ARG(l-ARG_LVAR_OFFSET),rn);
        } else { /* callee's arguments */
            printf("%d+%s%d@l(%s)\n",CALLEE_ARG(l),lpfx,lvar_offset_label,rn);
        }
        free_register(large_offset_reg);
    }
}

/* if size of local variables / input variables is more then 64k,
   lo16 does not work. We have to use ha16 also. But we can't know
   the exact size in one path compile. We may safely use lvar16ha 
   if disp or max_func_args > 32k. Of course this is redundant for
   smaller offset. But who cares who use very large local variables?
 */

#define LARGE_OFFSET(l) (l<-32000||l>32000)

static void
lvar_intro(int l)
{
    char *rn;
    large_offset_reg=0;
    if (is_code(fnptr)) {
        if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
            if (LARGE_OFFSET(CODE_CALLER_ARG(l-ARG_LVAR_OFFSET))) {
                rn=register_name(large_offset_reg=get_register());
                printf("\taddis %s,1,%d@ha\n",rn,
                    CODE_CALLER_ARG(l-ARG_LVAR_OFFSET));
            }
        } else {
            if (LARGE_OFFSET(CODE_LVAR(l))) {
                rn=register_name(large_offset_reg=get_register());
                printf("\taddis %s,%d,%d@ha\n",rn,REG_fp,CODE_LVAR(l));
            }
        }
    } else if (l<0) {  /* local variable */
        if (LARGE_OFFSET(FUNC_LVAR(l))) {
            rn=register_name(large_offset_reg=get_register());
            printf("\taddis %s,%d,%d@ha\n",rn,REG_fp,FUNC_LVAR(l));
        }
    } else if (l>=ARG_LVAR_OFFSET) {  /* caller's arguments */
        if (LARGE_OFFSET(CALLER_ARG(l-ARG_LVAR_OFFSET))) {
            rn=register_name(large_offset_reg=get_register());
            printf("\taddis %s,1,%d@ha\n",rn,CALLER_ARG(l-ARG_LVAR_OFFSET));
        }
    } else { /* callee's arguments */
        if (LARGE_OFFSET(CALLEE_ARG(l))) {
            rn=register_name(large_offset_reg=get_register());
            printf("\taddis %s,%d,%d+%s%d@ha\n",
                rn,REG_fp,CALLEE_ARG(l),lpfx,lvar_offset_label);
        }
    }
}
#endif

void
code_lvar(int e2,int reg) {
    use_int(reg);
    lvar_intro(e2);
    printf("\tla %s,",register_name(reg));
    lvar(e2);
}

void
code_init(void)
{
    /* called only once */

    init_src = init_src0;
    size_of_int = SIZE_OF_INT;
    size_of_pointer = 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;
    struct_align = size_of_int;

    regv_l(RET_LREGISTER) = RET_LREGISTER_L;
    regv_h(RET_LREGISTER) = RET_LREGISTER_H;
}

extern void
emit_reinit()
{
    /* called for each file */
    /* heap is initialized here, setup ptr cache free list */
    output_mode = -1;
    init_ptr_cache();
}

void
gexpr_code_init(void){
}

void
code_gexpr(int e){
    if ((is_int_reg(creg))&&regs[creg]==REG_VAR)
        creg = ireg = 0;
    else if (is_float_reg(creg)&&regs[creg]==REG_VAR) 
        creg = lreg = 0;
    else if (is_longlong_reg(creg)&&regs[creg]==REG_VAR) 
        creg = lreg = 0;
    // if (is_int_reg(creg) && creg!=ireg) error(-1);
}

/*
    set variable storage type and offset
    save register contents to our stack 
    for & operator
 */

void
code_arg_register(NMTBL *fnptr, int in)
{
    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;
    arg_offset_v = 0;
    int offset = 0;

    function_type(fnptr->ty,&dots);

    if (dots && (in || !parse_mode)) {
        type = INT;
        mode = LDECL;
        stmode = 0;
        n = def(lsearch("__my_va_list",0),0);
        n->dsp = 0; // first argument
    }
    if (in) return;

    while (args) {
        /* process in reverse order */
        n = ncadddr(args);
        type = n->ty;
        int sz = size(type);
        offset = code_arg_alignment(offset,n,type,sz,is_code0);
        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++;
                arg_offset_v += (caddr(args)=SIZE_OF_INT);
            }
        } else if (type==FLOAT) {
            if ((reg = get_input_dregister_var(freg_var,n,is_code0,0))) {
                n->sc = DREGISTER;
                n->dsp = cadr(reg);
                regs[n->dsp]= INPUT_REG;
                freg_var++;
                arg_offset_v += (caddr(args)=size(type));
            }
        } else if (type==DOUBLE) {
            if ((reg = get_input_dregister_var(freg_var,n,is_code0,1))) {
                n->sc = DREGISTER;
                n->dsp = cadr(reg);
                regs[n->dsp]= INPUT_REG;
                freg_var++;
                arg_offset_v += (caddr(args)=size(type));
            }
        } else if (type==LONGLONG||type==ULONGLONG) {
            if ((reg = get_input_lregister_var(reg_var,n,is_code0))) {
                n->sc = LREGISTER;
                n->dsp = cadr(reg);
                regs[i=n->dsp]= INPUT_REG;
                regs[regv_l(i)]= INPUT_REG;
                regs[regv_h(i)]= INPUT_REG;
                reg_var+=2;
                arg_offset_v += (caddr(args)=size(type));
            }
        }
        args = cadr(args);
    }
    if (is_function(fnptr)) {
#ifndef __APPLE__
        if (dots) {
                arg_offset_v =
                    MAX_INPUT_REGISTER_VAR*SIZE_OF_INT +
                    MAX_INPUT_DREGISTER_VAR*SIZE_OF_DOUBLE;
        }
        printf(".set %s%d, %d\n",lpfx, arg_offset_label,
            arg_offset_v+ arg_offset);
#endif
        code_save_input_registers(dots);
    }
}


int 
get_register(void)
{    /* 使われていないレジスタを調べる */
    int i,j,reg;
    for(i=MAX_TMP_REG;i>MIN_TMP_REG;i--) {
        if (regs[i]) continue;  /* 使われている */
        regs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
        return i;   /* その場所を表す番号を返す */
    }
    /* PTR_CACHE をつぶす */
    if ((i=last_ptr_cache())) {
        clear_ptr_cache_reg(i);
        regs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
        return i;   /* その場所を表す番号を返す */
    }
    /* search register stack */
    for(i=0;i<reg_sp;i++) {
        if ((reg=reg_stack[i])>=0) {
            code_assign_lvar(
                (j=new_lvar(SIZE_OF_INT)),reg,0); 
            reg_stack[i]= j-REG_LVAR_OFFSET;
            return reg;
        }
    }
#if LONGLONG_CODE
    /* search register stack */
    for(i=0;i<lreg_sp;i++) {
        if ((reg=lreg_stack[i])>=0) {
            code_lassign_lvar(
                (j=new_lvar(SIZE_OF_LONGLONG)),reg); 
            lreg_stack[i]= j-REG_LVAR_OFFSET;
            free_register(reg);
            return get_register();
        }
    }
#endif
    for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) {
        reg =REG_VAR_BASE-i;
        if (! regs[reg]) {       /* 使われていないなら */
            regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */
            if (i>max_reg_var) max_reg_var=i;
            return reg;   /* その場所を表す番号を返す */
        }
    }
    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
    error(RGERR); return creg;
}

#if 0
int 
get_register(void)
{
    int i = get_register0();
    printf("## get_register %d\n",i);
    return i;
}
#endif

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

#if FLOAT_CODE
int 
get_dregister(int d)
{    /* 使われていないレジスタを調べる */
    int i,reg;
    for(i=MAX_TMP_FREG+FREG_OFFSET;i>MIN_TMP_FREG+FREG_OFFSET;i--) {
        if (regs[i]) continue;    /* 使われている */
        regs[i]=USING_REG;      /* そのレジスタを使うことを宣言し */
        return i;   /* その場所を表す番号を返す */
    }
    /* search register stack */
    for(i=0;i<freg_sp;i++) {
        if ((reg=freg_stack[i])>=0) {
            code_dassign_lvar(
                (freg_stack[i]=new_lvar(SIZE_OF_DOUBLE)),reg,1); 
            freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET;
            return reg;
        }
    }
    for(i=0;i<FREG_VAR_BASE-REG_VAR_MIN;i++) {
        reg =FREG_VAR_BASE-i+FREG_OFFSET;
        if (! regs[reg]) {       /* 使われていないなら */
            regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */
            if (i>max_freg_var) max_freg_var=i;
            return reg;   /* その場所を表す番号を返す */
        }
    }
    /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */
    error(REG_ERR); return freg;
}

#if 0
int 
get_dregister(int d)
{
    int i = get_dregister0(d);
printf("## get_dregister %d\n",i);
    return i;
}
#endif

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


int
get_lregister0()
{
    int i;
    for(i=LREG_OFFSET+1;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) {
        if (regs[i]==0) {
            return i;
        }
    }
    return -1;
}

static int
get_lregister1(int n,int m)
{
    int i;
#if 1
    for(i=LREG_OFFSET;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) {
        if (regv_l(i)==n && regv_h(i)==m) {
            return i;
        }
    }
#endif
    return get_lregister0();
}


static void
cleanup_lregister0()
{
    int i;
    // we should not have this, but powerpc's function
    // lost some input register variables.
#if 1
    for(i=LREG_OFFSET+1;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) {
        if (regs[i]) {
            if(!regv_l(i) && !regv_h(i)) {
                regs[i]=0;
                // printf("## cleanup lreg 0 %d\n",i);
            } else if(!regs[regv_l(i)] && !regs[regv_h(i)]) {
                free_register(i);
                // printf("## cleanup lreg 1 %d\n",i);
            }
        }
    }
#endif
}

int
get_lregister()
{
    int h,l,i;
    i = get_lregister0();
    if (i==-1) return -1;
    h = get_register(); 
    if (h==-1) return -1;
    regv_h(i) = h;
    l = get_register(); 
    if (l==-1) {
        if (regs[h]!=REG_VAR) free_register(h);
        if (regs[i]!=REG_VAR) free_register(i);
        return -1;
    }
    regv_l(i) = l;
    if (!regs[i]) regs[i]=USING_REG;
// printf("## get_lregister %d %s %s\n",i, lregister_name_high(i), lregister_name_low(i));
    return i;
}

int
get_lregister_var(NMTBL *n)
{
    int i,j,ll;
    int max_reg_var_save=max_reg_var;
    ll = get_lregister0();
    if (ll==-1) goto not_found;
    if (regs[ll]==0) {
        for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) {
            if (! regs[REG_VAR_BASE-i]) {       /* 使われていないなら */
                /* そのレジスタを使うことを宣言し */
                regs[REG_VAR_BASE-i]=USING_REG; 
                if (i>max_reg_var) max_reg_var=i;
                for(j=0;j<REG_VAR_BASE-REG_VAR_MIN;j++) {
                    if (! regs[REG_VAR_BASE-j]) {       
                        /* 使われていないなら */
                        /* そのレジスタを使うことを宣言し */
                        regs[REG_VAR_BASE-j]=REG_VAR; 
                        if (j>max_reg_var) max_reg_var=j;
                        /* その場所を表す番号を返す */
                        regs[ll]=REG_VAR;
                        regv_l(ll) = REG_VAR_BASE-j;
                        regv_h(ll) = REG_VAR_BASE-i;
                        return list3n(LREGISTER,ll,n); 
                    }
                }
                /* ひとつしかなかった */
                regs[REG_VAR_BASE-i]=0; 
                max_reg_var=max_reg_var_save;
                goto not_found;
            }
        }
    }
not_found:
    return list3n(LVAR,new_lvar(SIZE_OF_LONGLONG),0);
}

void
emit_pop_free(int xreg)
{
    if (xreg>=0 && xreg!=creg && regs[xreg]!=REG_VAR)
        free_register(xreg);
}

void

free_register(int i) {    /* いらなくなったレジスタを開放 */
    // printf("## free_register %d\n",i);
    if (is_longlong_reg(i)) {
        regs[regv_l(i)]=0;
        regs[regv_h(i)]=0;
    }
    regs[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)
{
    if (is_code) {
        if(!(i<FREG_VAR_BASE-FREG_VAR_MIN)) return 0;
        i = FREG_VAR_BASE-i+FREG_OFFSET;
    } else {
        if (i<0||i>=MAX_INPUT_DREGISTER_VAR) return 0;
        i = i+MIN_TMP_FREG+FREG_OFFSET;
    }
    return list3n(DREGISTER,i,n);
}

int
get_input_lregister_var(int i,NMTBL *n,int is_code)
{
    int ll;
    if (i!=-1) {
        if (is_code) {
            if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0;
            i = REG_VAR_BASE-i;
        } else {
            if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0;
#ifndef __APPLE__
            if (i%2==1) i++;
#endif
            i = i+MIN_TMP_REG;
        }
        ll = get_lregister1(i,i+1);
#if ENDIAN_L==0
        regv_l(ll)=i;
        regv_h(ll)=i+1;
#else
        regv_h(ll)=i;
        regv_l(ll)=i+1;
#endif
    } else { error(-1); ll=LREG_OFFSET+2; }
    return list3n(LREGISTER,ll,n);
}

int
get_input_register_var(int i,NMTBL *n,int is_code)
{
    if (is_code) {
        if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0;
        i = REG_VAR_BASE-i;
    } else {
        if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0;
        i = i+MIN_TMP_REG;
    }
    return list3n(REGISTER,i,n);
}

/* double register case? */

int
get_input_register_var_1(int i,NMTBL *n,int is_code)
{
    if (is_code) {
        if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0;
        i = REG_VAR_BASE-i;
    } else {
        if (i<0||i>=MAX_INPUT_REGISTER_VAR+1) return 0;
        i = i+MIN_TMP_REG;
    }
    return list3n(REGISTER,i,n);
}

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

#if 0
static int
register_full(void)
{
    int i;
    for(i=0;i<MAX_REGISTER;i++) {
        if (! regs[i]) { 
            return 0;  
        }
    }
    return 1;    
}
#endif

void
free_all_register(void)
{
    int i;
// printf("## free_all register\n");
#if LONGLONG_CODE
    for(i=0;i<REAL_MAX_LREGISTER;i++) {
        regs[i+LREG_OFFSET]=0; 
        regv_l(i+LREG_OFFSET) = 0;
        regv_h(i+LREG_OFFSET) = 0;
    }
    lreg = 0;
    // set_lreg(LREG_LREGISTER,0);
#endif
    for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; }
    for(i=0;i<MAX_FREGISTER;i++) { regs[i+FREG_OFFSET]=0; }
#if FLOAT_CODE
    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 DREGISTER: case FREGISTER: break;
        case REGISTER:
            if(cadr(s)==cadr(t)) return 1;
            break;
        case LREGISTER:
            if(cadr(s)==regv_l(cadr(t))) return 1;
            if(cadr(s)==regv_h(cadr(t))) return 1;
            break;
        }   
        break;
    case DREGISTER:
    case FREGISTER:
        switch(car(t)) {
        case REGISTER: case LREGISTER: break;
        case DREGISTER: case FREGISTER:
            if(cadr(s)==cadr(t)) return 1;
            break;
        }   
        break;
    case LREGISTER:
        switch(car(t)) {
        case DREGISTER: case FREGISTER: break;
        case REGISTER:
            if(cadr(t)==regv_l(cadr(s))) return 1;
            if(cadr(t)==regv_h(cadr(s))) return 1;
            break;
        case LREGISTER:
            if(regv_l(cadr(t))==regv_l(cadr(s))) return 1;
            if(regv_l(cadr(t))==regv_h(cadr(s))) return 1;
            if(regv_h(cadr(t))==regv_l(cadr(s))) return 1;
            if(regv_h(cadr(t))==regv_h(cadr(s))) return 1;
            break;
        }   
        break;
    }   
    return 0;
}

// int lreg_count;

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",fregister_name(freg));
    if (lreg) printf(" lreg=%s,%s",lregister_name_high(lreg),
        lregister_name_low(lreg));
#if 1
    for(j=0,i=0;i<MAX_REGISTER;i++) if (regs[i]) j++;
    if (j>USAGE_MAX) {
        printf("\n## regs(%d):",j);
        for(i=0;i<MAX_REGISTER;i++) {  printf("%d",regs[i]); }
    }
    if (reg_sp>0) {
        printf(" stack ");
        for(i=reg_sp;i>0;i--) {
            if(reg_stack[i-1]>=0) {
                printf(" %s",register_name(reg_stack[i-1]));
            } else 
                printf(",%d",reg_stack[i-1]);
        }
    }
    for(j=0,i=0;i<MAX_FREGISTER;i++) if (regs[i+FREG_OFFSET]) j++;
    if (j>USAGE_MAX) {
        printf("\n## freg(%d):",j);
        for(i=0;i<MAX_FREGISTER;i++) {  printf("%d",regs[i+FREG_OFFSET]); }
    }
    if (freg_sp>0) {
        printf(" fstack ");
        for(i=freg_sp;i>0;i--) {
            if(freg_stack[i-1]>=0) {
                printf(" %s",fregister_name(freg_stack[i-1]));
            } else 
                printf(",%d",freg_stack[i-1]);
        }
    }

    for(j=0,i=0;i<REAL_MAX_LREGISTER;i++) if (regs[i+LREG_OFFSET]) j++;
//    lreg_count = j;
    if (j>USAGE_MAX) {
        printf("\n## lreg(%d):",j);
        for(i=0;i<REAL_MAX_LREGISTER;i++) {  printf("%d",regs[i+LREG_OFFSET]); }
#if 0
        for(i=0;i<REAL_MAX_LREGISTER;i++) {  
            if (regs[i+LREG_OFFSET] && regv_l(i+LREG_OFFSET))
                printf(" %s-%s", lregister_name_high(i+LREG_OFFSET),lregister_name_low(i+LREG_OFFSET));
            else if (regv_l(i+LREG_OFFSET))
                printf(" *%s-%s", lregister_name_high(i+LREG_OFFSET),lregister_name_low(i+LREG_OFFSET));
        }
#endif
    }
    if (lreg_sp>0) {
        printf(" lstack ");
        for(i=lreg_sp;i>0;i--) {
            if(lreg_stack[i-1]>=0) {
                printf(" %s",lregister_name_high(lreg_stack[i-1]));
                printf(",%s",lregister_name_low(lreg_stack[i-1]));
            } else 
                printf(",%d",lreg_stack[i-1]);
        }
    }
#endif
    printf("\n");
}

void

gexpr_init(void)
{
    while(reg_sp > 0) {
        error(-1);
        free_register(reg_stack[--reg_sp]);
    }
    while(freg_sp > 0) {
        error(-1);
        free_register(freg_stack[--freg_sp]);
    }
    while(lreg_sp > 0) {
        error(-1);
        free_register(lreg_stack[--lreg_sp]);
    }
    use_int0();
    text_mode(0);
    gexpr_code_init();
    register_usage("gexpr_init");
}


void

emit_init(void)
{
    /* called before each declaration */

    free_all_register();
    max_reg_var=-1; max_freg_var=-1;
    reg_sp = 0;
    freg_sp = 0;
}


int
get_register_var(NMTBL *n)
{
    int i;
    for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) {
        if (! regs[REG_VAR_BASE-i]) {       /* 使われていないなら */
            /* そのレジスタを使うことを宣言し */
            regs[REG_VAR_BASE-i]=REG_VAR; 
            if (i>max_reg_var) max_reg_var=i;
            /* その場所を表す番号を返す */
            return list3n(REGISTER,REG_VAR_BASE-i,n); 
        }
    }
    return list3n(LVAR,new_lvar(SIZE_OF_INT),0);
}

int
get_dregister_var(NMTBL *n,int d)
{
    int i;
    for(i=0;i<FREG_VAR_BASE-FREG_VAR_MIN;i++) {
        if (! regs[FREG_VAR_BASE-i+FREG_OFFSET]) {       /* 使われていないなら */
            regs[FREG_VAR_BASE-i+FREG_OFFSET]=REG_VAR; /*そのレジスタを使うことを宣言し*/
            if (i>max_freg_var) max_freg_var=i;
            /* その場所を表す番号を返す */
            return list3n(DREGISTER,
                FREG_VAR_BASE-i+FREG_OFFSET,n); 
        }
    }
    return list3n(LVAR,new_lvar(SIZE_OF_DOUBLE),0);
}

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

#ifdef __APPLE__
static int code_base;
#endif

extern void
code_ptr_cache_def(int r,NMTBL *nptr)
{
    char *rrn = register_name(r);
#ifdef __APPLE__
    if (nptr->sc==STATIC && !(is_code(nptr)||is_function(nptr))) {
        printf("\taddis %s,r31,ha16(_%s-L_%d)\n",
                 rrn,nptr->nm,code_base);
        printf("\tla %s,lo16(_%s-L_%d)(%s)\n",
                 rrn,nptr->nm,code_base,rrn);
    } else {
        printf("\taddis %s,r31,ha16(L_%s$non_lazy_ptr-L_%d)\n",
                 rrn,nptr->nm,code_base);
        printf("\tlwz %s,lo16(L_%s$non_lazy_ptr-L_%d)(%s)\n",
                 rrn,nptr->nm,code_base,rrn);
    }
#else
    printf("\tlis %s,%s@ha\n",
             rrn,nptr->nm);
    printf("\tla %s,%s@l(%s)\n",
             rrn,nptr->nm,rrn);
#endif
}

static char *cload(int sz) { return sz==1?"lbz":sz==SIZE_OF_SHORT?"lhz":"lwz"; }
static char *cstore(int sz) { return sz==1?"stb":sz==SIZE_OF_SHORT?"sth":"stw"; }

static void
cext(int sign,int sz,int reg)
{
    char *crn = register_name(reg);
    if (sign) {
        if (sz==1) 
            printf("\textsb %s,%s\n",crn,crn);
        else if (sz==SIZE_OF_SHORT)
            printf("\textsh %s,%s\n",crn,crn);
    } else {
        if (sz==1) 
            printf("\trlwinm %s,%s,0,0xff\n",crn,crn);
        else if (sz==SIZE_OF_SHORT)
            printf("\trlwinm %s,%s,0,0xffff\n",crn,crn);
    }
}


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

static void 
code_add(int reg,int offset,int r)
{
    char *crn = register_name(reg);
    char *rrn = register_name(r);
    if (offset==0) {
        if(r!=reg)
            printf("\tmr %s,%s\n",crn,rrn);
    } else if (LARGE_OFFSET(offset)) {
#ifdef __APPLE__
        printf("\tla   %s,lo16(%d)(%s)\n",crn,offset,rrn);
        printf("\taddis %s,%s,ha16(%d)\n",crn,crn,offset);
#else
        printf("\tla   %s,%d@l(%s)\n",crn,offset,rrn);
        printf("\taddis %s,%s,%d@ha\n",crn,crn,offset);
#endif
    } else
        printf("\taddi %s,%s,%d\n",crn,rrn,offset);
}

static void 
code_ld(char *ld,int reg,int offset,int r)
{
    char *crn = register_name(reg);
    char *rrn = register_name(r);
    if (LARGE_OFFSET(offset)) {
#ifdef __APPLE__
        printf("\taddis %s,%s,ha16(%d)\n",crn,rrn,offset);
        printf("\t%s %s,lo16(%d)(%s)\n",ld,crn,offset,crn);
#else
        printf("\taddis %s,%s,%d@ha\n",crn,rrn,offset);
        printf("\t%s %s,%d@l(%s)\n",ld,crn,offset,crn);
#endif
    } else
        printf("\t%s %s,%d(%s)\n",ld,crn,offset,rrn);
}

static void 
code_ldf(char *ld,char *crn,int offset,int r)
{
    char *rrn = register_name(r);
    int reg;
    char *lrn;
    if (offset<-32768||32767<offset) {
        lrn = register_name(reg = get_register());
#ifdef __APPLE__
        printf("\taddis %s,%s,ha16(%d)\n",lrn,rrn,offset);
        printf("\t%s %s,lo16(%d)(%s)\n",ld,crn,offset,lrn);
#else
        printf("\taddis %s,%s,%d@ha\n",lrn,rrn,offset);
        printf("\t%s %s,%d@l(%s)\n",ld,crn,offset,lrn);
#endif
        free_register(reg);
    } else
        printf("\t%s %s,%d(%s)\n",ld,crn,offset,rrn);
}

void
code_gvar(int e1,int reg) {
    use_int(reg);
    code_add(reg,cadr(e1),get_ptr_cache(ncaddr(e1)));
    return;
}

void
code_rgvar(int e1,int reg) {
    use_int(reg);
    code_ld("lwz",reg,cadr(e1),get_ptr_cache(ncaddr(e1)));
}

void
code_crgvar(int e1,int reg,int sign,int sz){
    use_int(reg);
    code_ld(cload(sz),reg,cadr(e1),get_ptr_cache(ncaddr(e1)));
    cext(sign,sz,reg);
}



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

extern void
code_i2c(int reg)
{
    use_int(reg);
    cext(1,1,reg);
}

extern void
code_i2s(int reg)
{
    use_int(reg);
    cext(1,SIZE_OF_SHORT,reg);
}

extern void
code_u2uc(int reg)
{
    use_int(reg);
    cext(0,1,reg);
}

extern void
code_u2us(int reg)
{
    use_int(reg);
    cext(0,SIZE_OF_SHORT,reg);
}

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

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

void
code_fname(NMTBL *n,int reg) {
    int r;
    use_int(reg);
    r = get_ptr_cache(n);
    if(r!=reg)
        printf("\tmr %s,%s\n",register_name(reg),register_name(r));
    return;
}

void
code_label_value(int label,int reg) {
    char *crn;
    use_int(reg);
    crn = register_name(reg);
#ifdef __APPLE__
    printf("\taddis %s,r31,ha16(L_%d-L_%d)\n",crn,label,code_base);
    printf("\tla %s,lo16(L_%d-L_%d)(%s)\n",crn,label,code_base,crn);
#else
    printf("\tlis %s,.LC%d@ha\n",crn,label);
    printf("\tla %s,.LC%d@l(%s)\n",crn,label,crn);
#endif
    return;
}

void
code_const(int e2,int reg) {
    char *crn;
    use_int(reg);
    crn = register_name(reg);
    // printf("## 0x%08x\n",e2);
#ifdef __APPLE__
    if (-32768<e2&&e2<32768)
        printf("\tli %s,%d\n",crn,e2);
    else if ((e2&0xffff)==0)
        printf("\tlis %s,ha16(%d)\n",crn,e2);
    else {
        printf("\tlis %s,ha16(%d)\n",crn,e2);
        printf("\taddi %s,%s,lo16(%d)\n",crn,crn,e2);
    }
#else
    if (-32768<e2&&e2<32768)
        printf("\tli %s,%d\n",crn,e2);
    else if ((e2&0xffff)==0)
        printf("\tlis %s,%d@ha\n",crn,e2);
    else {
        printf("\tlis %s,%d@ha\n",crn,e2);
        printf("\taddi %s,%s,%d@l\n",crn,crn,e2);
    }
#endif
}

void
code_neg(int creg) {
    use_int(creg);
    printf("\tneg %s,%s\n", register_name(creg), register_name(creg));
}


void
code_not(int creg) {
    use_int(creg);
    printf("\tnor %s,%s,%s\n", 
        register_name(creg), register_name(creg),register_name(creg));
}


void
code_lnot(int creg) {
    use_int(creg);
#ifdef __APPLE__
    printf("\tsubfic r0,%s,0\n", register_name(creg));
    printf("\tadde %s,r0,%s\n", register_name(creg),register_name(creg));
#else
    printf("\tsubfic 0,%s,0\n", register_name(creg));
    printf("\tadde %s,0,%s\n", register_name(creg),register_name(creg));
#endif
}

void
code_preinc(int e1,int e2,int dir,int sign,int sz,int reg) {
    char *xrn,*drn;
    if (car(e2)==REGISTER) {
        use_int(reg);
        printf("\taddi %s,%s,%d\n", 
                register_name(cadr(e2)),register_name(cadr(e2)), dir);
        if (use && cadr(e2)!=reg)
            printf("\tmr %s,%s\n",register_name(reg),register_name(cadr(e2)));
        return;
    } 
    g_expr(e2);
    if (!is_int_reg(creg)) error(-1);
    xrn = register_name(creg);
    if (reg==USE_CREG) {
        reg=get_register(); if (!reg) error(-1);
        drn = register_name(reg);
        set_ireg(reg,0);
    } else {
        drn = register_name(reg);
    }
    printf("\t%s %s,0(%s)\n",cload(sz),drn,xrn);
    if (use) cext(sign,sz,reg);
    printf("\taddi %s,%s,%d\n",drn,drn,dir);
    printf("\t%s %s,0(%s)\n",cstore(sz),drn,xrn);
}


void
code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) {
    char *xrn,*crn,*nrn;
    int nreg;
    if (car(e2)==REGISTER) {
        use_int(reg);
        if (use)
            printf("\tmr %s,%s\n",register_name(reg),register_name(cadr(e2)));
        printf("\taddi %s,%s,%d\n", 
            register_name(cadr(e2)),register_name(cadr(e2)),dir);
        return;
    } 
    g_expr(e2);
    if (!is_int_reg(creg)) error(-1);
    crn = register_name(creg);
    nreg=get_register(); if (!nreg) error(-1);
    nrn = register_name(nreg);
    if (reg==USE_CREG) {
        reg=get_register(); if (!reg) error(-1);
        xrn = register_name(reg);
        set_ireg(reg,0);
    } else {
        xrn = register_name(reg);
    }
    printf("\t%s %s,0(%s)\n",cload(sz),xrn,crn);
    if (use) cext(sign,sz,reg);
    printf("\taddi %s,%s,%d\n",nrn,xrn,dir);
    printf("\t%s %s,0(%s)\n",cstore(sz),nrn,crn);
    free_register(nreg);
}


void
code_return(int creg) {

    use_int(creg);
    code_label_value(retcont,creg);
}

#define R1SAVE 0

void
code_environment(int creg) {
    /* save frame pointer */
    use_int(creg);
#if R1SAVE
    printf("\tlwz %s,0(%s)\n",register_name(creg),register_name(1));
#else
    printf("\tmr %s,%s\n",register_name(creg),register_name(REG_fp));
//    int l = 0;
//    printf("\tla %s,",register_name(creg));
//    printf("lo16(%d+L_%d)(r30)\n",FUNC_LVAR,lvar_offset_label);
#endif
}

static int rexpr_bool(int e1,int reg);

#if FLOAT_CODE
static int drexpr_bool(int e1,int reg);
#endif

#if LONGLONG_CODE
static int lrexpr_bool(int e1,int reg)
{
    return 0;
}
#endif



void
code_bool(int e1,int reg) {
    char *xrn;
    int e2,e3;

    if (rexpr_bool(e1,reg)) return;
#if FLOAT_CODE
    else if (drexpr_bool(e1,reg)) return;
#endif
#if LONGLONG_CODE
    else 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("\tli %s,0\n",xrn);
        jmp(e3=fwdlabel());
        fwddef(e2);
        printf("\tli %s,1\n",xrn);
        fwddef(e3);
    } else {
        fwddef(e2);
    }
}

#define code_gt(cond) (cond?"gt":"le")

#define code_ugt(cond) (cond?"gt":"le")

#define code_ge(cond) (cond?"ge":"lt")

#define code_uge(cond) (cond?"ge":"lt")

#define code_eq(cond) (cond?"eq":"ne")

static int cmpflag = 7;

static void
inc_cmpflag()
{
    //  gcc use cmpflag 4 and 7, and gcc4 believes flag 4 is preserved.
    do {
        cmpflag = (cmpflag+1)%8;
    } while (cmpflag!=4 && cmpflag!=7);
}

#ifdef __APPLE__
static
char *crname_[] = { "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7" };
#else
static
char *crname_[] = { "0", "1", "2", "3", "4", "5", "6", "7" };
#endif
#define crname(d)  (crname_[d])

void
code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) {
    use_int(reg);
    code_ld(cload(sz),reg,cadr(e1),get_ptr_cache(ncaddr(e1)));
    cext(0,sz,reg);
    inc_cmpflag();
    printf("\tcmpwi %s,%s,0\n",crname(cmpflag),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 %s,",cload(sz),crn);
    lvar(e2);
    cext(0,sz,reg);
    code_cmp_register(reg,label,cond);
}


void
code_cmp_rgvar(int e1,int reg,int label,int cond) {
    use_int(reg);
    code_ld("lwz",reg,cadr(e1),get_ptr_cache(ncaddr(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("\tlwz %s,",crn);
    lvar(e2);
    code_cmp_register(reg,label,cond);
}


void
code_cmp_register(int e2,int label,int cond) {
    use_int(e2);
    inc_cmpflag();
    printf("\tcmpwi %s,%s,0\n",crname(cmpflag),register_name(e2));
    jcond(label,cond);
}


void
code_string(int e1,int creg)
{
    int lb;
    NMTBL *n = ncaddr(e1);
    if ((lb=attr_value(n,LABEL))) {
        // already defined
        return code_label_value(lb,creg) ;
    }

    use_int(creg);
    lb = emit_string_label();
    ascii(n->nm,n->dsp);
    if (output_mode==TEXT_EMIT_MODE) {
        printf(".text\n");
    } else {
        text_mode(0);
    }
    code_label_value(lb,creg);
    set_attr(n,LABEL,lb);
}


void
emit_strings(NMTBL *n)
{
    int l = emit_string_label();
    int i;
    for(i = n->dsp; i; i = cadr(i)) {
        ascii(scaddr(i),car(i));
    }
    emit_label(l);
}

void
code_strings(int e2,int reg)
{
    int l = emit_string_label();
    int i;
    for(i = e2; i; i = cadr(i)) {
        ascii(scaddr(i),car(i));
    }
    if (output_mode==TEXT_EMIT_MODE) {
        printf(".text\n");
    } else {
        text_mode(0);
    }
    code_label_value(l,reg);
}

#define MAX_COPY_LEN 20
// #define MAX_COPY_LEN 10

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 l;
    int dreg = get_register(); if (!dreg) error(-1);

    drn  = register_name(dreg);
    use_int(from);
    use_int(to);
    frn =       register_name(from);
    trn =       register_name(to);

    /* length <0 means upward direction copy */
    switch (length) {
    case 0:     break;
    case 1: case -1:
        printf("\tlbz %s,%d(%s)\n",drn,offset,frn);
        printf("\tstb %s,%d(%s)\n",drn,offset,trn);
        break;
    case 2: case -2:
        printf("\tlhz %s,%d(%s)\n",drn,offset,frn);
        printf("\tsth %s,%d(%s)\n",drn,offset,trn);
        break;
    case 4: case -4:
        printf("\tlwz %s,%d(%s)\n",drn,offset,frn);
        printf("\tstw %s,%d(%s)\n",drn,offset,trn);
        break;
    default:
        if (length <0) {
            if (length >= -MAX_COPY_LEN) {
                free_register(dreg); dreg = 0;
                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) {
            free_register(dreg); dreg = 0;
            for(;length>=4;length-=4,offset+=4)
                emit_copy(from,to,4,offset,0,det);
            for(;length>=2;length-=2,offset+=2)
                emit_copy(from,to,2,offset,0,det);
            if(length>0)
                emit_copy(from,to,length,offset,0,det);
            break;
        }
        clear_ptr_cache();
        code_save_stacks();

        l = list3(3,0,to);
        l = list3(4,l,from);
        parallel_rassign(l);

#ifdef __APPLE__
        printf("\tli r5,%d\n",length>0?length:-length);
        /* offset should be ignored */
        /* overrap must be allowed */
        printf("\tbl L_%s$stub\n",memmove);
#else
        printf("\tli 5,%d\n",length>0?length:-length);
        /* offset should be ignored */
        /* overrap must be allowed */
        printf("\tbl %s\n",memmove);
#endif
        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(to);
            // set_ireg(to,1);
        }
    }
    if (dreg) free_register(dreg);
}

int
push_struct(int e4,int t,int arg) 
{
    int length,count;
    int dreg,sreg; char *drn,*crn,*srn;
    g_expr(e4);
    if (!is_int_reg(creg)) error(-1);
    length=size(t); 
    if(length%SIZE_OF_INT) {
        length += SIZE_OF_INT - (length%SIZE_OF_INT);
    }
    dreg = get_register(); if (!dreg) error(-1);
    drn = register_name(dreg);
    crn = register_name(creg);
    if (length<MAX_COPY_LEN) {
        sreg = get_register(); if (!sreg) error(-1);
        srn = register_name(sreg);
        code_lvar(cadr(arg),dreg);
        for(count=0;count<length;count+=SIZE_OF_INT) {
            printf("\tlwz %s,%d(%s)\n",srn,count,crn);
            printf("\tstw %s,%d(%s)\n",srn,count,drn);
        }
        free_register(sreg);
        free_register(dreg);
        return length/SIZE_OF_INT;
    } else {
        code_lvar(cadr(arg),dreg);
        /* downward direction copy */
        emit_copy(creg,dreg,length,0,0,1);
    }
    free_register(dreg);
    return length/SIZE_OF_INT;
}

static void
set_ireg(int reg,int mode)
{
    if (!is_int_reg(reg)) error(-1);
    if (reg!=creg) {
        clear_ptr_cache_reg(reg);
        if (ireg && reg!=ireg ) {
            clear_ptr_cache_reg(ireg);
            if (regs[ireg]!=REG_VAR) free_register(ireg);
            if (mode) {
                printf("\tmr %s,%s\n",register_name(reg),register_name(ireg));
            }
        }
        if (regs[creg]!=REG_VAR) {
            clear_ptr_cache_reg(creg);
            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("\tfmr %s,%s\n",fregister_name(reg),fregister_name(freg));
            }
        }
        // if (creg!=ireg) free_register(creg);
        regs[reg]=USING_REG;
    }
    creg = freg = reg;
}

static void
set_lreg(int reg,int mode)
{
    if (reg==RET_LREGISTER) {
        regv_l(reg) = RET_LREGISTER_L;
        regv_h(reg) = RET_LREGISTER_H;
    }
    if (!is_longlong_reg(reg)) error(-1);
    if (reg!=creg) {
        if (lreg) {
            if (reg!=lreg) {
                if (mode) {
                    printf("\tmr %s,%s\n",
                        lregister_name_low(reg),lregister_name_low(lreg));
                    printf("\tmr %s,%s\n",
                        lregister_name_high(reg),lregister_name_high(lreg));
                }
                free_register(lreg);
            }
            if (lreg==creg) creg=0;
        }
        if (creg) free_register(creg);
        regs[reg]=USING_REG;
        clear_ptr_cache_reg(regv_l(reg));
        regs[regv_l(reg)]=USING_REG;
        clear_ptr_cache_reg(regv_h(reg));
        regs[regv_h(reg)]=USING_REG;
        creg = lreg = reg;
    }
}

static void
set_lreg_operand(int reg,int mode)
{
    // save_stack,clear_ptr_cache is assumed    
    if (!is_longlong_reg(reg)) { error(-1); return; }
    if (mode) {
        if (regv_l(reg)!=3)
            printf("\tmr %s,%s\n", register_name(3),lregister_name_high(reg));
        if (regv_l(reg)!=4)
            printf("\tmr %s,%s\n", register_name(4),lregister_name_low(reg));
    }
}

static void
set_lreg_operand1(int reg,int mode)
{
    // save_stack,clear_ptr_cache is assumed    
    if (!is_longlong_reg(reg)) { error(-1); return; }
    if (mode) {
        if (regv_l(reg)!=5)
            printf("\tmr %s,%s\n", register_name(5),lregister_name_high(reg));
        if (regv_l(reg)!=6)
            printf("\tmr %s,%s\n", register_name(6),lregister_name_low(reg));
    }
}

static void
use_reg(int arg)
{
// printf("## use reg %d\n",arg);
    if (arg<0||arg> REAL_MAX_REGISTER+REAL_MAX_FREGISTER+ REAL_MAX_LREGISTER)
        error(-1);
    clear_ptr_cache_reg(arg);
    regs[arg]=USING_REG;
    if (is_longlong_reg(arg)) {
        clear_ptr_cache_reg(regv_l(arg));
        regs[regv_l(arg)]=USING_REG;
        clear_ptr_cache_reg(regv_h(arg));
        regs[regv_h(arg)]=USING_REG;
    }
}

/*
    store input argument into stack
    we need this always because of one path compiler
 */
static void
code_save_input_registers(int dots)
{
    int args;
    NMTBL *n;
    int reg;
    int tag;
    // int lvar;
    int t;
    /* fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); */
    int reg_offset = 0;
    int offset = 0;
    int reg_var = 0;
    if (!parse_mode && dots) {
        int stype = type; int smode = mode;
        type = INT;
        mode = LDECL;
        stmode = 0;
        // lsearch defines local name
        NMTBL *n = def(lsearch("__my_va_list",0),0);
        n->dsp = offset;
        type = stype; mode = smode;
    }


    for(args = fnptr->dsp;args;args = cadr(args)) {
        n = ncadddr(args);
        tag = n->sc;
        reg = n->dsp;
        if (!n||n==&null_nptr) error(REG_ERR);
        if (tag==REGISTER) {
            n->dsp = offset;
            offset+=SIZE_OF_INT;
            t = INT;
            reg += reg_offset; /* for duplicated floating point argument */
            reg_var++;
        } else if (tag==DREGISTER) {
            n->dsp = offset;
            t = n->ty;
#ifdef __APPLE__
            if(t==FLOAT) { offset+=SIZE_OF_FLOAT; reg_offset+=1; }
            else if(t==DOUBLE) { offset+=SIZE_OF_DOUBLE; reg_offset+=2; }
            else error(-1);
            reg_var += 2;
#else
            if(t==FLOAT) { offset+=SIZE_OF_FLOAT;  }
            else if(t==DOUBLE) { offset+=SIZE_OF_DOUBLE; }
            else error(-1);
#endif
        } else if (tag==LREGISTER) {
            n->dsp = offset;
            t = n->ty;
            offset+=SIZE_OF_LONGLONG; 
            reg_offset+=2;
            reg_var += 2;
        } else {
            // n->dsp = offset;  this is no allowed becase of arg reorder
            offset += size(n->ty);
            continue;
        }
        n->sc  = LVAR;
        g_expr_u(assign_expr0(
            list3n(LVAR,n->dsp,0),list3n(tag,reg,n),n->ty,t));
        if (tag==REGISTER||tag==DREGISTER||tag==FREGISTER||tag==LREGISTER) {
            free_register(reg);
        }
    }
    if (dots) {
        while ((reg = get_input_register_var(reg_var,0,0))) {
            g_expr_u(assign_expr0(
                list3n(LVAR,offset,0),reg,INT,INT));
            offset+=SIZE_OF_INT;
            reg_var++;
        }
#ifndef __APPLE__
        int skip = fwdlabel();
        int freg_var = 0;
        printf("\tbne 1,%s%d\n",lpfx,skip);
        while ((reg = get_input_dregister_var(freg_var,0,0,1))) {
            g_expr_u(assign_expr0(
                list3n(LVAR,offset,0),reg,DOUBLE,DOUBLE));
            offset+=SIZE_OF_DOUBLE;
            freg_var++;
        }
        fwddef(skip);
#endif
    }
    my_func_args = offset;
}

int
not_simple_p(int e3)
{
    switch (e3) {
        case FUNCTION: case CONV: case LCALL: case STASS:  
        case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: 
        case LDIV: case LUDIV: case LMOD: case LUMOD: case LASSOP: case ALLOCA:
        case INLINE:
    return 1;
    }
    return 0;
}

static int
simple_arg(int e3)
{
    return !contains_p(e3,not_simple_p);
}

#define caller_arg_offset_v(arg) (ARG_LVAR_OFFSET+(arg)*SIZE_OF_INT)

/*
     use input register as current register
        なんで、こんなに複雑なんだ?
        むしろ、INPUT_REG みたいな mark をいれたら?
 */

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) {
            // free_regsiter(lreg) でいいんじゃないの?
            if (regv_l(lreg)==reg) {
                regs[lreg]=0;
                if (regv_h(lreg)>reg&&regs[regv_h(lreg)]==USING_REG) {
                    free_register(regv_h(lreg));
                }
                if (creg==lreg) creg = ireg;
                free_register(lreg);
                lreg = 0;
            } else if (regv_h(lreg)==reg) {
                regs[lreg]=0;
                if (regv_h(lreg)>reg&&regs[regv_l(lreg)]==USING_REG) {
                    free_register(regv_l(lreg));
                }
                if (creg==lreg) creg = ireg;
                free_register(lreg);
                lreg = 0;
            }
        }
    } else if (is_longlong_reg(reg)) {
        use_input_reg(regv_h(reg),mode);
        use_input_reg(regv_l(reg),mode);
    } else if (is_float_reg(reg)) {
        if (freg&&reg == freg) {
            if (creg==freg) creg = ireg; 
            freg = 0;
        } 
    }
    if (mode) use_reg(reg);
}

static int
compute_complex_arg(int e3,int reg_arg_list,int arg) {
    int t=caddr(e3);
    int e4 = car(e3);
    reg_arg_list = list2(arg,reg_arg_list);
    if (car(arg)==REGISTER||car(arg)==DREGISTER||
        car(arg)==FREGISTER||car(arg)==LREGISTER)
        use_input_reg(cadr(arg),1);
    g_expr_u(assign_expr0(arg,e4,t,t));
    car(e3) = arg;
    return reg_arg_list;
}


#ifdef __APPLE__
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=type_value(caddr(e3));
    if (t>=0&&(car(t)==BIT_FIELD)) {
        t = type_value(cadr(t));
    }
    if(scalar(t)) {
        nargs ++ ; reg_arg++;
    } else if (t==LONGLONG||t==ULONGLONG) {
        nargs ++ ; reg_arg++;
        nargs ++ ; reg_arg++;
    } else if (t==FLOAT) {
        if (*preg_arg<MAX_INPUT_REGISTER_VAR) {
            reg_arg += 1;
        }
        freg_arg++;
        nargs += size(t)/SIZE_OF_INT;
    } else if (t==DOUBLE) {
        if (*preg_arg<MAX_INPUT_REGISTER_VAR) {
            reg_arg += 2;
        }
        nargs += size(t)/SIZE_OF_INT;
        freg_arg++;
    } 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;
}
#else
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=type_value(caddr(e3));
    if (t>=0&&(car(t)==BIT_FIELD)) {
        t = type_value(cadr(t));
    }
    if(scalar(t)) {
        reg_arg++;
        if (*preg_arg>=MAX_INPUT_REGISTER_VAR) nargs ++ ; 
    } else if (t==LONGLONG||t==ULONGLONG) {
        if (*preg_arg%2==1) reg_arg++;  // alignment
        if (*pnargs%2==1) nargs++;  // alignment
        reg_arg++; reg_arg++;
        if (*preg_arg+1>=MAX_INPUT_REGISTER_VAR)  nargs += 2;
    } else if (t==FLOAT) {
        freg_arg++;
        if (*pfreg_arg>=MAX_INPUT_DREGISTER_VAR) nargs += size(t)/SIZE_OF_INT;
    } else if (t==DOUBLE) {
        freg_arg++;
        if (*pfreg_arg>=MAX_INPUT_DREGISTER_VAR) nargs += round4(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;
}
#endif

#define AS_SAVE 1
#define AS_ARG  0

/*
     set storage type of caller's arguments
         register or stack
     this muse corprate with code_arg_register();
     if AS_SAVE is set, register variable (or temporary local variable)
     is used.
 */

static int
get_input_arg(int t,int mode,int nargs,int reg_arg,int freg_arg) 
{
    t = type_value(t);
    if (t>=0&&(car(t)==BIT_FIELD)) {
        t = type_value(cadr(t));
    }
    if(scalar(t)) {
        if (mode==AS_SAVE) {
            return get_register_var(0);
        } else if (reg_arg>=MAX_INPUT_REGISTER_VAR) {
            return list3n(LVAR,caller_arg_offset_v(nargs),0);
        } else  {
            int e =  get_input_register_var(reg_arg,0,0);
            clear_ptr_cache_reg(cadr(e));
            return e;
        }
    } 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 list3n(LVAR,caller_arg_offset_v(nargs),0);
        } else {
            int e =  get_input_lregister_var(reg_arg,0,0);
            clear_ptr_cache_reg(regv_l(cadr(e)));
            clear_ptr_cache_reg(regv_h(cadr(e)));
            return e;
        }
    } else if (t==FLOAT) {
        if (mode==AS_SAVE) {
            return get_dregister_var(0,0);
        } else if (freg_arg>=MAX_INPUT_DREGISTER_VAR) {
            return list3n(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 (freg_arg>=MAX_INPUT_DREGISTER_VAR) {
            return list3n(LVAR,caller_arg_offset_v(nargs),0);
        } else
            return get_input_dregister_var(freg_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 list3n(LVAR,caller_arg_offset_v(nargs),0);
    } else {
        error(-1);
        return get_register_var(0);
    }
}

int
function(int e1)
{
    int e2,e3,e4,e5,nargs,t,r0;
    int arg,reg_arg,freg_arg,arg_assign;
    int dots;
    int reg_arg_list=0,ret_type,special_lvar;
    NMTBL *fn = 0;
    int jmp = 0;
    char *jrn;
    int complex_;
    int pnargs=0,preg_arg=0,pfreg_arg=0;
    int stargs;

    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=ncaddr(e2);
    } else {    
        if (car(e2)==INDIRECT) e2=cadr(e2); // (*func)(i) case
        jmp = get_register_var(0);
        if (car(jmp)!=REGISTER) error(-1);
        reg_arg_list = list2(jmp,reg_arg_list);
        if (!simple_arg(e2)) {
            g_expr_u(assign_expr0(jmp,e2,INT,INT));
        } else
            arg_assign = list2(assign_expr0(jmp,e2,INT,INT),arg_assign);
    }
    /* first we execute complex argument to avoid interaction with
       input variables */
    stargs = 0;
    complex_ = 0;
    nargs = reg_arg = freg_arg = 0;
    for (e3 = e1 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) {    
        t=caddr(e3);
        if ((e5= !simple_arg(car(e3)))) {
            if (complex_) {
                arg = get_input_arg(caddr(complex_),AS_SAVE,
                                        pnargs,preg_arg,pfreg_arg);
                reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg);
            }
            pnargs=nargs;preg_arg=reg_arg;pfreg_arg=freg_arg;
            complex_ = e3;
        }
        if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) {
            // The struct should be pushed after complex arguments.
            if (e5) { // compute address only, complex_ is me now. Clear it.
                complex_ = 0;
                e4 = car(e3);
                if (car(e4)==INDIRECT) e4 = cadr(e4);
                if (!simple_arg(e4)) {
                    // Calculate complex struct address here.
                    // If simple, leave it.
                    arg = get_register_var(0);
                    g_expr_u(assign_expr0(arg,e4,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
        }
    } 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);
        }
    }

    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));
        if (t==LONGLONG||t==ULONGLONG) {
            if (reg_arg+1==MAX_INPUT_REGISTER_VAR) {
                // half register, half memory case
                arg_assign = list2(
                    assign_expr0(r0=get_input_register_var(reg_arg,0,0),
                        arg,INT,INT),
                    arg_assign);
                use_input_reg(cadr(r0),1);
            }
        }
        car(e3)=0;  // done
    }
    nargs = reg_arg = freg_arg = 0;
    for (e3 = e1; e3; 
                increment_function_arg(e3,&nargs,&reg_arg,&freg_arg),
                e3 = cadr(e3)) {        
        if (!(e4=car(e3))) continue;
        t=type_value(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) {
                set_ireg(cadr(arg),0);
                g_expr_u(assign_expr0(arg,e4,t,t));
                use_input_reg(cadr(arg),1);
            } else
                g_expr_u(assign_expr0(arg,e4,t,t));
        } else if (t==LONGLONG||t==ULONGLONG) {
            if (reg_arg+1==MAX_INPUT_REGISTER_VAR) { 
                // half register, half memory case
                // put whole long long anyway
                arg_assign = list2(
                    assign_expr0(r0=get_input_register_var(reg_arg,0,0),
                        arg,INT,INT),
                    arg_assign);
                use_input_reg(cadr(r0),1);
                reg_arg_list = list2(r0,reg_arg_list);
            } else {
                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||t==FLOAT) {
#ifdef __APPLE__
            if (reg_arg<MAX_INPUT_REGISTER_VAR) {
                /* sigh... 
                   printf requires floating value in integer registers
                 */
                if (dots) {
                    int r1;
                    if (car(e4)==DRLVAR) {
                        special_lvar = cadr(e4);
                        e5 = list3n(LVAR,special_lvar,0);
                    } else {
                        special_lvar = new_lvar(SIZE_OF_DOUBLE);
                        g_expr(assign_expr0(
                            (e5=list3n(LVAR,special_lvar,0)),e4,DOUBLE,t));
                        reg_arg_list = list2(e5,reg_arg_list);
                        e4 = list2(DREGISTER,freg);
                        /* freg should not change until XXX */
                    }
                    r0=get_input_register_var(reg_arg,0,0);
                    r1 = reg_arg+1+MIN_TMP_REG;
                    if (regs[r1]==PTRC_REG) 
                        clear_ptr_cache_reg(list2(REGISTER,r1));
                    /* else if (regs[r1]) error(-1); */
                    r1=get_input_register_var_1(reg_arg+1,0,0);
                    use_input_reg(cadr(r0),1); /* protect from input register free */
                    use_input_reg(cadr(r1),1); /* protect from input register free */
                    reg_arg_list = list2(r0,reg_arg_list);
                    reg_arg_list = list2(r1,reg_arg_list);
                    arg_assign = list2( assign_expr0(r0,e5,INT,INT), arg_assign);
                    arg_assign = list2( assign_expr0(r1,
                            list3n(LVAR,special_lvar+SIZE_OF_INT,0),
                            INT,INT), arg_assign);
                }
            }
            if (dots && (freg_arg*8+reg_arg*4)>=32 && freg_arg<MAX_INPUT_DREGISTER_VAR) { 
                /* 
                   it requires integer register and floating register and
                   stack value.
                 */
                arg_assign = list2(
                    assign_expr0(list3n(LVAR,caller_arg_offset_v(nargs),0),
                            get_input_dregister_var(freg_arg,0,0,1),t,t),
                    arg_assign);
            }
#endif
            reg_arg_list = list2(arg,reg_arg_list);
            if (car(arg)==DREGISTER) {
                set_freg(cadr(arg),0);
                g_expr_u(assign_expr0(arg,e4,t,t));
                use_input_reg(cadr(arg),1);
            } else
                g_expr_u(assign_expr0(arg,e4,t,t));
        }
        // 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();
#ifndef __APPLE__
    if (dots) {
        if (freg_arg) {
        //  variadic function has floating value in register
            printf("\tcreqv 6,6,6\n");
        } else {
        //    printf("\tcrxor 6,6,6\n"); // for value in stack 
        }
    }
#endif
    if (car(e2) == FNAME) {     
#ifdef __APPLE__
        printf("\tbl\tL_%s$stub\n",fn->nm);
#else
        printf("\tbl\t%s\n",fn->nm);
#endif
    } else {
        jrn = register_name(cadr(jmp));
        printf("\tmtctr %s\n",jrn);
        printf("\tbctrl\n");
    }
    free_register_var(reg_arg_list);
    if (ret_type==DOUBLE||ret_type==FLOAT) {
        set_freg(RET_FREGISTER,0);
    } else if (ret_type==ULONGLONG||ret_type==LONGLONG) {
        set_lreg(RET_LREGISTER,0);
        use_reg(RET_LREGISTER);
    } else if (ret_type==VOID) {
    } else {
        set_ireg(RET_REGISTER,0);
    }
    cleanup_lregister0();
    return ret_type;
}

void
code_alloca(int e1,int reg)
{
    char *crn,*grn;
    int g;

    if (!is_const(e1)) {
        g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); 
        use_int(reg);
    } else {
        use_int(reg);
        code_const(round16(cadr(e1)),reg);
    }
    use_int(reg);
    g = get_register();
    crn = register_name(reg);
    grn = register_name(g);
//    printf("\trlwinm r0,%s,0,0,27\n",crn);
#ifdef R1SAVE
    printf("\tlwz %s,0(%s)\n",grn,register_name(1));
    printf("\tneg %s,%s\n",crn,crn);
    printf("\tstwux %s,%s,%s\n",grn,register_name(1),crn);
#else
    printf("\tlwz %s,0(%s)\n",grn,register_name(1));
    printf("\tneg %s,%s\n",crn,crn);
    printf("\tstwux %s,%s,%s\n",grn,register_name(1),crn);
#endif
//    printf("\tstw %s,0(r1)\n",grn);
    if (!max_func_arg_label) max_func_arg_label = fwdlabel();
#ifdef __APPLE__
    printf("\taddis r1,r1,ha16(L_%d)\n",max_func_arg_label);
    printf("\taddi %s,r1,lo16(L_%d)\n",crn,max_func_arg_label);
#else
    printf("\taddis 1,1,.LC%d@ha\n",max_func_arg_label);
    printf("\taddi %s,1,.LC%d@l\n",crn,max_func_arg_label);
#endif
    free_register(g);
}

void
code_frame_pointer(int e3) {
    use_int(e3);
#if R1SAVE
    printf("\tmr %s,%s\n",register_name(1),register_name(e3));
#else
    printf("\tmr %s,%s\n",register_name(REG_fp),register_name(e3));
#endif
}

int
code_frame_pointer_register()
{
    return list2(REGISTER,REG_fp);
}

void
code_fix_frame_pointer(int disp_offset) {
#if 0
    printf("\tla r30,");
    printf("lo16(%d)(r30)\n",FUNC_LVAR(0)-CODE_LVAR(0));
#endif
}

void
code_jmp(char *s) {
    max_reg_var = REG_VAR_BASE-REG_VAR_MIN;
    max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN;
#ifdef __APPLE__
    printf("\tb L_%s$stub\n",s);
#else
    printf("\tb %s\n",s);
#endif
    control=0;
}


void
code_indirect_jmp(int e2) {
    max_reg_var = REG_VAR_BASE-REG_VAR_MIN;
    max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN;
    use_int(e2);
    printf("\tmtctr %s\n",register_name(e2));
    printf("\tbctr\n");
    control=0;
}

static void
code_add_op(char *op, char *crn, int offset, char *rrn)
{
#ifdef __APPLE__
    if (LARGE_OFFSET(offset)) {
        printf("\taddis %s,%s,ha16(%d)\n",crn,crn,offset);
    }
    printf("\t%s %s,lo16(%d)(%s)\n",op,crn,offset,rrn);
#else
    if (LARGE_OFFSET(offset)) {
        printf("\taddis %s,%s,%d@ha\n",crn,crn,offset);
    }
    printf("\t%s %s,%d@l(%s)\n",op,crn,offset,rrn);
#endif
}

void
code_rindirect(int e1, int reg,int offset, int sign,int sz)
{
    char *crn,*rrn;
    g_expr(e1);
    if (!is_int_reg(creg)) error(-1);
    crn=register_name(creg);
    use_int(reg);
    rrn=register_name(reg);
    code_add_op(cload(sz),rrn,offset,crn);
    cext(sign,sz,reg);
}

#if FLOAT_CODE
int
code_drindirect(int e1, int reg,int offset, int d)
{
    char *crn;
    g_expr(e1);
    if (!is_int_reg(creg)) error(-1);
    crn=register_name(creg);
    use_float(d,reg);
    code_add_op(fload(d),fregister_name(reg),offset,crn);

    return d?DOUBLE:FLOAT;
}
#endif

#if LONGLONG_CODE


static void
lload(int creg,int reg,int offset)
{
    char *crn = register_name(creg);
#ifdef __APPLE__
    if (LARGE_OFFSET(offset)) {
        printf("\taddis %s,%s,ha16(%d)\n",crn,crn,offset);
    }
#if ENDIAN_L==0
    if (creg!=regv_l(reg)) {
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset,crn);
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn);
    } else {
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn);
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset,crn);
    }
#else
    if (creg!=regv_h(reg)) {
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset,crn);
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn);
    } else {
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn);
        printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset,crn);
    }
#endif
#else
    if (LARGE_OFFSET(offset)) {
        printf("\taddis %s,%s,%d@ha\n",crn,crn,offset);
    }
#if ENDIAN_L==0
    if (creg!=regv_l(reg)) {
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset,crn);
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn);
    } else {
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn);
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset,crn);
    }
#else
    if (creg!=regv_h(reg)) {
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset,crn);
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn);
    } else {
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn);
        printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset,crn);
    }
#endif

#endif
}

int
code_lrindirect(int e1, int reg, int offset, int us)
{
    char *crn;
    int creg0;

    g_expr(e1);
    if (!is_int_reg(creg)) error(-1);
    crn=register_name(creg0=creg);
    use_longlong(reg);
    lload(creg0,reg,offset);
    return us?ULONGLONG:LONGLONG;
}
#endif

void
code_assign_gvar(int e2,int creg,int byte) {
    use_int(creg);
    code_ldf(cstore(byte),register_name(creg),cadr(e2),
        get_ptr_cache(ncaddr(e2)));
}

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 %s,",cstore(byte),crn);
    lvar(e2);
}

void
code_assign_register(int e2,int byte,int creg) {
    use_int(creg);
    if (e2!=creg)
        printf("\tmr %s,%s\n",register_name(e2),register_name(creg));
}

void
code_assign(int e2,int byte,int creg) {
    char *drn;
    char *crn;
    use_int(e2);
    drn=register_name(e2);
    use_int(creg);
    crn=register_name(creg);

    printf("\t%s %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) {
    int xreg;
    //  (*pop()) op = creg
    //     creg should be ecx 
    
    use_int(creg);
    xreg = emit_pop(0);       /* pop e3 value */
    emit_push();
    ld_indexx(byte,0,creg,ireg,sign);
    tosop(op,ireg,xreg);
    emit_pop_free(xreg);
    xreg = emit_pop(0);       /* pop e3 value */
    printf("\t%s %s,0(%s)\n",cstore(byte),
        register_name(ireg),register_name(xreg));
    emit_pop_free(xreg);
}

int
tosop_operand_safe_p(int op)
{
    return 1;
}

void
tosop(int op,int creg,int oreg)
{
    int dx = -1;
    int ox = -1;
    char *orn,*crn,*drn;
    // 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("slw",creg,oreg);
        if(ox!=-1) free_register(ox);
        return;
    case RSHIFT:
        shift("sraw",creg,oreg);
        if(ox!=-1) free_register(ox);
        return;
    case URSHIFT:
        shift("srw",creg,oreg);
        if(ox!=-1) free_register(ox);
        return;
    }
    orn = register_name(oreg);
    crn = register_name(creg);
    switch(op) {
    case ADD:
        printf("\tadd %s,%s,%s\n",crn,crn,orn);
        break;
    case SUB:
        printf("\tsub %s,%s,%s\n",crn,crn,orn);
        break;
    case CMP:
        inc_cmpflag();
        printf("\tcmpw %s,%s,%s\n",crname(cmpflag),crn,orn);
        break;
    case UCMP:
        inc_cmpflag();
        printf("\tcmplw %s,%s,%s\n",crname(cmpflag),crn,orn);
        break;
    case BAND: 
        printf("\tand %s,%s,%s\n",crn,crn,orn);
        break;
    case EOR: 
        printf("\txor %s,%s,%s\n",crn,crn,orn);
        break;
    case BOR:
        printf("\tor %s,%s,%s\n",crn,crn,orn);
        break;
    case MUL:
        printf("\tmullw %s,%s,%s\n",crn,crn,orn);
        break;
    case UMUL:
        printf("\tmullw %s,%s,%s\n",crn,crn,orn);
        break;
    case DIV:
        printf("\tdivw %s,%s,%s\n",crn,crn,orn);
        break;
    case UDIV:
        printf("\tdivwu %s,%s,%s\n",crn,crn,orn);
        break;
    case MOD:
        dx=get_register();
        drn = register_name(dx);
        printf("\tdivw %s,%s,%s\n",drn,crn,orn);
        printf("\tmullw %s,%s,%s\n",drn,drn,orn);
        printf("\tsubf %s,%s,%s\n",crn,drn,crn);
        break;
    case UMOD:
        dx=get_register();
        drn = register_name(dx);
        printf("\tdivwu %s,%s,%s\n",drn,crn,orn);
        printf("\tmullw %s,%s,%s\n",drn,drn,orn);
        printf("\tsubf %s,%s,%s\n",crn,drn,crn);
        break;
    default:
        error(-1);
    }
    if(dx!=-1) free_register(dx);
    if(ox!=-1) free_register(ox);
}

int 
code_const_op_p(int op,int v)
{
    if (car(v)!=CONST) return 0;
    if (op==DIV||op==UDIV) return ilog(v);
    if (op==BAND||op==MOD||op==UMOD) return 0;
    v = cadr(v);
    return (-32766<v&&v<32767);
}

void
oprtc(int op,int creg, int v)
{
    char *crn;
    int l;
    use_int(creg);
    crn = register_name(creg);
    v = cadr(v);
    
    switch(op) {
    case LSHIFT:
    case ULSHIFT:
        printf("\tslwi %s,%s,%d\n",crn,crn,v);
        return;
    case DIV:
        v = ilog(v);
    case RSHIFT:
        printf("\tsrawi %s,%s,%d\n",crn,crn,v);
        return;
    case UDIV:
        v = ilog(v);
    case URSHIFT:
        printf("\tsrwi %s,%s,%d\n",crn,crn,v);
        return;
    case ADD:
#ifdef __APPLE__
        printf("\taddi %s,%s,lo16(%d)\n",crn,crn,v);
#else
        printf("\taddi %s,%s,%d@l\n",crn,crn,v);
#endif
        break;
    case SUB:
#ifdef __APPLE__
        printf("\taddi %s,%s,lo16(-%d)\n",crn,crn,v);
#else
        printf("\taddi %s,%s,-%d@l\n",crn,crn,v);
#endif
        break;
    case CMP:
        inc_cmpflag();
#ifdef __APPLE__
        printf("\tcmpwi %s,%s,lo16(%d)\n",crname(cmpflag),crn,v);
#else
        printf("\tcmpwi %s,%s,%d@l\n",crname(cmpflag),crn,v);
#endif
        break;
    case UCMP:
        inc_cmpflag();
#ifdef __APPLE__
        printf("\tcmplwi %s,%s,lo16(%d)\n",crname(cmpflag),crn,v);
#else
        printf("\tcmplwi %s,%s,%d@l\n",crname(cmpflag),crn,v);
#endif
        break;
    case EOR: 
#ifdef __APPLE__
        printf("\txori %s,%s,lo16(%d)\n",crn,crn,v);
#else
        printf("\txori %s,%s,%d@l\n",crn,crn,v);
#endif
        break;
    case BOR:
#ifdef __APPLE__
        printf("\tori %s,%s,lo16(%d)\n",crn,crn,v);
#else
        printf("\tori %s,%s,%d@l\n",crn,crn,v);
#endif
        break;
    case MUL:
    case UMUL:
        if ((l=ilog(v))) {
            printf("\tslwi %s,%s,%d\n",crn,crn,l);
        } else
#ifdef __APPLE__
            printf("\tmulli %s,%s,lo16(%d)\n",crn,crn,v);
#else
            printf("\tmulli %s,%s,%d@l\n",crn,crn,v);
#endif
        break;
    default:
        error(-1);
    }
}

void
shift(char *op, int creg, int reg)
{
    char *crn;
    char *rrn = register_name(reg);
    use_int(creg);
    crn = register_name(creg);
    printf("\t%s %s,%s,%s\n",op,crn,crn,rrn);
}

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

int
code_csvalue()
{
    return glist2(REGISTER,creg);
}

void
code_cmpdimm(int e, int csreg,int label,int cond)
{
    int reg,regsv;
    /* used in dosiwtch() */
    inc_cmpflag();
    if (-32767<e&&e<32767) {
        printf("\tcmpwi %s,%s,%d\n",crname(cmpflag),register_name(csreg),e);
        jcond(label,cond);
    } else {
        regsv = regs[csreg]; regs[csreg]=USING_REG;
        reg = get_register();
        regs[csreg]= regsv;
        code_const(e,reg);
        printf("\tcmpw %s,%s,%s\n",crname(cmpflag),register_name(csreg),register_name(reg));
        jcond(label,cond);
        free_register(reg);
    }
}

void
code_opening(char *filename)
{
    printf("\t.file \"%s\"\n",filename);
    /* printf("\t.version\t\"01.01\"\n"); */
    printf("cbc_compiled.:\n"); 
    // printf(".text\n");
#ifndef __APPLE__
    printf(
"     .set r0,0\n"
"     .set r1,1\n"
"     .set r2,2\n"
"     .set r3,3\n"
"     .set r4,4\n"
"     .set r5,5\n"
"     .set r6,6\n"
"     .set r7,7\n"
"     .set r8,8\n"
"     .set r9,9\n"
"     .set r10,10\n"
"     .set r11,11\n"
"     .set r12,12\n"
"     .set r13,13\n"
"     .set r14,14\n"
"     .set r15,15\n"
"     .set r16,16\n"
"     .set r17,17\n"
"     .set r18,18\n"
"     .set r19,19\n"
"     .set r20,20\n"
"     .set r21,21\n"
"     .set r22,22\n"
"     .set r23,23\n"
"     .set r24,24\n"
"     .set r25,25\n"
"     .set r26,26\n"
"     .set r27,27\n"
"     .set r28,28\n"
"     .set r29,29\n"
"     .set r30,30\n"
"     .set r31,31\n"
      );
#endif

}

#define CRBITSIZ 4

static int
rexpr_bool(int e1,int reg)
{
    int t,flag=-1,eq=-1,neg=-1;
    char *rn;
    switch(car(e1)) {
    case GT:  t=INT; flag = 2; break;
    case UGT: t=0;   flag = 2; break;
    case GE:  t=INT; flag = 2; eq=3; break;
    case UGE: t=0;   flag = 2; eq=3; break;
    case LT:  t=INT; flag = 1; break;
    case ULT: t=0;   flag = 1; break;
    case LE:  t=INT; flag = 1; eq=3; break;
    case ULE: t=0;   flag = 1; eq=3; break;
    case EQ:  t=INT; flag = 3; break;
    case NEQ: t=INT; flag = 3; neg=3; break;
    default: return 0;
    }
    g_expr(list3((t==INT?CMP:UCMP),cadr(e1),caddr(e1)));
    use_int(reg);
    rn = register_name(reg);
    t = CRBITSIZ*cmpflag;
    if (eq>0) {
        printf("\tcror %d,%d,%d\n",t+flag-1,t+eq-1,t+flag-1);
    }
    if (neg>0) {
        neg = t+neg-1,
        printf("\tcrnor %d,%d,%d\n",neg,neg,neg);
    }
    printf("\tmfcr %s\n",rn);
    printf("\trlwinm %s,%s,%d,1\n",rn,rn,t+flag);
    return 1;
}

int
rexpr(int e1, int l1, int cond,int t)
{       
    char *s=0;
    switch(car(e1)+BNOT*(!cond)) {
    case GT:  s=code_gt(1);  break;
    case UGT: s=code_ugt(1); break;
    case GE:  s=code_ge(1);  break;
    case UGE: s=code_uge(1); break;
    case LT:  s=code_ge(!1); break;
    case ULT: s=code_uge(!1);break;
    case LE:  s=code_gt(!1); break;
    case ULE: s=code_ugt(!1);break;
    case EQ:  s=code_eq(1);  break;
    case NEQ: s=code_eq(!1); break;
    case GT+BNOT:  s=code_gt(0);  break;
    case UGT+BNOT: s=code_ugt(0); break;
    case GE+BNOT:  s=code_ge(0);  break;
    case UGE+BNOT: s=code_uge(0); break;
    case LT+BNOT:  s=code_ge(!0); break;
    case ULT+BNOT: s=code_uge(!0);break;
    case LE+BNOT:  s=code_gt(!0); break;
    case ULE+BNOT: s=code_ugt(!0);break;
    case EQ+BNOT:  s=code_eq(0);  break;
    case NEQ+BNOT: s=code_eq(!0); break;
    default: error(-1);
    }
    g_expr(list3((t==INT?CMP:UCMP),cadr(e1),caddr(e1)));
    printf("\tb%s %s,%s%d\n",s,crname(cmpflag),lpfx,l1);
    return l1;
}

static void
jcond(int l, char cond)
{       
    if (cond==LT) {
        printf("\tb%s %s,%s%d\n",code_ge(0),crname(cmpflag),lpfx,l);
    } else if (cond==1||cond==0) {
        printf("\tb%s %s,%s%d\n",cond?"ne":"eq",crname(cmpflag),lpfx,l);
    } else error(-1);
}

void
jmp(int l)
{       
    printf("\tb\t%s%d\n",lpfx,l);
}

extern void
code_comment(char *s)
{
    printf("## %s",s);
}

void
code_enter(char *name)
{
#ifdef __APPLE__
    if (output_mode!=TEXT_EMIT_MODE) 
        text_mode(0);
    else
        printf("\t.align 2\n");
    if (stmode!=STATIC)
        printf(".globl _%s\n",name);
#ifdef DOT_SIZE
    printf("\t.type\t%s,@function\n",name);
#endif
    printf("_%s:\n",name);
    code_disp_label=fwdlabel();
#if 0
    printf("\tla r1,lo16(L_%d)(r30)\n",code_disp_label);
#else
    printf("\tla r1,lo16(L_%d)(r30)\n",code_disp_label);
    printf("\taddis r1,r1,ha16(L_%d)\n",code_disp_label);
#endif
    printf("\tbcl 20,31,L_%d\n",code_base = fwdlabel());
    fwddef(code_base);
    printf("\tmflr r31\n");
    max_func_args = 0;
    clear_ptr_cache();
#else
    if (output_mode!=TEXT_EMIT_MODE) 
        text_mode(0);
    else
        printf("\t.align 2\n");
    if (stmode!=STATIC)
        printf(".globl %s\n",name);
#ifdef DOT_SIZE
    printf("\t.type\t%s,@function\n",name);
#endif
    printf("%s:\n",name);
    code_disp_label=fwdlabel();
#if 0
    printf("\tla r1,lo16(L_%d)(r30)\n",code_disp_label);
#else
    printf("\tla 1,%s%d@l(31)\n",lpfx,code_disp_label);
    printf("\taddis 1,1,%s%d@ha\n",lpfx,code_disp_label);
#endif
    max_func_args = 0;
    clear_ptr_cache();
#endif
}


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)
{
    int r1_offsetv;
    disp&= -SIZE_OF_INT;
    r1_offsetv = -disp+max_func_args*SIZE_OF_INT -code_disp_offset0 +8+32+48;
#ifdef __APPLE__
    printf(".set L_%d,%d\n",code_disp_label,-r1_offsetv);
    if (max_func_arg_label) {
        printf(".set L_%d,%d\n",max_func_arg_label,max_func_args*SIZE_OF_INT+24);
        max_func_arg_label = 0;
    }
#else
    printf(".set .LC%d,%d\n",code_disp_label,-r1_offsetv);
    if (max_func_arg_label) {
        printf(".set .LC%d,%d\n",max_func_arg_label,max_func_args*SIZE_OF_INT+24);
        max_func_arg_label = 0;
    }
#endif
    local_table();
    // free_all_register();
}

void
enter(char *name)
{
#ifdef __APPLE__
    if (output_mode!=TEXT_EMIT_MODE) 
        text_mode(0);
    else
        printf("\t.align 2\n");
    if (stmode!=STATIC)
        printf(".globl %s%s\n",npfx,name);
/*
    printf("\t.type\t%s,@function\n",name);
 */
    printf("%s%s:\n",npfx,name);
    code_setup=fwdlabel();
    printf("\tmflr r0\n");
    printf("\tbl L_%d\n",code_setup);
    code_base=fwdlabel();
    fwddef(code_base);
    r1_offset_label = fwdlabel();
    lvar_offset_label = fwdlabel();
#if 0
    printf("\taddi r30,r1,lo16(-L_%d)\n",lvar_offset_label);
    printf("\tstwu r1,lo16(-L_%d)(r1)\n",r1_offset_label);
    // printf("\tmr r30,r1\n");
#else
    printf("\taddi r30,r1,lo16(-L_%d)\n",lvar_offset_label);
    printf("\tlis r31,ha16(-L_%d)\n",r1_offset_label);
    printf("\taddi r31,r31,lo16(-L_%d)\n",r1_offset_label);
    printf("\tstwux r1,r1,r31\n");
#endif
    printf("\tmflr r31\n");
#else
    if (output_mode!=TEXT_EMIT_MODE) 
        text_mode(0);
    else
        printf("\t.align 2\n");
    if (stmode!=STATIC)
        printf(".globl %s%s\n",npfx,name);
/*
    printf("\t.type\t%s,@function\n",name);
 */
    printf("%s:\n",name);
    control = 1;
    code_setup=fwdlabel();
    arg_offset_label = fwdlabel();
    printf("\tmflr 0\n");
    printf("\tstwu %d,-%s%d@l(%d)\n",1,lpfx,arg_offset_label,1);
    printf("\tbl .LC%d\n",code_setup);
    r1_offset_label = fwdlabel();
    lvar_offset_label = fwdlabel();

    printf("\tmr %d,1\n",REG_fp);
    printf("\taddi %d,1,-%s%d@l\n",REG_fp,lpfx,lvar_offset_label);
    printf("\tlis %d,-%s%d@ha\n",30,lpfx,r1_offset_label);
    printf("\taddi %d,%d,-%s%d@l\n",30,30,lpfx,r1_offset_label);
    printf("\tstwux 1,1,%d\n",30);
#endif
    max_func_args = 0;
    clear_ptr_cache();
}

void
enter1()
{
    text_mode(0);
    // set_lreg(LREG_LREGISTER,0);
    set_ireg(CREG_REGISTER,0);
    set_freg(FREG_FREGISTER,0);
}

int
reg_save_offset()
{
    return -(
        (REAL_MAX_REGISTER-(REG_VAR_BASE-max_reg_var))*SIZE_OF_INT+
        (REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*SIZE_OF_DOUBLE
        );
}

void
code_label_call(int l)
{
#ifdef __APPLE__
        printf("\tbl\tL_%d\n",l);
#else
        printf("\tbl\t.LC%d\n",l);
#endif
}

void
code_ret()
{
        printf("\tblr\n");
}

#ifndef __APPLE__
static int saveFP_used=0;
static char *saveFP_lib[] = {
".saveFP:    stfd    14,-144(1)",
" stfd    15,-136(1)",
" stfd    16,-128(1)",
" stfd    17,-120(1)",
" stfd    18,-112(1)",
" stfd    19,-104(1)",
" stfd    20,-96(1)",
" stfd    21,-88(1)",
" stfd    22,-80(1)",
" stfd    23,-72(1)",
" stfd    24,-64(1)",
" stfd    25,-56(1)",
" stfd    26,-48(1)",
" stfd    27,-40(1)",
" stfd    28,-32(1)",
" stfd    29,-24(1)",
" stfd    31,-16(1)",
" stfd    30,-8(1)",
" stw     0,4(1)",
" blr",
".restFP:    ",
" lfd     14,-144(1)",
" lfd     15,-136(1)",
" lfd     16,-128(1)",
" lfd     17,-120(1)",
" lfd     18,-112(1)",
" lfd     19,-104(1)",
" lfd     20,-96(1)",
" lfd     21,-88(1)",
" lfd     22,-80(1)",
" lfd     23,-72(1)",
" lfd     24,-64(1)",
" lfd     25,-56(1)",
" lfd     26,-48(1)",
" lfd     27,-40(1)",
" lfd     28,-32(1)",
" lfd     29,-24(1)",
" lwz     0,4(1)",
" lfd     31,-16(1)",
" lwz     1,0(1)",
" mtlr    0",
" blr",
0
};
#endif

static void 
make_return_continuation()
{
#if R1SAVE
        retcont1 = fwdlabel();
#endif
        fwddef(retcont);
        if (cadr(fnptr->ty)==FLOAT||cadr(fnptr->ty)==DOUBLE) {
            printf("\tfmr %s,%s\n",fregister_name(1),fregister_name(31));
            printf("\tmr %s,%s\n",register_name(30),register_name(28));
        } else if (cadr(fnptr->ty)>0&&(
            car(cadr(fnptr->ty))==STRUCT ||
            car(cadr(fnptr->ty))==UNION)) {
            int sz = size(cadr(fnptr->ty));
#ifdef __APPLE__
            printf("\tli r7,%d\n",sz);
            printf("\tsubl r6,r7,r30\n");
            printf("\tlwz r3,lo16(%d)(r30)\n",(my_func_args-1)*SIZE_OF_INT);
            // emit_copy(6,3,sz,0,1,1);
#else
            printf("\tli 7,%d\n",sz);
            printf("\tsubl 6,7,%d\n",REG_fp);
            printf("\tlwz 3,%d@l(%d)\n",(my_func_args-1)*SIZE_OF_INT,REG_fp);
            // emit_copy(6,3,sz,0,1,1);
#endif
            printf("\tmr %s,%s\n",register_name(30),register_name(28));
        } else if (cadr(fnptr->ty)!=VOID) {
            printf("\tmr %s,%s\n",register_name(3),register_name(29));
            printf("\tmr %s,%s\n",register_name(30),register_name(28));
        }
#if R1SAVE
        jmp(retcont1);
#else
#endif
}

void
leave(int control, char *name)
{
#if R1SAVE
    int retcont1=0;
#else
#endif

    if (max_freg_var>=0 && max_freg_var<=3) max_freg_var=3; 
    reg_save = reg_save_offset();

    if (control) {
        code_set_return_register(1);
    }
    if (retcont) { 
        if (control) jmp(retlabel);
        make_return_continuation();
    }
    fwddef(retlabel);
#if R1SAVE
    printf("\tlwz %s,0(%s)\n",register_name(1),register_name(1));
    if (retcont) {
        fwddef(retcont1);
    }
#else
#ifdef __APPLE__
    printf("\taddi r1,r30,lo16(L_%d)\n",lvar_offset_label);
#else
    printf("\taddi 1,%d,%s%d@l\n",REG_fp,lpfx,lvar_offset_label);
#endif
#endif
    if (max_freg_var>=0) {
#ifdef __APPLE__
        printf("\tlmw r%d,%d(%s)\n",
                        REG_VAR_BASE-max_reg_var,reg_save,register_name(1));
        freg_save = 72-(REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*4;
        printf("\tb restFP+%d ; restore f%d-f31\n",
                        freg_save,
                        FREG_VAR_BASE-max_freg_var);
#else
        printf("\tlmw %d,%d(%s)\n",
                        REG_VAR_BASE-max_reg_var,reg_save,register_name(1));
        freg_save = 72-(REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*4;
        printf("\tb .restFP+%d # restore f%d-f31\n",
                        freg_save,
                        FREG_VAR_BASE-max_freg_var);
#endif
    } else {
#ifdef __APPLE__
        printf("\tlwz r0,8(r1)\n");
        printf("\tmtlr r0\n");
        printf("\tlmw r%d,%d(r1)\n",
                    REG_VAR_BASE-max_reg_var,reg_save);
#else
        printf("\tlmw %d,%d(1)\n",
                    REG_VAR_BASE-max_reg_var,reg_save);
        printf("\tlwz %s,4(1)\n",register_name(0));
        printf("\tlwz 1,0(1)\n");
        printf("\tmtlr %s\n",register_name(0));
#endif
        code_ret();
    }

    disp &= -SIZE_OF_INT;
    fwddef(code_setup);
#ifdef __APPLE__
    printf("\tstmw %s,%d(%s)\n",
                    register_name(REG_VAR_BASE-max_reg_var),reg_save,register_name(1));
    printf("\tstw %s,8(%s)\n",register_name(0),register_name(1));
#else
    printf("\tstmw %s,%d(%s)\n",
                    register_name(REG_VAR_BASE-max_reg_var),reg_save,register_name(1));
    printf("\tstw %s,4(%s)\n",register_name(0),register_name(1));
#endif
    if (max_freg_var>=0) {
#ifdef __APPLE__
        printf("\tb saveFP+%d ; save f%d-f31\n",
                        freg_save,
                        FREG_VAR_BASE-max_freg_var);
#else
        saveFP_used = 1;
        printf("\tb .saveFP+%d # save f%d-f31\n",
                        freg_save,
                        FREG_VAR_BASE-max_freg_var);
#endif
    } else {
        printf("\tblr\n");
    }

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


int
code_set_return_register(int mode) {
    if (cadr(fnptr->ty)==DOUBLE||cadr(fnptr->ty)==FLOAT) {
        set_freg(RET_FREGISTER,mode);
        return freg;
    } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) {
        set_lreg(RET_LREGISTER,mode);
        return lreg;
    } else if (cadr(fnptr->ty)==VOID) {
        return 0;
    } else {
        set_ireg(RET_REGISTER,mode);
        return ireg;
    }
}

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

void
code_set_fixed_creg(int reg,int mode,int type) {
    if (type==FLOAT||type==DOUBLE) {
        set_freg(reg,mode);
    } else if (type==LONGLONG||type==ULONGLONG) {
        set_lreg(reg,mode);
        // use_reg(reg);
    } else {
        set_ireg(reg,mode);
    }
}

void
gen_gdecl(char *n, int gpc)
{
    /*
    if (stmode!=STATIC)
        printf(".globl _%s\n",n); 
     */
}

extern void
ascii(char *s,int len)
{
    cstring_mode();
    if (s[len-1]==0) 
        printf("\t.string \"");
    else
        printf("\t.ascii \"");
    while(len-->0) {
        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("%c\n\t.align 2\n",34);
}


extern int
emit_string_label() {
    int lb;

    lb=fwdlabel();
    cstring_mode();
    printf("%s%d:\n",lpfx,lb);
    return lb;
}

extern void 
emit_string(char *s,int t,int len)
{
    t = type_value(t);
    if (car(t)==ARRAY &&  
            (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) {
        ascii(s,len);
    } else {
        int l = emit_string_label();
        ascii(s,len);
        emit_label(l);
    }
    return;
}

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

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);
    if (n && n->sc!=STATIC)
        printf("\t.globl\t%s%s\n",npfx,n->nm);
    printf("%s%s:\n",npfx,n->nm);
}

extern void
emit_space(int sp)
{
    data_mode(0);
    printf("\t.space\t%d\n",sp);
}

extern void
emit_char(int d)
{
    data_mode(0);
    printf("\t.byte %d\n",d);
}

extern void
emit_short(int d)
{
    data_mode(0);
    printf("\t.short %d\n",d);
}

extern void
emit_int(int d)
{
    data_mode(0);
    printf("\t.long %d\n",d);
}

extern void
emit_longlong(int e)
{
#if LONGLONG_CODE
    long long d = lcadr(e);
    data_mode(0);
#if ENDIAN_L==0
    printf("\t.long\t0x%x,0x%x\n",code_l1(d),code_l2(d));
#else
    printf("\t.long\t0x%x,0x%x\n",code_l2(d),code_l1(d));
#endif
#endif
}

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

extern void
emit_float(int e)
{
#if FLOAT_CODE
    float f = dcadr(e);
    data_mode(0);
    printf("\t.long\t0x%x\n",*(int *)&f);
#endif
}

extern void
emit_address(char *s,int offset)
{
    data_mode(0);
    if (offset) 
        printf("\t.long %s%s+%d\n",npfx,s,offset);
    else 
        printf("\t.long %s%s\n",npfx,s);
}

extern void
emit_label(int labelno)
{
    data_mode(0);
    printf("\t.long %s%d\n",lpfx,labelno);
}

extern void
emit_data_closing(NMTBL *n)
{
#ifdef DOT_SIZE
    int lb;
#endif
    if (mode==GDECL) {
#ifdef DOT_SIZE
#ifdef __APPLE__
        data_mode(0);
        lb=fwdlabel();
        printf("%s%d:\n",lpfx,lb);
        printf("\t.size\t%s,%s%d-%%ss\n",n->nm,lb,lpfx,npfx,n->nm);
#else
        data_mode(0);
        lb=fwdlabel();
        printf(".LC%d:\n",lb);
        printf("\t.size\t%s,%s%d-%s%s\n",n->nm,lb,lpfx,npfx,n->nm);
#endif
#endif
    }
}

#ifdef __APPLE__
void
global_table(void)
{
    NMTBL *n;
    int init; char *extrn;
    init=0;
    global_list = reversen(global_list);
    text_mode(0);
    for(n = global_list;n!=&null_nptr;n = n->next) {
        if ((n->sc == GVAR) && n->dsp != -1) {
            /* n->dsp = -1 means initialized global */
            if (init==0) {
                // data_mode(0);
                text_mode(0);
                printf("\t.align 3\n");
                init=1;
            }
            int align;
            if ((align=attr_value(n,ALIGNED))) {
                int a = ilog(caddr(align));
                printf(".comm %s%s,%d,%d\n",npfx,n->nm,size(n->ty),a);
            } else if (size(n->ty)>1) {
                printf(".comm %s%s,%d,2\n",npfx,n->nm,size(n->ty));
            } else
                printf(".comm %s%s,%d\n",npfx,n->nm,size(n->ty));
        } 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) {
                text_mode(0);
                printf("\t.align 8\n");
                // data_mode(0);
                init=1;
            }
            printf(".lcomm %s%s,%d\n",npfx,n->nm,size(n->ty));
        }
    }
    for(n = global_list;n!=&null_nptr;n = n->next) {
        if (is_code(n)||is_function(n)) {
            extrn = n->nm;
            if (n->sc==EXTRN1) {
                data_mode(0);
printf(".picsymbol_stub\n");
printf("L_%s$stub:\n",extrn);
printf("\t.indirect_symbol _%s\n",extrn);
printf("\tmflr r0\n");
printf("\tbcl 20,31,L0$_%s\n",extrn);
printf("L0$_%s:\n",extrn);
printf("\tmflr r11\n");
printf("\taddis r11,r11,ha16(L_%s$lazy_ptr-L0$_%s)\n",extrn,extrn);
printf("\tmtlr r0\n");
printf("\tlwz r12,lo16(L_%s$lazy_ptr-L0$_%s)(r11)\n",extrn,extrn);
printf("\tmtctr r12\n");
printf("\taddi r11,r11,lo16(L_%s$lazy_ptr-L0$_%s)\n",extrn,extrn);
printf("\tbctr\n");
printf(".data\n");
printf(".lazy_symbol_pointer\n");
printf("L_%s$lazy_ptr:\n",extrn);
printf("\t.indirect_symbol _%s\n",extrn);
printf("\t.long dyld_stub_binding_helper\n");
            } else if (n->sc==STATIC) {
                text_mode(0);
printf("\t.set L_%s$stub,_%s\n",extrn,extrn);
                data_mode(0);
printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",extrn,extrn);
            } 
        }
    }
    init=0;
    for(n = global_list;n!=&null_nptr;n = n->next) {
        if (n->sc == GVAR) {
            if (init==0) {
                printf(".data\n");
                init=1;
            }
printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",n->nm,n->nm);
        }
    }
    init = 0;
    for(n = global_list;n!=&null_nptr;n = n->next) {
        if ((is_code(n)||is_function(n))&& 
            !has_attr(n,FNAME))   // not used as value
                continue;
        if (n->sc==EXTRN1) {
            if(init==0) {
                printf(".data\n");
printf(".non_lazy_symbol_pointer\n");
                init=1;
            }
printf("L_%s$non_lazy_ptr:\n",n->nm);
printf("\t.indirect_symbol _%s\n",n->nm);
printf("\t.long\t0\n");
        }
    }
}
#else

static void
comm(NMTBL *n)
{
    int align = 1;
    if ((align=attr_value(n,ALIGNED))) {
        align = ilog(caddr(align));
    } else  {
        if (size(n->ty)>4)
            align = 2;
        else if (size(n->ty)>4)
            align = 0;
        switch(n->ty) {
        case DOUBLE:
        case LONGLONG:
        case ULONGLONG:
            align = 8; break;
        case INT:
        case UNSIGNED:
        case FLOAT:
            align = 4; break;
        case SHORT:
        case USHORT:
            align = 2; break;
        }
    }
    printf("\t.comm %s,%d,%d\n",n->nm,size(n->ty),align);
}

void
global_table(void)
{
    NMTBL *n;
    int init;
    init=0;
    global_list = reversen(global_list);
    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);
        }
    }
}
#endif

#ifdef __APPLE__
void
local_table(void)
{
    NMTBL *n;
    int init;
    init=0;
    /* static local variables */
    for(n = local_static_list;n!=&null_nptr;n = n->next) {
        if (n->sc == STATIC) {
            if (init==0) {
                data_mode(0);
                init=1;
            }
            if (n->dsp != -1) /* initialized static */
                printf(".lcomm _%s,%d\n",n->nm,size(n->ty));
            printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",n->nm,n->nm);
        }
    }
}
#else
void
local_table(void)
{
    NMTBL *n;
    int init;
    init=0;
    /* static local variables */
    for(n = local_static_list;n!=&null_nptr;n = n->next) {
        if (n->sc == STATIC) {
            if (init==0) {
                data_mode(0);
                init=1;
            }
            if (n->dsp != -1) /* initialized static */
                printf(".lcomm %s,%d\n",n->nm,size(n->ty));
        }
    }
}
#endif

void
cstring_mode(int align)
{
    if (output_mode!=RODATA_EMIT_MODE) {
#ifdef __APPLE__
        printf(".cstring\n\t.align 2\n");
#else
        printf("\t.section\t.rodata\n\t.align 2\n");
#endif
        output_mode = RODATA_EMIT_MODE;
    }
}

void
text_mode(int align)
{
    if (output_mode!=TEXT_EMIT_MODE) {
        printf(".text\n");
        printf("\t.align 2\n");
        output_mode = TEXT_EMIT_MODE;
    }
}

void
data_mode(char *name)
{
    if (output_mode!=DATA_EMIT_MODE) {
        printf(".data\n");
        output_mode = DATA_EMIT_MODE;
    }
/*
    if (name)
        printf("\t.type\t%s,@object\n",name);
 */
}

#if FLOAT_CODE

/* floating point */

static int float_one_lib_used=0;
static char *float_one_lib[] = {
".data",
/* ".literal8", */
"        .align 3",
"__float_one:",
"        .long   1065353216",
".text",
/* ".set L__float_one$non_lazy_ptr,__float_one", */
0
};
static int float_zero_lib_used=0;
static char *float_zero_lib[] = {
".data",
/* ".literal8", */
"        .align 3",
"__float_zero:",
"        .long   0",
".text",
/* ".set L__float_zero$non_lazy_ptr,__float_zero", */
0
};

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

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

void
code_cmp_dregister(int e2,int d,int label,int cond)
{
    char *frn,*rrn,*grn;
    int greg,r;
    grn =  fregister_name(greg = get_dregister(d));
    use_float(d,e2);
    frn = register_name(e2);
    float_zero_lib_used=1;
    r = get_ptr_cache(&float_zero);
    rrn = register_name(r);
    printf("\tlfs %s,0(%s)\n",grn,rrn);
    inc_cmpflag();
    printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),grn,frn);
    free_register(greg);
    jcond(label,cond);
    return;
}

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

void
code_dassign_gvar(int e2,int freg,int d)
{ 
    use_float(d,freg);
    code_ldf(fstore(d),fregister_name(freg),cadr(e2),
        get_ptr_cache(ncaddr(e2)));
}

void
code_dassign_lvar(int e2,int freg,int d)
{ 
    use_float(d,freg);
    lvar_intro(e2);
    printf("\t%s %s,",fstore(d),fregister_name(freg));
    lvar(e2);
}

void
code_dassign(int e2,int freg,int d)
{ 
    use_float(d,freg);
    printf("\t%s %s,0(%s)\n",fstore(d),fregister_name(freg),register_name(e2));
}

void
code_dassign_dregister(int e2,int d,int freg) {
    use_float(d,freg);
    if (e2!=freg) {
        printf("\tfmr %s,%s\n",fregister_name(e2),fregister_name(freg));
    }
}

static double d0 = 1.0;

int
code_d1(double d)
{
    int *i = (int *)&d0; int *j = (int *)&d;
    return (i[1] == 0x3ff00000)?j[0]:j[1];
}

int
code_d2(double d)
{
    int *i = (int *)&d0; int *j = (int *)&d;
    return (i[1] == 0x3ff00000)?j[1]:j[0];
}

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

static void emit_dconst0(ValuePtr value, int lb, void *arg)
{
    long d = (long) arg;
    printf(" \t.data\n\t.align 3\n");
    printf("%s%d:\n",lpfx,lb);
    if (d) {
#if ENDIAN_D==0
        printf("\t.long\t0x%x,0x%x\n",code_d1(value->d),code_d2(value->d));
#else
        printf("\t.long\t0x%x,0x%x\n",code_d2(value->d),code_d1(value->d));
#endif
    } else {
        printf("\t.long\t0x%x\n",code_f(value->f));
    }
    if (output_mode==TEXT_EMIT_MODE) {
        printf(".text\n");
    } else {
        text_mode(0);
    }
}

/* load double / float const
   we should keep what constant we have create
 */

void
code_dconst(int e2,int freg,int d)
{ 
    int sz;
    Value value;
    value.d = dcadr(e2);
    int r;
    char *rrn,*frn;
    use_float(d,freg);
    frn = fregister_name(freg);
    if (value.d==0.0) {
        float_zero_lib_used=1;
        r = get_ptr_cache(&float_zero);
        rrn = register_name(r);
        printf("\tlfs %s,0(%s)\n",frn,rrn);
        return;
    }
    if (value.d==1.0) {
        float_one_lib_used=1;
        r = get_ptr_cache(&float_one);
        rrn = register_name(r);
        printf("\tlfs %s,0(%s)\n",frn,rrn);
        return;
    }
    if (d) {
       sz = sizeof(double);
    } else {
       sz = sizeof(float);
       value.f = (float) value.d;
    }

    long d_mode = d;
    int lb = get_data_label(&value,sz,emit_dconst0, (void*) d_mode);

    rrn = register_name((r=get_register()));
    // use_reg(r); // to clear ptr cache
    code_label_value(lb,r);
    if (d) {
        printf("\tlfd %s,0(%s)\n",frn,rrn);
    } else {
        printf("\tlfs %s,0(%s)\n",frn,rrn);
    }
    free_register(r);
}

void
code_builtin_fabsf(int e)
{
    char *frn;
    g_expr0(e);
    use_float(0,freg);
    frn = fregister_name(freg);
    printf("\tfabs %s,%s\n",frn,frn);
}

void
code_builtin_fabs(int e)
{
    char *frn;
    g_expr0(e);
    use_float(1,freg);
    frn = fregister_name(freg);
    printf("\tfabs %s,%s\n",frn,frn);
}

static void
code_inf(int d)
{
    int lb;
    int r;
    char *rrn,*frn;
    int freg = USE_CREG;

    use_float(d,freg);
    frn = fregister_name(freg);
    rrn = register_name((r=get_register()));
    use_reg(r); // to clear ptr cache
    printf(" \t.data\n\t.align 3\n");
    lb=fwdlabel();
    printf("L_%d:\n",lb);
    if (d) {
#if ENDIAN_D==0
        printf("\t.long\t0x%x,0x%x\n",0,0x7ff00000);
#else
        printf("\t.long\t0x%x,0x%x\n",0x7ff00000,0);
#endif
    } else {
        printf("\t.long\t0x%x\n",0x7f800000);
    }
    if (output_mode==TEXT_EMIT_MODE) {
        printf(".text\n");
    } else {
        text_mode(0);
    }
    code_label_value(lb,r);
    if (d) {
        printf("\tlfd %s,0(%s)\n",frn,rrn);
    } else {
        printf("\tlfs %s,0(%s)\n",frn,rrn);
    }
    free_register(r);
}

void
code_builtin_inff()
{
    code_inf(0);
}

void
code_builtin_inf()
{
    code_inf(1);
}



void
code_dneg(int freg,int d)
{ 
    char *frn;
    use_float(d,freg);
    frn = fregister_name(freg);
    printf("\tfneg %s,%s\n",frn,frn);
}

void
code_d2i()
{ 
    char *frn;
    char *crn;
    int e2 = new_lvar(SIZE_OF_DOUBLE);

    use_double0();
    frn = fregister_name(freg);
    use_int0();
    crn = register_name(creg);

    free_lvar(e2);
    printf("\tfctiwz  %s,%s\n",frn,frn);
    lvar_intro(e2);
    printf("\tstfd  %s,",frn); lvar(e2);
    lvar_intro(e2+SIZE_OF_DOUBLE-SIZE_OF_INT);
    printf("\tlwz %s,",crn); lvar(e2+SIZE_OF_DOUBLE-SIZE_OF_INT);
}

static int i2d_lib_used=0;
#ifdef __APPLE__
static char *i2d_lib[] = {
".data",
/* ".literal8", */
"        .align 3",
"__i2dLC0:",
"        .long   1127219200",
"        .long   -2147483648",
".text",
"        .align 2",
"i2d_:",
"        mflr r0",
"        bcl 20,31,__i2dL1$pb",
"__i2dL1$pb:",
"        mflr r10",
"        mtlr r0",
"        xoris r3,r3,0x8000",
"        stw r3,-28(r1)",
"        lis r0,0x4330",
"        stw r0,-32(r1)",
"        lfd f0,-32(r1)",
"        addis r9,r10,ha16(__i2dLC0-__i2dL1$pb)",
"        lfd f1,lo16(__i2dLC0-__i2dL1$pb)(r9)",
"        fsub f1,f0,f1",
"        blr",
0
};
#else
static char *i2d_lib[] = {
".data",
/* ".literal8", */
"        .align 3",
"__i2dLC0:",
"        .long   1127219200",
"        .long   -2147483648",
".text",
"        .align 2",
"i2d_:",
"        xoris 3,3,0x8000",
"        stw 3,-28(1)",
"        lis 0,0x4330",
"        stw 0,-32(1)",
"        lfd 0,-32(1)",
"        lis 9,__i2dLC0@ha",
"        lfd 1,__i2dLC0@l(9)",
"        fsub 1,0,1",
"        blr",
0
};
#endif

void
code_i2d()
{ 
    i2d_lib_used = 1;
    clear_ptr_cache();
    code_save_stacks();
    set_ireg(RET_REGISTER,1);
    printf("\tbl i2d_\n");
    set_freg(RET_FREGISTER,0);
}

static int d2u_lib_used=0;
#ifdef __APPLE__
static char *d2u_lib[] = {
/* ".literal8", */
"        .align 3",
"__d2uLC0:",
"        .long   1105199104",
"        .long   0",
".text",
"        .align 2",
"d2u_:",
"        mflr r0",
"        bcl 20,31,__d2uL1$pb",
"__d2uL1$pb:",
"        mflr r10",
"        mtlr r0",
"        addis r9,r10,ha16(__d2uLC0-__d2uL1$pb)",
"        lfd f0,lo16(__d2uLC0-__d2uL1$pb)(r9)",
"        fcmpu cr0,f1,f0",
"        cror 2,1,2",
"        beq- cr0,__d2uL2",
"        fctiwz f0,f1",
"        stfd f0,-32(r1)",
"        lwz r3,-28(r1)",
"        blr",
"__d2uL2:",
"        addis r9,r10,ha16(__d2uLC0-__d2uL1$pb)",
"        lfd f0,lo16(__d2uLC0-__d2uL1$pb)(r9)",
"        fsub f0,f1,f0",
"        fctiwz f0,f0",
"        stfd f0,-24(r1)",
"        lwz r3,-20(r1)",
"        xoris r3,r3,0x8000",
"        blr",
0
};
#else
static char *d2u_lib[] = {
/* ".literal8", */
"        .align 3",
"__d2uLC0:",
"        .long   1105199104",
"        .long   0",
".text",
"        .align 2",
"d2u_:",
"        lis 9,__d2uLC0@ha",
"        lfd 0,__d2uLC0@l(9)",
"        fcmpu 0,1,0",
"        cror 2,1,2",
"        beq- 0,__d2uL2",
"        fctiwz 0,1",
"        stfd 0,-32(1)",
"        lwz 3,-28(1)",
"        blr",
"__d2uL2:",
"        lis 9,__d2uLC0@ha",
"        lfd 0,__d2uLC0@l(9)",
"        fsub 0,1,0",
"        fctiwz 0,0",
"        stfd 0,-24(1)",
"        lwz 3,-20(1)",
"        xoris 3,3,0x8000",
"        blr",
0
};
#endif

void
code_d2u()
{ 
    code_save_stacks();
    clear_ptr_cache();
    d2u_lib_used=1;
    set_freg(RET_FREGISTER,1);
    printf("\tbl d2u_\n");
    set_ireg(RET_REGISTER,0);
}

static int u2d_lib_used=0;
#ifdef __APPLE__
static char *u2d_lib[] = {
".data",
/* ".literal8", */
"        .align 3",
"__u2dLC1:",
"        .long   1127219200",
"        .long   0",
".text",
"        .align 2",
"u2d_:",
"        mflr r0",
"        bcl 20,31,__u2dL2$pb",
"__u2dL2$pb:",
"        mflr r10",
"        mtlr r0",
"        stw r3,-28(r1)",
"        lis r0,0x4330",
"        stw r0,-32(r1)",
"        lfd f0,-32(r1)",
"        addis r9,r10,ha16(__u2dLC1-__u2dL2$pb)",
"        lfd f1,lo16(__u2dLC1-__u2dL2$pb)(r9)",
"        fsub f1,f0,f1",
"        blr",
0
};
#else
static char *u2d_lib[] = {
".data",
/* ".literal8", */
"        .align 3",
"__u2dLC1:",
"        .long   1127219200",
"        .long   0",
".text",
"        .align 2",
".u2d_:",
"        stw 3,-28(1)",
"        lis 0,0x4330",
"        stw 0,-32(1)",
"        lfd 0,-32(1)",
"        lis 9,__u2dLC1@ha",
"        lfd 1,__u2dLC1@l(9)",
"        fsub 1,0,1",
"        blr",
0
};
#endif

void
code_u2d()
{ 
    code_save_stacks();
    clear_ptr_cache();
    u2d_lib_used = 1;
    set_ireg(RET_REGISTER,1);
#ifdef __APPLE__
    printf("\tbl u2d_\n");
#else
    printf("\tbl .u2d_\n");
#endif
    set_freg(RET_FREGISTER,0);
}

void
code_d2f() { }
void
code_f2d() { }
void
code_f2i() { code_d2i(); }
void
code_f2u() { code_d2u(); }
void
code_i2f() { code_i2d(); }
void
code_u2f() { code_u2d(); }

void
code_drgvar(int e2,int d,int freg)
{ 
    use_float(d,freg);
    code_ldf(fload(d),fregister_name(freg),cadr(e2),
        get_ptr_cache(ncaddr(e2)));
}


void
code_drlvar(int e2,int d,int freg)
{ 
    use_float(d,freg);
    lvar_intro(e2);
    printf("\t%s %s,",fload(d),fregister_name(freg)); lvar(e2);
}

void
code_cmp_drgvar(int e2,int reg,int d,int label,int cond)
{ 
    char *frn;
    int g=get_dregister(d);
    char *grn=fregister_name(g);

    use_float(d,reg);
    frn=fregister_name(reg);

    code_ldf(fload(1),grn,cadr(e2),
        get_ptr_cache(ncaddr(e2)));
    inc_cmpflag();
    printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn);
    free_register(g);
    jcond(label,cond);
}

void
code_cmp_drlvar(int e2,int reg,int d,int label,int cond)
{ 
    char *frn;
    int g=get_dregister(d);
    char *grn=fregister_name(g);

    use_float(d,reg);
    frn=fregister_name(reg);

    lvar_intro(e2);
    printf("\t%s %s,",fload(1),grn); lvar(e2);
    inc_cmpflag();
    printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn);
    free_register(g);
    jcond(label,cond);
}

void
dtosop(int op,int reg,int oreg)
{ 
    char *opn="";
    char *frn;
    char *grn;
    int ox = -1;

    use_float(1,reg);
    if(oreg==-1) {
        error(-1);
    } else if (oreg<= -REG_LVAR_OFFSET) {
        ox = get_dregister(1); if (ox<0) error(-1);
        use_reg(ox);
        code_drlvar(oreg+REG_LVAR_OFFSET,1,ox);
        oreg = ox;
    }
    grn=fregister_name(oreg);
    frn=fregister_name(reg);
    switch(op) {
    case FADD:
    case DADD: opn="fadd"; break;
    case FSUB:
    case DSUB: opn="fsub"; break;
    case FDIV:
    case DDIV: opn="fdiv"; break;
    case FMUL:
    case DMUL: opn="fmul"; break;
    case FCMP:
    case DCMP: 
        inc_cmpflag();
        printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn);
        if (ox!=-1) free_register(ox);
        return;
    case FCMPGE: 
    case DCMPGE: 
        inc_cmpflag();
        printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn);
        if (ox!=-1) free_register(ox);
        return;
    default:
        error(-1); return;
    }
    printf("\t%s %s,%s,%s\n",opn,frn,frn,grn);
    if (ox!=-1) free_register(ox);
}

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=emit_dpop(d);
    char *crn;
    char *frn;

    crn=register_name(ireg);
    use_float(d,reg);
    frn  =fregister_name(reg);

    printf("\t%s %s,0(%s)\n",fload(d),frn,crn);
    dtosop(op,reg,xreg);
    printf("\t%s %s,0(%s)\n",fstore(d),frn,crn);
    emit_dpop_free(xreg,d);
}

void
code_register_dassop(int reg,int op,int d) {
    // reg op= dpop()
    int  xreg=emit_dpop(d);
    dtosop(op,reg,xreg);
    emit_dpop_free(xreg,d);
}   

static int
code_dload_1(int d)
{
    int r,g;
    char *drn,*grn;
    // load 1
    float_one_lib_used=1;
    r = get_ptr_cache(&float_one);
    drn=register_name(r);
    grn=fregister_name(g=get_dregister(d));
    printf("\tlfs %s,0(%s)\n",grn,drn);
    return g;
}

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

    if (car(e2)==DREGISTER||car(e2)==FREGISTER) {
        crn=register_name(cadr(e2));
        grn = fregister_name(g = code_dload_1(d));
        if (reg==USE_CREG) {
            reg=get_dregister(d); if (!reg) error(-1);
            set_freg(reg,0);
        }
        frn=fregister_name(reg);
        printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",crn,crn,grn);
        if (use && reg!=cadr(e2))
            printf("\tfmr %s,%s\n",frn,crn);
    } else {
        g_expr(e2);
        if (!is_int_reg(creg)) error(-1);
        crn=register_name(ireg);
        if (reg==USE_CREG) {
            reg=get_dregister(d); if (!reg) error(-1);
            set_freg(reg,0);
        }
        frn=fregister_name(reg);
        grn = fregister_name(g = code_dload_1(d));
        printf("\t%s %s,0(%s)\n",fload(d),frn,crn);
        printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",frn,frn,grn);
        printf("\t%s %s,0(%s)\n",fstore(d),frn,crn);
    }
    free_register(g);
}

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

    if (car(e2)==DREGISTER||car(e2)==FREGISTER) {
        crn=register_name(cadr(e2));
        grn = fregister_name(g = code_dload_1(d));
        if (reg==USE_CREG) {
            reg=get_dregister(d); if (!reg) error(-1);
            set_freg(reg,0);
        }
        frn=fregister_name(reg);
        if (use && reg!=cadr(e2))
            printf("\tfmr %s,%s\n",frn,crn);
        printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",crn,crn,grn);
    } else {
        g_expr(e2);
        if (!is_int_reg(creg)) error(-1);
        crn=register_name(ireg);
        if (reg==USE_CREG) {
            reg=get_dregister(d); if (!reg) error(-1);
            set_freg(reg,0);
        }
        frn=fregister_name(reg);
        grn = fregister_name(g = code_dload_1(d));
        printf("\t%s %s,0(%s)\n",fload(d),frn,crn);
        printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",grn,frn,grn);
        printf("\t%s %s,0(%s)\n",fstore(d),grn,crn);
    }
    free_register(g);
}

static int
drexpr_bool(int e1,int reg)
{
    int flag=-1,eq=-1,neg=-1,t;
    char *rn;
    switch(car(e1)) {
    case DOP+GT: case FOP+GT:  flag = 2; break;
    case DOP+GE: case FOP+GE:  flag = 2; eq=3; break;
    case DOP+LT: case FOP+LT:  flag = 1; break;
    case DOP+LE: case FOP+LE:  flag = 1; eq=3; break;
    case DOP+EQ: case FOP+EQ:  flag = 3; break;
    case DOP+NEQ: case FOP+NEQ: flag = 3; neg=3; break;
    default: return 0;
    }
    g_expr(list3(DCMP,cadr(e1),caddr(e1)));
    use_int(reg);
    rn = register_name(reg);
    t = CRBITSIZ*cmpflag;
    if (eq>0) {
        printf("\tcror %d,%d,%d\n",t+flag-1,t+eq-1,t+flag-1);
    }
    if (neg>0) {
        neg = t+neg-1,
        printf("\tcrnor %d,%d,%d\n",neg,neg,neg);
    }
    printf("\tmfcr %s\n",rn);
    printf("\trlwinm %s,%s,%d,1\n",rn,rn,t+flag);
    return 1;
}

int
drexpr(int e1, int e2,int l1, int op,int cond)
{
    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;
        }
    }
    g_expr(list3(DCMP, e1,e2));
    switch(op) {
        case DOP+GT: case FOP+GT:
            printf("\tbgt\t%s,%s%d\n",crname(cmpflag),lpfx,l1);
            break;
        case DOP+GE: case FOP+GE:
            printf("\tbge\t%s,%s%d\n",crname(cmpflag),lpfx,l1);
            break;
        case DOP+EQ: case FOP+EQ:
            printf("\tbeq\t%s,%s%d\n",crname(cmpflag),lpfx,l1);
            break;
        case DOP+NEQ: case FOP+NEQ:
            printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,l1);
            break;
    }
    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)
{ 
    if (e1>=0 && e1!=creg && regs[e1]!=REG_VAR)
        free_register(e1);
}

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

#endif

#if LONGLONG_CODE


/* 64bit int part */
static void
lmove(int to,int from)   //   to <= from
{
    int tmp;
    if (regv_h(to)==regv_l(from)&&(regv_l(to)==regv_h(from))) {
        tmp = get_register();
        printf("\tmr %s,%s\n",register_name(tmp),lregister_name_low(from));
        printf("\tmr %s,%s\n",lregister_name_high(to),lregister_name_high(from));
        printf("\tmr %s,%s\n",lregister_name_low(to),register_name(tmp));
        free_register(tmp);
    } else if (regv_h(to)==regv_l(from)) {
        printf("\tmr %s,%s\n",lregister_name_low(to),lregister_name_low(from));
        printf("\tmr %s,%s\n",lregister_name_high(to),lregister_name_high(from));
    } else {
        printf("\tmr %s,%s\n",lregister_name_high(to),lregister_name_high(from));
        printf("\tmr %s,%s\n",lregister_name_low(to),lregister_name_low(from));
    }
}

static void
pcond(char *s,int cmpflag,int l1)
{
    printf("\tb%s %s,%s%d\n",s,crname(cmpflag),lpfx,l1);
}

static int
lcmp(int op,int cond)
{
    if (op==LOP+UGT||op==LOP+UGE) {
        return UCMP;
    } else if (op==LOP+LE||op==LOP+GE) {
        return CMP;
    } else {
        return CMP;
    }
}

int
lrexpr(int e1, int e2,int l1, int op,int cond)
{
    int reg;
    int e3;
    int l2;
    int op1,cr0,cr1;

    g_expr(e1);
    emit_lpush();
    g_expr(e2);
    e3 = emit_lpop();
    if (!is_longlong_reg(creg)) error(-1);
    reg = lreg;
    op1 = lcmp(op,cond);
    tosop(op1,regv_h(e3),regv_h(reg));
    cr0 = cmpflag;
    tosop(op1,regv_l(e3),regv_l(reg));
    cr1 = cmpflag;

    l2 = fwdlabel();
    // cond==0 jump on false condtion   ( if(x) => rexpr(..  cond=0 ...) )
    switch(op+(!cond)*BNOT) {
    case LOP+GT:
    case LOP+GE:
        pcond(code_gt(1),cr0,1?l1:l2);
        pcond(code_eq(0),cr0,1?l2:l1);
        break;
    case LOP+UGT:
    case LOP+UGE:
        pcond(code_ugt(1),cr0,1?l1:l2);
        pcond(code_eq(0), cr0,1?l2:l1);
        break;
    case LOP+EQ:
        pcond(code_eq(0),cr0,(1?l2:l1));
        pcond(code_eq(cond),cr1,l1);
        break;
    case LOP+NEQ:
        pcond(code_eq(0),cr0,(1?l1:l2));
        pcond(code_eq(!1),cr1,l1);
        break;
    case LOP+GT+BNOT:
    case LOP+GE+BNOT:
        pcond(code_gt(1),cr0,0?l1:l2);
        pcond(code_eq(0),cr0,0?l2:l1);
        break;
    case LOP+UGT+BNOT:
    case LOP+UGE+BNOT:
        pcond(code_ugt(1),cr0,0?l1:l2);
        pcond(code_eq(0), cr0,0?l2:l1);
        break;
    case LOP+EQ+BNOT:
        pcond(code_eq(0),cr0,(0?l2:l1));
        pcond(code_eq(0),cr1,l1);
        break;
    case LOP+NEQ+BNOT:
        pcond(code_eq(0),cr0,(0?l1:l2));
        pcond(code_eq(!0),cr1,l1);
        break;
    default:
        error(-1);
    }
    switch(op+BNOT*(!cond)) {
    case LOP+GT:  pcond(code_gt(1),  cr1,l1); break;
    case LOP+GE:  pcond(code_ge(1),  cr1,l1); break;
    case LOP+UGT: pcond(code_ugt(1), cr1,l1); break;  
    case LOP+UGE: pcond(code_uge(1), cr1,l1); break;  
    case LOP+GT+BNOT:  pcond(code_gt(0),  cr1,l1); break;
    case LOP+GE+BNOT:  pcond(code_ge(0),  cr1,l1); break;
    case LOP+UGT+BNOT: pcond(code_ugt(0), cr1,l1); break;  
    case LOP+UGE+BNOT: pcond(code_uge(0), cr1,l1); break;  
    }  
    fwddef(l2);  
    emit_lpop_free(e3); 
    return l1;
} 

int
emit_lpop()
{
    int xreg,reg;
    xreg=lreg_stack[--lreg_sp];
    if (xreg<= -REG_LVAR_OFFSET) {
        reg = get_lregister();
        code_lrlvar(REG_LVAR_OFFSET+xreg,reg);
        free_lvar(REG_LVAR_OFFSET+xreg);
        xreg = reg;
    }
    return xreg;
}

void
code_lregister(int e2,int reg)
{
    use_longlong(reg);
    if (reg!=e2) {
        lmove(reg,e2);
    }
}

void
code_cmp_lregister(int reg,int label,int cond)
{
    use_longlong(reg);
    printf("\tor %s,%s,%s\n",
                lregister_name_low(reg),
                lregister_name_low(reg),
                lregister_name_high(reg));
    inc_cmpflag();
    printf("\tcmpwi %s,%s,0\n",crname(cmpflag),lregister_name_low(reg));
    jcond(label,cond);
}

void
code_cmp_lrgvar(int e1,int creg,int label,int cond)
{
    use_longlong(creg);
    code_lrgvar(e1,creg);
    code_cmp_lregister(creg,label,cond);
}

void
code_cmp_lrlvar(int e1,int creg,int label,int cond)
{
    use_longlong(creg);
    code_lrlvar(e1,creg);
    code_cmp_lregister(creg,label,cond);
}

void
code_lassign(int e2,int creg)
{
    char *drn = register_name(e2);
    char *crn_h;
    char *crn_l;

    use_longlong(creg);
    crn_h = lregister_name_high(creg);
    crn_l = lregister_name_low(creg);
#if ENDIAN_L==0
    printf("\tstw %s,0(%s)\n",crn_l,drn);
    printf("\tstw %s,%d(%s)\n",crn_h,SIZE_OF_INT,drn);
#else
    printf("\tstw %s,0(%s)\n",crn_h,drn);
    printf("\tstw %s,%d(%s)\n",crn_l,SIZE_OF_INT,drn);
#endif
}

void
code_lassign_gvar(int e2,int creg)
{
    int r;
    use_longlong(creg);
    r = get_ptr_cache(ncaddr(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("\tstw %s,",crn_l);lvar(e2);
    printf("\tstw %s,",crn_h);lvar(e2+SIZE_OF_INT);
#else
    printf("\tstw %s,",crn_h);lvar(e2);
    printf("\tstw %s,",crn_l);lvar(e2+SIZE_OF_INT);
#endif
}

void
code_lassign_lregister(int e2,int reg)
{
    use_longlong(reg);
    if (e2!=reg) {
        lmove(e2,reg);
    }
}

static long long ll0 = 1LL;

static int 
code_l1(long long d)
{
    int *i = (int *)&ll0; int *j = (int *)&d;
    return (i[1] == 1)?j[1]:j[0];
}

static int 
code_l2(long long d)
{
    int *i = (int *)&ll0; int *j = (int *)&d;
    return (i[1] == 1)?j[0]:j[1];
}

void
code_lconst(int e1,int creg)
{
    use_longlong(creg);
#if ENDIAN_L==0
    code_const(code_l1(lcadr(e1)),regv_h(creg));
    code_const(code_l2(lcadr(e1)),regv_l(creg));
#else
    code_const(code_l1(lcadr(e1)),regv_l(creg));
    code_const(code_l2(lcadr(e1)),regv_h(creg));
#endif
}

void
code_lneg(int creg)
{
    use_longlong(creg);
    printf("\tsubfic %s,%s,0\n",
        lregister_name_low(creg),lregister_name_low(creg));
    printf("\tsubfze %s,%s\n",
        lregister_name_high(creg),lregister_name_high(creg));
}

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(ncaddr(e1));
#if ENDIAN_L==0
    code_ldf(cload(0),crn_l,cadr(e1),r);
    code_ldf(cload(0),crn_h,cadr(e1)+SIZE_OF_INT,r);
#else
    code_ldf(cload(0),crn_h,cadr(e1),r);
    code_ldf(cload(0),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);
#if ENDIAN_L==0
    printf("\tlwz %s,",crn_l); lvar(e1);
    printf("\tlwz %s,",crn_h); lvar(e1+SIZE_OF_INT);
#else
    printf("\tlwz %s,",crn_h); lvar(e1);
    printf("\tlwz %s,",crn_l); lvar(e1+SIZE_OF_INT);
#endif
}

#if 0
static int lumod_lib_used=0;
static char *lumod_lib[] = {
};

static int lmod_lib_used=0;
static char *lmod_lib[] = {
};

static int ludiv_lib_used=0;
static char *ludiv_lib[] = {
};

static int ldiv_lib_used=0;
static char *ldiv_lib[] = {
};
#endif

static int lsrd_lib_used=0;
static char *lsrd_lib[] = {
#ifdef __APPLE__
".text",
"        .align 2",
".lsrd__:",
"       mr.     r5,r5",
"       beqlr",
"       subfic  r2,r5,32",
"      stw     r3,-32(r1)",
"      stw     r4,-28(r1)",
"      cmpwi   cr7,r2,0",
"      bgt+    cr7,L__lsrd1",
"      neg     r0,r2",
"      lwz     r2,-32(r1)",
"      li      r9,0",
"      srw     r2,r2,r0",
"      stw     r9,-48(r1)",
"      b       L__lsrd2",
"L__lsrd1:      lwz     r0,-32(r1)",
"      slw     r9,r0,r2",
"      lwz     r2,-28(r1)",
"      srw     r0,r0,r5",
"      srw     r2,r2,r5",
"      stw     r0,-48(r1)",
"      or      r2,r2,r9",
"L__lsrd2:      stw     r2,-44(r1)",
"      lwz     r3,-48(r1)",
"      lwz     r4,-44(r1)",
"      blr",
#else
".text",
"        .align 2",
".lsrd__:",
"       mr.     5,5",
"       beqlr",
"       subfic  8,5,32",
"      stw     3,-32(1)",
"      stw     4,-28(1)",
"      cmpwi   7,8,0",
"      bgt+    7,.L__lsrd1",
"      neg     0,2",
"      lwz     8,-32(1)",
"      li      9,0",
"      srw     8,8,0",
"      stw     9,-48(1)",
"      b       .L__lsrd2",
".L__lsrd1:      lwz     0,-32(1)",
"      slw     9,0,8",
"      lwz     8,-28(1)",
"      srw     0,0,5",
"      srw     8,8,5",
"      stw     0,-48(1)",
"      or      8,8,9",
".L__lsrd2:      stw     8,-44(1)",
"      lwz     3,-48(1)",
"      lwz     4,-44(1)",
"      blr",
#endif
0
};

static int asld_lib_used=0;
static char *asld_lib[] = {
#ifdef __APPLE__
".text",
"        .align 2",
".asld__:",
"       mr.     r5,r5",
"       beqlr",
"       subfic  r2,r5,32",
"      stw     r3,-32(r1)",
"      stw     r4,-28(r1)",
"      cmpwi   cr7,r2,0",
"      bgt+    cr7,L__asld1",
"      neg     r0,r2",
"      lwz     r2,-28(r1)",
"      li      r9,0",
"      slw     r2,r2,r0",
"      stw     r9,-44(r1)",
"      b       L__asld2",
"L__asld1:      lwz     r0,-28(r1)",
"      srw     r9,r0,r2",
"      lwz     r2,-32(r1)",
"      slw     r0,r0,r5",
"      slw     r2,r2,r5",
"      stw     r0,-44(r1)",
"      or      r2,r2,r9",
"L__asld2:      stw     r2,-48(r1)",
"      lwz     r3,-48(r1)",
"      lwz     r4,-44(r1)",
"      blr",
#else
".text",
"        .align 2",
".asld__:",
"       mr.     5,5",
"       beqlr",
"       subfic  8,5,32",
"      stw     3,-32(1)",
"      stw     4,-28(1)",
"      cmpwi   7,8,0",
"      bgt+    7,.L__asld1",
"      neg     0,8",
"      lwz     8,-28(1)",
"      li      9,0",
"      slw     8,8,0",
"      stw     9,-44(1)",
"      b       .L__asld2",
".L__asld1:      lwz     0,-28(1)",
"      srw     9,0,8",
"      lwz     8,-32(1)",
"      slw     0,0,5",
"      slw     8,8,5",
"      stw     0,-44(1)",
"      or      8,8,9",
".L__asld2:      stw     8,-48(1)",
"      lwz     3,-48(1)",
"      lwz     4,-44(1)",
"      blr",
#endif
0
};

static int asrd_lib_used=0;
static char *asrd_lib[] = {
#ifdef __APPLE__
".text",
"        .align 2",
".asrd__:",
"       mr.     r5,r5",
"       beqlr",
"       subfic  r2,r5,32",
"      stw     r3,-32(r1)",
"      stw     r4,-28(r1)",
"      cmpwi   cr7,r2,0",
"      bgt+    cr7,L__asrd1",
"      lwz     r0,-32(r1)",
"      neg     r2,r2",
"      sraw    r2,r0,r2",
"      srawi   r0,r0,31",
"      b       L__asrd2",
"L__asrd1:      lwz     r0,-32(r1)",
"      slw     r9,r0,r2",
"      lwz     r2,-28(r1)",
"      sraw    r0,r0,r5",
"      srw     r2,r2,r5",
"      or      r2,r2,r9",
"L__asrd2:      stw     r0,-48(r1)",
"      stw     r2,-44(r1)",
"      lwz     r3,-48(r1)",
"      lwz     r4,-44(r1)",
"      blr",
#else
".text",
"        .align 2",
".asrd__:",
"       mr.     5,5",
"       beqlr",
"       subfic  8,5,32",
"      stw     3,-32(1)",
"      stw     4,-28(1)",
"      cmpwi   7,8,0",
"      bgt+    7,.L__asrd1",
"      lwz     0,-32(1)",
"      neg     8,8",
"      sraw    8,0,8",
"      srawi   0,0,31",
"      b       .L__asrd2",
".L__asrd1:      lwz     0,-32(1)",
"      slw     9,0,8",
"      lwz     8,-28(1)",
"      sraw    0,0,5",
"      srw     8,8,5",
"      or      8,8,9",
".L__asrd2:      stw     0,-48(1)",
"      stw     8,-44(1)",
"      lwz     3,-48(1)",
"      lwz     4,-44(1)",
"      blr",
#endif
0
};

#endif

static void
extern_conv(char *conv)
{
    code_save_stacks();
    clear_ptr_cache();
    extern_define(conv,0,FUNCTION,1);
#ifdef __APPLE__
    printf("\tbl L_%s$stub\n",conv);
#else
    printf("\tbl %s\n",conv);
#endif
}

#if FLOAT_CODE
#if 0
static int d2ll_lib_used=0;
static char *d2ll_lib[] = {
};

static int d2ull_lib_used=0;
static char *d2ull_lib[] = {
};

static int f2ll_lib_used=0;
static char *f2ll_lib[] = {
};

static int f2ull_lib_used=0;
static char *f2ull_lib[] = {
};

static int ll2d_lib_used=0;
static char *ll2d_lib[] = {
};

static int ll2f_lib_used=0;
static char *ll2f_lib[] = {
};
#endif

#endif

static void
code_asld_lib(int reg,int oreg)
{ 
    code_save_stacks();
    clear_ptr_cache();
    asld_lib_used = 1;
    set_lreg_operand(reg,1);
    set_lreg(RET_LREGISTER,0);
    if (regv_l(oreg)!=5) {
        printf("\tmr %s,%s\n", 
            register_name(5),
            lregister_name_low(oreg));
    }
    printf("\tbl .asld__\n");
}

static void
code_asrd_lib(int reg,int oreg) // ___ashrdi3$stub
{
    code_save_stacks();
    clear_ptr_cache();
    asrd_lib_used = 1;
    set_lreg_operand(reg,1);
    set_lreg(RET_LREGISTER,0);
    if (regv_l(oreg)!=5) {
        printf("\tmr %s,%s\n",
            register_name(5),
            lregister_name_low(oreg));
    }
    printf("\tbl .asrd__\n");
}

static void
code_lsrd_lib(int reg,int oreg) // ___lshrdi3$stub
{
    code_save_stacks();
    clear_ptr_cache();
    lsrd_lib_used = 1;
    set_lreg_operand(reg,1);
    set_lreg(RET_LREGISTER,0);
    if (regv_l(oreg)!=5) {
        printf("\tmr %s,%s\n",
            register_name(5),
            lregister_name_low(oreg));
    }
    printf("\tbl .lsrd__\n");
}

static void
code_ldiv_lib(int reg,int oreg) // ___divdi3$stub
{
    code_save_stacks();
    clear_ptr_cache();
    set_lreg_operand(reg,1);
    set_lreg(RET_LREGISTER,0);
    set_lreg_operand1(oreg,1);
    extern_conv("__divdi3");
}

static void
code_ludiv_lib(int reg,int oreg) // ___udivdi3$stub
{
    code_save_stacks();
    clear_ptr_cache();
    set_lreg_operand(reg,1);
    set_lreg(RET_LREGISTER,0);
    set_lreg_operand1(oreg,1);
    extern_conv("__udivdi3");
}

static void
code_lmod_lib(int reg,int oreg) // ___moddi3$stub
{
    code_save_stacks();
    clear_ptr_cache();
    set_lreg_operand(reg,1);
    set_lreg(RET_LREGISTER,0);
    set_lreg_operand1(oreg,1);
    extern_conv("__moddi3");
}

static void
code_lumod_lib(int reg,int oreg) // ___umoddi3$stub
{
    code_save_stacks();
    clear_ptr_cache();
    set_lreg(RET_LREGISTER,0);
    set_lreg_operand(reg,1);
    set_lreg_operand1(oreg,1);
    extern_conv("__umoddi3");
}

#define check_lreg(reg) if (reg!=lreg) { lmove(reg,lreg); /* reg<=lreg */ }

//   reg = reg op oreg

void
ltosop(int op,int reg,int oreg)
{
    int dx = -1;
    int ox = -1;
    int creg_mode = (reg==USE_CREG);
    char *orn_h,*crn_h,*drn_h;
    char *orn_l,*crn_l,*drn_l;
    // creg = creg 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_lrlvar(oreg+REG_LVAR_OFFSET,ox);
        oreg = ox;
    }

    switch(op) {
    case LLSHIFT:
    case LULSHIFT:
        code_asld_lib(reg,oreg); // ___ashldi3$stub
        check_lreg(reg);
        if(ox!=-1) free_register(ox);
        return;
    case LRSHIFT:
        code_asrd_lib(reg,oreg); // ___ashrdi3$stub
        check_lreg(reg);
        if(ox!=-1) free_register(ox);
        return;
    case LURSHIFT:
        code_lsrd_lib(reg,oreg); // ___lshrdi3$stub
        check_lreg(reg);
        if(ox!=-1) free_register(ox);
        return;
    }
    orn_h = lregister_name_high(oreg);
    orn_l = lregister_name_low(oreg);
    crn_h = lregister_name_high(reg);
    crn_l = lregister_name_low(reg);
    switch(op) {
    case LADD:
        printf("\taddc %s,%s,%s\n",crn_l,crn_l,orn_l);
        printf("\tadde %s,%s,%s\n",crn_h,crn_h,orn_h);
        break;
    case LSUB:
        printf("\tsubfc %s,%s,%s\n",crn_l,orn_l,crn_l);
        printf("\tsubfe %s,%s,%s\n",crn_h,orn_h,crn_h);
        break;
    case LCMP:
        error(-1);
        break;
    case LBAND: 
        printf("\tand %s,%s,%s\n",crn_l,crn_l,orn_l);
        printf("\tand %s,%s,%s\n",crn_h,crn_h,orn_h);
        break;
    case LEOR: 
        printf("\txor %s,%s,%s\n",crn_l,crn_l,orn_l);
        printf("\txor %s,%s,%s\n",crn_h,crn_h,orn_h);
        break;
    case LBOR:
        printf("\tor %s,%s,%s\n",crn_l,crn_l,orn_l);
        printf("\tor %s,%s,%s\n",crn_h,crn_h,orn_h);
        break;
    case LMUL:
    case LUMUL:
        // code_save_stacks();
        // clear_ptr_cache();
        dx=get_lregister(); if (dx<0) error(-1);
        use_reg(dx);
        drn_l = lregister_name_low(dx);
        drn_h = lregister_name_high(dx);
        /*
            drn_l = l32( crn_l * orn_l);
            drn_h = h32( crn_l * orn_l);
            crn_h = l32( crn_h * orn_l);
            drn_h = drn_h + crn_h;
            crn_l = l32( crn_l * orn_h);
            crn_h = drn_h + crn_l;
            crn_l = drn_l;
        */
        printf("\tmulhwu %s,%s,%s\n",drn_h,crn_l,orn_l);
        printf("\tmullw %s,%s,%s\n", drn_l,crn_l,orn_l);
        printf("\tmullw %s,%s,%s\n", crn_h,crn_h,orn_l);
        printf("\tadd %s,%s,%s\n",   drn_h,drn_h,crn_h);
        printf("\tmullw %s,%s,%s\n", crn_l,orn_h,crn_l);
        printf("\tadd %s,%s,%s\n",   crn_h,drn_h,crn_l);
        printf("\tmr %s,%s\n",       crn_l,drn_l);
        break;
    case LDIV:
        code_ldiv_lib(reg,oreg); // ___divdi3$stub
        if (!creg_mode) check_lreg(reg);
        break;
    case LUDIV:
        code_ludiv_lib(reg,oreg); // ___udivdi3$stub
        if (!creg_mode) check_lreg(reg);
        break;
    case LMOD:
        code_lmod_lib(reg,oreg); // ___moddi3$stub
        if (!creg_mode) check_lreg(reg);
        break;
    case LUMOD:
        code_lumod_lib(reg,oreg); // ___umoddi3$stub
        if (!creg_mode) check_lreg(reg);
        break;
    default:
        error(-1);
    }
    if(ox!=-1) free_register(ox);
    if(dx!=-1) free_register(dx);
}

int
code_lconst_op_p(int op,int e)
{
    int v;
    if (car(e)==LCONST) {
        if (!(-32766<lcadr(e)&&lcadr(e)<32767)) return 0;
        v = lcadr(e);
    } else if (car(e)==CONST) {
        if (!(-32766<cadr(e)&&cadr(e)<32767)) return 0;
        v = cadr(e);
    } else return 0;
    
    switch(op) {
    case LMUL: case LUMUL: case LUDIV:
// case LDIV: 
        return ilog(v);
    case LLSHIFT:
    case LULSHIFT:
    case LRSHIFT:
    case LURSHIFT:
        return  (0<=v&&v<=64);
    case LADD:
    case LSUB:
        return 1;
    case LBOR:
        return  (v>0);
    default:
        return 0;
    }
}

void
loprtc(int op,int creg,int e)
{
    char *crn_h;
    char *crn_l;
    char *grn;
    int v=0;
    int greg;

    use_longlong(creg);
    crn_h = lregister_name_high(creg);
    crn_l = lregister_name_low(creg);

    if (car(e)==LCONST) v = lcadr(e);
    else if (car(e)==CONST) v = cadr(e);

    switch(op) {
    case LMUL: case LUMUL:
        v=ilog(v);
    case LLSHIFT:
    case LULSHIFT:
        if (v==0) return;
        if (v==32) {
            code_register(regv_l(creg),regv_h(creg));
            code_const(0,regv_l(creg));
            return;
        } else if (v>31) {
            printf("\tslwi %s,%s,%d\n",crn_h,crn_l,v-32);
            code_const(0,regv_l(creg));
            return;
        }
        greg = get_register();
        grn = register_name(greg);
        use_reg(greg);
        printf("\tsrwi %s,%s,%d\n",grn,crn_l,32-v);
        printf("\tslwi %s,%s,%d\n",crn_h,crn_h,v);
        printf("\tor %s,%s,%s\n",crn_h,grn,crn_h);
        printf("\tslwi %s,%s,%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(regv_h(creg),regv_l(creg));
            printf("\tsrawi %s,%s,31\n",crn_h,crn_l);
            return;
        } else if (v>31) {
            printf("\tsrawi %s,%s,%d\n",crn_l,crn_h,v-32);
            printf("\tsrawi %s,%s,31\n",crn_h,crn_l);
            return;
        }
        greg = get_register();
        use_reg(greg);
        grn = register_name(greg);
        printf("\tsrwi %s,%s,%d\n",grn,crn_l,v);
        printf("\tinsrwi %s,%s,%d,0\n",grn,crn_h,v);
        printf("\tsrawi %s,%s,%d\n",crn_h,crn_h,v);
        printf("\tmr %s,%s\n",crn_l,grn);
        free_register(greg);
        return;
    case LUDIV:
        v=ilog(v);
    case LURSHIFT:
        if (v==0) return;
        if (v==32) {
            code_register(regv_h(creg),regv_l(creg));
            code_const(0,regv_h(creg));
            return;
        } else if (v>31) {
            printf("\tsrwi %s,%s,%d\n",crn_l,crn_h,v-32);
            code_const(0,regv_h(creg));
            return;
        }
        greg = get_register();
        use_reg(greg);
        grn = register_name(greg);
        printf("\tslwi %s,%s,%d\n",grn,crn_h,32-v);
        printf("\tsrwi %s,%s,%d\n",crn_l,crn_l,v);
        printf("\tor %s,%s,%s\n",crn_l,grn,crn_l);
        printf("\tsrwi %s,%s,%d\n",crn_h,crn_h,v);
        free_register(greg);
        return;
    case LSUB:
        v = -v;
    case LADD:
        printf("\taddic %s,%s,%d\n",crn_l,crn_l,v);
        if (v<0)
            printf("\taddme %s,%s\n",crn_h,crn_h);
        else
            printf("\taddze %s,%s\n",crn_h,crn_h);
        break;
    case LBOR:
#ifdef __APPLE__
        printf("\tori %s,%s,lo16(%d)\n",crn_l,crn_l,v);
#else
        printf("\tori %s,%s,%d@l\n",crn_l,crn_l,v);
#endif
        break;
    default:
        error(-1);
    }
}


void
emit_lpop_free(int xreg)
{
    if (xreg>=0 && xreg!=creg && regs[xreg]!=REG_VAR)
        free_register(xreg);
}

void
emit_lpush()
{
    int new_reg;
    if (!is_longlong_reg(creg)) error(-1);
    if (lreg_sp>MAX_MAX) error(-1);
    new_reg = get_lregister();        /* 絶対に取れる(?) */
    lreg_stack[lreg_sp++] = creg;     /* push するかわりにレジスタを使う */
    lreg = creg = new_reg;
}

void
code_i2ll(int reg)
{
    char *crn,*crn_h,*crn_l;
    int reg0;
    crn = register_name(reg0 = ireg);
    use_longlong(reg);
    crn_h = lregister_name_high(lreg);
    crn_l = lregister_name_low(lreg);
    if (reg0!=regv_l(lreg))
        printf("\tmr %s,%s\n",crn_l,crn);
    printf("\tsrawi %s,%s,31\n",crn_h,crn_l);
}

void
code_i2ull(int reg)
{
    code_i2ll(reg);
}

void
code_u2ll(int reg)
{
    char *crn,*crn_h,*crn_l;
    int reg0;
    crn = register_name(reg0 = ireg);
    use_longlong(reg);
    crn_h = lregister_name_high(lreg);
    crn_l = lregister_name_low(lreg);
    if (reg0!=regv_l(lreg))
        printf("\tmr %s,%s\n",crn_l,crn);
    printf("\tli %s,0\n",crn_h);
}

void
code_u2ull(int creg)
{
    code_u2ll(creg);
}

void
code_ll2i(int reg)
{
    char *crn_l;
    int reg0;
    crn_l = lregister_name_low(reg0=lreg);
    use_int(reg);
    if (ireg!=regv_l(reg0))
        printf("\tmr %s,%s\n",register_name(ireg),crn_l);
}

void
code_ll2u(int creg)
{
    code_ll2i(creg);
}

void
code_ull2i(int creg)
{
    code_ll2i(creg);
}

void
code_ull2u(int creg)
{
    code_ll2i(creg);
}

#if FLOAT_CODE

void
code_d2ll(int reg)
{
    // fixdfdi$stub
    set_freg(RET_FREGISTER,1);
    extern_conv("__fixdfdi");
    set_lreg(RET_LREGISTER,0);
    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
        use_longlong(reg);
}

void
code_d2ull(int reg)
{
    set_freg(RET_FREGISTER,1);
    extern_conv("__fixunsdfdi");
    set_lreg(RET_LREGISTER,0);
    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
        use_longlong(reg);
}

void
code_f2ll(int reg)
{
    set_freg(RET_FREGISTER,1);
    extern_conv("__fixdfdi");
    set_lreg(RET_LREGISTER,0);
    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
        use_longlong(reg);
}

void
code_f2ull(int reg)
{
    set_freg(RET_FREGISTER,1);
    extern_conv("__fixsfdi");
    set_lreg(RET_LREGISTER,0);
    if (reg!=USE_CREG&&reg!=RET_LREGISTER)
        use_longlong(reg);
}

void
code_ll2d(int reg)
{
    set_lreg(RET_LREGISTER,1);
    extern_conv("__floatdidf");
    set_freg(RET_FREGISTER,0);
    if (reg!=USE_CREG&&reg!=RET_FREGISTER)
        use_float(1,reg);
}


void
code_ll2f(int reg)
{
    set_lreg(RET_LREGISTER,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);
}


static void
ladd(int creg,int reg,int dir)   // creg=reg+dir
{
    printf("\taddic %s,%s,%d\n", 
            lregister_name_low(creg),lregister_name_low(reg), dir);
    printf("\tadd%s %s,%s\n", dir>0?"ze":"me",
            lregister_name_high(creg),lregister_name_high(reg));
}

void
code_lpreinc(int e1,int e2,int reg)
{
    int dreg,xreg;
    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);
}

void
code_lpostinc(int e1,int e2,int reg)
{
    int dreg,nreg,xreg;
    int dir=caddr(e1);
    if (car(e2)==LREGISTER) {
        use_longlong(reg);
        if (use && reg!=cadr(e2))
            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(nreg,dreg,dir);
    code_lassign(xreg,nreg);
    emit_pop_free(xreg);
    free_register(nreg);
}

void
code_lassop(int op,int reg)
{
    int xreg;
    int edx,edx0=-1;

    // (*creg) op = pop()
    xreg = emit_lpop(0);       /* pop e3 value */
    if (!is_int_reg(creg)) error(-1);
    edx = ireg;
    emit_push();
    use_longlong(reg);
    if (regv_l(lreg)==edx || regv_h(lreg)==edx) {
        // this can't happen
        edx0 = get_register(); if(!edx0) error(-1);
        printf("## lassop\n\tmr %s,%s\n",register_name(edx0),register_name(edx));
        edx = edx0;
    }
    lload(edx0=edx,reg,0);
    ltosop(op,reg,xreg);
    use_reg(reg);
    edx = emit_pop(0);
    code_lassign(edx,reg);
    if (edx0!=-1)
        free_register(edx0);
    emit_pop_free(edx);
    emit_lpop_free(xreg);
}

void
code_register_lassop(int reg,int op) {
    // reg op = pop()
    int  xreg=emit_lpop();
    ltosop(op,reg,xreg);
    emit_lpop_free(xreg);
}   


#endif

void
code_save_stacks()
{
    int i,reg;
    for(i=0;i<reg_sp;i++) {
        if ((reg=reg_stack[i])>=0) {
            code_assign_lvar(
                (reg_stack[i]=new_lvar(SIZE_OF_INT)),reg,0); 
            reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET;
            free_register(reg);
        }
    }
#if FLOAT_CODE
    for(i=0;i<freg_sp;i++) {
        if ((reg=freg_stack[i])>=0) {
            code_dassign_lvar(
                (freg_stack[i]=new_lvar(SIZE_OF_DOUBLE)),reg,1); 
            freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET;
            free_register(reg);
        }
    }
#endif
#if LONGLONG_CODE
    for(i=0;i<lreg_sp;i++) {
        if ((reg=lreg_stack[i])>=0) {
            code_lassign_lvar(
                (lreg_stack[i]=new_lvar(SIZE_OF_LONGLONG)),reg); 
            lreg_stack[i]= lreg_stack[i]-REG_LVAR_OFFSET;
            free_register(reg);
        }
    }
#endif
}

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

void
code_closing()
{
#if FLOAT_CODE
    if (d2u_lib_used) emit_lib(d2u_lib);
    if (u2d_lib_used) emit_lib(u2d_lib);
    if (float_one_lib_used) emit_lib(float_one_lib);
    if (float_zero_lib_used) emit_lib(float_zero_lib);
    if (i2d_lib_used) emit_lib(i2d_lib);
    d2u_lib_used = u2d_lib_used= float_one_lib_used= float_zero_lib_used = i2d_lib_used = 0;
#endif
#if LONGLONG_CODE
    if (asld_lib_used) emit_lib(asld_lib);
    if (lsrd_lib_used) emit_lib(lsrd_lib);
    if (asrd_lib_used) emit_lib(asrd_lib);
    asld_lib_used = lsrd_lib_used = asrd_lib_used = 0;
#if 0
    if (lumod_lib_used) emit_lib(lumod_lib);
    if (lmod_lib_used) emit_lib(lmod_lib);
    if (ludiv_lib_used) emit_lib(ludiv_lib);
    if (ldiv_lib_used) emit_lib(ldiv_lib);
#endif
#if FLOAT_CODE
#if 0
    if (dl2ll_lib_used) emit_lib(dl2ll_lib);
    if (d2ull_lib_used) emit_lib(d2ull_lib);
    if (f2ll_lib_used) emit_lib(f2ll_lib);
    if (f2ull_lib_used) emit_lib(f2ull_lib);
    if (ll2d_lib_used) emit_lib(ll2d_lib);
    if (ll2f_lib_used) emit_lib(ll2f_lib);
#endif
#endif
#endif
#ifndef __APPLE__
    if (saveFP_used) emit_lib(saveFP_lib);
#endif
    global_table();
    /* printf("\t.ident \"Micro-C compiled\"\n"); */
}

#if CASE_CODE

int
code_table_jump_p(int delta) { return 1; }

void
code_table_jump(int l,int csvalue,int delta,int max,int min,int dlabel)
{
    int t,s,u=-1;
    char *crn = register_name(csvalue); // can be t,s,u
    char *trn = register_name(t=get_register());
    char *srn = register_name(s=get_register());
    char *urn;

    inc_cmpflag();
    if (min>32767||min<-32765) {
        if (t==csvalue) {
            code_const(min,s);
            printf("\tsub\t%s,%s,%s\n",trn,crn,srn);
        } else {
            code_const(min,t);
            printf("\tsub\t%s,%s,%s\n",trn,crn,trn);
        }
    } else {
#ifdef __APPLE__
        printf("\taddi\t%s,%s,lo16(%d)\n",trn,crn,-min);
#else
        printf("\taddi\t%s,%s,%d@l\n",trn,crn,-min);
#endif
    }
    printf("\tcmplwi   %s,%s,%d\n",crname(cmpflag),trn,max-min);
    printf("\tbgt-\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel);
    inc_cmpflag();
    switch(delta) {
    case 1: printf("\tslwi %s,%s,2\n",trn,trn); break;
    case 2: 
        printf("\tli %s,1\n",srn);
        printf("\tand %s,%s,%s\n",srn,srn,trn);
        printf("\tcmplwi   %s,%s,0\n",crname(cmpflag),srn);
        printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel);
        printf("\tslwi %s,%s,1\n",trn,trn);
        break;
    case 4: 
        printf("\tli %s,3\n",srn);
        printf("\tand %s,%s,%s\n",srn,srn,trn);
        printf("\tcmplwi   %s,%s,0\n",crname(cmpflag),srn);
        printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel);
        break;
    default:
        urn = register_name(u=get_register());
        printf("\tli %s,%d\n",srn,delta);
        printf("\tdivwu %s,%s,%s\n",urn,trn,srn);
        printf("\tmullw %s,%s,%s\n",srn,urn,srn);
        printf("\tsubf %s,%s,%s\n",srn,trn,srn);
        printf("\tcmplwi   %s,%s,0\n",crname(cmpflag),srn);
        printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel);
        printf("\tslwi %s,%s,2\n",trn,urn);
    }
#ifdef __APPLE__
    printf("\taddis %s,r31,ha16(L_%d-L_%d)\n",
             srn,l,code_base);
    printf("\tla %s,lo16(L_%d-L_%d)(%s)\n",
             srn,l,code_base,srn);
    printf("\tadd %s,%s,%s\n",trn,srn,trn);
    printf("\tlwz r0,0(%s)\n",trn);
    printf("\tadd r0,r0,%s\n",srn);
    printf("\tmtctr r0\n");
    printf("\tbctr\n");
#else
    printf("\tlis %s,%s%d@ha\n",srn,lpfx,l);
    printf("\tla %s,%s%d@l(%s)\n",srn,lpfx,l,srn);
    printf("\tadd %s,%s,%s\n",trn,srn,trn);
    printf("\tlwz 0,0(%s)\n",trn);
    printf("\tadd 0,0,%s\n",srn);
    printf("\tmtctr 0\n");
    printf("\tbctr\n");
#endif

    free_register(s);
    free_register(t);
    if (u!=-1) free_register(u);
}

void
code_table_open(int l)
{
    printf("\t.p2align 2\n");
    fwddef(l);
}

void
code_table_value(int label,int table_top)
{
    printf("\t.long %s%d-%s%d\n",lpfx,label,lpfx,table_top);
}

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",ncaddr(rstr)->nm);
    } else if (car(rstr)==LABEL) {
        printf("%s%d:\n",lpfx,cadr(rstr));
    } else {
        error(-1);
    }
}

/*
     prepare asm operands

     char *constraints sgtring
     int  oeprand 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
 */

extern 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);
retry:
    switch((c=*p)) {
    case '?':
    case '!':
    case '+':
    case '%':
    case '#':
    case '*':
    case '=':
        // output register
        p++;
        goto retry;
    case '&':
        // earlyclobber
        p++;
        clobber = 1;
        goto retry;
    case 'b':  // address base register (what?)
    case '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);
        break;
    case 'm':
        repl = list3(list2(0,0),repl,clobber);
        break;
    case 'i':
        if (car(e1)==GVAR) {
            e1=list3n(FNAME,0,ncaddr(e1));
        } else if (car(e1)==FNAME) {
            e1=list3n(FNAME,0,ncaddr(e1));
        } else if (car(e1)==STRING) {
            val = emit_string_label();
            ascii(ncaddr(e1)->nm,ncaddr(e1)->dsp);
            e1=list2(LABEL,val);
        } else if (car(e1)==CONST) {
        } else error(-1);
        repl = list3(e1,repl,clobber);
        break;
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
        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);
        break;
    default:
        printf("### unknown asm constraint %c\n",c);
    }
    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(0);
    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=4,l=0;
    *pbitpos = cadr(caddr(type));
    *pbitsize = caddr(caddr(type));
    switch(cadr(type)) {   /* value type */
    case INT:           sign=1; bitsz=32; align=4;break; 
    case UNSIGNED:              bitsz=32; align=4;break; 
    case CHAR:          sign=1; bitsz= 8; align=1;break; 
    case UCHAR:                 bitsz= 8; align=1;break; 
    case SHORT:         sign=1; bitsz=16; align=2;break; 
    case USHORT:        sign=1; bitsz=16; align=2;break; 
#ifdef __APPLE__
    case LONGLONG:      sign=1; bitsz=64; align=4;l=1; break; 
    case ULONGLONG:             bitsz=64; align=4;l=1; break; 
#else
    case LONGLONG:      sign=1; bitsz=64; align=8;l=1; break; 
    case ULONGLONG:             bitsz=64; align=8;l=1; break; 
#endif
    default: error(-1);
    }
    *psign = sign;
    *pbitsz = bitsz;
    *palign = align;
    *pl = l;
}

/*
      bit field alignment calcuration
        this is architecture depenedent
 */

extern int
code_bit_field_disp(int type,int *poffset,int *bfd,int *sz)
{
    int sign,bitsz,align;
    int i;
    int bitpos = *bfd;
    int bitpos0;
    int bitsize;
    int offset = *poffset;
    int l;
    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 */

        i= offset-(bitpos+7)/8;

        for(l = bitpos;l>0;l -= 8,i++) {
            if ((i & (align-1))==0 && l+bitsize <= bitsz) {
                /* alignment is correct and space remains */
                *poffset=offset=i;
                i = l+bitsize;
                *bfd = (i==bitsz)?0:i;
                *sz = (i+7)/8;
// printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",l,bitsize,bitsz,*poffset);
                return l;
            } 
        }
    }

    /* first bit-field */

    if ((i=(offset & (align-1)))) {
        *poffset = (offset += (align-i));
    }
    bitpos = 0;
    *bfd = (bitsize==bitsz)?0:bitsize;
    *sz = (bitsize+7)/8;

// printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",bitpos,bitsize,bitsz,*poffset);
    return bitpos;
}

/* bit field value */

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 (bitpos) 
            loprtc(LLSHIFT,reg,list2(CONST,bitpos));
        /* shift right */
        if ((i=bitsz-bitsize)) 
            loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i));
#endif
    } else {
        // use_int(adr);
        use_int(reg);
#ifdef __APPLE__
        printf("\t%s %s,lo16(%d)(%s)\n",cload(size),
                register_name(reg),0,register_name(adr));
#else
        printf("\t%s %s,%d@l(%s)\n",cload(size),
                register_name(reg),0,register_name(adr));
#endif
        cext(sign,size,reg);
        /* shift left */
        if ((i=bitpos+(32-bitsz))) 
            oprtc(LSHIFT,reg,list2(CONST,i));
        /* shift right */
        if ((i=bitsz-bitsize+(32-bitsz))) 
            oprtc(sign?RSHIFT:URSHIFT,reg,list2(CONST,i));
    }
}

/* bit field replacement */

static void
make_mask_and_or(int mask,int tmp,char *trn,char *crn,char *lrn)
{
// printf("## mask 0x%08x ~0x%08x\n",mask,~mask);
        code_const(~mask,tmp);
        printf("\tor %s,%s,%s\n",trn,crn,trn);
        /* do conjunction  */
        printf("\tand %s,%s,%s\n",lrn,trn,lrn);
        /* make or-mask  */
        code_const(mask,tmp);
        printf("\tand %s,%s,%s\n",trn,crn,trn);
        /* do disjunction  */
        printf("\tor %s,%s,%s\n",crn,trn,lrn);
}

extern void
code_bit_replace(int adr,int value,int type)
{
    int sign,bitsz,l,align;
    int bitsize,bitpos;
    int mask = 0;
    int tmp = -1;
    int i;
    int lvalue;
    char *crn,*lrn,*trn;
    int 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);
    if (l) {
#if LONGLONG_CODE
        // use_int(adr);
        lvalue = get_lregister();
        lload(adr,lvalue,0);
        use_longlong(value);
        crn = lregister_name_low(value);
        lrn = lregister_name_low(lvalue);
        /* shift left */
        if ((i=bitsz-bitsize-bitpos)) 
            loprtc(LLSHIFT,value,list2(CONST,i));
        trn = register_name(tmp = get_register());
        if (bitpos+bitsize>=32) {
            /* make and-mask lower */
            mask = make_mask(bitpos>=32?bitpos-32:0,bitpos+bitsize-32-1);
            make_mask_and_or(mask,tmp,trn,crn,lrn);
        }
        crn = lregister_name_high(value);
        lrn = lregister_name_high(lvalue);
        if (bitpos<32) {
            /* make and-mask upper */
            mask = make_mask(bitpos,bitpos+bitsize>=32?31:bitpos+bitsize-1);
            make_mask_and_or(mask,tmp,trn,crn,lrn);
        }
        code_lassign(adr,value);
        free_register(lvalue);
        // free_register(adr);
#endif
    } else {
        // use_int(adr);
        use_int(value);
        lvalue = get_register();
#ifdef __APPLE__
        printf("\t%s %s,lo16(%d)(%s)\n",cload(size),
                register_name(lvalue),0,register_name(adr));
#else
        printf("\t%s %s,%d@l(%s)\n",cload(size),
                register_name(lvalue),0,register_name(adr));
#endif
        cext(sign,size,lvalue);
        crn = register_name(value);
        lrn = register_name(lvalue);
        /* shift left */
        if ((i=bitsz-bitsize-bitpos)) 
            oprtc(LSHIFT,value,list2(CONST,i));
        trn = register_name(tmp = get_register());
        /* make and-mask */
        mask = make_mask(bitpos+(32-bitsz),bitpos+bitsize-1+(32-bitsz));
        make_mask_and_or(mask,tmp,trn,crn,lrn);
        free_register(lvalue);
        code_assign(adr,size,value);
    }
    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;
// printf("## mask 0x%08x ~0x%08x\n",mask,~mask);
    if ((~mask|c)!=-1) {
        trn = register_name(tmp=get_register());
        code_const((~mask|c),tmp);
        /* do conjunction  */
        printf("\tand %s,%s,%s\n",crn,trn,crn);
    }
    /* make or-mask  */
    c = mask&c;
    if (c!=0) {
        /* do disjunction  */
        if (!((mask&c)&0xffff0000)) {
#ifdef __APPLE__
            printf("\tori %s,%s,lo16(%d)\n",crn,crn,c);
#else
            printf("\tori %s,%s,%d@l\n",crn,crn,c);
#endif
        } else {
            trn = register_name(tmp=get_register());
            code_const(c,tmp);
            printf("\tor %s,%s,%s\n",crn,trn,crn);
        }
    }
    if (tmp!=-1) free_register(tmp);
}

extern void
code_bit_replace_const(int value,int adr,int type)
{
    int sign,bitsz,l,align;
    int bitsize,bitpos,size;
    int mask = 0;
    int i;
    int c;
    int lvalue;
#if LONGLONG_CODE
    long long lc;
#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) {
#if LONGLONG_CODE
        use_int(adr);
        lvalue = get_lregister();
        lload(adr,lvalue,0);
        crn = lregister_name_low(lvalue);
        /* shift left */
        lc = lcadr(value);
        if ((i=bitsz-bitsize-bitpos)) 
            lc <<= i;
        if (bitpos+bitsize>=32) {
            /* make and-mask lower */
            mask = make_mask(bitpos>=32?bitpos-32:0,bitpos+bitsize-32-1);
            make_mask_and_or_const(mask,crn,(int)lc);
        }
        crn = lregister_name_high(lvalue);
        if (bitpos<32) {
            /* make and-mask upper */
            mask = make_mask(bitpos,bitpos+bitsize>=32?31:bitpos+bitsize-1);
            make_mask_and_or_const(mask,crn,(int)(lc>>32));
        }
        code_lassign(adr,lvalue);
        free_register(lvalue);
#endif
    } else {
        use_int(adr);
        lvalue = get_register();
#ifdef __APPLE__
        printf("\t%s %s,lo16(%d)(%s)\n",cload(size),
                register_name(lvalue),0,register_name(adr));
#else
        printf("\t%s %s,%d@l(%s)\n",cload(size),
                register_name(lvalue),0,register_name(adr));
#endif
        cext(sign,size,lvalue);
        crn = register_name(lvalue);
        /* shift left */
        c = cadr(value);
        if ((i=bitsz-bitsize-bitpos)) 
            c <<= i;
        /* make and-mask */
        mask = make_mask(bitpos+(32-bitsz),bitpos+bitsize-1+(32-bitsz));
        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

extern int 
code_arg_alignment(int args,NMTBL *n, int type0,int sz, int is_code)
{
    return code_arg_alignment0(args,n, type0,sz, is_code);
}


extern int 
code_lvar_alignment(int args,NMTBL *n, int type0,int sz)
{
    return code_lvar_alignment0(args,n, type0,sz);
}


/* end */