Mercurial > hg > CbC > old > device
view mc-code-mips.c @ 935:7672a37e7545 default tip
Raspbery PI ARM support begin
author | kono |
---|---|
date | Sat, 24 Dec 2016 03:02:57 +0000 |
parents | 35b339b36c88 |
children |
line wrap: on
line source
/* Micro-C Code Generation Part for MIPS (ps2linux) */ /* ************************************************************************ ** Copyright (C) 2006 Shinji Kono ** 連絡先: 琉球大学情報工学科 河野 真治 ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) ** ** このソースのいかなる複写,改変,修正も許諾します。ただし、 ** その際には、誰が貢献したを示すこの部分を残すこと。 ** 再配布や雑誌の付録などの問い合わせも必要ありません。 ** 営利利用も上記に反しない範囲で許可します。 ** バイナリの配布の際にはversion messageを保存することを条件とします。 ** このプログラムについては特に何の保証もしない、悪しからず。 ** ** Everyone is permitted to do anything on this program ** including copying, modifying, improving, ** as long as you don't try to pretend that you wrote it. ** i.e., the above copyright notice has to appear in all copies. ** Binary distribution requires original version messages. ** You don't have to ask before copying, redistribution or publishing. ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. ***********************************************************************/ #include <stdio.h> #include "mc.h" #include "mc-parse.h" #include "mc-code.h" #include "mc-codegen.h" #if 0 char *l_include_path[] = { "/usr/include/", "/usr/lib/gcc-lib/mipsEEel-linux/2.95.2/include/", 0 }; #else #include "mc-include.c" #endif // va_start, va_arg is wrong, use va_mips.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 __mips__ 1\n\ #define __LITTLE_ENDIAN__ 1\n\ #define __inline__ inline\n\ #define __STDC__ 1\n\ #define __SIZE_TYPE__ int\n\ #define __extension__\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 __signed__ signed\n\ #define alloca __builtin_alloca\n\ "; int eval_order = NORMAL; int data_alignment = 0; #define TEXT_EMIT_MODE 0 #define DATA_EMIT_MODE 1 #define RODATA_EMIT_MODE 2 #define DOT_SIZE 1 // static void data_mode(char *name); // static void text_mode(int alignment); static void ld_indexx(int byte, int n, int xreg,int reg,int sign); static void local_table(void); static void shift(char *op, int creg,int reg); static int push_struct(int e4,int t,int arg); static void register_usage(char *s); static int get_input_dregister_var0(int i,int reg_var,NMTBL *n,int is_code,int d); static void ascii(char *s,int len); 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 #define ENDIAN_L 0 #define ENDIAN_D 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 1 #define REG_sp 30 #define REG_VAR_BASE 21 #define REG_VAR_MIN 16 #define MIN_TMP_REG 4 #define MAX_TMP_REG 11 #define FREG_VAR_BASE 21 #define FREG_VAR_MIN 16 #define MIN_TMP_FREG 0 #define MAX_TMP_FREG 11 int MAX_REGISTER=30; /* MIPSのレジスタを10個まで使う*/ int MAX_FREGISTER=31; #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 #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 = 4; int MAX_INPUT_FREGISTER_VAR = 4; int MAX_CODE_INPUT_DREGISTER_VAR = 14-MIN_TMP_FREG; int MAX_CODE_INPUT_FREGISTER_VAR = 14-MIN_TMP_FREG; #define LREG_V 3 /* for virtual long long/double register */ #define REGS_MAX (REAL_MAX_REGISTER+REAL_MAX_FREGISTER+REAL_MAX_LREGISTER+LREG_V) static int mips_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 = mips_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[] = { "$0","$fp","$2","$3","$4","$5","$6","$7","$8","$9", "$10","$11","$12","$13","$14","$15","$16","$17","$18","$19", "$20","$21","$22","$23","$24","$25","$26","$27","$28","$29", "$30","$31", "$f0","$f1","$f2","$f3","$f4","$f5","$f6","$f7","$f8","$f9", "$f10","$f11","$f12","$f13","$f14","$f15","$f16","$f17","$f18","$f19", "$f20","$f21","$f22","$f23","$f24","$f25","$f26","$f27","$f28","$f29", "$f30","$f31" }; #define register_name(i) reg_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(int i) { return register_name(i); } char *f(int i) { return fregister_name(i); } char *ll(int i) { return lregister_name_low(i); } char *lh(int 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||FLOAT_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 #define USING_DREG 5 #define INPUT_DREG 6 #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; } 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); void code_lassign_lvar(int e2,int creg); int code_lrindirect(int e1, int reg, int offset, int us); void code_lregister(int e2,int reg); void code_lassign_gvar(int e2,int creg); void code_lassign(int e2,int creg); void code_lassign_lregister(int e2,int reg); void code_lrgvar(int e1,int creg); void code_lrlvar(int e1,int creg); void emit_lpop_free(int xreg); void emit_lpush(); int emit_lpop(); #endif #if LONGLONG_CODE static int code_l1(long long ll); static int code_l2(long long ll); static void set_lreg(int,int); #endif 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 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) align(i,16) #define round4(i) align(i,4) /* 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 return address $sp 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 $fp prev $sp $fp $sp */ #define arg_offset 8 #define arg_offset1 0 int disp_offset = 0; #define disp_offset0 0 #define code_disp_offset0 0 #define CODE_LVAR(l) ((l)+code_disp_offset0) #define CODE_CALLER_ARG(l) ((l)+arg_offset1) #define FUNC_LVAR(l) (l+disp_offset0) #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+16) + round16((max_func_args<2?2:max_func_args)*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 ; r1_offsetv = round16(r1_offsetv); #if 1 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 ); #endif #if 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 #if 1 printf("## $L_%d=%d\n",r1_offset_label,r1_offsetv); printf("## $L_%d=%d\n",lvar_offset_label,r1_offsetv-lvar_offsetv); 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,r1_offsetv-lvar_offsetv); return r1_offsetv; } static void lvar(int l) { if (is_code(fnptr)) { 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($fp)\n",FUNC_LVAR(l)); } 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),lvar_offset_label); } } static void lvar_address(int l,int creg) { if (is_code(fnptr)) { 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\n",register_name(creg), FUNC_LVAR(l)); } 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),lvar_offset_label); } } #define lvar_intro(e) /* do nothing */ void code_lvar(int e2,int reg) { use_int(reg); lvar_address(e2,reg); } void code_init(void) { int reg; /* called only once */ size_of_int = SIZE_OF_INT; size_of_pointer = SIZE_OF_INT; size_of_short = SIZE_OF_SHORT; size_of_float = SIZE_OF_FLOAT; size_of_double = SIZE_OF_DOUBLE; size_of_longlong = SIZE_OF_LONGLONG; endian = ENDIAN; struct_align = size_of_int; 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(); output_mode = -1; } 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 in) { int args = fnptr->dsp; NMTBL *n; int reg_var = 0; int freg_var = 0; int type; int reg; int i; int is_code0 = is_code(fnptr); int dots; if (in) return; function_type(fnptr->ty,&dots); while (args) { /* process in reverse order */ n = ncadddr(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++; freg_var++; caddr(args)=SIZE_OF_INT; } } else if (type==FLOAT) { if ((reg = get_input_dregister_var0(freg_var,reg_var,n,is_code0,0))) { n->sc = FREGISTER; n->dsp = cadr(reg); regs[n->dsp]= INPUT_REG; reg_var++; freg_var++; caddr(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; caddr(args)=size(type); } } else if (type==LONGLONG||type==ULONGLONG) { if ((reg = get_input_lregister_var(reg_var,n,is_code0))) { n->sc = LREGISTER; n->dsp = cadr(reg); regs[i=n->dsp]= INPUT_REG; regs[regv_l(i)]= INPUT_REG; regs[regv_h(i)]= INPUT_REG; reg_var+=2; caddr(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(RGERR); return creg; } #if 0 int get_register(void) { int i = get_register0(); printf("## get_register %d\n",i); return i; } #endif int pop_register(void) { /* レジスタから値を取り出す */ return reg_stack[--reg_sp]; } #if FLOAT_CODE int get_dregister(int d) { /* 使われていないレジスタを調べる */ int i,reg; 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_FLOAT)),reg,0); freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET; return reg; } } for(i=0;i<FREG_VAR_BASE-REG_VAR_MIN;i++) { reg =FREG_VAR_BASE-i+FREG_OFFSET; if (! regs[reg]) { /* 使われていないなら */ regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */ if (i+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 list3n(LREGISTER,ll,n); } } /* ひとつしかなかった */ regs[REG_VAR_BASE-i]=0; max_reg_var=max_reg_var_save; goto not_found; } } } not_found: return list3n(LVAR,new_lvar(SIZE_OF_LONGLONG),0); } void emit_pop_free(int xreg) { if (xreg>=0 && xreg!=creg) 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; } static int get_input_dregister_var0(int i,int reg_var,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 { /* f50(float,float,float...) => f12,f14,$6,$7 test3(int,float,float,float...) => $4,$5,$6,$7 */ if (i==0) i=12+FREG_OFFSET; else if (i==1 && reg_var==0) i=14+FREG_OFFSET; else if (i==1) return list3n(REGISTER,5,n); else if (i==2) return list3n(REGISTER,6,n); else if (i==3) return list3n(REGISTER,7,n); else return 0; } return list3n(FREGISTER,i,n); } int get_input_dregister_var(int i,NMTBL *n,int is_code,int d) { return get_input_dregister_var0(i,0,n,is_code,d); } 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_L==0 regv_l(ll)=i; regv_h(ll)=i+1; #else regv_h(ll)=i; regv_l(ll)=i+1; #endif } else { error(-1); ll=LREG_OFFSET+2; } return list3n(LREGISTER,ll,n); } int get_input_register_var(int i,NMTBL *n,int is_code) { if (is_code) { if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0; i = REG_VAR_BASE-i; } else { if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0; i = i+MIN_TMP_REG; } return list3n(REGISTER,i,n); } /* double register case? */ int get_input_register_var_1(int i,NMTBL *n,int is_code) { if (is_code) { if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0; i = REG_VAR_BASE-i; } else { if (i<0||i>=MAX_INPUT_REGISTER_VAR+1) return 0; i = i+MIN_TMP_REG; } return list3n(REGISTER,i,n); } int free_register_count(int d) { int i,count,fcount; fcount = count = 0; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) count++; } for(i=0;i<MAX_FREGISTER;i++) { if (! regs[i+FREG_OFFSET]) fcount++; } printf("## free reg %d freg %d\n",count,fcount); return d?fcount:count; } #if 0 static int register_full(void) { int i; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) { return 0; } } return 1; } #endif void free_all_register(void) { int i; // printf("## free_all register\n"); #if LONGLONG_CODE||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 (!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; } #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 list3n(REGISTER,j,n); } } return list3n(LVAR,new_lvar(SIZE_OF_INT),0); } #define freg_var_num(i) (FREG_VAR_BASE-i+FREG_OFFSET) int get_dregister_var(NMTBL *n,int d) { int i,j; 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 list3n(FREGISTER,j,n); } } return list3n(LVAR,new_lvar(SIZE_OF_DOUBLE),0); } int emit_push() { int new_reg,old=creg; if (!is_int_reg(creg)) error(-1); if (reg_sp>MAX_MAX) error(-1); new_reg = get_register(); /* 絶対に取れる */ if (creg==new_reg) error(-1); /* some one free creg */ reg_stack[reg_sp++] = creg; /* push するかわりにレジスタを使う */ ireg = creg = new_reg; if (!regs[creg]) regs[creg]=USING_REG; return old; } int emit_pop(int type) { int xreg,reg; xreg=pop_register(); if (xreg<= -REG_LVAR_OFFSET) { reg = get_register(); code_rlvar(REG_LVAR_OFFSET+xreg,reg); free_lvar(REG_LVAR_OFFSET+xreg); xreg = reg; } return xreg; } 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(ncaddr(e1))); return; } void code_rgvar(int e1,int reg) { use_int(reg); code_ld("lw",reg,cadr(e1),get_ptr_cache(ncaddr(e1))); } void code_crgvar(int e1,int reg,int sign,int sz){ use_int(reg); code_ld(cload(sz,sign),reg,cadr(e1),get_ptr_cache(ncaddr(e1))); cext(sign,sz,reg); } void code_register(int e2,int reg) { use_int(reg); if (reg!=e2) printf("\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 (use && cadr(e2)!=reg) 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); if (use) 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); #if 0 printf("\taddu %s,",register_name(creg)); printf("$fp,%d+$L_%d\n",FUNC_LVAR(0),lvar_offset_label); #else printf("\tmove %s,$fp\n",register_name(creg)); #endif #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); } } 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(ncaddr(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(ncaddr(e1))); code_cmp_register(reg,label,cond); } void code_cmp_rlvar(int e2,int reg,int label,int cond) { char *crn; use_int(reg); crn = register_name(reg); lvar_intro(e2); printf("\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; NMTBL *n = ncaddr(e1); if ((lb=attr_value(n,LABEL))) { // already defined return code_label_value(lb,creg) ; } use_int(creg); crn = register_name(creg); s=n->nm; lb = emit_string_label(); ascii(s,n->dsp); text_mode(2); printf("\tla %s,$L_%d\n",crn,lb); set_attr(n,LABEL,lb); } void emit_strings(NMTBL *n) { int l = emit_string_label(); int i; for(i = n->dsp; i; i = cadr(i)) { ascii(scaddr(i),car(i)); } emit_label(l); } void code_strings(int e2,int reg) { int l = emit_string_label(); int i; for(i = e2; i; i = cadr(i)) { ascii(scaddr(i),car(i)); } text_mode(2); code_label_value(l,reg); } #define MAX_COPY_LEN 20 void emit_copy(int from,int to,int length,int offset,int value,int det) { char *frn; char *trn; char *drn; char *memmove = "memmove"; int l; int dreg = get_register(); if (!dreg) error(-1); drn = register_name(dreg); use_int(from); use_int(to); frn = register_name(from); trn = register_name(to); /* length <0 means upward direction copy */ switch (length) { case 0: break; case 1: case -1: printf("\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) { free_register(dreg); dreg = 0; for(;length<=-4;length+=4,offset-=4) emit_copy(from,to,-4,offset-4,0,det); for(;length<=-2;length+=2,offset-=2) emit_copy(from,to,-2,offset-2,0,det); if(length<0) emit_copy(from,to,length,offset-1,0,det); break; } } else if (length <=MAX_COPY_LEN) { free_register(dreg); dreg = 0; for(;length>=4;length-=4,offset+=4) emit_copy(from,to,4,offset,0,det); for(;length>=2;length-=2,offset+=2) emit_copy(from,to,2,offset,0,det); if(length>0) emit_copy(from,to,length,offset,0,det); break; } clear_ptr_cache(); code_save_stacks(); l = list3(4,0,to); l = list3(5,l,from); parallel_rassign(l); printf("\tli $6,%d\n",length>0?length:-length); /* overrap must be allowed */ if (is_code(fnptr)) { printf("\tla\t$25,%s\n",memmove); printf("\tjalr\t$25\n"); printf("\tlw\t$gp,$L_%d($sp)\n",cprestore_label); } else { printf("\tjal %s\n",memmove); } extern_define(memmove,0,FUNCTION,1); set_ireg(RET_REGISTER,0); break; } if (value) { /* creg must point top of the destination data */ /* this code is necessary for the value of assignment or function call */ /* otherwise we don't need this */ if(creg!=to) { free_register(to); // set_ireg(to,1); } } if (dreg) free_register(dreg); } int push_struct(int e4,int t,int arg) { int length,count; int dreg,sreg; char *drn,*crn,*srn; g_expr(e4); if (!is_int_reg(creg)) error(-1); length=size(t); if(length%SIZE_OF_INT) { length += SIZE_OF_INT - (length%SIZE_OF_INT); } dreg = get_register(); if (!dreg) error(-1); drn = register_name(dreg); crn = register_name(creg); if (length<MAX_COPY_LEN) { sreg = get_register(); if (!sreg) error(-1); srn = register_name(sreg); code_lvar(cadr(arg),dreg); for(count=0;count<length;count+=SIZE_OF_INT) { printf("\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); if (creg==lreg) lreg = 0; regs[reg]=USING_REG; } creg = ireg = reg; } static void set_freg(int reg,int mode) { if (!is_float_reg(reg)) error(-1); if (reg!=creg) { if (freg && reg!=freg) { free_register(freg); if (mode) { printf("\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; } #if FLOAT_CODE static void set_lreg_operand(int reg,int mode) { // save_stack,clear_ptr_cache is assumed if (!is_longlong_reg(reg)) { error(-1); return; } if (mode) { lmove(LREGISTER_OPERAND,reg); } } static void set_dreg_operand(int reg,int mode) { set_lreg_operand(reg,mode); } #endif void use_reg(int arg) { // printf("## use reg %d\n",arg); if (arg<0||arg> REGS_MAX) error(-1); clear_ptr_cache_reg(arg); regs[arg]=USING_REG; if (is_longlong_reg(arg)) { clear_ptr_cache_reg(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 = ncadddr(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==5||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(list3n(LVAR,n->dsp,0),list3n(tag,reg,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( list3n(LVAR,offset,0),reg,INT,INT)); offset+=SIZE_OF_INT; reg_var++; } } my_func_args = offset; } int not_simple_p(int e3) { switch(e3) { case FUNCTION: case CONV: case STASS: case ALLOCA: case LDIV: case LUDIV: case LMOD: case LUMOD: case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: case DDIV: case DADD: case DSUB: case DMUL: case DMINUS: case DPOSTINC : case DPREINC : case DASSOP : case DOP+LT : case DOP+LE : case DOP+GT : case DOP+GE : case DOP+EQ : case DOP+NEQ: case INLINE: return 1; } return 0; } 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; free_register(lreg); lreg = 0; } else if (regv_h(lreg)==reg) { regs[lreg]=0; if (regv_h(lreg)>reg && ( (regs[regv_l(lreg)]==USING_REG) || (regs[regv_l(lreg)]==USING_DREG) )) { free_register(regv_l(lreg)); } if (creg==lreg) creg = ireg; free_register(lreg); lreg = 0; } } } else if (is_longlong_reg(reg)) { use_input_reg(regv_h(reg),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 = ireg; freg = 0; } } if (mode) use_reg(reg); } #define FASS_INPUT (FOP+199) static void code_assign_input_float_int(int e0) { #if FLOAT_CODE 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(ncaddr(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); printf("\tmfc1 %s,%s\n",frn,fregister_name(freg)); break; case FREGISTER: printf("\tmfc1 %s,%s\n",frn,fregister_name(cadr(e2))); } #endif } static int compute_complex_arg(int e3,int reg_arg_list,int arg) { int t=caddr(e3); int e4 = car(e3); reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER||car(arg)==DREGISTER|| car(arg)==FREGISTER||car(arg)==LREGISTER) use_input_reg(cadr(arg),1); if (t==FLOAT&&car(arg)==REGISTER) code_assign_input_float_int(list3(FASS_INPUT, arg, e4)); else g_expr_u(assign_expr0(arg,e4,t,t)); car(e3) = arg; return reg_arg_list; } static void increment_function_arg(int e3,int *pnargs,int *preg_arg,int *pfreg_arg) { int nargs=0,reg_arg=0,freg_arg=0; int t=caddr(e3); if(scalar(t)) { nargs ++ ; reg_arg++; freg_arg++; } else if (t==LONGLONG||t==ULONGLONG||t==DOUBLE) { 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 list3n(LVAR,caller_arg_offset_v(nargs),0); } 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 list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_lregister_var(reg_arg,0,0); } else if (t==FLOAT) { if (mode==AS_SAVE) { return get_dregister_var(0,0); } else if (freg_arg>=MAX_INPUT_DREGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_dregister_var0(freg_arg,reg_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 list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_dregister_var(reg_arg,0,0,1); } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { if (mode==AS_SAVE) { return get_register_var(0); } else return list3n(LVAR,caller_arg_offset_v(nargs),0); } else { error(-1); return get_register_var(0); } } static void code_call(int e2,NMTBL *fn,int jmp) { // char *jrn; if (is_code(fnptr)) { 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=0,preg_arg=0,pfreg_arg=0; int stargs; special_lvar = -1; ret_type = function_type(cadddr(e1),&dots); if (caddr(cadddr(e1))==0) dots=1; arg_assign = 0; e2 = cadr(e1); if (car(e2) == FNAME) { fn=ncaddr(e2); } else { if (car(e2)==INDIRECT) e2=cadr(e2); // (*func)(i) case jmp = 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) e4 = cadr(e4); else if (car(e4)!=INDIRECT) e4 = cadr(e4); if (!simple_arg(e4)) { // Calculate complex struct address here. // If simple, leave it. arg = get_register_var(0); g_expr_u(assign_expr0(arg,e4,INT,INT)); car(e3)=arg; reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER) use_input_reg(cadr(arg),1); else car(e3) = rvalue_t(arg,INT); } } stargs = list4(e3,stargs,nargs,reg_arg); } increment_function_arg(e3,&nargs,®_arg,&freg_arg); } /* now all input register vars are free */ code_save_stacks(); // set_lreg(LREG_LREGISTER,0); set_freg(FREG_FREGISTER,0); set_ireg(CREG_REGISTER,0); // Struct arguments need emit_copy. it destructs 3 input registers. // But it returns no value on a register. So calculate it here. // We cannot do this in the previous loop, because the copied struct may be // override by other complex arguments. But before this we have to check // complex_. if (stargs) { if (complex_) { arg = get_input_arg(caddr(complex_),AS_SAVE, pnargs,preg_arg,pfreg_arg); reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); } for(stargs=reverse0(stargs);stargs;stargs = cadr(stargs)) { e3 = car(stargs); e4 = car(e3); t = caddr(e3); arg = get_input_arg(t,AS_ARG,caddr(stargs),cadddr(stargs),0); push_struct(e4,t,arg); car(e3)=0; // done if (car(arg)==REGISTER) use_input_reg(cadr(arg),1); } } else { // last complex argument can use input register if (complex_) { arg = get_input_arg(caddr(complex_),AS_ARG,pnargs,preg_arg,pfreg_arg); reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); car(complex_) = 0; // done. if (car(arg)==REGISTER) use_input_reg(cadr(arg),1); } } nargs = reg_arg = freg_arg = 0; // calc stack arguments first, it may requires extra registers, // and we can still use input registers now. for (e3 = e1; e3; increment_function_arg(e3,&nargs,®_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); free_register_var(reg_arg_list); 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; g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15+4)),list2(CONST,~15))); use_int(reg); crn = register_name(reg); printf("\tsubu $sp,$sp,%s\n",crn); printf("\taddu %s,$sp,$L_%d+4\n",crn,cprestore_label); if (is_code(fnptr)) { printf("\tsw\t$gp,$L_%d($sp)\n",cprestore_label); } } 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 } int code_frame_pointer_register() { return list2(REGISTER,REG_fp); } void code_fix_frame_pointer(int offset) { } // 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||FLOAT_CODE static void lload(int creg,int reg,int offset) { char *crn=register_name(creg); #if ENDIAN_L==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_L==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(ncaddr(e2))); } void code_assign_lvar(int e2,int creg,int byte) { char *crn; use_int(creg); crn=register_name(creg); lvar_intro(e2); printf("\t%s %s,",cstore(byte),crn); lvar(e2); } void code_assign_register(int e2,int byte,int creg) { use_int(creg); if (e2!=creg) printf("\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); printf("\t%s %s,0(%s)\n",cstore(byte),crn,drn); } void code_register_assop(int e2,int reg, int op,int byte) { // reg <= reg(e2) op=reg use_int(reg); tosop(op,e2,reg); } void code_assop(int op,int creg, int byte,int sign) { char *crn,*drn; int xreg; int edx = get_register(); if(!edx) error(-1); // (*creg) op = pop() use_int(creg); xreg = emit_pop(0); /* pop e3 value */ set_ireg(edx,0); ld_indexx(byte,0,creg,ireg,sign); tosop(op,ireg,xreg); crn = register_name(ireg); drn = register_name(creg); printf("\t%s %s,0(%s)\n",cstore(byte),crn,drn); free_register(edx); emit_pop_free(xreg); } int tosop_operand_safe_p(int op) { switch(op) { case CMPGE: case CMP: case UCMPGE: return CMP; // creg is not safe default: return 1; } } 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); free_lvar(oreg+REG_LVAR_OFFSET); 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 glist2(REGISTER,creg); } void code_cmpdimm(int e, int csreg,int label,int cond) { /* used in dosiwtch() */ int reg=-1,regsv; char *rn,*crn; crn = register_name(csreg); if (e<-32767||32766<e) { regsv=regs[csreg]; use_reg(csreg); rn = register_name(reg= get_register()); regs[csreg]=regsv; code_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: 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: regsv=regs[csreg]; use_reg(csreg); rn = register_name(reg= get_register()); regs[csreg]=regsv; 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); 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,0,0,COND_VALUE); emit_pop_free(e2); return 1; } int rexpr(int e1, int l1, int cond,int t) { int e2; int op = car(e1); 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); return l1; } #define CMP_C1T (-1) static void jcond(int l, char cond) { 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) { printf("\tj\t$L_%d\n",l); } void code_comment(char *s) { 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,-%d($13)\n",register_name(i), -disp); disp -= SIZE_OF_INT; } for (i=freg_var_num(0);i>freg_var_num(freg_save);i--) { printf("\ts.s %s,-%d($13)\n",register_name(i), -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,-%d($13)\n",register_name(i), -disp); disp -= SIZE_OF_INT; } for (i=freg_var_num(0);i>freg_var_num(freg_save);i--) { printf("\tl.s %s,-%d($13)\n",register_name(i), -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; clear_ptr_cache(); } void code_enter1(int args) { // set_lreg(LREG_LREGISTER,0); set_ireg(CREG_REGISTER,0); set_freg(FREG_FREGISTER,0); } void code_leave(char *name) { code_offset_set(fnptr); local_table(); printf("\t.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 $sp,$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("\tmove $13,$sp\n"); printf("\tsubu $sp,$sp,$L_%d\n",r1_offset_label); printf("\t.cprestore $L_%d\n",cprestore_label=fwdlabel()); printf("\tsw $31,-%d($13)\n",arg_offset); printf("\tsw $fp,-%d($13)\n",arg_offset+SIZE_OF_INT); printf("\tj $L_%d\n",register_save_label=fwdlabel()); register_save_return_label = backdef(); printf("\tsubu $fp,$13,$L_%d\n",lvar_offset_label); clear_ptr_cache(); } void enter1() { text_mode(0); // set_lreg(LREG_LREGISTER,0); set_ireg(CREG_REGISTER,0); set_freg(FREG_FREGISTER,0); } void code_label_call(int l) { if (is_code(fnptr)) { printf("\tla\t$25,L_%d\n",l); printf("\tjalr\t$25\n"); printf("\tlw\t$gp,$L_%d($sp)\n",cprestore_label); } else printf("\tjal L_%d\n",l); } void code_ret() { printf("\tj $31\n"); control=1; } static void make_return_continuation() { // 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); printf("\tmove $fp,$21\n"); } else if (cadr(fnptr->ty)==DOUBLE) { creg = lreg = cadr(get_input_dregister_var(0,0,1,1)); set_dreg(RET_DREGISTER,1); printf("\tmove $fp,$19\n"); } else if (cadr(fnptr->ty)>0&&( car(cadr(fnptr->ty))==STRUCT || car(cadr(fnptr->ty))==UNION)) { int 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); printf("\tmove $fp,$20\n"); // 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); printf("\tmove $fp,$20\n"); } #if R1SAVE #else #if 0 printf("\tsubu $fp,"); printf("$fp,%d+$L_%d\n",FUNC_LVAR(0),lvar_offset_label); // printf("\tj $L_%d\n",retcont1); #endif #endif } void leave(int control, char *name) { // int retcont1=0; int r1_offsetv; if (control) { code_set_return_register(1); } else text_mode(2); if (retcont) { /* return from CbC segement */ if (control) jmp(retlabel); make_return_continuation(); } fwddef(retlabel); // if (retcont) { // fwddef(retcont1); // } r1_offsetv = code_offset_set(fnptr); printf("\taddu $13,$fp,$L_%d\n",lvar_offset_label); printf("\tlw $31,-%d($13)\n",arg_offset); printf("\tlw $fp,-%d($13)\n",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("\tmove $sp,$13\n"); code_ret(); // 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(); } int code_set_return_register(int mode) { if (cadr(fnptr->ty)==FLOAT) { set_freg(RET_FREGISTER,mode); return freg; } else if (cadr(fnptr->ty)==DOUBLE) { set_dreg(RET_DREGISTER,mode); return lreg; } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) { set_lreg(RET_LREGISTER,mode); return lreg; } else if (cadr(fnptr->ty)==VOID) { return 0; } else { set_ireg(RET_REGISTER,mode); return ireg; } } int code_get_fixed_creg(int reg,int type) { switch(type) { #if FLOAT_CODE case DOUBLE: use_float(1,reg); break; case FLOAT: use_float(0,reg); break; #endif #if LONGLONG_CODE case LONGLONG: case ULONGLONG: use_longlong(reg); break; #endif default: if (reg==USE_CREG) { if (regs[CREG_REGISTER]==0||regs[CREG_REGISTER]==PTRC_REG) { set_ireg(CREG_REGISTER,is_int_reg(creg)&®s[creg]==USING_REG); return CREG_REGISTER; } } use_int(reg); break; } return reg; } void code_set_fixed_creg(int reg,int mode,int type) { if (type==FLOAT) { 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 code_align(int t) { int d; switch(t) { case CHAR: case UCHAR: return; case SHORT: case USHORT: d = data_alignment & 1; break; default: d = data_alignment & 3; } if (d) { printf("\t.align 2\n"); data_alignment = 0; } } extern void ascii(char *s,int len) { if (s[len-1]==0) printf("\t.string \""); else printf("\t.ascii \""); while(len-->0) { if (*s=='\n') printf("%cn",92); else if (*s<' ') printf("%c%03o",92,*s); else if (*s=='\\') printf("\\\\"); else if (*s==34) printf("%c%c",92,34); else printf("%c",*s); s++; } printf("%c\n",34); } extern int emit_string_label() { int lb; lb=fwdlabel(); cstring_mode(); printf("$L_%d:\n",lb); return lb; } extern void emit_string(char *s,int t,int len) { t = type_value(t); if (car(t)==ARRAY && (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { ascii(s,len); } else { int l = emit_string_label(); ascii(s,len); emit_label(l); } return; } extern void emit_global(NMTBL *n,int a,int e) { int t = type_value(n->ty); if (e>0 && car(e)==STRING && t>0 && car(t)==ARRAY && (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { cstring_mode(); } else data_mode(n->nm); code_align(a); if (n && n->sc!=STATIC) printf("\t.globl\t%s\n",n->nm); printf("%s:\n",n->nm); } extern void emit_space(int sp) { data_mode(0); printf("\t.space\t%d\n",sp); } extern void emit_char(int d) { data_mode(0); printf("\t.byte %d\n",d); } extern void emit_short(int d) { data_mode(0); printf("\t.short %d\n",d); } extern void emit_int(int d) { data_mode(0); printf("\t.long %d\n",d); } extern void emit_longlong(int e) { #if LONGLONG_CODE long long ll = lcadr(e); data_mode(0); #if (ENDIAN_L==0) printf("\t.long\t0x%x,0x%x\n",code_l1(ll),code_l2(ll)); #else printf("\t.long\t0x%x,0x%x\n",code_l2(ll),code_l1(ll)); #endif #endif } extern void emit_double(int e) { #if FLOAT_CODE double d = dcadr(e); data_mode(0); #if (ENDIAN_D==0) printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d)); #else printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d)); #endif #endif } extern void emit_float(int e) { #if FLOAT_CODE float f = dcadr(e); data_mode(0); printf("\t.long\t0x%x\n",*(int *)&f); #endif } extern void emit_address(char *s,int offset) { data_mode(0); if (offset) printf("\t.long %s+%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 (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) { // is this really happen? why don't we use local static list? if (is_function(n)||is_code(n)) continue; /* 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 == STATIC) { if (n->dsp != -1) { /* initialized static */ if (init==0) { data_mode(0); init=1; } comm(n); } } } text_mode(2); } void cstring_mode(int align) { if (output_mode!=RODATA_EMIT_MODE) { printf(".section\t.rodata\n\t.align 2\n"); output_mode = RODATA_EMIT_MODE; } } void text_mode(int align) { if (output_mode!=TEXT_EMIT_MODE) { printf(".text\n"); if (align) printf("\t.align %d\n",align); output_mode = TEXT_EMIT_MODE; } } void data_mode(char *name) { if (output_mode!=DATA_EMIT_MODE) { printf(".data\n"); output_mode = DATA_EMIT_MODE; } if (name) printf("\t.type\t%s,@object\n",name); } #define lib_args(max) if (max_func_args<max) max_func_args=max #if FLOAT_CODE||LONGLONG_CODE static void extern_conv(char *conv) { code_save_stacks(); clear_ptr_cache(); extern_define(conv,0,FUNCTION,1); if (is_code(fnptr)) { printf("\tla\t$25,%s\n",conv); printf("\tjalr\t$25\n"); printf("\tlw\t$gp,$L_%d($sp)\n",cprestore_label); } else printf("\tjal %s\n",conv); lib_args(16); } #endif #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(ncaddr(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_D==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_builtin_fabsf(int e) { } void code_builtin_fabs(int e) { } void code_builtin_inff() { } void code_builtin_inf() { } 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(ncaddr(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); } } int drexpr(int e1, int e2,int l1, int op,int cond) { int op1=0; if (!cond) { switch(op) { case FOP+GT: return drexpr(e2,e1,l1,FOP+GE,1); case FOP+GE: return drexpr(e2,e1,l1,FOP+GT,1); case FOP+EQ: op=FOP+NEQ; break; case FOP+NEQ: op=FOP+EQ; break; case DOP+GT: return drexpr(e2,e1,l1,DOP+GE,1); case DOP+GE: return drexpr(e2,e1,l1,DOP+GT,1); case DOP+EQ: op=DOP+NEQ; break; case DOP+NEQ: op=DOP+EQ; break; } } switch(op) { case FOP+GT: op1=FOP+CMP; 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; } return l1; } 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,0,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 */ int 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); return l1; } #endif #if LONGLONG_CODE||FLOAT_CODE 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); } } #endif #if LONGLONG_CODE 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); } #endif #if LONGLONG_CODE||FLOAT_CODE 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(ncaddr(e2)); #if ENDIAN_L==0 code_ldf(cstore(0),lregister_name_low(creg),cadr(e2),r); code_ldf(cstore(0),lregister_name_high(creg),cadr(e2)+SIZE_OF_INT,r); #else code_ldf(cstore(0),lregister_name_high(creg),cadr(e2),r); code_ldf(cstore(0),lregister_name_low(creg),cadr(e2)+SIZE_OF_INT,r); #endif } void code_lassign_lvar(int e2,int creg) { char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); lvar_intro(e2); #if ENDIAN_L==0 printf("\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); } } void code_lrgvar(int e1,int creg) { int r; char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); r = get_ptr_cache(ncaddr(e1)); #if ENDIAN_L==0 code_ldf("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); #if ENDIAN_L==0 printf("\tlw %s,",crn_l); lvar(e1); printf("\tlw %s,",crn_h); lvar(e1+SIZE_OF_INT); #else printf("\tlw %s,",crn_h); lvar(e1); printf("\tlw %s,",crn_l); lvar(e1+SIZE_OF_INT); #endif } #endif #if LONGLONG_CODE static long long ll0 = 1LL; static int code_l1(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[1]:j[0]; } static int code_l2(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[0]:j[1]; } void code_lconst(int e1,int creg) { use_longlong(creg); #if ENDIAN_L==0 code_const(code_l1(lcadr(e1)),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); } 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(); int sreg = get_register(); ch = lregister_name_high(reg); cl = lregister_name_low(reg); oh = register_name(sreg); ol = lregister_name_low(oreg); dh = lregister_name_high(dreg); dl = lregister_name_low(dreg); printf("\tmove %s,%s\n",oh,lregister_name_high(oreg)); 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(sreg); // 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(); int sreg = get_register(); ch = lregister_name_high(creg); cl = lregister_name_low(creg); oh = register_name(sreg); ol = lregister_name_low(oreg); dh = lregister_name_high(dreg); dl = lregister_name_low(dreg); printf("\tmove %s,%s\n",oh,lregister_name_high(oreg)); 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); free_register(sreg); 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(); int sreg = get_register(); ch = lregister_name_high(reg); cl = lregister_name_low(reg); oh = register_name(sreg); ol = lregister_name_low(oreg); dh = lregister_name_high(dreg); dl = lregister_name_low(dreg); printf("\tmove %s,%s\n",oh,lregister_name_high(oreg)); 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); free_register(sreg); 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); crn_h 7 = l32( crn_h * orn_l); 7, 3 drn_h 5 = drn_h + crn_h; 5, 7 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",crn_h,crn_h,orn_l); printf("\taddu %s,%s,%s\n",drn_h,drn_h,crn_h); 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); case LMUL: case LUMUL: case LUDIV: /* case LDIV: */ return ilog(v); 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); else { v=0; error(-1); } switch(op) { case LMUL: case LUMUL: v=ilog(v); case LLSHIFT: case LULSHIFT: if (v==0) return; if (v==32) { code_register(regv_l(creg),regv_h(creg)); code_const(0,regv_l(creg)); return; } else if (v>31) { printf("\tsll %s,%s,%d\n",crn_h,crn_l,v-32); code_const(0,regv_l(creg)); return; } 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: if (v==0) return; if (v==32) { code_register(regv_h(creg),regv_l(creg)); printf("\tsra %s,%s,31\n",crn_h,crn_l); return; } else if (v>31) { printf("\tsra %s,%s,%d\n",crn_l,crn_h,v-32); printf("\tsra %s,%s,31\n",crn_h,crn_l); return; } 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 LUDIV: v=ilog(v); case LURSHIFT: if (v==0) return; if (v==32) { code_register(regv_h(creg),regv_l(creg)); code_const(0,regv_h(creg)); return; } else if (v>31) { printf("\tsrl %s,%s,%d\n",crn_l,crn_h,v-32); code_const(0,regv_h(creg)); return; } 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); } #endif #if LONGLONG_CODE||FLOAT_CODE 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; } #endif #if LONGLONG_CODE 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 (use && 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); if (use) 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); if (reg!=lreg) free_register(reg); } void code_register_lassop(int reg,int op) { // reg op = pop() int xreg=emit_lpop(); ltosop(op,reg,xreg); emit_lpop_free(xreg); } #endif void code_save_stacks() { int i,reg; for(i=0;i<reg_sp;i++) { if ((reg=reg_stack[i])>=0) { code_assign_lvar( (reg_stack[i]=new_lvar(SIZE_OF_INT)),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_FLOAT)),reg,0); 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(int delta) { 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",ncaddr(rstr)->nm); } else if (car(rstr)==LABEL) { 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=list3n(FNAME,0,ncaddr(e1)); } else if (car(e1)==FNAME) { e1=list3n(FNAME,0,ncaddr(e1)); } else if (car(e1)==STRING) { val = emit_string_label(); ascii(ncaddr(e1)->nm,ncaddr(e1)->dsp); e1=list3(LABEL,val,0); } else if (car(e1)==CONST) { } else error(-1); repl = list3(e1,repl,clobber); } else if (digit(c)) { val = 0; do { val = val*10 + c-'0'; } while (digit(c=*p++)); if (val>MAX_ASM_REG) error(-1); // too large register if (n-val<0) error(-1); repl = list3(car(nth(n-val-1,repl0)),repl,clobber); } else error(-1); return repl; } void code_free_asm_operand(int repl) { for(;repl;repl=cadr(repl)) { if (car(car(repl))==REGISTER) free_register(cadr(car(repl))); } } extern void code_asm(char *asm_str,int repl) { int c,i,rstr,val; char *p; int reg[MAX_ASM_REG]; text_mode(2); c = *asm_str; if (c!='\t'&&c!=' ') printf("\t"); for(i=0;repl && i<MAX_ASM_REG;i++) { reg[i] = car(repl); repl = cadr(repl); } p = asm_str; while((c = *p++)) { if (c=='%') { c = *p++; if (!c) { break; } else if (c=='%') { printf("%%"); continue; } else if (!digit(c)) { printf("%%%c",c); continue; } val = 0; do { val = val*10 + c-'0'; } while (digit(c=*p++)) ; p--; if (val>MAX_ASM_REG) error(-1); // too large register rstr = reg[val]; emit_asm_operand(rstr); } else { printf("%c",c); } } printf("\n"); } #endif #if BIT_FIELD_CODE /* bit field alignment calcuration */ static void set_bitsz(int type,int *pbitpos, int *pbitsize, int *psign,int *pbitsz,int *palign,int *pl) { int sign=0,bitsz=0; int align=4,l=0; *pbitpos = cadr(caddr(type)); *pbitsize = caddr(caddr(type)); switch(cadr(type)) { /* value type */ case INT: sign=1; bitsz=32; align=4;break; case UNSIGNED: bitsz=32; align=4;break; case CHAR: sign=1; bitsz= 8; align=1;break; case UCHAR: bitsz= 8; align=1;break; case SHORT: sign=1; bitsz=16; align=2;break; case USHORT: sign=1; bitsz=16; align=2;break; 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,bitpos0; set_bitsz(type,&bitpos0,&bitsize,&sign,&bitsz,&align,&l); if (bitsize>bitsz) { error(BTERR); bitsize = bitsz; } /* bfd means previous bit field bit offset */ if (bitpos) { /* previous field is bit field and spaces may remain */ /* calc previsous offset */ i= offset-(bitpos+7)/8; for(l = bitpos;l>0;l -= 8,i++) { if ((i & (align-1))==0 && l+bitsize <= bitsz) { /* alignment is correct and space remains */ *poffset=offset=i; i = l+bitsize; *bfd = (i==bitsz)?0:i; *sz = (i+7)/8; // printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",l,bitsize,bitsz,*poffset); return l; } } } /* first bit-field */ if ((i=(offset & (align-1)))) { *poffset = (offset += (align-i)); } bitpos = 0; *bfd = (bitsize==bitsz)?0:bitsize; *sz = (bitsize+7)/8; // printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",bitpos,bitsize,bitsz,*poffset); return bitpos; } /* bit field value */ extern void code_bit_field(int type,int adr,int reg) { int sign,bitsz,l,align; int bitsize,bitpos; int i,size; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); /* this implementation returns -1 for int i:1; */ if (l==1) { #if LONGLONG_CODE use_int(adr); use_longlong(reg); lload(adr,reg,0); /* shift left */ if ((i=bitsz-bitsize-bitpos)) loprtc(LLSHIFT,reg,list2(CONST,i)); /* shift right */ if ((i=bitsz-bitsize)) loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i)); #endif } else { use_int(adr); use_int(reg); ld_indexx(size, 0, adr, reg, sign); /* 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 adr,int value,int type) { int sign,bitsz,l,align; int bitsize,bitpos; int mask = 0; int tmp = -1,lvalue,size; char *crn,*lrn,*trn; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); if (l) { #if LONGLONG_CODE use_int(adr); lvalue = get_lregister(); lload(adr,lvalue,0); use_longlong(value); crn = lregister_name_high(value); lrn = lregister_name_high(lvalue); /* shift left */ if (bitpos) loprtc(LLSHIFT,value,list2(CONST,bitpos)); trn = register_name(tmp = get_register()); if (bitpos+bitsize>=32) { /* make and-mask upper */ mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); make_mask_and_or(mask,tmp,trn,crn,lrn); } crn = lregister_name_low(value); lrn = lregister_name_low(lvalue); if (bitpos<32) { /* make and-mask lower */ mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); make_mask_and_or(mask,tmp,trn,crn,lrn); } code_lassign(adr,value); #endif } else { use_int(adr); use_int(value); lvalue = get_register(); ld_indexx(size, 0, adr, lvalue, sign); crn = register_name(value); lrn = register_name(lvalue); /* shift left */ if (bitpos) oprtc(LSHIFT,value,list2(CONST,bitpos)); trn = register_name(tmp = get_register()); /* make and-mask */ mask = make_mask(32-bitpos-bitsize,31-bitpos); make_mask_and_or(mask,tmp,trn,crn,lrn); code_assign(adr,size,value); } free_register(lvalue); if (tmp!=-1) free_register(tmp); if (use) { code_bit_field(type,adr,USE_CREG); } } static void make_mask_and_or_const(int mask,char *crn,int c) { char *trn; int tmp = -1; // 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); } if (tmp!=-1) { free_register(tmp); tmp=-1; } /* 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 adr,int type) { int sign,bitsz,l,align; int bitsize,bitpos,size; int mask = 0; int c; int lvalue; #if LONGLONG_CODE long long lc; #endif char *crn; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); if (l) { #if LONGLONG_CODE use_int(adr); lvalue = get_lregister(); lload(adr,lvalue,0); crn = lregister_name_high(lvalue); /* shift left */ lc = lcadr(value); lc <<= bitpos; if (bitpos+bitsize>=32) { /* make and-mask upper */ mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); make_mask_and_or_const(mask,crn,(int)(lc>>32)); } crn = lregister_name_low(lvalue); if (bitpos<32) { /* make and-mask lower */ mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); make_mask_and_or_const(mask,crn,(int)lc); } code_lassign(adr,lvalue); #endif } else { use_int(adr); lvalue = get_register(); crn = register_name(lvalue); ld_indexx(size, 0, adr, lvalue, sign); /* shift left */ c = cadr(value); c <<= bitpos; /* make and-mask */ mask = make_mask(32-bitpos-bitsize,31-bitpos); make_mask_and_or_const(mask,crn,c); code_assign(adr,size,lvalue); } free_register(lvalue); if (use) { code_bit_field(type,adr,USE_CREG); } } #endif extern int code_arg_alignment(int args,NMTBL *n, int type0,int sz, int is_code) { return code_arg_alignment0(args,n, type0,sz, is_code); } extern int code_lvar_alignment(int args,NMTBL *n, int type0,int sz) { return code_lvar_alignment0(args,n, type0,sz); } /* end */