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