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