Mercurial > hg > CbC > old > device
view mc-code-spu.c @ 935:7672a37e7545 default tip
Raspbery PI ARM support begin
author | kono |
---|---|
date | Sat, 24 Dec 2016 03:02:57 +0000 |
parents | 35b339b36c88 |
children |
line wrap: on
line source
/* Micro-C Code Generation Part for 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 cext(int sz, int sign, int from, int to); 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); #endif static void use_input_reg(int reg,int mode); static void ascii(char *s,int len); 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; 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 SIZE_OF_VECTOR 16 #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 127 #define REG_sp 1 #define REG_VAR_BASE 3 #define REG_VAR_MIN 3 #define REG_VAR_USER_MAX (127-8) /* at leat 6 tmp var */ #define REG_VAR_MAX (127-8) #define MIN_TMP_REG 3 #define MAX_TMP_REG 126 #define FREG_VAR_BASE 3 #define FREG_VAR_MIN 3 #define FREG_VAR_MAX REG_VAR_MAX #define MIN_TMP_FREG 3 #define MAX_TMP_FREG 126 int MAX_REGISTER=127; /* ARMのレジスタを10個まで使う*/ #define REAL_MAX_REGISTER 128 /* 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 static int *regs = spu_regs; #define CREG_REGISTER REGISTER_OPERAND #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] char *rn(int i) { return register_name(i); } // input register mark #define USING_DREG 5 #define INPUT_DREG 6 #if FLOAT_CODE 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 #define is_int_reg(reg) (1) #define is_float_reg(reg) (1) #define is_longlong_reg(reg) (1) #define use_int(reg) if (reg==USE_CREG) reg=use_int0() #define use_float(d,reg) if (reg==USE_CREG) reg=use_int0() #define use_longlong(reg) if (reg==USE_CREG) reg=use_int0() static int use_int0() { if (!creg) creg = get_register(); return creg; } static void set_ireg(int reg,int mode); #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 int max_func_args; static int my_func_args; static void jcond(int l, int cond); #define ARG_LVAR_OFFSET 0x10000000 #define round16(i) align(i,16) #define round4(i) align(i,4) /* 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 = -(-32 - 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; } #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("0(%s)\n",register_name(large_lvar)); free_register(large_lvar); return; } if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("%d($sp)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); } else { printf("%d($sp)\n",CODE_LVAR(l)); } } else if (l<0) { /* local variable */ printf(".LC%d+%d($sp)\n",lvar_offset_label,FUNC_LVAR(l)); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("%d($sp)%s\n",CALLER_ARG(l-ARG_LVAR_OFFSET),cext); } else { /* callee's arguments */ printf("%d($sp)%s\n",CALLEE_ARG(l),cext); } } static void lvar_address(int l,int creg) { //int label,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 */ trn = register_name(tmp = get_register()); printf("\tlqd\t%s, 64($sp)\n",trn); printf("\ta\t%s, $sp, %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_pointer = SIZE_OF_INT; size_of_vector = SIZE_OF_VECTOR; size_of_short = SIZE_OF_SHORT; size_of_float = SIZE_OF_FLOAT; size_of_double = SIZE_OF_DOUBLE; size_of_longlong = SIZE_OF_LONGLONG; size_of_vector = SIZE_OF_VECTOR; endian = ENDIAN; struct_align = size_of_int; init_src = init_src0; } extern void emit_reinit() { /* called for each file */ // SPU では ptr cache は使わない方が良い? init_ptr_cache(); output_mode = -1; } void gexpr_code_init(void){ } void code_gexpr(int e){ } void code_arg_register(NMTBL *fnptr, int in) { int args = fnptr->dsp; NMTBL *n; int reg_var = 0; int freg_var = 0; int type; int reg; int i; int is_code0 = is_code(fnptr); int dots; if (in) return; function_type(fnptr->ty,&dots); while (args) { /* process in reverse order */ n = ncadddr(args); type = n->ty; if (scalar(type)) { if ((reg = get_input_register_var(reg_var,n,is_code0))) { n->sc = REGISTER; n->dsp = cadr(reg); regs[n->dsp]= INPUT_REG; reg_var++; caddr(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++; caddr(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++; caddr(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; caddr(args)=size(type); } } else if (type==LONGLONG||type==ULONGLONG) { if ((reg = get_input_lregister_var(reg_var,n,is_code0))) { n->sc = LREGISTER; n->dsp = cadr(reg); regs[i=n->dsp]= INPUT_REG; regs[i]= INPUT_REG; //regs[(i)]= INPUT_REG; reg_var+=2; caddr(args)=size(type); } } args = cadr(args); } if (is_function(fnptr)) code_save_input_registers(dots); } int get_register(void) { /* 使われていないレジスタを調べる */ int i,j,reg; for(i=MAX_TMP_REG;i>=MIN_TMP_REG;i--) { if (regs[i]) continue; /* 使われている */ regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ return i; /* その場所を表す番号を返す */ } 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; } } for(i=0;i<REG_VAR_MAX-REG_VAR_MIN;i++) { reg =REG_VAR_BASE+i; } /* あいている場所がないなら、エラー(いったい誰が使ってるの?) */ error(RGERR); return creg; } int pop_register(void) { /* レジスタから値を取り出す */ return reg_stack[--reg_sp]; } #if FLOAT_CODE int get_dregister(int d) { /* 使われていないレジスタを調べる */ return get_register(); } 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) { /* いらなくなったレジスタを解放 */ regs[i]=0; } extern void use_ptr_cache(int r) { regs[r]=PTRC_REG; } int get_input_dregister_var(int i,NMTBL *n,int is_code,int d) { 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 list3n(FREGISTER,i,n); } if (d) { j = get_input_lregister_var(i,n,is_code); return j; } else { if (i==0) return list3n(REGISTER,1,n); else if (i==1) return list3n(REGISTER,2,n); else if (i==2) return list3n(REGISTER,3,n); else if (i==3) return list3n(REGISTER,4,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+MIN_TMP_REG; } return list3n(REGISTER,i,n); } int free_register_count(int d) { int i,count,fcount; fcount = count = 0; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) count++; } for(i=0;i<MAX_REGISTER;i++) { if (! regs[i+FREG_OFFSET]) fcount++; } printf("## free reg %d freg %d\n",count,fcount); return d?fcount:count; } void free_all_register(void) { int i; for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; } creg = get_register(); set_ireg(CREG_REGISTER,0); return; } extern int code_register_overlap(int s,int t) { switch(car(s)) { case REGISTER: case FREGISTER: case DREGISTER: case LREGISTER: switch(car(t)) { case REGISTER: case FREGISTER: case DREGISTER: case LREGISTER: return cadr(s)==cadr(t); } } 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 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]); } } #endif printf("\n"); } void gexpr_init(void) { 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 list3n(REGISTER,j,n); } } return list3n(LVAR,new_lvar(SIZE_OF_INT),n); } #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 list3n(FREGISTER,j,n); } } return list3n(LVAR,new_lvar(SIZE_OF_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 するかわりにレジスタを使う */ creg = new_reg; if (!regs[creg]) regs[creg]=USING_REG; return old; } int emit_pop(int type) { int xreg,reg; xreg=pop_register(); // REG_LVAR_OFFSET = 2 if (xreg<= -REG_LVAR_OFFSET) { reg = get_register(); code_rlvar(REG_LVAR_OFFSET+xreg,reg); free_lvar(REG_LVAR_OFFSET+xreg); //free_lvar(-4); xreg = reg; } return xreg; } static int const_list; static int const_list_label; static int prev_const_list; static int prev_const_list_label; extern void code_ptr_cache_def(int r, NMTBL *nptr) { } static int is_stage1_const(int c,int mode) { return mode?(0<=c && c<262143): (-32768<=c && c<32767); } extern void code_const(int e2,int reg) { char *crn; int r; //code_const0(e2,reg,""); // printf("code_const\n"); /************************************************************ * ここでp1の値によって、命令が異なる...... * * il命令は-32768~32767 * * ila命令は262143まで * * それ以上はilhuとiohlを混合して使う。 * * example:15728639 * * 15728639/16^4 = 239 ilhu $4,239 * * 15728639%16^4 = 65535 iohl $4,65535 * *負の場合も異なる * * example : -99999 fffe7961 * * r = ~(-99999) r = (r >> 16) & 0xffff; r += 1; r=-r;* * ilhu $4,-2 * * -99999 & 0xfff iohl $4,31073 -> 0x7961 * * example : -15728639 ff100001 * ***********************************************************/ use_int(reg); crn = register_name(reg); if (-32768<e2&&e2<32768) printf("\til %s,%d\n",crn,e2); else if(32767<e2&&e2<262144) printf("\tila %s,%d\n",crn,e2); else if(262143<e2) { printf("\t ilhu\t%s,%d\n",crn,e2/65536); printf("\t iohl %s,%d\n",crn,e2%65536); } else { r = (~e2 >> 16) & 0xffff; r += 1; r = -r; printf("\tilhu\t%s,%d\n",crn,r); if((e2&0xffff) > -262143) printf("\tiohl %s,%d\n",crn, (e2&0xffff)); else printf("\tori %s,%s,%d\n",crn,crn,(e2&0xffff)); } } static void code_add(int reg,int offset,int r) { char *crn = register_name(reg); char *rrn = register_name(r); // char *rn2 = register_name(r+1); char *drn; int dreg; if (offset==0) { if(r!=reg) printf("\tori\t%s, %s, 0\n",crn,rrn); } else if (-32768<offset&&offset<32768) printf("\tai\t%s, %s, %d\n",crn,rrn,offset); } else { drn = register_name(dreg = get_register()); code_const(offset, dreg); 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 *crn = register_name(reg); char *rrn = register_name(r); if (-1024<offset&&offset<1024) { printf("\t%s\t%s, %d(%s)\n",ld,crn,offset,rrn); } else { code_add(reg,offset,r); printf("\t%s\t%s, 0(%s)\n",ld,crn,crn); } } /* store lqd $2,176($sp) cbd $3,0($sp) shufb $2,$4,$2,$3 stqd $2,176($sp) unsigned load rotqbyi $2,$2,13 andi $4,$2,0x00ff */ void code_label(int labelno) { printf(".LC%d:\n",labelno); } void code_gvar(int e1,int reg) { use_int(reg); printf("\tila\t%s,%s",register_name(reg),ncaddr(e1)->nm); } void code_rgvar(int e1,int reg) { code_crvar(e1,reg,0,SIZE_OF_INT); } void code_crgvar(int e1,int reg,int sign,int sz){ use_int(reg); printf("\tlqr\t%s,%s",register_name(reg),ncaddr(e1)->nm); cext(sz, sign, reg, reg); } void code_register(int e2,int reg) { use_int(reg); 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)); lvar(e2,""); } extern void code_i2c(int reg) { } extern void code_i2s(int reg) { } extern void code_u2uc(int reg) { use_int(reg); printf("\tandbi\t%s, %s, 255\n",register_name(reg),register_name(reg)); } extern void code_u2us(int reg) { // &! ということらしい、だけど16711680とかは使えない。よってilhuとかで16711680をレジスタに格納して // and rt,rs,ra でandを行えば良いが、!はどうすんだ? use_int(reg); //printf("bic\t%s, %s, #16711680\n",register_name(reg),register_name(reg)); printf("\tilhu\t%s,255\n", register_name(reg+1)); printf("\tand\t%s,%s,%s\n",register_name(reg),register_name(reg),register_name(reg+1)); //printf("bic\t%s, %s, #-16777216\n",register_name(reg),register_name(reg)); printf("\tilhu\t%s,-256\n", register_name(reg+1)); printf("\tand\t%s,%s,%s\n",register_name(reg),register_name(reg),register_name(reg+1)); } static void cext(int sz, int sign, int from, int to) { if (sz==1 && !sign) { // unsigned char printf(" rotqbyi %s,%s,13\n",fn,fn); printf(" andi %s,%s,0x00ff\n",tn,fn); } else if (sz==1 && sign) { // signed char printf(" rotqbyi %s,%s,13\n",fn,fn); printf(" xsbh %s,%s\n",fn,fn); printf(" xshw %s,%s\n",tn,fn); } else if (sz==2 && !sign) { // unsigned short int t = get_register(); char *tmp = register_name(t); printf(" rotqbyi %s,%s,14\n",fn,fn); printf(" ori %s,%s,0\n",tmp,fn); printf(" ila %s,65535\n",fn,fn); printf(" and %s,%s,%s\n",tn,tmp,fn); free_register(t); } else if (sz==2 && !sign) { // singed short printf(" rotqbyi %s,%s,14\n",fn,fn); printf(" xshw %s,%s\n",tn,fn); } } static void shuffle_offset(int sz, int offset, int base, int to) { int tmp = get_register(); char *bn = register_name(base); char *tn = register_name(tmp); if (sz==1) { printf(" cbd %s %d(%s)\n",tn,offset, bn); printf(" shufb %s,%s,%s,%s\n",tn,fn,tn); } else if (sz==1 && sign) { // signed char printf(" rotqbyi %s,%s,13\n",fn,fn); printf(" xsbh %s,%s\n",fn,fn); printf(" xshw %s,%s\n",tn,fn); } else if (sz==2 && !sign) { // unsigned short int t = get_register(); char *tmp = register_name(t); printf(" rotqbyi %s,%s,14\n",fn,fn); printf(" ori %s,%s,0\n",tmp,fn); printf(" ila %s,65535\n",fn,fn); printf(" and %s,%s,%s\n",tn,tmp,fn); free_register(t); } else if (sz==2 && !sign) { // singed short printf(" rotqbyi %s,%s,14\n",fn,fn); printf(" xshw %s,%s\n",tn,fn); } free_register(tmp); } void code_crlvar(int e2,int reg,int sign,int sz) { use_int(reg); int tmp = 0; if (size<4) tmp = get_register(); lvar_intro(e2); printf("\tlqd\t%s,",register_name(size<4?tmp:reg)); lvar(e2); cext(sign,sz,reg,tmp); if (tmp) free_register(tmp); } void code_fname(NMTBL *n,int reg) { use_int(reg); printf("\tila\t%s, %s\n",register_name(reg),n->nm); return; } void code_label_value(int label,int reg) { use_int(reg); printf("\tila\t%s,.LC%d\n",register_name(reg),label); return; } void code_neg(int creg) { use_int(creg); printf("\tsfi\t%s, %s, 0\n", register_name(creg), register_name(creg)); } void code_not(int creg) { use_int(creg); printf("\tnor\t%s, %s, %s\n", register_name(creg), register_name(creg), register_name(creg)); } void code_lnot(int creg) { use_int(creg); printf("\tceqi\t%s,%s,0\n",register_name(creg),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); } code_ld(cload(sz,sign),reg,0,xreg); code_add(reg,dir,reg); code_ld(cstore(sz),drn,0,xreg); } 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); } code_ld(cload(sz,sign),reg,0,xreg); code_add(nreg,dir,reg); code_ldf(cstore(sz),nrn,0,xreg); free_register(nreg); } void code_return(int creg) { char *crn; use_int(creg); crn = register_name(creg); } void code_environment(int creg) { /* save frame pointer */ if (is_code(fnptr)) { use_int(creg); printf("\tori\t%s, $sp, 0\n",register_name(creg),trn); } else { //int disp,label; use_int(creg); printf("\tori\t%s, $sp, 0\n",register_name(creg),trn); } } static int rexpr_bool(int e1, int reg); void code_bool(int e1,int reg) { int e2,e3; char *xrn; if (rexpr_bool(e1, reg)) return; if (use) { use_int(reg); xrn = register_name(reg); printf("\tceqi\t%s, %s, 0\n",xrn,xrn); printf("\tnor\t%s, %s, %s\n",xrn,xrn,xrn); printf("\tsfi\t%s, %s, 0\n",xrn,xrn); } } void code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) { use_int(reg); code_ld(cload(sz,0),reg,cadr(e1),get_ptr_cache(ncaddr(e1))); cext(0,sz,r); printf("\tceqi\t%s, %s, 0\n",register_name(reg), 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,hoge2 ",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_crvar(e1,reg,0,SIZE_OF_INT); 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); lvar(e2,""); code_cmp_register(reg,label,cond); } void code_cmp_register(int e2,int label,int cond) { use_int(e2); printf("\tceqi\t%s, %s, 0\n",register_name(e2), register_name(e2)); jcond(label,cond); } void code_string(int e1,int creg) { char *s,*crn; //int lb,label; int lb; NMTBL *n = ncaddr(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,n->dsp); text_mode(2); printf("\tila\t%s, .LC%d\n",crn,lb); set_attr(n,LABEL,lb); } void emit_strings(NMTBL *n) { int l = emit_string_label(); int i; for(i = n->dsp; i; i = cadr(i)) { ascii(scaddr(i),car(i)); } emit_label(l); } void code_strings(int e2,int reg) { int l = emit_string_label(); int i; for(i = e2; i; i = cadr(i)) { ascii(scaddr(i),car(i)); } text_mode(2); code_label_value(l,reg); } #define MAX_COPY_LEN 20 void emit_copy(int from,int to,int length,int offset,int value,int det) { char *frn; char *trn; char *drn; char *memmove = "memmove"; int 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("\tlqd\t%s, %d(%s)\n",drn,(offset*4),trn); printf("\tstqd\t%s,%d(%s)\n",drn,(offset*4),trn); break; case 4: case -4: printf("\tlqd\t%s, %d(%s)\n",drn,(offset*4),trn); printf("\tstqd\t%s,%d(%s)\n",drn,(offset*4),trn); break; default: if (length <0) { if (length > -MAX_COPY_LEN) { for(;length<=-4;length+=4,offset-=4) emit_copy(from,to,-4,offset-4,0,det); for(;length<=-2;length+=2,offset-=2) emit_copy(from,to,-2,offset-2,0,det); if(length<0) emit_copy(from,to,length,offset-1,0,det); break; } } else if (length <=MAX_COPY_LEN) { for(;length>=4;length-=4,offset+=4) emit_copy(from,to,4,offset,0,det); for(;length>=2;length-=2,offset+=2) emit_copy(from,to,2,offset,0,det); if(length>0) emit_copy(from,to,length,offset,0,det); break; } clear_ptr_cache(); code_save_stacks(); 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; } } // 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 = (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, %d(%s)\n",srn,count+on_register*SIZE_OF_INT,crn); printf("\tstqd\t%s, %d(%s)\n",srn,count,drn); } 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, %d(%s)\n", cload(0,0), register_name(arg_reg), count,crn); use_input_reg(arg_reg,1); } return length/SIZE_OF_INT; } static void set_ireg(int reg,int mode) { if (reg!=creg) { clear_ptr_cache_reg(reg); if (creg && reg!=creg ) { if (mode) { printf("\tori\t%s, %s, 0\n", register_name(reg),register_name(creg)); } } free_register(creg); regs[reg]=USING_REG; } creg = reg; } void use_reg(int arg) { if (arg<0||arg> REGS_MAX) error(-1); 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 = ncadddr(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(list3n(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( list3n(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 (creg&® == creg) { creg = 0; } if (mode) use_reg(reg); } static int compute_complex_arg(int e3,int reg_arg_list,int arg) { int t=caddr(e3); int e4 = car(e3); reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER||car(arg)==DREGISTER|| car(arg)==FREGISTER||car(arg)==LREGISTER) use_input_reg(cadr(arg),1); g_expr_u(assign_expr0(arg,e4,t,t)); car(e3) = arg; return reg_arg_list; } static void increment_function_arg(int e3,int *pnargs,int *preg_arg,int *pfreg_arg) { int nargs=0,reg_arg=0; nargs ++ ; reg_arg++; *pnargs += nargs; *preg_arg += reg_arg; } #define AS_SAVE 1 #define AS_ARG 0 static int get_input_arg(int t,int mode,int nargs,int reg_arg,int freg_arg) { if(scalar(t)) { if (mode==AS_SAVE) { return get_register_var(0); } else if (reg_arg+1>MAX_INPUT_REGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_register_var(reg_arg,0,0); } else if (t==LONGLONG||t==ULONGLONG) { if (mode==AS_SAVE) { return get_lregister_var(0); } else if (reg_arg>=MAX_INPUT_REGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_lregister_var(reg_arg,0,0); } else if (t==FLOAT) { if (mode==AS_SAVE) { return get_dregister_var(0,0); } else if (reg_arg>=MAX_INPUT_REGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_dregister_var(freg_arg,0,0,0); } else if (t==DOUBLE) { if (mode==AS_SAVE) { return get_dregister_var(0,1); } else if (reg_arg>=MAX_INPUT_DREGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_dregister_var(reg_arg,0,0,1); } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { // 16byte もあるんだから、ほとんどの構造体は、レジスタに // 乗ってしまうらしい。なので、レジスタに乗っている前提の // コードを書いた方が良いらしい... // でも、strop を書き直さないと出来ない if (mode==AS_SAVE) { return get_register_var(0); } else return list3n(LVAR,caller_arg_offset_v(nargs),0); } else { error(-1); return get_register_var(0); } } static void code_call(int e2,NMTBL *fn,int jmp) { if (car(e2) == FNAME) { printf("\tbrsl\t$lr,%s\n",fn->nm); } else { //printf("\tmov\tlr, pc\n"); printf("\tori\t$sp,%s,0\n",register_name(cadr(jmp))); printf("\tori\t$sp, %s,0\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=ncaddr(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 (!simple_arg(cadr(e4))) { // Calculate complex struct address here. // If simple, leave it. arg = get_register_var(0); g_expr_u(assign_expr0(arg,e4,INT,INT)); car(e3)=arg; reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER) use_input_reg(cadr(arg),1); else car(e3) = rvalue_t(arg,INT); } } stargs = list4(e3,stargs,nargs,reg_arg); } increment_function_arg(e3,&nargs,®_arg,&freg_arg); } /* now all input register vars are free */ code_save_stacks(); set_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), list3n(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)==REGISTER) { use_input_reg(cadr(arg),1); } 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 */ } else { g_expr_u(assign_expr0(arg,e4,t,t)); /* XXX */ } } // structs are finished } if (max_func_args<nargs) max_func_args=nargs; for(;arg_assign;arg_assign=cadr(arg_assign)) { g_expr_u(car(arg_assign)); } clear_ptr_cache(); code_call(e2,fn,jmp); free_register_var(reg_arg_list); for(i=1;i<MAX_INPUT_REGISTER_VAR;i++) { free_register(i); } if (ret_type!=VOID) { set_ireg(RET_REGISTER,0); use_reg(RET_REGISTER); } else { } 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("\tsfi\t$sp, %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, $sp\n",crn); } void code_frame_pointer(int e3) { use_int(e3); printf("\tori\t$sp,%s\n",register_name(e3)); } int code_frame_pointer_register() { return list2(REGISTER,REG_fp); } void code_fix_frame_pointer(int env) { char *trn; if (is_function(fnptr) && ! env) { trn = register_name(REG_ip); printf("\ta\t$sp, $sp, %s\n",trn); } } static void code_unfix_frame_pointer() { char *trn; trn = register_name(REG_ip); printf("\tori\t$sp, $sp, %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)); // ?! printf("\tbi\t%s\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(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_ld("lqd",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); printf("\tlqd\t%s, %d(%s)\n",register_name(reg),offset,crn); } static void lmove(int to,int from) { printf("\tori\t%s, %s, 0\n", register_name(to),register_name(from)); } static void set_operands(int r0,int r1,int r2,int r3) { } static void lstore(int e2,int creg) { char *drn = register_name(e2); printf("\tstqd\t%s, 0(%s)\n",register_name(creg),drn); } 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) { return "stqd"; } void code_assign_gvar(int e2,int creg,int byte) { use_int(creg); printf("\tstqr\t%s,%s\n",regsister_name(creg),ncaddr(e2)->nm); } 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("\tceqp\t%s, %s\n",crn,orn); break; case BAND: printf("\tand\t%s, %s, %s\n",crn,crn,orn); break; case EOR: printf("\txor\t%s, %s, %s\n",crn,crn,orn); break; case BOR: printf("\tor\t%s, %s, %s\n",crn,crn,orn); break; case MUL: case UMUL: /* target!=source */ printf("\tmpy\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("\troti\t%s, %s,-%d\n",crn,crn,v); break; case DIV: v=ilog(v); case RSHIFT: printf("\troti\t%s, %s, -%d\n",crn,crn,v); break; case UDIV: v=ilog(v); case URSHIFT: printf("\tshli\t%s, %s,%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("\tceq\t%s,%d\n",crn,v); break; case BOR: printf("\tori\t%s, %s, %d\n",crn,crn,v); break; case EOR: printf("\txori\t%s, %s, %d\n",crn,crn,v); break; case BAND: printf("\tandi\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); if(crn == "asr") printf("\tshl\t%s, %s,%s\n",crn,crn,rrn); //算術右シフト if(crn == "asl") printf("\trotma\t%s, %s, -%s\n",crn,crn,rrn); //算術左シフト if(crn == "lsr") printf("\trot\t%s, %s, %s\n",crn,crn,rrn); //左シフト //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("\tceq\t%s, %s, %s\n",crn,crn,rn); } else { if (sign>0) printf("\tceqi\t%s, %s, %d\n",crn,crn,e); else //printf("\tcmn\t%s, #%d\n",crn,-e); printf("\tceqi\t%s, %s, %d\n",crn,crn,-e); } switch(cond) { case -1: break; case 1: printf("\tbr\t.LC%d\n",label); break; case 0: printf("\tbr\t.LC%d\n",label); break; case LT: printf("\tbra\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("\tceqi\t%s, %s, %d\n",rn1,rn1,r2); else printf("\tceqi\t%s, %s, -%d\n",rn1,rn1,-r2); } else { rn1 = register_name(r1); rn2 = register_name(r2); printf("\tceq\t%s, %s, %s\n",rn1,rn1,rn2); } switch(op+(!cond)*BNOT) { case GT: case LE+BNOT: cc="r"; ncc="r"; break; case LE: case GT+BNOT: cc="r"; ncc="r"; break; case GE: case LT+BNOT: cc="r"; ncc="r"; break; case LT: case GE+BNOT: cc="r"; ncc="r"; break; case UGT: case ULE+BNOT: cc="r"; ncc="r"; break; case ULE: case UGT+BNOT: cc="r"; ncc="r"; break; case UGE: case ULT+BNOT: cc="r"; ncc="r"; break; case ULT: case UGE+BNOT: cc="r"; ncc="r"; break; case EQ: case NEQ+BNOT: cc="r"; ncc="r"; break; //case NEQ: case EQ+BNOT: cc="rnz"; ncc="r"; break; case NEQ: case EQ+BNOT: cc="r"; ncc="r"; break; default: error(-1); } if (mode==COND_BRANCH||mode==COND_BRANCH_CONST) { printf("\tb%s\t.LC%d\n",cc,l1); //printf("\tb%s\t%s, .LC%d\n",cc,rn1,l1); } else if (mode==COND_VALUE||mode==COND_VALUE_CONST) { rn0 = register_name(r0); // ここはnccで分岐させなきゃダメだな printf("#####pcond##########\n"); //printf("\tmovhoge%s\t%s, #0\n",ncc,rn0); //printf("\tmovfuho%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 = creg; 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 = creg; 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)),creg,0,cond,l1,COND_BRANCH_CONST); } else { g_expr(cadr(e1)); emit_push(); g_expr(caddr(e1)); e2 = emit_pop(1); pcond(op, creg,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?"r":"r",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_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("\tlqd\t$sp,%d($sp)\n",i); } for (i=reg_var_num(0);i<reg_var_num(reg_save);i++) { printf("\tlqd\t%s,-%d($sp)\n",register_name(i),-disp); disp -= SIZE_OF_FLOAT*4; } 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\t$sp, $sp, $fp\n"); clear_ptr_cache(); } void code_enter1(int args) { set_ireg(CREG_REGISTER,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\t$sp, $lr,0\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_ireg(CREG_REGISTER,0); } void code_label_call(int l) { printf("\tbr\tL_%d\n",l); } void code_ret() { //printf("\tmov\tpc, lr\n"); control=0; } static void make_return_continuation() { fwddef(retcont); if (cadr(fnptr->ty)==FLOAT) { #if FLOAT_CODE creg = cadr(get_input_dregister_var(0,0,1,0)); set_ireg(RET_REGISTER,1); #endif printf("\t%s\t%s, %s, 0\n",movef(0), register_name(REG_fp),register_name( cadr(get_input_register_var(1,0,1,0))); } else if (cadr(fnptr->ty)==DOUBLE) { #if FLOAT_CODE creg = cadr(get_input_dregister_var(0,0,1,1)); set_ireg(RET_REGISTER,1); printf("\t%s\t%s, %s, 0\n",movef(0), register_name(REG_fp),register_name( cadr(get_input_register_var(1,0,1,0))); #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\t$1, $2, $sp\n"); printf("\tlqd\t$1, %d($sp)\n",(my_func_args-1)*SIZE_OF_INT); // emit_copy(6,3,sz,0,1,1); printf("\t%s\t%s, %s, 0\n",movef(0), register_name(REG_fp),register_name( cadr(get_input_register_var(1,0,1,0))); } else if (cadr(fnptr->ty)!=VOID) { creg = cadr(get_input_register_var(0,0,1)); if (creg!=RET_REGISTER) set_ireg(RET_REGISTER,1); printf("\t%s\t%s, %s, 0\n",movef(0), register_name(REG_fp),register_name( cadr(get_input_register_var(1,0,1,0))); } code_unfix_frame_pointer(); } void leave(int control0, char *name) { if (control0) { code_set_return_register(1); } else text_mode(2); if (retcont) { /* return from CbC segement */ if (control0) gen_jmp(retlabel); make_return_continuation(); } 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\t$sp, $sp, %d\n",arg_on_register); // code_register_save(max_reg_var,max_reg_var,0); 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(); } int code_set_return_register(int mode) { set_ireg(RET_REGISTER,mode); return creg; } int code_get_fixed_creg(int reg,int type) { if (reg==USE_CREG) { if (regs[CREG_REGISTER]==0||regs[CREG_REGISTER]==PTRC_REG) { set_ireg(CREG_REGISTER,regs[creg]==USING_REG); return CREG_REGISTER; } } use_int(reg); return reg; } void code_set_fixed_creg(int reg,int mode,int type) { set_ireg(reg,mode); } void gen_gdecl(char *n, int gpc) { } void code_align(int t) { int d; switch(t) { case CHAR: case UCHAR: return; case SHORT: case USHORT: d = data_alignment & 1; break; default: d = data_alignment & 3; } if (d) { printf("\t.align 2\n"); data_alignment = 0; } } extern void ascii(char *s,int len) { if (s[len-1]==0) printf("\t.string \""); else printf("\t.ascii \""); while(len-->0) { if (*s=='\n') printf("%cn",92); else if (*s<' ') printf("%c%03o",92,*s); else if (*s=='\\') printf("\\\\"); else if (*s==34) printf("%c%c",92,34); else printf("%c",*s); s++; } printf("%c\n",34); } 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,int len) { t = type_value(t); if (car(t)==ARRAY && (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { ascii(s,len); } else { int l = emit_string_label(); ascii(s,len); emit_label(l); } return; } void emit_global(NMTBL *n,int a,int e) { int t = type_value(n->ty); if (e>0 && car(e)==STRING && t>0 && car(t)==ARRAY && (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { cstring_mode(); } else data_mode(n->nm); code_align(a); if (n && n->sc!=STATIC) printf("\t.globl\t%s\n",n->nm); printf("%s:\n",n->nm); } 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); code_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 .LC%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,.LC%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("\tbr\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("\tbr\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?"ori":"ori"; } static char * fload(int d) { return d?"lqd":"lqd"; } static char * fstore(int d) { return d?"stqd":"stqd"; } 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, 0\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(ncaddr(e2)),""); } 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,""); } void code_dassign(int e2,int freg,int d) { use_float(d,freg); //printf("\t%s\t%s, [%s, #0] @ float\n",fstore(d), printf("\t%s\t%s, 0(%s)\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, 0\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; } void code_dconst(int e2,int freg,int d) { double value = dcadr(e2); 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, %s, %d\n",movef(d),frn,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("\tlqd\t%s, .LC%d+%d($sp)\n",frn,label,disp); } else { } } 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\t%s, %s\n", register_name(lreg),register_name(reg)); set_ireg(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("\tori\t%s, %s, 0\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(creg); set_ireg(reg0=get_register(),0); crn = register_name(reg0); printf("\tcmfe\t%s, %s\n",lrn,frn); printf("\tbr\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 freg1; char *crn,*frn,*lrn; use_int(reg); crn = register_name(reg); set_ireg(reg=get_dregister(1),0); frn = register_name(reg); printf("\tfltd\t%s, %s\n",frn,crn); printf("\tceqi\t%s, %s, 0\n",crn,crn); printf("\tbr\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(creg); printf("\tmvfs\t%s,%s\n",frn,frn); return; } void code_f2d(int reg) { char *frn; frn = register_name(creg); printf("\tori\t%s, %s, 0\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(ncaddr(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); } 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(creg); use_float(d,reg); frn =register_name(reg); code_ldf(fload(d),register_name(creg),0,creg,""); dtosop(op,reg,xreg); code_ldf(fstore(d),register_name(creg),0,creg,""); 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\t%s,#1\n",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); set_ireg(reg,0); } frn=register_name(reg); printf("\t%s\t%s, %s, %s\n", dir>0?"adf":"suf", crn,crn,grn); if (use && reg!=cadr(e2)) { printf("\tmvf\t%s, %s\n",frn,crn); } } else { g_expr(e2); if (!is_int_reg(creg)) error(-1); reg0 = creg; if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); set_ireg(reg,0); } grn = register_name(g = code_dload_1(d)); frn=register_name(reg); code_ldf(fload(d),frn,0,reg0,""); printf("\t%s\t%s, %s, %s\n", dir>0?"adf":"suf", 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_ireg(reg,0); } frn=register_name(reg); if (use && reg!=cadr(e2)) { printf("\tmvf\t%s, %s\n",frn,crn); } printf("\t%s\t%s,%s,%s\n",dir>0?"adf":"suf", crn,crn,grn); } else { g_expr(e2); if (!is_int_reg(creg)) error(-1); crn=register_name(reg0=creg); if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); set_ireg(reg,0); } frn=register_name(reg); grn = register_name(g = code_dload_1(d)); code_ldf(fload(d),frn,0,reg0,""); printf("\t%s\t%s, %s, %s\n", dir>0?"adf":"suf", 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 = "br"; break; case FOP+GE: op1=FOP+CMPGE; opn = "br"; break; case FOP+EQ: op1=FOP+CMP; opn = "br"; break; case FOP+NEQ: op1=FOP+CMP; opn = "br"; break; case DOP+GT: op1=DOP+CMP; opn = "br"; break; case DOP+GE: op1=DOP+CMPGE; opn = "br"; break; case DOP+EQ: op1=DOP+CMP; opn = "br"; break; case DOP+NEQ: op1=DOP+CMP; opn = "br"; 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++] = creg; /* push ???????????????? */ creg = new_reg; } #endif #if LONGLONG_CODE /* 64bit int part */ int lrexpr(int e1, int e2,int l1, int op,int cond) { int reg,regh,regl,e3h,e3l; int e3,l2; g_expr(e1); emit_lpush(); g_expr(e2); e3 = emit_lpop(); reg = creg; 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); 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(ncaddr(e2)); code_ldf(cstore(0),register_name(creg),cadr(e2),r,""); } void code_lassign_lvar(int e2,int creg) { char *crn; use_longlong(creg); crn = register_name(creg); lvar_intro(e2); printf("\tstqd\t%s, ",crn);lvar(e2,""); } 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 ???????????????? */ creg = new_reg; } void code_lrgvar(int e1,int creg) { int r; char *crn; use_longlong(creg); crn = register_name(creg); r = get_ptr_cache(ncaddr(e1)); code_ldf("lqd",crn,cadr(e1),r,""); } void code_lrlvar(int e1,int creg) { char *crn; use_longlong(creg); crn = register_name(creg); lvar_intro(e1); printf("\tlqd\t%s, ",crn); lvar(e1,""); } #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); code_const(code_l2(lcadr(e1)),(creg)); } void code_lneg(int creg) { char *rh; use_longlong(creg); rh=register_name(creg); 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); } #define check_lreg(reg) lmove(reg,RET_REGISTER) void ltosop(int op,int reg,int oreg) { int dx = -1; int ox = -1; char *orn, *crn; // 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 = register_name(oreg); crn = register_name(reg); switch(op) { case LADD: printf("\tadds\t%s, %s, %s\n",crn,crn,orn); break; case LSUB: printf("\tsubs\t%s, %s, %s\n",crn,crn,orn); break; case LCMP: error(-1); break; case LBAND: printf("\tand\t%s, %s, %s\n",crn,crn,orn); break; case LEOR: printf("\teor\t%s, %s, %s\n",crn,crn,orn); break; case LBOR: printf("\tor\t%s, %s, %s\n",crn,crn,orn); 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; char *grn; int v=0; int vh=0; int greg,dx=-1; use_longlong(creg); crn = register_name(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("\troti\t%s,%s,%d\n",crn,crn,96-v); code_const(0,(creg)); return; } greg = get_register(); grn = register_name(greg); printf("\tshli\t%s, %s, %d\n",crn,crn,v); printf("\troti\t%s, %s, -%d\n",grn,crn,32-v); printf("\torc\t%s, %s,%s\n",crn,crn,grn); printf("\tshli\t%s, %s,%d\n",crn,crn,v); free_register(greg); return; case LDIV: v=ilog(v); case LRSHIFT: if (v==0) return; if (v==32) { code_register((creg),(creg)); printf("\tshli\t%s, %s, 31\n",crn,crn); return; } else if (v>31) { printf("\t\t%s, %s, asr #%d\n",crn,crn,v-32); printf("\tshl\t%s, %s, 31\n",crn,crn); return; } greg = get_register(); grn = register_name(greg); printf("\troti \t%s, %s, %d\n",crn,crn,v); printf("\troti\t%s, %s, %d\n",grn,crn,160-v); printf("\tor\t%s, %s,%s\n",crn,crn,grn); printf("\tshli\t%s, %s, %d\n",crn,crn,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,crn,v-32); code_const(0,(creg)); return; } greg = get_register(); grn = register_name(greg); printf("\troti\t%s, %s, %d\n",grn,crn,96-v); printf("\troti\t%s, %s, %d\n",crn,crn,v); printf("\tor\t%s, %s,%s\n",crn,grn,crn); printf("\troti\t%s, %s, %d\n",crn,crn,v); free_register(greg); return; case LADD: printf("\tadds\t%s, %s, #%d\n",crn,crn,v); printf("\tadc\t%s, %s, #%d\n",crn,crn,vh); break; case LSUB: printf("\tsubs\t%s, %s, #%d\n",crn,crn,v); printf("\tsbc\t%s, %s, #%d\n",crn,crn,vh); break; case LBAND: printf("\tandi\t%s, %s, %d\n",crn,crn,v); printf("\tandi\t%s, %s, %d\n",crn,crn,vh); break; case LEOR: printf("\teor\t%s, %s, #%d\n",crn,crn,v); printf("\teor\t%s, %s, #%d\n",crn,crn,vh); break; case LBOR: printf("\tori\t%s, %s, %d\n",crn,crn,v); printf("\tori\t%s, %s, %d\n",crn,crn,vh); break; default: error(-1); } if (dx!=-1) free_register(dx); } void code_i2ll(int reg) { char *crn; int reg0; crn = register_name(reg0 = creg); use_longlong(reg); if (reg0!=(creg)) printf("\tori\t%s, %s, 0\n",crn,crn); printf("\tshli\t%s, %s, 31\n",crn,crn); } void code_i2ull(int reg) { code_i2ll(reg); } void code_u2ll(int reg) { char *crn; int reg0; crn = register_name(reg0 = creg); use_longlong(reg); if (reg0!=(creg)) printf("\tori\t%s, %s, 0\n",crn,crn); printf("\tmov\t%s, #0\n",crn); } void code_u2ull(int creg) { code_u2ll(creg); } void code_ll2i(int reg) { char *crn; int reg0; crn = register_name(reg0=creg); use_int(reg); if (creg!=(reg0)) { printf("\tori\t%s, %s, 0\n",register_name(creg),crn); } } 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 extern_conv("__fixdfdi"); set_ireg(RET_REGISTER,0); if (reg!=USE_CREG&®!=RET_REGISTER) { use_longlong(reg); } } void code_d2ull(int reg) { extern_conv("__fixunsdfdi"); set_ireg(RET_REGISTER,0); if (reg!=USE_CREG&®!=RET_REGISTER) { use_longlong(reg); } } void code_f2ll(int reg) { extern_conv("__fixsfdi"); set_ireg(RET_REGISTER,0); if (reg!=USE_CREG&®!=RET_REGISTER) { use_longlong(reg); } } void code_f2ull(int reg) { extern_conv("__fixunssfdi"); set_ireg(RET_REGISTER,0); if (reg!=USE_CREG&®!=RET_REGISTER) { use_longlong(reg); } } void code_ll2d(int reg) { set_ireg(REGISTER_OPERAND,1); extern_conv("__floatdidf"); set_ireg(RET_REGISTER,0); if (reg!=USE_CREG&®!=RET_REGISTER) use_float(1,reg); } void code_ll2f(int reg) { set_ireg(REGISTER_OPERAND,1); extern_conv("__floatdisf"); set_ireg(RET_REGISTER,0); if (reg!=USE_CREG&®!=RET_REGISTER) 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("\taddq\t%s, %s, #%d\n", register_name(rreg),register_name(dreg), v); } else { printf("\tsubq\t%s, %s, #%d\n", register_name(rreg),register_name(dreg), -v); } } 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_ireg(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_ireg(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 = creg; emit_push(); use_longlong(reg); if ((creg)==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!=creg) 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_VECTOR)),reg,0); reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET; free_register(reg); } } } void emit_lib(char *p[]) { while(*p) { printf("%s\n",*p++); } } void code_closing() { global_table(); } #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("\tbr\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("\tbr\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("\thbr\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",ncaddr(rstr)->nm); } else if (car(rstr)==LABEL) { printf(".L%d",cadr(rstr)); } else { error(-1); } } /* prepare asm operands char *constraints string int operand expr int mode (ASM_INPUT,ASM_OUTPUT) int replacement list int output operands count int output operands replacement list retrun replacement list list3( operands, next, clobber ) 0 can be shared in input/output 1 can't be used in input */ int code_asm_operand(char *p,int e1,int mode,int repl,int n,int repl0) { int r; int c; int val; int clobber = 0; printf("## constraint %s\n",p); if (*p=='=') { // output register p++; } if (*p=='&') { // earlyclobber p++; clobber = 1; } c = *p; if (c=='r') { if (mode==ASM_INPUT) { for(;repl0;repl0 = cadr(repl0)) { if (car(car(repl0))==REGISTER && caddr(repl0)==0) { r = cadr(car(repl0)); caddr(repl0) = ASM_USED; break; } } r = get_register(); } else { r = get_register(); } repl = list3(list2(REGISTER,r),repl,clobber); } else if (c=='m') { repl = list3(list2(0,0),repl,clobber); } else if (c=='i') { if (car(e1)==GVAR) { e1=list3n(FNAME,0,ncaddr(e1)); } else if (car(e1)==FNAME) { e1=list3n(FNAME,0,ncaddr(e1)); } else if (car(e1)==STRING) { val = emit_string_label(); ascii(ncaddr(e1)->nm,ncaddr(e1)->dsp); e1=list2(LABEL,val); } 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("\tor\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("\tor\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 = register_name(value); lrn = register_name(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 = register_name(value); lrn = register_name(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 = register_name(value); code_ld(cload(0,0),(value),0,adr,cext_at(0,0)); lrn = register_name(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("\tandi\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("\tori\t%s, %s, %d\n",crn,crn,c); } else { trn = register_name(tmp=get_register()); code_const(c,tmp); printf("\tor\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 = register_name(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 = register_name(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 extern int code_arg_alignment(int args,NMTBL *n, int type0,int sz, int is_code) { if(type0==CHAR||type0==UCHAR) { if (n->dsp==0) { n->dsp = args; if (endian) n->dsp += size_of_int-1; } args += size_of_int; } else if(type0==SHORT||type0==USHORT) { if (n->dsp==0) { n->dsp = args; if (endian) n->dsp += size_of_int-size_of_short; } args += size_of_int; } else if(type0>0&&(car(type0)==UNION||car(type0)==STRUCT)) { /* alignment in struct in argument */ /* should be GCD of member alignment */ /* __attribute(alignment(16)) is ignored in argments */ n->dsp = args; args += ((sz+(size_of_int-1))&~(size_of_int-1)); } else { /* if (n->dsp==0) (argument list in ADECL is useless, type list can be found in type ) */ n->dsp = args; args += sz; } return args; } extern int code_lvar_alignment(int disp0,NMTBL *n,int type0,int sz) { int align; /* local variable alignment is done by new_lvar */ if ((align=attr_value(n,ALIGNED))) { if (car(align)!=CONST) error(-1); n->sc = LVAR; n->dsp = new_lvar_align(sz,caddr(align)); } else { n->sc = LVAR; n->dsp = new_lvar(sz); } return disp; } /* end */