Mercurial > hg > CbC > old > device
view mc-code-arm.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 Linux Zaurus and GameBoy Advance */ /* ************************************************************************ ** Copyright (C) 2006 Shinji Kono ** 連絡先: 琉球大学情報工学科 河野 真治 ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) ** ** このソースのいかなる複写,改変,修正も許諾します。ただし、 ** その際には、誰が貢献したを示すこの部分を残すこと。 ** 再配布や雑誌の付録などの問い合わせも必要ありません。 ** 営利利用も上記に反しない範囲で許可します。 ** バイナリの配布の際にはversion messageを保存することを条件とします。 ** このプログラムについては特に何の保証もしない、悪しからず。 ** ** Everyone is permitted to do anything on this program ** including copying, modifying, improving, ** as long as you don't try to pretend that you wrote it. ** i.e., the above copyright notice has to appear in all copies. ** Binary distribution requires original version messages. ** You don't have to ask before copying, redistribution or publishing. ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. ***********************************************************************/ #include <stdio.h> #include "mc.h" #include "mc-parse.h" #include "mc-code.h" #include "mc-codegen.h" #define UseFPP 1 int arch_mode = UseFPP; char *l_include_path[]={ "/Developer/Zaurus-X-gcc/opt/Embedix/tools/arm-linux/include", "/Developer/Zaurus-X-gcc/opt/Embedix/tools/arm-linux/include/linux", "/home/zaurus/develop/include", "/home/zaurus/develop/include/linux", "/home/zaurus/develop/lib/gcc-lib/armv4l-redhat-linux/2.95.1/include/", "/usr/include", 0}; // va_start, va_arg is wrong, use va_arm.h static char *init_src0 = "\ /* #define __builtin_va_list int */\n\ /* #define __builtin_va_start(ap,arg) ap=(((int)(&arg))+sizeof(arg)) */\n\ /* #define __builtin_va_arg(ap,type) (*((type *)ap)++) */\n\ #define __builtin_next_arg(arg) (__gnuc_va_list)((char *)(&arg) + __va_rounded_size (typeof(arg)))\n\ #define __arm__ 1\n\ #define __STDC__ 1\n\ #define __SIZE_TYPE__ int\n\ #define __attribute__(a)\n\ #define __flexarr\n\ #define __ARM_ARCH_4__\n\ #define __WCHAR_TYPE__ int\n\ #define __alignof__(type) (sizeof(type)==1?1:sizeof(type)==2?2:sizeof(type)<=4?4:8)\n\ #define __PTRDIFF_TYPE__ int\n\ #define __GNUC__ 2\n\ #define __const const\n\ #define alloca __builtin_alloca\n\ #define __restrict\n\ #define __flexarr\n\ #define __const const\n\ #define __THORW\n\ // #define __attribute__(a)\n\ #define __inline__ inline\n\ #define size_t int\n\ #define wchar_t int\n\ "; int data_alignment = 0; #define TEXT_EMIT_MODE 0 #define DATA_EMIT_MODE 1 #define RODATA_EMIT_MODE 2 #define DOT_SIZE 1 // static void data_mode(char *name); // static void text_mode(int alignment); static void ld_indexx(int byte, int n, int xreg,int reg,int sign); static void local_table(void); static void shift(char *op, int creg,int reg); static int push_struct(int e4,int t,int arg); static void register_usage(char *s); static void code_add(int reg,int offset,int r); static void const_list_table(); static int search_const(int tag,int value,int *label); static char * cstore(int sz); static void code_int_lib(char *lib,int reg,int oreg); static int caller_arg_offset_v(int arg); static void pcond(int op, int r2,int r1,int r0,int cond,int l1,int mode); #if FLOAT_CODE static int code_d1(double d); static int code_d2(double d); static void code_float_lib(char *opc,int oreg,int in_reg,int e1); static void code_float_lib_c(char *lib,int from,int to,double value); static void code_double_lib(char *lib,int to,int reg,int oreg); static void code_double_lib_c(char *lib,int from,int to,double value); static void dconst(int l,int h,double value); static void code_assign_input_double_long(int e1,int e2) ; static void code_assign_input_float_int(int e1,int e2) ; #endif static void use_input_reg(int reg,int mode); static void ascii(char *s, 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; static int freg,ireg,lreg; int code_lassop_p = 1; #define SIZE_OF_INT 4 #define SIZE_OF_SHORT 2 #define SIZE_OF_FLOAT 4 #define SIZE_OF_DOUBLE 8 #define SIZE_OF_LONGLONG 8 #define ENDIAN 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]; /* 実際のレジスタの領域 */ /* floating point registers */ static int freg_sp; /* floating point REGister Stack-Pointer */ static int freg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ static int lreg_sp; /* longlong REGister Stack-Pointer */ static int lreg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ #define REG_ip 13 #define REG_fp 14 #define REG_sp 15 #define REG_VAR_BASE 5 #define REG_VAR_MIN 5 #define REG_VAR_USER_MAX 9 /* at leat 6 tmp var */ #define REG_VAR_MAX 12 #define MIN_TMP_REG 1 #define MAX_TMP_REG 4 #define FREG_VAR_BASE 4 #define FREG_VAR_MIN 4 #define FREG_VAR_MAX 7 #define MIN_TMP_FREG 0 #define MAX_TMP_FREG 3 int MAX_REGISTER=17; /* ARMのレジスタを10個まで使う*/ int MAX_FREGISTER=8; #define REAL_MAX_REGISTER 17 /* ARMのレジスタが32ということ*/ #define REAL_MAX_FREGISTER 8 /* ARMのレジスタが32ということ*/ #define REAL_MAX_LREGISTER 6 #define FREG_OFFSET REAL_MAX_REGISTER #define LREG_OFFSET (REAL_MAX_REGISTER+REAL_MAX_FREGISTER) int MAX_INPUT_REGISTER_VAR = 4; int MAX_INPUT_DREGISTER_VAR = 4; int MAX_INPUT_FREGISTER_VAR = 4; int MAX_CODE_INPUT_REGISTER_VAR = 4; int MAX_CODE_INPUT_DREGISTER_VAR = 6; int MAX_CODE_INPUT_FREGISTER_VAR = 6; #define LREG_V 3 /* mark for virtual long long/double register */ #define REGS_MAX (REAL_MAX_REGISTER+REAL_MAX_FREGISTER+REAL_MAX_LREGISTER+LREG_V) static int arm_regs[REGS_MAX]; static int regv_h0[REAL_MAX_LREGISTER+LREG_V]; static int regv_l0[REAL_MAX_LREGISTER+LREG_V]; #define regv_h(i) regv_h0[(i)-LREG_OFFSET] #define regv_l(i) regv_l0[(i)-LREG_OFFSET] #define RET_REGISTER 1 #define REGISTER_OPERAND 1 #define REGISTER_OPERAND_1 2 #define RET_FREGISTER FREG_OFFSET #define FREGISTER_OPERAND (FREG_OFFSET) #define FREGISTER_OPERAND_1 (FREG_OFFSET+1) #define RET_LREGISTER (LREG_OFFSET+REAL_MAX_LREGISTER) #define LREGISTER_OPERAND (LREG_OFFSET +REAL_MAX_LREGISTER +1) #define LREGISTER_OPERAND_1 (LREG_OFFSET +REAL_MAX_LREGISTER +2) #define RET_LREGISTER_L 1 /* low word */ #define RET_LREGISTER_H 2 /* high word */ #define LREGISTER_OPERAND_L 1 /* low word */ #define LREGISTER_OPERAND_H 2 /* high word */ #define LREGISTER_OPERAND_1_L 3 /* low word */ #define LREGISTER_OPERAND_1_H 4 /* high word */ #define RET_DREGISTER RET_LREGISTER #define DREGISTER_OPERAND LREGISTER_OPERAND #define DREGISTER_OPERAND_1 LREGISTER_OPERAND_1 #define RET_DREGISTER_L RET_LREGISTER_L #define RET_DREGISTER_H RET_LREGISTER_H #define DREGISTER_OPERAND_H LREGISTER_OPERAND_H #define DREGISTER_OPERAND_L LREGISTER_OPERAND_L #define DREGISTER_OPERAND_1_L LREGISTER_OPERAND_1_L #define DREGISTER_OPERAND_1_H LREGISTER_OPERAND_1_H static int *regs = arm_regs; // #define CREG_REGISTER (MAX_TMP_REG) #define CREG_REGISTER REGISTER_OPERAND // #define FREG_FREGISTER (MAX_TMP_FREG+FREG_OFFSET) #define FREG_FREGISTER FREGISTER_OPERAND // #define LREG_LREGISTER (MAX_TMP_REG+LREG_OFFSET) #define LREG_LREGISTER LREGISTER_OPERAND #define DREG_DREGISTER LREG_LREGISTER #define CMP_C1T (-1) static int max_reg_var, max_freg_var; static char *reg_name[] = { "xx", "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "lr", "ip", "fp", "sp", "pc", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" // "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", // "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s0", "s2", "s4", "s6", "s8", "s10","s12", "s14", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", }; #define register_name(i) reg_name[i] #define fregister_name(i) reg_name[i] #define dregister_name(i) reg_name[i+8] #define lregister_name_low(i) reg_name[regv_l(i)] #define lregister_name_high(i) reg_name[regv_h(i)] char *rn(int i) { return register_name(i); } char *fn(int i) { return fregister_name(i); } char *dn(int i) { return dregister_name(i+8); } char *lln(int i) { return lregister_name_low(i); } char *lhn(int i) { return lregister_name_high(i); } int ll(int i) { return regv_l(i); } int lh(int i) { return regv_h(i); } #define is_int_reg(i) (0<=i&&i<REAL_MAX_REGISTER) #define is_float_reg(i) (arch_mode&UseFPP?(REAL_MAX_REGISTER<=i&&i<REAL_MAX_FREGISTER+REAL_MAX_REGISTER):is_int_reg(i)) #define is_longlong_reg(i) (LREG_OFFSET<=i&&i<LREG_OFFSET+REAL_MAX_LREGISTER+LREG_V) #define is_double_reg(i) (arch_mode&UseFPP?is_float_reg(i):is_longlong_reg(i)) #define use_int(reg) if (reg==USE_CREG) reg=use_int0() static int use_int0() { int i = creg; if (!i||!ireg||!is_int_reg(i)) { if (lreg) { if (regs[lreg]) free_register(lreg); lreg = 0; } if (!ireg) ireg = get_register(); // else if (ireg!=i) free_register(i); i = ireg; } if (!regs[i]) regs[i]=USING_REG; creg = i; return i; } #if LONGLONG_CODE||FLOAT_CODE #define use_longlong(reg) if (reg==USE_CREG) reg=use_longlong0() static int use_longlong0() { int i = creg; if (!is_longlong_reg(i)) { if (ireg) { free_register(ireg); ireg=0; } if (!lreg||!regs[lreg]) lreg = get_lregister(); // else if (lreg!=i) free_register(i); i = lreg; } if (!regv_l(i)) regv_l(i) = get_register(); if (!regv_h(i)) regv_h(i) = get_register(); if (!regs[i]) regs[i]=USING_REG; if (!regs[regv_l(i)]) regs[regv_l(i)]=USING_REG; if (!regs[regv_h(i)]) regs[regv_h(i)]=USING_REG; creg = i; return i; } static void lmove(int to,int from); #endif #define USING_DREG 5 #define INPUT_DREG 6 #if FLOAT_CODE #define dsuffix(d) (d?'d':'s') #define use_float(d,reg) if (reg==USE_CREG) { reg=(arch_mode&UseFPP)?use_float0():(d?use_double0():use_float0());} static int use_float0() { int i = creg; if (!is_float_reg(i)) { if (lreg) { free_register(lreg); lreg = 0; } if (!freg) freg = get_dregister(0); // else if (freg!=i) free_register(i); i = freg; } if (!regs[i]) regs[i]=USING_REG; creg = i; return i; } static int use_double0() { int i; use_longlong0(); i = lreg; if (!regs[i]) regs[i]=USING_DREG; if (!regs[regv_l(i)]) regs[regv_l(i)]=USING_REG; if (!regs[regv_h(i)]) regs[regv_h(i)]=USING_REG; creg = i; return i; } void code_lassign_lvar(int e2,int creg); int code_lrindirect(int e1, int reg, int offset, int us); void code_lregister(int e2,int reg); void code_lassign_gvar(int e2,int creg); void code_lassign(int e2,int creg); void code_lassign_lregister(int e2,int reg); void code_lrgvar(int e1,int creg); void code_lrlvar(int e1,int creg); void emit_lpop_free(int xreg); void emit_lpush(); int emit_lpop(); #endif #if LONGLONG_CODE static int code_l1(long long ll); static int code_l2(long long ll); #endif static void code_save_input_registers(int dots); static void set_ireg(int,int); #if FLOAT_CODE static void set_dreg(int,int); static void set_freg(int,int); #endif #if LONGLONG_CODE static void set_lreg(int,int); #endif static void inc_inst(int count); static int max_func_args; static int my_func_args; static void jcond(int l, int cond); #define ARG_LVAR_OFFSET 0x10000000 /* 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 (4) #define arg_offset1 (-16) 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 .L%d, %d\n",r1_offset_label,r1_offsetv); } else { lvar_offsetv = -12 - max_reg_var*SIZE_OF_INT-max_freg_var*SIZE_OF_DOUBLE; printf("\t.set .L%d, %d\n",lvar_offset_label,lvar_offsetv); } if (max_func_arg_label) { printf("\t.set .L%d, %d\n",max_func_arg_label,max_func_args*SIZE_OF_INT); max_func_arg_label = 0; } // printf(" @ args = %d, pretend = %d, frame = %d\n", // max_func_args,0,align(-disp,16)); // printf(" @ frame_needed = 1, current_function_anonymous_args = 0\n"); #if 0 printf("## vars= %d, regs= %d/%d, args= %d, extra= %d\n", align(-disp,16), max_reg_var+2, max_freg_var, align(max_func_args*SIZE_OF_INT,16), 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_freg_var*SIZE_OF_FLOAT-2*SIZE_OF_INT+ r1_offsetv); printf("## lvar_offset=\t\t%d %d\n",lvar_offsetv,lvar_offsetv%16); printf("## min local var=\t%d\n",FUNC_LVAR(0)+lvar_offsetv); printf("## max local var=\t%d\n",FUNC_LVAR(disp)+lvar_offsetv); printf("## min caller arg var=\t%d\n", CALLER_ARG(align(max_func_args*SIZE_OF_INT,16))); printf("## max caller arg var=\t%d\n",CALLER_ARG(0)); printf("##\n"); #endif return 0; } #define LARGE_OFFSET(l) (l<-511||l>511) static void lvar_address(int l,int creg); static int large_lvar; static void lvar_intro(int l) { int large; if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { large = LARGE_OFFSET(CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); } else large = LARGE_OFFSET(CODE_LVAR(l)); } else if (l<0) { /* local variable */ large = LARGE_OFFSET(FUNC_LVAR(l)); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ large = LARGE_OFFSET(CALLER_ARG(l-ARG_LVAR_OFFSET)); } else { /* callee's arguments */ large = LARGE_OFFSET(CALLEE_ARG(l)); } if (large) { large_lvar = get_register(); lvar_address(l,large_lvar); } else { large_lvar = 0; } } static void lvar(int l,char *cext) { if (large_lvar) { printf("[%s, #0]%s\n",register_name(large_lvar),cext); free_register(large_lvar); return; } if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("[sp, #%d]%s\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),cext); } else printf("[fp, #%d]%s\n",CODE_LVAR(l),cext); } else if (l<0) { /* local variable */ printf("[fp, #%d+.L%d]%s\n",FUNC_LVAR(l),lvar_offset_label,cext); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("[sp, #%d]%s\n",CALLER_ARG(l-ARG_LVAR_OFFSET),cext); } else { /* callee's arguments */ printf("[fp, #%d]%s\n",CALLEE_ARG(l),cext); } } static void lvar_address(int l,int creg) { int label,disp; int tmp = -1; char *trn; inc_inst(1); if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ code_add(creg,CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),REG_sp); } else code_add(creg,CODE_LVAR(l),REG_fp); } else if (l<0) { /* local variable */ // printf("\tsub\t%s, fp, #%d\n",register_name(creg), FUNC_LVAR(l)); trn = register_name(tmp = get_register()); disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(l)),&label); printf("\tldr\t%s, .L%d+%d\n",trn,label,disp); printf("\tadd\t%s, fp, %s\n",register_name(creg),trn); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ code_add(creg,CALLER_ARG(l-ARG_LVAR_OFFSET),REG_sp); } else { /* callee's arguments */ code_add(creg,CALLEE_ARG(l),REG_fp); } if (tmp!=-1) free_register(tmp); } void code_lvar(int e2,int reg) { use_int(reg); lvar_address(e2,reg); } void code_init(void) { int reg; /* called only once */ size_of_pointer = SIZE_OF_INT; size_of_int = SIZE_OF_INT; size_of_short = SIZE_OF_SHORT; size_of_float = SIZE_OF_FLOAT; size_of_double = SIZE_OF_DOUBLE; size_of_longlong = SIZE_OF_LONGLONG; endian = ENDIAN; struct_align = size_of_int; init_src = init_src0; reg=RET_LREGISTER; regv_l(reg) = RET_LREGISTER_L; regv_h(reg) = RET_LREGISTER_H; reg=LREGISTER_OPERAND; regv_l(reg) = LREGISTER_OPERAND_L; regv_h(reg) = LREGISTER_OPERAND_H; reg=LREGISTER_OPERAND_1; regv_l(reg) = LREGISTER_OPERAND_1_L; regv_h(reg) = LREGISTER_OPERAND_1_H; } extern void emit_reinit() { /* called for each file */ init_ptr_cache(); output_mode = -1; } void gexpr_code_init(void){ } void code_gexpr(int e){ if (is_int_reg(creg) && creg!=ireg) error(-1); // register_usage("code_gexpr"); } void code_arg_register(NMTBL *fnptr, int in) { int args = fnptr->dsp; NMTBL *n; int reg_var = 0; int freg_var = 0; int type; int reg; int i; int is_code0 = is_code(fnptr); int dots; if (in) return; function_type(fnptr->ty,&dots); while (args) { /* process in reverse order */ n = ncadddr(args); type = n->ty; if (scalar(type)) { if ((reg = get_input_register_var(reg_var,n,is_code0))) { n->sc = REGISTER; n->dsp = cadr(reg); regs[n->dsp]= INPUT_REG; reg_var++; 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[regv_l(i)]= INPUT_REG; regs[regv_h(i)]= INPUT_REG; reg_var+=2; caddr(args)=size(type); } } else if (type==LONGLONG||type==ULONGLONG) { if ((reg = get_input_lregister_var(reg_var,n,is_code0))) { n->sc = LREGISTER; n->dsp = cadr(reg); regs[i=n->dsp]= INPUT_REG; regs[regv_l(i)]= INPUT_REG; regs[regv_h(i)]= INPUT_REG; reg_var+=2; caddr(args)=size(type); } } args = cadr(args); } if (is_function(fnptr)) code_save_input_registers(dots); } int get_register(void) { /* 使われていないレジスタを調べる */ int i,j,reg; for(i=MAX_TMP_REG;i>=MIN_TMP_REG;i--) { if (regs[i]) continue; /* 使われている */ regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ return i; /* その場所を表す番号を返す */ } 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)),reg,0); reg_stack[i]= j-REG_LVAR_OFFSET; return reg; } } #if LONGLONG_CODE||FLOAT_CODE /* search register stack */ for(i=0;i<lreg_sp;i++) { if ((reg=lreg_stack[i])>0) { code_lassign_lvar( (j=new_lvar(SIZE_OF_LONGLONG)),reg); lreg_stack[i]= j-REG_LVAR_OFFSET; free_register(reg); return get_register(); } } #endif /* PTR_CACHE をつぶす */ for(i=MAX_TMP_REG;i>=MIN_TMP_REG;i--) { if (regs[i]==PTRC_REG) { clear_ptr_cache_reg(i); } else continue; regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ return i; /* その場所を表す番号を返す */ } for(i=0;i<REG_VAR_MAX-REG_VAR_MIN;i++) { reg =REG_VAR_BASE+i; /* PTR_CACHE をつぶす */ if (regs[reg]==PTRC_REG) { clear_ptr_cache_reg(reg); regs[reg]=0; return reg; /* その場所を表す番号を返す */ } } /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */ error(RGERR); return creg; } #if 0 int get_register(void) { int i = get_register0(); printf("## get_register %d\n",i); return i; } #endif int pop_register(void) { /* レジスタから値を取り出す */ return reg_stack[--reg_sp]; } #if FLOAT_CODE int get_dregister(int d) { /* 使われていないレジスタを調べる */ int i,reg; if (!(arch_mode&UseFPP)) { i = get_lregister(); if (i!=-1) regs[i]=USING_DREG; return i; } for(i=0;i<MAX_TMP_FREG;i++) { reg = i+MIN_TMP_FREG+FREG_OFFSET; if (regs[reg]) continue; /* 使われている */ regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */ return reg; /* その場所を表す番号を返す */ } /* search register stack */ for(i=0;i<freg_sp;i++) { if ((reg=freg_stack[i])>=0) { code_dassign_lvar( (freg_stack[i]=new_lvar(SIZE_OF_DOUBLE)),reg,1); freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET; return reg; } } for(i=0;i<FREG_VAR_MAX;i++) { reg =FREG_VAR_BASE+i+FREG_OFFSET; if (! regs[reg]) { /* 使われていないなら */ regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */ if (i>max_freg_var) max_freg_var=i; return reg; /* その場所を表す番号を返す */ } } /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */ error(RGERR); return freg; } #if 0 int get_dregister(int d) { int i = get_dregister0(d); printf("## get_dregister %d\n",i); return i; } #endif int pop_fregister(void) { /* レジスタから値を取り出す */ return freg_stack[--freg_sp]; } #endif // static int lreg_count; int get_lregister0() { int i; for(i=LREG_OFFSET;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) { if (regs[i]==0) { // printf("## get_lregister %d (%d)\n",i,lreg_count++); return i; } } return -1; } int get_lregister() { int h,l,i; i = get_lregister0(); if (i==-1) return -1; h = get_register(); if (h==-1) return -1; regv_h(i) = h; l = get_register(); if (l==-1) { free_register(h); return -1; } regv_l(i) = l; regs[i]=USING_REG; return i; } int get_lregister_var(NMTBL *n) { int i,j,ll; int max_reg_var_save=max_reg_var; ll = get_lregister0(); if (ll==-1) return -1; if (regs[ll]==0) { for(i=0;i<REG_VAR_MAX-REG_VAR_MIN;i++) { if (! regs[REG_VAR_BASE+i]) { /* 使われていないなら */ /* そのレジスタを使うことを宣言し */ regs[REG_VAR_BASE+i]=USING_REG; if (i+1>max_reg_var) max_reg_var=i+1; for(j=0;j<REG_VAR_MAX-REG_VAR_MIN;j++) { if (! regs[REG_VAR_BASE+j]) { /* 使われていないなら */ /* そのレジスタを使うことを宣言し */ regs[REG_VAR_BASE+j]=USING_REG; if (j+1>max_reg_var) max_reg_var=j+1; /* その場所を表す番号を返す */ regs[ll]=USING_REG; regv_l(ll) = REG_VAR_BASE+j; regv_h(ll) = REG_VAR_BASE+i; return list3n(LREGISTER,ll,n); } } /* ひとつしかなかった */ regs[REG_VAR_BASE+i]=0; max_reg_var=max_reg_var_save; goto not_found; } } } not_found: return list3n(LVAR,new_lvar(SIZE_OF_LONGLONG),0); } void emit_pop_free(int xreg) { if (xreg>=0 && xreg!=creg) free_register(xreg); } void free_register(int i) { /* いらなくなったレジスタを開放 */ // printf("## free_register %d\n",i); regs[i]=0; if (is_longlong_reg(i)) { // printf("## free lregister %d (%d)\n",i,lreg_count++); regs[regv_l(i)]=0; regs[regv_h(i)]=0; //regv_l(i)=0; //regv_h(i)=0; } } extern void use_ptr_cache(int r) { regs[r]=PTRC_REG; } int get_input_dregister_var(int i,NMTBL *n,int is_code,int d) { int j; if (is_code) { if (!(arch_mode&UseFPP)) { 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); } else { return get_input_lregister_var(i,n,is_code); } } 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) { int ll; ll = get_lregister0(); if (ll!=-1) { 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++; } #if ENDIAN==0 regv_l(ll)=i; regv_h(ll)=i+1; #else regv_h(ll)=i; regv_l(ll)=i+1; #endif } else { error(-1); ll=LREG_OFFSET+2; } return list3n(LREGISTER,ll,n); } int get_input_register_var(int i,NMTBL *n,int is_code) { if (is_code) { if(!(i<REG_VAR_MAX-REG_VAR_MIN)) return 0; i = REG_VAR_BASE+i; use_input_reg(i,1); } else { if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0; i = i+1; } return list3n(REGISTER,i,n); } int free_register_count(int d) { int i,count,fcount; fcount = count = 0; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) count++; } for(i=0;i<MAX_FREGISTER;i++) { if (! regs[i+FREG_OFFSET]) fcount++; } printf("## free reg %d freg %d\n",count,fcount); return d?fcount:count; } #if 0 static int register_full(void) { int i; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) { return 0; } } return 1; } #endif void free_all_register(void) { int i; // printf("## free_all register\n"); #if LONGLONG_CODE||FLOAT_CODE for(i=0;i<REAL_MAX_LREGISTER;i++) { regs[i+LREG_OFFSET]=0; } lreg = 0; // set_lreg(LREG_LREGISTER,0); #endif for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; } #if FLOAT_CODE for(i=0;i<MAX_FREGISTER;i++) { regs[i+FREG_OFFSET]=0; } freg = get_dregister(1); set_freg(FREG_FREGISTER,0); #endif ireg = creg = get_register(); set_ireg(CREG_REGISTER,0); return; } extern int code_register_overlap(int s,int t) { switch(car(s)) { case REGISTER: switch(car(t)) { case FREGISTER: break; case REGISTER: return cadr(s)==cadr(t); break; case LREGISTER: case DREGISTER: if(cadr(s)==regv_l(cadr(t))) return 1; if(cadr(s)==regv_h(cadr(t))) return 1; break; } break; case FREGISTER: switch(car(t)) { case REGISTER: case LREGISTER: case DREGISTER: break; case FREGISTER: return cadr(s)==cadr(t); break; } break; case DREGISTER: case LREGISTER: switch(car(t)) { case FREGISTER: break; case REGISTER: if(cadr(t)==regv_l(cadr(s))) return 1; if(cadr(t)==regv_h(cadr(s))) return 1; break; case LREGISTER: case DREGISTER: if(regv_l(cadr(t))==regv_l(cadr(s))) return 1; if(regv_l(cadr(t))==regv_h(cadr(s))) return 1; if(regv_h(cadr(t))==regv_l(cadr(s))) return 1; if(regv_h(cadr(t))==regv_h(cadr(s))) return 1; break; } break; } return 0; } void register_usage(char *s) { #if 1 int i,j; #endif #define USAGE_MAX 4 if (!lsrc) return; printf("## %d: %s:",lineno,s); if (ireg) printf(" creg=%s",register_name(ireg)); if (freg) printf(" freg=%s",fregister_name(freg)); if (lreg) printf(" lreg=%s,%s",lregister_name_high(lreg), lregister_name_low(lreg)); #if 1 for(j=0,i=1;i<MAX_REGISTER;i++) if (regs[i]) j++; if (j>USAGE_MAX) { // printf("\n# regs:01234567890123456789012"); printf("\n# regs:"); for(i=1;i<MAX_REGISTER;i++) { printf("%d",regs[i]); } } if (reg_sp>0) { printf(" stack "); for(i=reg_sp;i>0;i--) { if(reg_stack[i-1]>=0) { printf(" %s",register_name(reg_stack[i-1])); } else printf(",%d",reg_stack[i-1]); } } for(j=0,i=0;i<MAX_FREGISTER;i++) if (regs[i+FREG_OFFSET]) j++; if (j>USAGE_MAX) { printf("\n# freg:"); for(i=0;i<MAX_FREGISTER;i++) { printf("%d",regs[i+FREG_OFFSET]); } } if (freg_sp>0) { printf(" fstack "); for(i=freg_sp;i>0;i--) { if(freg_stack[i-1]>=0) { printf(" %s",fregister_name(freg_stack[i-1])); } else printf(",%d",freg_stack[i-1]); } } for(j=0,i=0;i<REAL_MAX_LREGISTER;i++) if (regs[i+LREG_OFFSET]) j++; if (j>USAGE_MAX) { printf("\n# lreg:"); for(i=0;i<REAL_MAX_LREGISTER;i++) { printf("%d",regs[i+LREG_OFFSET]); } } if (lreg_sp>0) { printf(" lstack "); for(i=lreg_sp;i>0;i--) { if(lreg_stack[i-1]>=0) { printf(" %s",lregister_name_high(lreg_stack[i-1])); printf(",%s",lregister_name_low(lreg_stack[i-1])); } else printf(",%d",lreg_stack[i-1]); } } #endif printf("\n"); } void gexpr_init(void) { while(reg_sp > 0) { error(-1); free_register(reg_stack[--reg_sp]); } while(freg_sp > 0) { error(-1); free_register(freg_stack[--freg_sp]); } while(lreg_sp > 0) { error(-1); free_register(lreg_stack[--lreg_sp]); } use_int0(); text_mode(2); gexpr_code_init(); register_usage(""); } void emit_init(void) { /* called before each declaration */ free_all_register(); max_reg_var=0; max_freg_var=0; reg_sp = 0; freg_sp = 0; } #define reg_var_num(i) (REG_VAR_BASE+i) int get_register_var(NMTBL *n) { int i,j; 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),0); } #define freg_var_num(i) (FREG_VAR_BASE+i+FREG_OFFSET) int get_dregister_var(NMTBL *n,int d) { int i,j; if ((arch_mode&UseFPP)) { 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_freg_var) max_freg_var=i+1; /* その場所を表す番号を返す */ return list3n(FREGISTER,j,n); } } } return list3n(LVAR,new_lvar(d?SIZE_OF_DOUBLE:SIZE_OF_FLOAT),0); } int emit_push() { int new_reg,old=creg; if (!is_int_reg(creg)) error(-1); if (reg_sp>MAX_MAX) error(-1); new_reg = get_register(); /* 絶対に取れる */ if (new_reg==creg) error(-1); /* who freed creg? */ reg_stack[reg_sp++] = creg; /* push するかわりにレジスタを使う */ ireg = creg = new_reg; if (!regs[creg]) regs[creg]=USING_REG; return old; } int emit_pop(int type) { int xreg,reg; xreg=pop_register(); if (xreg<= -REG_LVAR_OFFSET) { reg = get_register(); code_rlvar(REG_LVAR_OFFSET+xreg,reg); free_lvar(REG_LVAR_OFFSET+xreg); xreg = reg; } return xreg; } static int const_list; static int const_list_label; static int prev_const_list; static int prev_const_list_label; /* constant table glist3( tag, next, value ) LVAR glist2(label,offset) GVAR nptr CONST value LABEL value nth element has offset n * SIZE_OF_INT */ #define CONST_TBL_COUNT 100 static int search_const(int tag,int value,int *label) { int p,i,j,list,prev; for(j=0;j<2;j++) { i = 0; if(j==1) { if (!const_list_label) const_list_label = fwdlabel(); *label = const_list_label; if (const_list==0) { const_list = glist3(tag,0,value); return 0; } else { prev = list = const_list; } } else { prev = list = prev_const_list; *label = prev_const_list_label; } for(p = list; p ;prev=p,p=cadr(p),i+=SIZE_OF_INT) { if (car(p)!=tag) continue; switch(tag) { case GVAR: case CONST: case LABEL: if (caddr(p)!=value) continue; return i; case LVAR: if (car(caddr(p))!=car(value)) continue; if (cadr(caddr(p))!=cadr(value)) continue; return i; } } } cadr(prev) = glist3(tag,0,value); if (i>CONST_TBL_COUNT) { const_list_table(); } return i; } #if FLOAT_CODE static int search_double_const(int tag,int value1,int value2,int *label) { int p,i,j,list,prev; for(j=0;j<2;j++) { i = 0; if(j==1) { if (!const_list_label) const_list_label = fwdlabel(); *label = const_list_label; if (const_list==0) { const_list = glist3(tag,glist3(tag,0,value2),value1); return 0; } else { prev = list = const_list; } } else { prev =list = prev_const_list; *label = prev_const_list_label; } for(p = list; p ;prev=p,p=cadr(p),i+=SIZE_OF_INT) { if (car(p)!=tag) continue; switch(tag) { case DCONST: case LCONST: if (caddr(p)!=value1) continue; p = cadr(p); if (!p||car(p)!=tag) error(-1); if (caddr(p)!=value2) continue; return i; } prev = p; } } cadr(prev) = glist3(tag,glist3(tag,0,value2),value1); if (i>CONST_TBL_COUNT) { const_list_table(); } return i; } #endif static int inst_count; static void const_list_table() { int p,lb=0; inst_count = 0; if (const_list) { if (control) { lb = fwdlabel(); gen_jmp(lb); // printf("\t.align\t2\n"); } fwddef(const_list_label); control=0; for(p = const_list; p ; p = cadr(p)) { switch(car(p)) { case GVAR: printf("\t.word\t%s\n",(ncaddr(p))->nm); break; case DCONST: case LCONST: case CONST: printf("\t.word\t%d\n",caddr(p)); break; case LABEL: printf("\t.word\t.L%d\n",caddr(p)); break; case LVAR: printf("\t.word\t.L%d+%d\n", car(caddr(p)),cadr(caddr(p))); break; default: error(-1); } } if (lb) { fwddef(lb); // control==1 now } prev_const_list_label=const_list_label; const_list_label = 0; } for(p = prev_const_list; p ; p = cadr(p)) { if (car(p)==LVAR) { free_glist2(caddr(p)); } } free_glist3_a(prev_const_list); prev_const_list=const_list; const_list = 0; } static void inc_inst(int count) { // printf("## inst %d\n",inst_count); if ((inst_count+=count)>CONST_TBL_COUNT) { inst_count = 0; const_list_table(); } } extern void code_ptr_cache_def(int r, NMTBL *nptr) { int label,disp; char *rrn = register_name(r); disp = search_const(GVAR,(int)nptr,&label); inc_inst(1); printf("\tldr\t%s, .L%d+%d\n",rrn,label,disp); } #define mask8(d,bit) (d & (255 << bit)) /* mode CONST or other (CMP is Ok only in stage 1 result) *p1 stage 1 const *p2 stage 2 const *p3 stage 3 const return 0 ... require 4 stage 1 ... positive result -1 ... negative result */ static int make_const(int c,int *p1,int *p2,int *p3,int mode) { int sign,im,jm,km; int min_stage = 4; int msign=0,mim=0,mjm,mkm; int id,jd,kd; int i,j,k; int d; if (c == (d = mask8(c,0))) { min_stage=1; min_stage=1; msign = 1; mim = d;mjm = 0;mkm = 0; } else if (mode!=CONST) { if (-c == (d = mask8(-c,0))) { min_stage=1; min_stage=1; msign = -1; mim = d;mjm = 0;mkm = 0; } } else { if (~c== (d = mask8(~c,0))) { min_stage=1; min_stage=1; msign = -1; mim = d;mjm = 0;mkm = 0; } } for(sign=1;sign>=-1;sign-=2) { if (min_stage==1) break; for(i=24;i>=0;i-=2) { jm = km = 0; if (sign>0) { if (c == (d = mask8(c,i))) { min_stage=1; min_stage=1; msign = 1; mim = d;mjm = 0;mkm = 0; break; } id = c - d; } else if (mode!=CONST) { if (-c == (d = mask8(-c,i))) { min_stage=1; min_stage=1; msign = -1; mim = d;mjm = 0;mkm = 0; break; } id = -c - d; } else { if (~c== (d = mask8(~c,i))) { min_stage=1; min_stage=1; msign = -1; mim = d;mjm = 0;mkm = 0; break; } id = ~c - d; } if (d==0) continue; im = d; if (min_stage<=2) continue; for(j=i-8;j>=0;j-=2) { km = 0; if (!(jm=mask8(id,j))) continue; jd = id - jm; if (jd==0) { min_stage=2; msign = sign; mim = im;mjm = jm;mkm = km; break; } if (min_stage<=3) continue; for(k=j-8;k>=0;k-=2) { if (!(km=mask8(jd,k))) continue; kd = jd - km; if (kd==0) { min_stage=3; msign = sign; mim = im;mjm = jm;mkm = km; break; } } } } } if (min_stage<=3) { *p1 = mim; *p2= mjm; *p3 = mkm; return msign; } else return 0; } static int is_stage1_const(int c,int mode) { int sign,p1=0,p2=0,p3=0; sign = make_const(c,&p1,&p2,&p3,mode); return (c==0||(p1&&!p2&&!p3))?sign:0; } static void code_const0(int e2,int reg,char *opt) { char *crn,*add,*mov; int s,p1,p2,p3; int label,disp; use_int(reg); crn = register_name(reg); inc_inst(3); if ((s=make_const(e2,&p1,&p2,&p3,CONST))) { add = s>0?"add":"sub"; mov = s>0?"mov":"mvn"; printf("\t%s\t%s, #%d\n",mov,crn,p1); if (p2) printf("\t%s\t%s, %s, #%d\n",add,crn,crn,p2); if (p3) printf("\t%s\t%s, %s, #%d\n",add,crn,crn,p3); } else { disp = search_const(CONST,e2,&label); printf("\tldr\t%s, .L%d+%d%s\n",crn,label,disp,opt); } } extern void code_const(int e2,int reg) { code_const0(e2,reg,""); } static void code_add(int reg,int offset,int r) { char *crn = register_name(reg); char *rrn = register_name(r); char *drn; int dreg; int s,p1,p2,p3; char *add; int label,disp; inc_inst(3); if (offset==0) { if(r!=reg) printf("\tmov\t%s, %s\n",crn,rrn); } else if ((s=make_const(offset,&p1,&p2,&p3,0))) { add = s>0?"add":"sub"; printf("\t%s\t%s, %s, #%d\n",add,crn,rrn,p1); if (p2) printf("\t%s\t%s, %s, #%d\n",add,crn,crn,p2); if (p3) printf("\t%s\t%s, %s, #%d\n",add,crn,crn,p3); } else { disp = search_const(CONST,offset,&label); drn = register_name(dreg = get_register()); printf("\tldr\t%s, .L%d+%d\n",drn,label,disp); printf("\tadd\t%s, %s, %s\n",crn,drn,rrn); free_register(dreg); } } static void code_ld(char *ld,int reg,int offset,int r,char *cext) { char *crn = register_name(reg); char *rrn = register_name(r); inc_inst(1); if (-1024<offset&&offset<1024) { printf("\t%s\t%s, [%s, #%d]%s\n",ld,crn,rrn,offset,cext); } else { code_add(reg,offset,r); printf("\t%s\t%s, [%s, #0]%s\n",ld,crn,crn,cext); } } static void code_ldf(char *ld,char *crn,int offset,int r,char *cext) { char *rrn = register_name(r); char *orn; int reg; inc_inst(1); if (-1024<offset&&offset<1024) { printf("\t%s\t%s, [%s, #%d]%s\n",ld,crn,rrn,offset,cext); } else { orn = register_name(reg=get_register()); code_add(reg,offset,r); printf("\t%s\t%s, [%s, #0]%s\n",ld,crn,orn,cext); free_register(reg); } } #define cload(sz,sign) \ (sz==1?(sign?"ldrsb":"ldrb"):sz==SIZE_OF_SHORT?(sign?"ldrsh":"ldrh"):"ldr") #define cext(sign,sz,reg) static char * cext_at(int sz,int sign) { return ((sz==1&&!sign)?" @ zero_extendqisi2":""); } void code_label(int labelno) { clear_ptr_cache(); printf(".L%d:\n",labelno); } void code_gvar(int e1,int reg) { use_int(reg); code_add(reg,cadr(e1),get_ptr_cache(ncaddr(e1))); return; } void code_rgvar(int e1,int reg) { use_int(reg); code_ld("ldr",reg,cadr(e1),get_ptr_cache(ncaddr(e1)),""); } void code_crgvar(int e1,int reg,int sign,int sz){ use_int(reg); code_ld(cload(sz,sign),reg,cadr(e1),get_ptr_cache(ncaddr(e1)), cext_at(sz,sign)); cext(sign,sz,reg); } void code_register(int e2,int reg) { use_int(reg); // reg = e2 if (reg!=e2) { inc_inst(1); printf("\tmov\t%s, %s\n",register_name(reg),register_name(e2)); } } void code_rlvar(int e2,int reg) { use_int(reg); inc_inst(1); lvar_intro(e2); printf("\tldr\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); inc_inst(1); printf("and\t%s, %s, #255\n",register_name(reg),register_name(reg)); } extern void code_u2us(int reg) { use_int(reg); inc_inst(2); printf("bic\t%s, %s, #16711680\n",register_name(reg),register_name(reg)); printf("bic\t%s, %s, #-16777216\n",register_name(reg),register_name(reg)); } void code_crlvar(int e2,int reg,int sign,int sz) { use_int(reg); inc_inst(1); lvar_intro(e2); printf("\t%s\t%s, ",cload(sz,sign),register_name(reg)); lvar(e2,cext_at(sz,sign)); cext(sign,sz,reg); } void code_fname(NMTBL *n,int reg) { int r; use_int(reg); r = get_ptr_cache(n); if(r!=reg) { inc_inst(2); printf("\tmov\t%s, %s\n",register_name(reg),register_name(r)); } return; } void code_label_value(int label,int reg) { int lb,disp; use_int(reg); disp = search_const(LABEL,label,&lb); inc_inst(1); printf("\tldr\t%s, .L%d+%d\n",register_name(reg),lb,disp); return; } void code_neg(int creg) { use_int(creg); inc_inst(1); printf("\trsb\t%s, %s, #0\n", register_name(creg), register_name(creg)); } void code_not(int creg) { use_int(creg); inc_inst(1); printf("\tmvn\t%s, %s\n", register_name(creg), register_name(creg)); } void code_lnot(int creg) { use_int(creg); inc_inst(3); printf("\tcmp\t%s, #0\n", register_name(creg)); printf("\tmovne\t%s, #0\n", register_name(creg)); printf("\tmoveq\t%s, #1\n", register_name(creg)); } void code_preinc(int e1,int e2,int dir,int sign,int sz,int reg) { char *xrn,*drn; int xreg; if (car(e2)==REGISTER) { use_int(reg); code_add(cadr(e2),dir,cadr(e2)); if (reg!=cadr(e2)) code_register(cadr(e2),reg); return; } g_expr(e2); if (!is_int_reg(creg)) error(-1); xrn = register_name(xreg = creg); if (reg==USE_CREG) { reg=get_register(); if (!reg) error(-1); drn = register_name(reg); set_ireg(reg,0); } else { drn = register_name(reg); } // ldrb r2, [ip, #-1]! @ zero_extendqisi2 // これはoffsetだから、12bit! code_ld(cload(sz,sign),reg,0,xreg,cext_at(sz,sign)); code_add(reg,dir,reg); code_ldf(cstore(sz),drn,0,xreg,sz==SIZE_OF_SHORT?" @ movhi":""); } void code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) { char *xrn,*crn,*nrn; int nreg,xreg; if (car(e2)==REGISTER) { use_int(reg); code_register(cadr(e2),reg); code_add(cadr(e2),dir,cadr(e2)); return; } g_expr(e2); if (!is_int_reg(creg)) error(-1); crn = register_name(xreg=creg); nreg=get_register(); if (!nreg) error(-1); nrn = register_name(nreg); if (reg==USE_CREG) { reg=get_register(); if (!reg) error(-1); xrn = register_name(reg); set_ireg(reg,0); } else { xrn = register_name(reg); } //_1: ldrb r4, [r0], #1 @ zero_extendqisi2 *buffer++ code_ld(cload(sz,sign),reg,0,xreg,cext_at(sz,sign)); code_add(nreg,dir,reg); code_ldf(cstore(sz),nrn,0,xreg,sz==SIZE_OF_SHORT?" @ movhi":""); free_register(nreg); } void code_return(int creg) { int label,disp; char *crn; use_int(creg); crn = register_name(creg); disp = search_const(LABEL,retcont,&label); inc_inst(1); printf("\tldr\t%s, .L%d+%d\n",crn,label,disp); } void code_environment(int creg) { /* save frame pointer */ if (is_code(fnptr)) { inc_inst(1); use_int(creg); printf("\tmov\t%s, fp\n",register_name(creg)); } else { int disp,label; char *trn = register_name(REG_ip); inc_inst(2); use_int(creg); disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label); printf("\tldr\t%s, .L%d+%d\n",trn,label,disp); printf("\tadd\t%s, fp, %s\n",register_name(creg),trn); } } static int rexpr_bool(int e1, int reg); #if LONGLONG_CODE static int lrexpr_bool(int e1, int reg); #endif void code_bool(int e1,int reg) { int e2,e3; char *xrn; if (rexpr_bool(e1, reg)) return; #if LONGLONG_CODE if (lrexpr_bool(e1, reg)) return; #endif b_expr(e1,1,e2=fwdlabel(),1); /* including > < ... */ if (use) { inc_inst(2); use_int(reg); xrn = register_name(reg); printf("\tmov\t%s, #0\n",xrn); gen_jmp(e3=fwdlabel()); fwddef(e2); printf("\tmov\t%s, #1\n",xrn); fwddef(e3); } else { fwddef(e2); } } void code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) { use_int(reg); code_ld(cload(sz,0),reg,cadr(e1),get_ptr_cache(ncaddr(e1)), cext_at(sz,0)); cext(0,sz,r); inc_inst(1); printf("\tcmp\t%s, #0\n",register_name(reg)); jcond(label,cond); } void code_cmp_crlvar(int e2,int reg, int sz,int label,int cond) { char *crn; use_int(reg); crn = register_name(reg); lvar_intro(e2); inc_inst(1); printf("\t%s\t%s, ",cload(sz,0),crn); lvar(e2,cext_at(sz,0)); cext(0,sz,reg); code_cmp_register(reg,label,cond); } void code_cmp_rgvar(int e1,int reg,int label,int cond) { use_int(reg); code_ld("ldr",reg,cadr(e1),get_ptr_cache(ncaddr(e1)),""); code_cmp_register(reg,label,cond); } void code_cmp_rlvar(int e2,int reg,int label,int cond) { char *crn; use_int(reg); crn = register_name(reg); inc_inst(1); lvar_intro(e2); printf("\tldr\t%s, ",crn); lvar(e2,""); code_cmp_register(reg,label,cond); } void code_cmp_register(int e2,int label,int cond) { use_int(e2); inc_inst(1); printf("\tcmp\t%s, #0\n",register_name(e2)); jcond(label,cond); } void code_string(int e1,int creg) { char *s,*crn; int lb,disp,label; NMTBL *n = ncaddr(e1); if ((lb=attr_value(n,LABEL))) { // already defined return code_label_value(lb,creg) ; } use_int(creg); crn = register_name(creg); s=n->nm; lb = emit_string_label(); ascii(s, n->dsp); text_mode(2); disp = search_const(LABEL,lb,&label); printf("\tldr\t%s, .L%d+%d\n",crn,label,disp); inc_inst(1); 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: inc_inst(2); printf("\tldrb\t%s, [%s,#%d]\n",drn,frn,offset); printf("\tstrb\t%s, [%s,#%d]\n",drn,trn,offset); break; case 2: case -2: inc_inst(2); printf("\tldrh\t%s, [%s,#%d]\n",drn,frn,offset); printf("\tstrh\t%s, [%s,#%d]\n",drn,trn,offset); break; case 4: case -4: inc_inst(2); printf("\tldr\t%s, [%s,#%d]\n",drn,frn,offset); printf("\tstr\t%s, [%s,#%d]\n",drn,trn,offset); break; default: if (length <0) { if (length > -MAX_COPY_LEN) { for(;length<=-4;length+=4,offset-=4) emit_copy(from,to,-4,offset-4,0,det); for(;length<=-2;length+=2,offset-=2) emit_copy(from,to,-2,offset-2,0,det); if(length<0) emit_copy(from,to,length,offset-1,0,det); break; } } else if (length <=MAX_COPY_LEN) { for(;length>=4;length-=4,offset+=4) emit_copy(from,to,4,offset,0,det); for(;length>=2;length-=2,offset+=2) emit_copy(from,to,2,offset,0,det); if(length>0) emit_copy(from,to,length,offset,0,det); break; } clear_ptr_cache(); code_save_stacks(); parallel_rassign(list3(1,list3(2,0,from),to)); code_const(length>0?length:-length,3); /* overlap must be allowed */ inc_inst(1); // offset have to be ignored */ printf("\tbl\t%s\n",memmove); extern_define(memmove,0,FUNCTION,1); set_ireg(RET_REGISTER,0); if (creg!=to) { free_register(to); to = creg; } break; } if (value) { /* creg must point top of the destination data */ /* this code is necessary for the value of assignment or function call */ /* otherwise we don't need this */ if(creg!=to) { free_register(creg); creg=to; ireg=to; } } // free_register(dreg); } int push_struct(int e4,int t,int arg) { int length,len0,count; int dreg = -1,sreg; char *drn,*crn,*srn; int arg_disp = cadr(arg); int on_register,arg_reg; g_expr(e4); if (!is_int_reg(creg)) error(-1); len0=length=size(t); if(length%SIZE_OF_INT) { length += SIZE_OF_INT - (length%SIZE_OF_INT); } crn = register_name(creg); on_register = 0; // arg_reg = 1-CALLER_ARG(arg_disp-ARG_LVAR_OFFSET)/SIZE_OF_INT; arg_reg = (arg_disp-ARG_LVAR_OFFSET)/SIZE_OF_INT + 1; while (length>0 && arg_disp>=ARG_LVAR_OFFSET && CALLER_ARG(arg_disp-ARG_LVAR_OFFSET)<0) { /* some part will be on registers */ on_register ++; length-=SIZE_OF_INT; arg_disp+= SIZE_OF_INT; } if (length>0) { dreg = get_register(); if (!dreg) error(-1); drn = register_name(dreg); if (length<MAX_COPY_LEN) { sreg = get_register(); if (!sreg) error(-1); srn = register_name(sreg); code_lvar(arg_disp,dreg); for(count=0;count<length;count+=SIZE_OF_INT) { inc_inst(2); printf("\tldr\t%s, [%s, #%d]\n",srn,crn,count+on_register*SIZE_OF_INT); printf("\tstr\t%s, [%s, #%d]\n",srn,drn,count); } free_register(sreg); if (on_register) { if (creg<=MAX_INPUT_REGISTER_VAR) { code_register(creg,REG_ip); crn = register_name(REG_ip); } } } else { code_lvar(arg_disp,dreg); /* downward direction copy */ if (on_register) { sreg = new_lvar(SIZE_OF_INT); code_assign_lvar(sreg,creg,0); code_add(creg,on_register*SIZE_OF_INT,creg); emit_copy(creg,dreg,length,0,0,1); code_rlvar(sreg,REG_ip); crn = register_name(REG_ip); free_lvar(sreg); } else { emit_copy(creg,dreg,length,0,0,1); } } if (dreg!=-1) free_register(dreg); } for (count=0,arg_reg; on_register-->0; arg_reg++,count+=SIZE_OF_INT) { // len0 = (len0>2)?0:len0; printf("\t%s\t%s, [%s, #%d]\n", cload(0,0), register_name(arg_reg), crn,count); use_input_reg(arg_reg,1); } return length/SIZE_OF_INT; } static void set_ireg(int reg,int mode) { if (!is_int_reg(reg)) error(-1); if (reg!=creg) { clear_ptr_cache_reg(reg); if (ireg && reg!=ireg ) { free_register(ireg); if (mode) { inc_inst(1); printf("\tmov\t%s, %s\n",register_name(reg),register_name(ireg)); } } free_register(creg); if (creg==lreg) lreg=0; regs[reg]=USING_REG; } creg = ireg = reg; } static void set_freg(int reg,int mode) { if (!is_float_reg(reg)) error(-1); if (reg!=creg) { if (freg && reg!=freg) { free_register(freg); if (mode) { inc_inst(1); printf("\t%s\t%s, %s\n", (arch_mode&UseFPP)?"mvfs":"mov", fregister_name(reg),fregister_name(freg)); } } // if (creg!=ireg) free_register(creg); regs[reg]=USING_REG; } creg = freg = reg; } #if LONGLONG_CODE||FLOAT_CODE static void set_lreg0(int reg,int mode) { if (reg!=creg) { if (lreg && reg!=lreg) { if (mode) { inc_inst(2); lmove(reg,lreg); } free_register(lreg); } if (creg!=lreg) { free_register(creg); if (creg==ireg) ireg = 0; } regs[reg]=USING_REG; clear_ptr_cache_reg(regv_l(reg)); regs[regv_l(reg)]=USING_REG; clear_ptr_cache_reg(regv_h(reg)); regs[regv_h(reg)]=USING_REG; } creg = lreg = reg; } #endif #if LONGLONG_CODE static void set_lreg(int reg,int mode) { if (!is_longlong_reg(reg)) error(-1); set_lreg0(reg,mode); } #endif #if FLOAT_CODE static void set_dreg(int reg,int mode) { if ((arch_mode&UseFPP)) { if (reg==RET_DREGISTER) { reg = RET_FREGISTER; } if (is_float_reg(reg)) { set_freg(reg,mode); } regs[reg]=USING_REG; return; } if (reg==RET_DREGISTER) { regv_l(reg) = RET_DREGISTER_L; regv_h(reg) = RET_DREGISTER_H; } else if (reg==DREGISTER_OPERAND) { regv_l(reg) = DREGISTER_OPERAND_L; regv_h(reg) = DREGISTER_OPERAND_H; } else if (reg==DREGISTER_OPERAND_1) { regv_l(reg) = DREGISTER_OPERAND_1_L; regv_h(reg) = DREGISTER_OPERAND_1_H; } set_lreg0(reg,mode); regs[regv_l(reg)]=USING_DREG; regs[regv_h(reg)]=USING_DREG; } static void set_lreg_operand(int reg,int mode) { // save_stack,clear_ptr_cache is assumed if (!is_longlong_reg(reg)) { error(-1); return; } if (mode) { lmove(LREGISTER_OPERAND,reg); } } static void set_dreg_operand(int reg,int mode) { set_lreg_operand(reg,mode); } #endif void use_reg(int arg) { // printf("## use reg %d\n",arg); if (arg<0||arg> REGS_MAX) error(-1); clear_ptr_cache_reg(arg); regs[arg]=USING_REG; if (is_longlong_reg(arg)) { clear_ptr_cache_reg(regv_l(arg)); regs[regv_l(arg)]=USING_REG; clear_ptr_cache_reg(regv_h(arg)); regs[regv_h(arg)]=USING_REG; } else if (is_double_reg(arg)) { clear_ptr_cache_reg(regv_l(arg)); regs[regv_l(arg)]=USING_DREG; clear_ptr_cache_reg(regv_h(arg)); regs[regv_h(arg)]=USING_DREG; } } void code_save_input_registers(int dots) { int args; NMTBL *n; int reg; int tag; /* 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 = align(len,4); 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 (is_int_reg(reg)) { if (ireg&® == ireg) { if (creg==ireg) creg = 0; ireg = 0; } if (lreg) { if (regv_l(lreg)==reg) { regs[lreg]=0; if (regv_h(lreg)>reg&& (regs[regv_h(lreg)]==USING_REG|| regs[regv_h(lreg)]==USING_DREG)) { free_register(regv_h(lreg)); } if (creg==lreg) creg = ireg; free_register(lreg); lreg = 0; } else if (regv_h(lreg)==reg) { regs[lreg]=0; if (regv_h(lreg)>reg && ( (regs[regv_l(lreg)]==USING_REG) || (regs[regv_l(lreg)]==USING_DREG) )) { free_register(regv_l(lreg)); } if (creg==lreg) creg = ireg; free_register(lreg); lreg = 0; } } } else if (is_longlong_reg(reg)) { use_input_reg(regv_h(reg),0); use_input_reg(regv_l(reg),0); } else if (is_double_reg(reg)) { use_input_reg(regv_h(reg),0); use_input_reg(regv_l(reg),0); } else if (is_float_reg(reg)) { if (freg&® == freg) { if (creg==freg) creg = ireg; freg = 0; } } if (mode) use_reg(reg); } static void code_assign_input_float_int(int e1,int e2) { #if FLOAT_CODE int r,tmp=-1; float f; char *frn; // e1 = e2; if (car(e1)!=REGISTER) { error(-1); return; } frn = register_name(r=cadr(e1)); switch(car(e2)) { case FCONST: f = dcadr(e2); code_const(*((int*)&f),r); break; case FRGVAR: code_rgvar(e2,r); break; case FRLVAR: code_rlvar(cadr(e2),r); break; default: g_expr(rvalue_t(e2,FLOAT)); case FREGISTER: tmp = new_lvar(SIZE_OF_INT); code_dassign_lvar(tmp, (car(e2)==FREGISTER)?cadr(e2):freg,0); code_rlvar(tmp,r); if (tmp!=-1) free_lvar(tmp); } #endif } static void code_assign_input_double_long(int e1,int e2) { #if FLOAT_CODE int r,tmp=-1,reg=0; double value; // e1 = e2; if (car(e1)!=LREGISTER) { error(-1); return; } r=cadr(e1); switch(car(e2)) { case DCONST: value = dcadr(e2); dconst(regv_l(r),regv_h(r),value); break; case DRGVAR: code_lrgvar(e2,r); break; case DRLVAR: code_lrlvar(cadr(e2),r); break; default: g_expr(rvalue_t(e2,DOUBLE)); reg = freg; case DREGISTER: if (car(e2)==DREGISTER) reg = cadr(e2); printf("\tstfd\t%s, [sp, #-8]!\n",fregister_name(reg)); printf("\tldmfd\tsp!, {%s, %s}\n",lregister_name_low(r),lregister_name_high(r)); } if (tmp!=-1) free_lvar(tmp); #endif } static int compute_complex_arg(int e3,int reg_arg_list,int arg) { int t=caddr(e3); int e4 = car(e3); reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER||car(arg)==DREGISTER|| car(arg)==FREGISTER||car(arg)==LREGISTER) use_input_reg(cadr(arg),1); if (t==FLOAT&&car(arg)==REGISTER) code_assign_input_float_int(arg, e4); else if (t==DOUBLE&&car(arg)==LREGISTER) code_assign_input_double_long(arg, e4); else g_expr_u(assign_expr0(arg,e4,t,t)); car(e3) = arg; return reg_arg_list; } static void increment_function_arg(int e3,int *pnargs,int *preg_arg,int *pfreg_arg) { int nargs=0,reg_arg=0,freg_arg=0; int t=caddr(e3); if(scalar(t)) { nargs ++ ; reg_arg++; freg_arg++; } else if (t==LONGLONG||t==ULONGLONG||t==DOUBLE) { nargs ++ ; reg_arg++; nargs ++ ; reg_arg++; } else if (t==FLOAT) { reg_arg ++ ; freg_arg++; nargs += size(t)/SIZE_OF_INT; } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { nargs += align(size(t),4)/SIZE_OF_INT; } else { error(TYERR); nargs ++ ; } *pnargs += nargs; *preg_arg += reg_arg; *pfreg_arg += freg_arg; } #define AS_SAVE 1 #define AS_ARG 0 static int get_input_arg(int t,int mode,int nargs,int reg_arg,int freg_arg) { if(scalar(t)) { if (mode==AS_SAVE) { return get_register_var(0); } else if (reg_arg+1>MAX_INPUT_REGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_register_var(reg_arg,0,0); } else if (t==LONGLONG||t==ULONGLONG) { if (mode==AS_SAVE) { return get_lregister_var(0); } else if (reg_arg+1>=MAX_INPUT_REGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_lregister_var(reg_arg,0,0); } else if (t==FLOAT) { if (mode==AS_SAVE) { return get_dregister_var(0,0); } else if (freg_arg>=MAX_INPUT_DREGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_dregister_var(freg_arg,0,0,0); } else if (t==DOUBLE) { if (mode==AS_SAVE) { return get_dregister_var(0,1); } else if (reg_arg+1>=MAX_INPUT_DREGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else return get_input_dregister_var(reg_arg,0,0,1); } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { if (mode==AS_SAVE) { return get_register_var(0); } else return list3n(LVAR,caller_arg_offset_v(nargs),0); } else { error(-1); return get_register_var(0); } } static void code_call(int e2,NMTBL *fn,int jmp) { if (car(e2) == FNAME) { inc_inst(1); printf("\tbl\t%s\n",fn->nm); } else { inc_inst(3); printf("\tmov\tlr, pc\n"); printf("\tmov\tpc, %s\n",register_name(cadr(jmp))); } } int function(int e1) { int e2,e3,e4,e5,nargs,t; int arg,reg_arg,freg_arg,arg_assign; int dots; int reg_arg_list=0,ret_type,special_lvar; NMTBL *fn = 0; int jmp = 0; int complex_; int pnargs,preg_arg,pfreg_arg; int stargs,i; int half_register = 0; special_lvar = -1; ret_type = function_type(cadddr(e1),&dots); if (caddr(cadddr(e1))==0) dots=1; arg_assign = 0; e2 = cadr(e1); if (car(e2) == FNAME) { fn=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 (car(e4)==INDIRECT) e4 = cadr(e4); if (!simple_arg(e4)) { // Calculate complex struct address here. // If simple, leave it. arg = get_register_var(0); g_expr_u(assign_expr0(arg,e4,INT,INT)); car(e3)=arg; reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER) use_input_reg(cadr(arg),1); else car(e3) = rvalue_t(arg,INT); } } stargs = list4(e3,stargs,nargs,reg_arg); } increment_function_arg(e3,&nargs,®_arg,&freg_arg); } /* now all input register vars are free */ code_save_stacks(); // set_lreg(LREG_LREGISTER,0); set_freg(FREG_FREGISTER,0); set_ireg(CREG_REGISTER,0); // Struct arguments need emit_copy. it destructs 3 input registers. // But it returns no value on a register. So calculate it here. // We cannot do this in the previous loop, because the copied struct may be // override by other complex arguments. But before this we have to check // complex_. if (stargs) { if (complex_) { arg = get_input_arg(caddr(complex_),AS_SAVE, pnargs,preg_arg,pfreg_arg); reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); } for(stargs=reverse0(stargs);stargs;stargs = cadr(stargs)) { e3 = car(stargs); e4 = car(e3); t = caddr(e3); arg = get_input_arg(t,AS_ARG,caddr(stargs),cadddr(stargs),0); push_struct(e4,t,arg); car(e3)=0; // done if (car(arg)==REGISTER) // 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)==LREGISTER) { use_input_reg(cadr(arg),1); code_assign_input_double_long(arg, e4); } else { g_expr_u(assign_expr0(arg,e4,t,t)); } } else if (t==FLOAT) { reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER) { use_input_reg(cadr(arg),1);/* protect from input register free */ code_assign_input_float_int(arg, e4); } else { g_expr_u(assign_expr0(arg,e4,t,t)); /* XXX */ } } // structs are finished } if (max_func_args<nargs) max_func_args=nargs; for(;arg_assign;arg_assign=cadr(arg_assign)) { g_expr_u(car(arg_assign)); } clear_ptr_cache(); code_call(e2,fn,jmp); free_register_var(reg_arg_list); for(i=1;i<MAX_INPUT_REGISTER_VAR;i++) { free_register(i); } if (ret_type==DOUBLE) { #if FLOAT_CODE set_dreg(RET_DREGISTER,0); use_reg(RET_DREGISTER); #endif } else if (ret_type==FLOAT) { #if FLOAT_CODE set_freg(RET_FREGISTER,0); #endif } else if (ret_type==ULONGLONG||ret_type==LONGLONG) { #if LONGLONG_CODE set_lreg(RET_LREGISTER,0); use_reg(RET_LREGISTER); #endif } else if (ret_type==VOID) { } else { set_ireg(RET_REGISTER,0); } return ret_type; } void code_alloca(int e1,int reg) { char *crn; g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); use_int(reg); crn = register_name(reg); inc_inst(2); printf("\trsb\tsp, %s, sp\n",crn); if (!max_func_arg_label) max_func_arg_label = fwdlabel(); code_label_value(max_func_arg_label ,REG_ip); printf("\tadd\t%s, sp, ip\n",crn); } void code_frame_pointer(int e3) { use_int(e3); inc_inst(1); printf("\tmov\tfp, %s\n",register_name(e3)); } int code_frame_pointer_register() { return list2(REGISTER,REG_fp); } void code_fix_frame_pointer(int env) { char *trn; int disp,label; if (is_function(fnptr) && ! env) { trn = register_name(REG_ip); disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label); printf("\tldr\t%s, .L%d+%d\n",trn,label,disp); printf("\tadd\tfp, fp, %s\n",trn); } } static void code_unfix_frame_pointer() { char *trn; int disp,label; trn = register_name(REG_ip); disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label); printf("\tldr\t%s, .L%d+%d\n",trn,label,disp); printf("\tsub\tfp, fp, %s\n",trn); } void code_jmp(char *s) { // jump to continuation means use all register variable max_reg_var = REG_VAR_MAX-REG_VAR_MIN; max_freg_var = FREG_VAR_MAX-FREG_VAR_MIN; inc_inst(1); printf("\tb\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_freg_var = FREG_VAR_MAX-FREG_VAR_MIN; use_int(e2); inc_inst(1); printf("\tmov\tpc, %s @ indirect jump\n",register_name(e2)); // ?! control=0; } void code_rindirect(int e1, int reg,int offset, int sign,int sz) { int lreg; g_expr(e1); if (!is_int_reg(creg)) error(-1); lreg = creg; use_int(reg); code_ld(cload(sz,sign),reg,offset,lreg,cext_at(sz,sign)); cext(sign,sz,reg); } #if FLOAT_CODE int code_drindirect(int e1, int reg,int offset, int d) { int xreg; if(!(arch_mode&UseFPP)) { if (d) { code_lrindirect(e1,reg,offset,1); return DOUBLE; } else { code_rindirect(e1,reg,offset,0,0); return FLOAT; } } g_expr(e1); if (!is_int_reg(creg)) error(-1); xreg = creg; use_float(d,reg); code_ldf(d?"ldfd":"ldfs",register_name(reg),offset,xreg,""); return d?DOUBLE:FLOAT; } #endif #if LONGLONG_CODE||FLOAT_CODE static void lload(int creg,int reg,int offset) { char *crn=register_name(creg); inc_inst(2); #if ENDIAN_L==0 if (creg!=regv_l(reg)) { printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset); printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset+SIZE_OF_INT); } else { printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset+SIZE_OF_INT); printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset); } #else if (creg!=regv_l(reg)) { printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset+SIZE_OF_INT); printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset); } else { printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset); printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset+SIZE_OF_INT); } #endif } static void lmove(int to,int from) { int l; l = list3(regv_l(to),0,regv_l(from)); l = list3(regv_h(to),l,regv_h(from)); parallel_rassign(l); } static void set_operands(int r0,int r1,int r2,int r3) { int l; l = list3(DREGISTER_OPERAND_L,0,r0); l = list3(DREGISTER_OPERAND_H,l,r1); l = list3(DREGISTER_OPERAND_1_L,l,r2); l = list3(DREGISTER_OPERAND_1_H,l,r3); parallel_rassign(l); } static void lstore(int e2,int creg) { char *drn = register_name(e2); char *crn_h; char *crn_l; crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); inc_inst(2); #if ENDIAN_L==0 printf("\tstr\t%s, [%s, #0]\n",crn_l,drn); printf("\tstr\t%s, [%s, #%d]\n",crn_h,drn,SIZE_OF_INT); #else printf("\tstr\t%s, [%s, #0]\n",crn_h,drn); printf("\tstr\t%s, [%s, #%d]\n",crn_l,drn,SIZE_OF_INT); #endif } int code_lrindirect(int e1, int reg, int offset, int us) { int creg0; g_expr(e1); if (!is_int_reg(creg)) error(-1); creg0=creg; use_longlong(reg); lload(creg0,reg,offset); return us?ULONGLONG:LONGLONG; } #endif static char * cstore(int sz) { switch(sz) { case 1: return "strb"; case SIZE_OF_SHORT: return "strh"; default: return "str"; } } void code_assign_gvar(int e2,int creg,int byte) { use_int(creg); code_ldf(cstore(byte),register_name(creg),cadr(e2), get_ptr_cache(ncaddr(e2)),byte==SIZE_OF_SHORT?" @ movhi":""); } void code_assign_lvar(int e2,int creg,int byte) { char *crn; use_int(creg); crn=register_name(creg); inc_inst(1); lvar_intro(e2); printf("\t%s\t%s, ",cstore(byte),crn); lvar(e2,""); } void code_assign_register(int e2,int byte,int creg) { use_int(creg); if (e2!=creg) { inc_inst(1); printf("\tmov\t%s, %s\n",register_name(e2),register_name(creg)); } } void code_assign(int e2,int byte,int creg) { char *drn; char *crn; use_int(e2); drn=register_name(e2); use_int(creg); crn=register_name(creg); inc_inst(1); printf("\t%s\t%s, [%s, #0]\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, [%s, #0]\n",cstore(byte),crn,drn); free_register(edx); free_register(creg); emit_pop_free(xreg); inc_inst(1); } 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: inc_inst(1); printf("\tadd\t%s, %s, %s\n",crn,crn,orn); break; case SUB: inc_inst(1); printf("\tsub\t%s, %s, %s\n",crn,crn,orn); break; case CMP: inc_inst(1); printf("\tcmp\t%s, %s\n",crn,orn); break; case BAND: inc_inst(1); printf("\tand\t%s, %s, %s\n",crn,crn,orn); break; case EOR: inc_inst(1); printf("\teor\t%s, %s, %s\n",crn,crn,orn); break; case BOR: inc_inst(1); printf("\torr\t%s, %s, %s\n",crn,crn,orn); break; case MUL: case UMUL: /* target!=source */ inc_inst(1); printf("\tmul\t%s, %s, %s\n",crn,orn,crn); break; case DIV: code_int_lib("__divsi3",creg,oreg); break; case UDIV: code_int_lib("__udivsi3",creg,oreg); break; case MOD: code_int_lib("__modsi3",creg,oreg); break; case UMOD: code_int_lib("__umodsi3",creg,oreg); break; default: error(-1); } if(ox!=-1) free_register(ox); } int code_const_op_p(int op,int v) { if (car(v)!=CONST) return 0; v = cadr(v); switch(op) { case MUL: case UMUL: case DIV: case UDIV: return ilog(v); case ADD: case SUB: return 1; case LSHIFT: case ULSHIFT: case RSHIFT: case URSHIFT: return 0<v&&v<=32; case CMP: return is_stage1_const(v,CMP); case EOR: case BOR: case BAND: return (is_stage1_const(v,0)>0); default: return 0; } } void oprtc(int op,int creg, int v) { char *crn; use_int(creg); crn = register_name(creg); v = cadr(v); switch(op) { case MUL: case UMUL: v=ilog(v); case LSHIFT: case ULSHIFT: printf("\tmov\t%s, %s, asl #%d\n",crn,crn,v); break; case DIV: v=ilog(v); case RSHIFT: printf("\tmov\t%s, %s, asr #%d\n",crn,crn,v); break; case UDIV: v=ilog(v); case URSHIFT: printf("\tmov\t%s, %s, lsr #%d\n",crn,crn,v); break; case ADD: code_add(creg,v,creg); break; case SUB: code_add(creg,-v,creg); break; case CMP: printf("\tcmp\t%s,%d\n",crn,v); break; case BOR: printf("\torr\t%s, %s, #%d\n",crn,crn,v); break; case EOR: printf("\teor\t%s, %s, #%d\n",crn,crn,v); break; case BAND: printf("\tand\t%s, %s, #%d\n",crn,crn,v); break; default: error(-1); } inc_inst(1); } void shift(char *op, int creg, int reg) { char *crn; char *rrn = register_name(reg); use_int(creg); crn = register_name(creg); inc_inst(1); 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); inc_inst(2); if (!(sign=is_stage1_const(e,CMP))) { regsv = regs[csreg]; regs[csreg]=1; rn = register_name(reg= get_register()); regs[csreg] = regsv; code_const(e,reg); printf("\tcmp\t%s, %s\n",crn,rn); } else { if (sign>0) printf("\tcmp\t%s, #%d\n",crn,e); else printf("\tcmn\t%s, #%d\n",crn,-e); } switch(cond) { case -1: break; case 1: printf("\tbne\t.L%d\n",label); break; case 0: printf("\tbeq\t.L%d\n",label); break; case LT: printf("\tblt\t.L%d\n",label); break; case GT: printf("\tbgt\t.L%d\n",label); break; default: error(-1); } if (reg!=-1) free_register(reg); } void code_opening(char *filename) { /* this is called once per file */ printf("@ Generated by mc for ARM/elf\n"); printf("\t.file \"%s\"\n",filename); // printf(".text\n"); } // should have pcond_const #define COND_BRANCH 1 #define COND_VALUE 2 #define COND_BRANCH_CONST 3 #define COND_VALUE_CONST 4 /* if (r1 cmp r2) goto l1 COND_BRANCH r0 = (r1 cmp r2) COND_VALUE */ static void pcond(int op, int r2,int r1,int r0,int cond,int l1,int mode) { char *rn2; char *rn1; char *rn0; char *cc=0,*ncc=0; if (mode==COND_BRANCH_CONST||mode==COND_VALUE_CONST) { rn1 = register_name(r1); if (r2>=0) printf("\tcmp\t%s, #%d\n",rn1,r2); else printf("\tcmn\t%s, #%d\n",rn1,-r2); } else { rn1 = register_name(r1); rn2 = register_name(r2); printf("\tcmp\t%s, %s\n",rn1,rn2); } switch(op+(!cond)*BNOT) { case GT: case LE+BNOT: cc="gt"; ncc="le"; break; case LE: case GT+BNOT: cc="le"; ncc="gt"; break; case GE: case LT+BNOT: cc="ge"; ncc="lt"; break; case LT: case GE+BNOT: cc="lt"; ncc="ge"; break; case UGT: case ULE+BNOT: cc="hi"; ncc="ls"; break; case ULE: case UGT+BNOT: cc="ls"; ncc="hi"; break; case UGE: case ULT+BNOT: cc="hs"; ncc="lo"; break; case ULT: case UGE+BNOT: cc="lo"; ncc="hs"; break; case EQ: case NEQ+BNOT: cc="eq"; ncc="ne"; break; case NEQ: case EQ+BNOT: cc="ne"; ncc="eq"; break; default: error(-1); } if (mode==COND_BRANCH||mode==COND_BRANCH_CONST) { printf("\tb%s\t.L%d\n",cc,l1); inc_inst(2); } else if (mode==COND_VALUE||mode==COND_VALUE_CONST) { rn0 = register_name(r0); printf("\tmov%s\t%s, #0\n",ncc,rn0); printf("\tmov%s\t%s, #1\n",cc,rn0); inc_inst(3); } else error(-1); } int rexpr_bool(int e1, int reg) { int e2,reg0; int op = car(e1); if (!( op== GT || op== LT || op== UGT || op== ULT || op== ULE || op== UGE || op== LE || op== GE || op== EQ || op== NEQ )) return 0; if (car(caddr(e1))==CONST && is_stage1_const(cadr(caddr(e1)),CMP)) { g_expr(cadr(e1)); reg0 = ireg; use_int(reg); pcond(op, cadr(caddr(e1)),reg0,reg,1,0,COND_VALUE_CONST); } else { g_expr(cadr(e1)); emit_push(); g_expr(caddr(e1)); e2 = emit_pop(1); reg0 = ireg; use_int(reg); pcond(op, reg0,e2,reg,1,0,COND_VALUE); emit_pop_free(e2); } return 1; } int rexpr(int e1, int l1, int cond,int t) { int e2; int op = car(e1); if (car(caddr(e1))==CONST && is_stage1_const(cadr(caddr(e1)),CMP)) { g_expr(cadr(e1)); pcond(op, cadr(caddr(e1)),ireg,0,cond,l1,COND_BRANCH_CONST); } else { g_expr(cadr(e1)); emit_push(); g_expr(caddr(e1)); e2 = emit_pop(1); pcond(op, ireg,e2,0,cond,l1,COND_BRANCH); emit_pop_free(e2); } return l1; } #define CMP_C1T (-1) static void jcond(int l, int cond) { inc_inst(1); printf("\tb%s\t.L%d\n",cond?"ne":"eq",l); } void jmp(int l) { printf("\tb\t.L%d\n",l); if (inst_count>CONST_TBL_COUNT/2) { const_list_table(); } else inc_inst(1); } void code_comment(char *s) { printf("## %s",s); } static int code_register_save(int reg_save,int freg_save,int disp) { int i; inc_inst(1); printf("\tstmfd\tsp!, {"); for (i=reg_var_num(0);i<reg_var_num(reg_save);i++) { printf("%s, ",register_name(i)); } printf("fp, ip, lr, pc}\n"); if (freg_save>0) { inc_inst(1); printf("\tsfmfd\tf4, %d, [sp]!\n",freg_save); } return disp; } static int code_register_restore(int reg_save,int freg_save,int disp) { int i; if (freg_save>0) { i=reg_save*SIZE_OF_INT+ freg_save*SIZE_OF_DOUBLE + 20; printf("\tlfm\tf4, %d, [fp, #%d]\n",freg_save,-i); inc_inst(1); } inc_inst(1); printf("\tldmea\tfp, {"); for (i=reg_var_num(0);i<reg_var_num(reg_save);i++) { printf("%s, ",register_name(i)); } printf("fp, sp, pc}\n"); return disp; } static int entry_label; void code_enter(char *name) { if (output_mode!=TEXT_EMIT_MODE) text_mode(3); else printf("\t.align 3\n"); if (stmode!=STATIC) printf("\t.globl\t%s\n",name); printf("\t.type\t%s,function\n",name); r1_offset_label = fwdlabel(); max_func_args = 0; printf("%s:\n",name); code_label_value(r1_offset_label,REG_ip); printf("\tadd\tsp, ip, fp\n"); clear_ptr_cache(); } void code_enter1(int args) { // set_lreg(LREG_LREGISTER,0); set_ireg(CREG_REGISTER,0); set_freg(FREG_FREGISTER,0); } void code_leave(char *name) { code_offset_set(fnptr); local_table(); printf("\t.size\t%s,.L%d-%s\n",name, backdef(),name); } void enter(char *name) { if (output_mode!=TEXT_EMIT_MODE) text_mode(2); else printf("\t.align 2\n"); max_func_args = 0; lvar_offset_label = fwdlabel(); // r1_offset_label = fwdlabel(); printf("\t.type\t%s,function\n",name); if (stmode!=STATIC) printf("\t.globl\t%s\n",name); printf("%s:\n",name); printf("\tmov\tip, sp\n"); gen_jmp(entry_label = fwdlabel()); register_save_return_label = backdef(); clear_ptr_cache(); } void enter1() { text_mode(0); // set_lreg(LREG_LREGISTER,0); set_ireg(CREG_REGISTER,0); set_freg(FREG_FREGISTER,0); } void code_label_call(int l) { printf("\tbl\tL_%d\n",l); } void code_ret() { printf("\tmov\tpc, lr\n"); control=0; } static void make_return_continuation() { fwddef(retcont); if (cadr(fnptr->ty)==FLOAT) { #if FLOAT_CODE creg = freg = cadr(get_input_dregister_var(0,0,1,0)); set_freg(RET_FREGISTER,1); #endif printf("\tmov\t%s, %s\n",register_name( cadr(get_input_register_var(1,0,0)) ),register_name(REG_fp)); } else if (cadr(fnptr->ty)==DOUBLE) { #if FLOAT_CODE creg = lreg = cadr(get_input_dregister_var(0,0,1,1)); set_dreg(RET_DREGISTER,1); printf("\tmov\t%s, %s\n",register_name( cadr(get_input_register_var(2,0,0)) ),register_name(REG_fp)); #endif } else if (cadr(fnptr->ty)>0&&( car(cadr(fnptr->ty))==STRUCT || car(cadr(fnptr->ty))==UNION)) { int sz = size(cadr(fnptr->ty)); inc_inst(3); code_const(sz,REGISTER_OPERAND); printf("\tsub\tr1, r2, fp\n"); printf("\tldr\tr0, [fp, #%d]\n",(my_func_args-1)*SIZE_OF_INT); printf("\tmov\t%s, %s\n",register_name( cadr(get_input_register_var(1,0,0)) ),register_name(REG_fp)); // emit_copy(6,3,sz,0,1,1); } else if (cadr(fnptr->ty)!=VOID) { creg = ireg = cadr(get_input_register_var(0,0,1)); if (creg!=RET_REGISTER) set_ireg(RET_REGISTER,1); printf("\tmov\t%s, %s\n",register_name( cadr(get_input_register_var(1,0,1)) ),register_name(REG_fp)); } 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_freg_var,0); // leave part end // entry part (save register) fwddef(entry_label); if (arg_on_register>0) printf("\tsub\tsp, sp, #%d\n",arg_on_register); code_register_save(max_reg_var,max_freg_var,0); printf("\tsub\tfp, ip, #%d\n",4+arg_on_register); code_add(REG_sp,disp-max_func_args*SIZE_OF_INT,REG_sp); gen_jmp(register_save_return_label); local_table(); printf("\t.size\t%s,.L%d-%s\n",name, backdef(),name); free_all_register(); } int code_set_return_register(int mode) { if (cadr(fnptr->ty)==FLOAT) { set_freg(RET_FREGISTER,mode); return freg; } else if (cadr(fnptr->ty)==DOUBLE) { #if FLOAT_CODE set_dreg(RET_DREGISTER,mode); return freg; #endif } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) { #if LONGLONG_CODE set_lreg(RET_LREGISTER,mode); return lreg; #endif } else if (cadr(fnptr->ty)==VOID) { return 0; } else { set_ireg(RET_REGISTER,mode); return ireg; } } int code_get_fixed_creg(int reg,int type) { switch(type) { #if FLOAT_CODE case DOUBLE: use_float(1,reg); break; case FLOAT: use_float(0,reg); break; #endif #if LONGLONG_CODE case LONGLONG: case ULONGLONG: use_longlong(reg); break; #endif default: if (reg==USE_CREG) { if (regs[CREG_REGISTER]==0||regs[CREG_REGISTER]==PTRC_REG) { set_ireg(CREG_REGISTER,is_int_reg(creg)&®s[creg]==USING_REG); return CREG_REGISTER; } } use_int(reg); break; } return reg; } void code_set_fixed_creg(int reg,int mode,int type) { if (type==FLOAT) { #if FLOAT_CODE set_freg(reg,mode); #endif } else if (type==DOUBLE) { #if FLOAT_CODE set_dreg(reg,mode); #endif } else if (type==LONGLONG||type==ULONGLONG) { #if LONGLONG_CODE set_lreg(reg,mode); // use_reg(reg); #endif } else { set_ireg(reg,mode); } } void gen_gdecl(char *n, int gpc) { /* if (stmode!=STATIC) printf(".globl %s\n",n); */ } void 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(".L%d:\n",lb); return lb; } extern void emit_string(char *s,int t,int len) { t = type_value(t); if (car(t)==ARRAY && (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { ascii(s,len); } else { int l = emit_string_label(); ascii(s,len); emit_label(l); } return; } 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 .L%d\n",labelno); } void emit_data_closing(NMTBL *n) { #ifdef DOT_SIZE int lb; #endif if (mode==GDECL) { data_mode(0); #ifdef DOT_SIZE lb=fwdlabel(); printf(".L%d:\n",lb); printf("\t.size\t%s,.L%d-%s\n",n->nm,lb,n->nm); #endif } } static void comm(NMTBL *n) { printf(".comm %s,%d @ %d\n",n->nm,size(n->ty), (n->ty==DOUBLE||n->ty==LONGLONG||n->ty==ULONGLONG)?8:4 ); } void global_table(void) { NMTBL *n; int init; init=0; for(n=global_list;n;n=n->next) { if ((n->sc == GVAR) && n->dsp != -1) { /* n->dsp = -1 means initialized global */ if (init==0) { data_mode(0); init=1; } comm(n); } else if ((n->sc==STATIC) && n->dsp != -1) { /* n->dsp = -1 means initialized global */ if (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); inc_inst(1); printf("\tbl\t%s\n",conv); lib_args(16); } #endif static void code_int_lib(char *lib,int reg,int oreg) { int g; code_save_stacks(); clear_ptr_cache(); g = list3(REGISTER_OPERAND,0,reg); g = list3(REGISTER_OPERAND_1,g,oreg); parallel_rassign(g); extern_define(lib,0,FUNCTION,1); inc_inst(1); printf("\tbl\t%s\n",lib); lib_args(16); set_ireg(RET_REGISTER,0); if (reg!=RET_REGISTER) { code_register(RET_REGISTER,reg); } } #if FLOAT_CODE /* floating point */ #define set_double(freg) if (regs[freg]) {regs[freg]=USING_DREG;} #define set_float(freg) if (regs[freg]) {regs[freg]=USING_DREG;} void code_cmp_dregister(int e2,int d,int label,int cond) { char *frn; use_float(d,e2); inc_inst(2); if (!(arch_mode&UseFPP)) { code_save_stacks(); clear_ptr_cache(); if (d) { set_dreg(DREGISTER_OPERAND,0); dconst(DREGISTER_OPERAND_1_L,DREGISTER_OPERAND_1_H,0.0); extern_conv("__nedf2"); printf("\tcmp\tr0, #0\n"); } else { set_freg(FREGISTER_OPERAND,0); printf("\tmov\t%s, #0\n", register_name(REGISTER_OPERAND)); // fconst(REGISTER_OPERAND,0.0); extern_conv("__nesf2"); printf("\tcmp\tr0, #0\n"); } } else { frn = register_name(e2); printf("\tcmf\t%s, #0\n",frn); } jcond(label,cond); return; } static char * movef(int d) { return d?"mvfd":"mvfs"; } static char * fload(int d) { return d?"ldfd":"ldfs"; } static char * fstore(int d) { return d?"stfd":"stfs"; } void code_dregister(int e2,int freg,int d) { use_float(d,freg); if (!(arch_mode&UseFPP)) { if (d) { code_lregister(e2,freg); set_double(freg); return; } else { code_register(e2,freg); set_float(freg); return; } } else { if (freg!=e2) { if (is_int_reg(e2)) error(-1); inc_inst(1); printf("\t%s\t%s, %s\n",movef(d), fregister_name(freg),fregister_name(e2)); } } } void code_dassign_gvar(int e2,int freg,int d) { if (!(arch_mode&UseFPP)) { if (d) { code_lassign_gvar(e2,freg); set_double(freg); return; } else { code_assign_gvar(e2,freg,0); set_float(freg); return; } } else { use_float(d,freg); code_ldf(fstore(d),fregister_name(freg),cadr(e2), get_ptr_cache(ncaddr(e2))," @ float"); } } void code_dassign_lvar(int e2,int freg,int d) { if (!(arch_mode&UseFPP)) { if (d) { code_lassign_lvar(e2,freg); set_double(freg); return; } else { code_assign_lvar(e2,freg,0); set_float(freg); return; } } else { use_float(d,freg); lvar_intro(e2); inc_inst(1); printf("\t%s\t%s, ",fstore(d),fregister_name(freg)); lvar(e2,"@ float"); } } void code_dassign(int e2,int freg,int d) { if (!(arch_mode&UseFPP)) { if (d) { code_lassign(e2,freg); set_double(freg); return; } else { code_assign(e2,freg,0); set_float(freg); return; } } use_float(d,freg); inc_inst(1); printf("\t%s\t%s, [%s, #0] @ float\n",fstore(d), fregister_name(freg),register_name(e2)); } void code_dassign_dregister(int e2,int d,int freg) { if (!(arch_mode&UseFPP)) { if (d) { code_lassign_lregister(e2,freg); set_double(freg); return; } else { code_assign_register(e2,0,freg); set_float(freg); return; } } use_float(d,freg); if (e2!=freg) { inc_inst(1); printf("\t%s\t%s, %s\n",movef(d), fregister_name(e2),fregister_name(freg)); } } static double d0 = 1.0; int code_d1(double d) { int *i = (int *)&d0; int *j = (int *)&d; return (i[1] == 0x3ff00000)?j[0]:j[1]; } int code_d2(double d) { int *i = (int *)&d0; int *j = (int *)&d; return (i[1] == 0x3ff00000)?j[1]:j[0]; } int code_f(double d) { float f = d; int *j = (int *)&f; return *j; } static void dconst(int l,int h,double value) { #if ENDIAN_D==0 code_const(code_d1(value),l); code_const(code_d2(value),h); #else code_const(code_d1(value),h); code_const(code_d2(value),l); #endif } static void fconst(int reg,double value) { float f = value; code_const(*((int*)&f),reg); } void code_dconst(int e2,int freg,int d) { double value = dcadr(e2); float f = value; char *frn; int label,disp; use_float(d,freg); if (!(arch_mode&UseFPP)) { if (d) { dconst(regv_l(freg),regv_h(freg),value); } else { code_const0(*((int*)&f),freg,"\t@ float"); } } else { frn = register_name(freg); inc_inst(1); if (value==0 || value==1 || value==10) { printf("\t%s\t%s, #%d\n",movef(d),frn,(int)value); } else if (value==-1 || value==-10) { printf("\t%s\t%s, #%d\n",d?"mnfd":"mnfs",frn,(int)-value); } else if (d) { #if ENDIAN_D==0 disp = search_double_const(DCONST, code_d1(value),code_d2(value),&label); #else disp = search_double_const(DCONST, code_d2(value),code_d1(value),&label); #endif printf("\tldfd\t%s, .L%d+%d\n",frn,label,disp); } else { disp = search_const(CONST,*((int*)&f),&label); printf("\tldfs\t%s, .L%d+%d\n",frn,label,disp); } } } void code_builtin_fabsf(int e) { } void code_builtin_fabs(int e) { } void code_builtin_inff() { } void code_builtin_inf(int op) { } void code_dneg(int freg,int d) { char *frn; use_float(d,freg); if (!(arch_mode&UseFPP)) { if (d) { code_save_stacks(); clear_ptr_cache(); set_dreg(DREGISTER_OPERAND_1,1); extern_conv("__negdf2"); set_dreg(RET_DREGISTER,0); return; } else { code_save_stacks(); clear_ptr_cache(); set_dreg(FREGISTER_OPERAND,1); extern_conv("__negsf2"); set_dreg(RET_FREGISTER,0); return; } } else { frn = fregister_name(freg); inc_inst(1); printf("\t%s\t%s, %s\n",d?"mnfd":"mnfs",frn,frn); } } void code_d2i0(int reg,int d) { int lreg; if (!(arch_mode&UseFPP)) { use_float(d,reg); code_save_stacks(); clear_ptr_cache(); set_dreg(d?DREGISTER_OPERAND:FREGISTER_OPERAND,1); extern_conv(d?"__fixdfsi":"__fixsfsi"); set_ireg(RET_REGISTER,0); } else { use_float(d,reg); lreg = get_register(); inc_inst(1); 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; if (!(arch_mode&UseFPP)) { set_ireg(REGISTER_OPERAND,1); code_save_stacks(); clear_ptr_cache(); extern_conv(d?"__floatsidf":"__floatsisf"); set_dreg(d?RET_DREGISTER:RET_FREGISTER,0); use_float(d,reg); } else { use_int(reg); lreg = get_dregister(1); inc_inst(1); printf("\tflt%c\t%s, %s\n",dsuffix(d), register_name(lreg),register_name(reg)); set_dreg(lreg,0); } return; } void code_d2u0(int reg,int d) { int lreg,reg0; char *lrn,*frn,*crn; if (!(arch_mode&UseFPP)) { use_float(1,reg); code_save_stacks(); clear_ptr_cache(); set_dreg(d?DREGISTER_OPERAND:FREGISTER_OPERAND,1); extern_conv(d?"__fixunsdfsi":"__fixunssfsi"); set_ireg(RET_REGISTER,0); } else { // u = (d>2.1e9)?((int)(d-2.1e9)^2147483648):(int)d inc_inst(7); use_float(1,reg); frn = register_name(reg); if (!d) printf("\tmvfd\t%s, %s\n",frn,frn); emit_dpush(1); code_dconst(dlist2(DCONST,2.147483648e9),USE_CREG,1); lrn = register_name(lreg = emit_dpop(d)); frn = register_name(freg); set_ireg(reg0=get_register(),0); crn = register_name(reg0); printf("\tcmfe\t%s, %s\n",lrn,frn); printf("\tbge\t1f\n"); printf("\tfixz\t%s, %s\n",crn,lrn); printf("\tb\t2f\n"); printf("1:\n"); printf("\tsufd\t%s, %s, %s\n",lrn,lrn,frn); printf("\tfixz\t%s, %s\n",crn,lrn); printf("\teor\t%s, %s, #-2147483648\n",crn,crn); printf("2:\n"); emit_dpop_free(lreg,d); } return; } void code_u2d0(int reg,int d) { int tmp,freg1; char *crn,*frn,*lrn; if (!(arch_mode&UseFPP)) { tmp=new_lvar(SIZE_OF_INT); set_ireg(REGISTER_OPERAND,1); code_assign_lvar(tmp,REGISTER_OPERAND,0); code_save_stacks(); clear_ptr_cache(); extern_conv(d?"__floatsidf":"__floatsisf"); code_rlvar(tmp,REGISTER_OPERAND); inc_inst(2); printf("\tcmp\t%s, #0\n",register_name(REGISTER_OPERAND)); printf("\tbge\t1f\n"); if (d) code_double_lib_c("__adddf3",RET_DREGISTER,RET_DREGISTER,4.29496729600000000000e9); else code_double_lib_c("__addsf3",RET_FREGISTER,RET_FREGISTER,4.29496729600000000000e9); printf("1:\n"); set_dreg(d?RET_DREGISTER:RET_FREGISTER,0); if (reg!=USE_CREG) { use_float(d,reg); if (d) { if (reg!=RET_DREGISTER) { lmove(reg,RET_DREGISTER); } } else { if (reg!=RET_FREGISTER) { code_register(reg,RET_FREGISTER); } } } free_lvar(tmp); } else { use_int(reg); crn = register_name(reg); set_dreg(reg=get_dregister(1),0); frn = register_name(reg); inc_inst(5); printf("\tfltd\t%s, %s\n",frn,crn); printf("\tcmp\t%s, #0\n",crn); printf("\tbge\t1f\n"); freg1 = get_dregister(1); code_dconst(dlist2(DCONST,4.29496729600000000000e9),freg1,1); frn = register_name(creg); lrn = register_name(freg1); printf("\tadfd\t%s, %s, %s\n",frn,frn,lrn); printf("1:\n"); if (!d) printf("\tmvfs\t%s, %s\n",frn,frn); free_register(freg1); } return; } void code_d2f(int reg) { char *frn; if (!(arch_mode&UseFPP)) { set_dreg(DREGISTER_OPERAND,1); code_save_stacks(); clear_ptr_cache(); extern_conv("__truncdfsf2"); set_freg(RET_FREGISTER,0); use_float(0,reg); } else { frn = register_name(freg); inc_inst(1); printf("\tmvfs\t%s,%s\n",frn,frn); } return; } void code_f2d(int reg) { char *frn; if (!(arch_mode&UseFPP)) { set_freg(FREGISTER_OPERAND,1); code_save_stacks(); clear_ptr_cache(); extern_conv("__extendsfdf2"); set_dreg(RET_DREGISTER,0); use_float(1,reg); } else { frn = register_name(freg); inc_inst(1); printf("\tmvfd\t%s, %s\n",frn,frn); } return; } void code_d2i(int reg) { code_d2i0(reg,1); } void code_d2u(int reg) { code_d2u0(reg,1); } void code_f2i(int reg) { code_d2i0(reg,0); } void code_f2u(int reg) { code_d2u0(reg,0); } void code_i2d(int reg) { code_i2d0(reg,1); } void code_i2f(int reg) { code_i2d0(reg,0); } void code_u2d(int reg) { code_u2d0(reg,1); } void code_u2f(int reg) { code_u2d0(reg,0); } void code_drgvar(int e2,int d,int freg) { if (!(arch_mode&UseFPP)) { if (d) { code_lrgvar(e2,freg); set_double(freg); return; } else { code_rgvar(e2,freg); set_float(freg); return; } } else { use_float(d,freg); code_ldf(fload(d),fregister_name(freg),cadr(e2), get_ptr_cache(ncaddr(e2)),""); } } void code_drlvar(int e2,int d,int freg) { if (!(arch_mode&UseFPP)) { if (d) { code_lrlvar(e2,freg); set_double(freg); return; } else { code_rlvar(e2,freg); set_float(freg); return; } } else { use_float(d,freg); lvar_intro(e2); inc_inst(1); printf("\t%s\t%s, ",fload(d),fregister_name(freg)); lvar(e2,d?"@ double":"@ float"); } } void code_cmp_drgvar(int e2,int reg,int d,int label,int cond) { use_float(d,reg); code_drgvar(e2,d,reg); code_cmp_dregister(reg,d,label,cond); } void code_cmp_drlvar(int e2,int reg,int d,int label,int cond) { use_float(d,reg); code_drlvar(e2,d,reg); code_cmp_dregister(reg,d,label,cond); } static void code_double_lib(char *lib,int to,int reg,int oreg) { code_save_stacks(); clear_ptr_cache(); set_operands(regv_l(reg),regv_h(reg),regv_l(oreg),regv_h(oreg)); extern_conv(lib); set_dreg(RET_DREGISTER,0); if (to!=RET_DREGISTER) { lmove(to,RET_DREGISTER); } } static void code_double_lib_c(char *lib,int from,int to,double value) { code_save_stacks(); clear_ptr_cache(); set_dreg_operand(from,1); dconst(DREGISTER_OPERAND_1_L,DREGISTER_OPERAND_1_H,value); extern_conv(lib); set_dreg(RET_DREGISTER,0); if (to!=RET_DREGISTER) { lmove(to,RET_DREGISTER); } } static void code_float_lib(char *lib,int to,int reg,int oreg) { code_save_stacks(); clear_ptr_cache(); if (reg!=FREGISTER_OPERAND) code_dregister(FREGISTER_OPERAND,reg,0); if (to!=FREGISTER_OPERAND_1) code_dregister(FREGISTER_OPERAND_1,to,0); extern_conv(lib); set_freg(RET_FREGISTER,0); if (to!=RET_FREGISTER) { code_dregister(to,RET_FREGISTER,0); } } static void code_float_lib_c(char *lib,int from,int to,double value) { code_save_stacks(); clear_ptr_cache(); set_dreg_operand(from,1); fconst(FREGISTER_OPERAND_1,value); extern_conv(lib); set_freg(RET_FREGISTER,0); if (to!=RET_FREGISTER) { code_dregister(to,RET_FREGISTER,0); } } void dtosop_d(int op,int reg,int e1) { char *opc=""; int d,reg0=reg; d=(op<FOP); use_float(d,reg); switch(op) { case DADD: opc="__adddf3"; break; case DSUB: opc="__subdf3"; break; case DDIV: opc="__divdf3"; break; case DMUL: opc="__muldf3"; break; case DCMPGE: opc="__gedf2"; break; case DCMP: opc="__gtdf2"; break; case FADD: opc="__addsf3"; break; case FSUB: opc="__subsf3"; break; case FDIV: opc="__divsf3"; break; case FMUL: opc="__mulsf3"; break; case FCMPGE: opc="__gesf2"; break; case FCMP: opc="__gtsf2"; break; default: error(-1); return; } if (d) code_double_lib(opc,reg0==USE_CREG?RET_DREGISTER:reg,reg,e1); else code_float_lib(opc,reg0==USE_CREG?RET_FREGISTER:reg,reg,e1); } void dtosop_f(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 = fregister_name(e1); frn = fregister_name(reg); inc_inst(1); 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 dtosop(int op,int reg,int e1) { if (!(arch_mode&UseFPP)) dtosop_d(op,reg,e1); else dtosop_f(op,reg,e1); } void code_dassop_d(int op,int reg,int d) { /* we have lvalue in creg, applied floating value is in freg */ // (*creg) op = pop() int xreg; int edx,edx0=-1; int reg0=reg; xreg = d?emit_lpop(0):emit_pop(0); /* pop e3 value */ if (!is_int_reg(creg)) error(-1); edx = ireg; emit_push(); use_float(d,reg); if (d) { if (regv_l(lreg)==edx || regv_h(lreg)==edx) { edx0 = get_register(); if(!edx0) error(-1); inc_inst(1); printf("## dassop\n\tmov\t%s, %s\n", register_name(edx0),register_name(edx)); edx = edx0; } lload(edx,reg,0); dtosop(op,USE_CREG,xreg); if (lreg!=RET_DREGISTER) error(-1); use_reg(lreg); edx = emit_pop(0); code_lassign(edx,RET_DREGISTER); if (edx0!=-1) free_register(edx0); emit_pop_free(edx); emit_lpop_free(xreg); if (reg0!=USE_CREG && reg!=RET_DREGISTER) lmove(reg,RET_DREGISTER); set_double(reg); } else { if (freg==edx) { edx0 = get_register(); if(!edx0) error(-1); inc_inst(1); printf("# dassop\n\tmov\t%s, %s\n", register_name(edx0),register_name(edx)); edx = edx0; } code_rindirect(edx,reg,0,0,0); dtosop(op,USE_CREG,xreg); use_reg(freg); edx = emit_pop(0); code_assign(edx,0,RET_FREGISTER); if (edx0!=-1) free_register(edx0); emit_pop_free(edx); emit_pop_free(xreg); if (reg0!=USE_CREG && reg!=RET_DREGISTER) code_register(RET_DREGISTER,reg); set_float(reg); } } void code_dassop_f(int op,int reg,int d) { /* we have lvalue in creg, applied floating value is in freg */ // (*creg) op = pop() int xreg; char *crn; char *frn; xreg=emit_dpop(d); crn=register_name(ireg); use_float(d,reg); frn =fregister_name(reg); code_ldf(fload(d),fregister_name(freg),0,ireg,""); dtosop(op,reg,xreg); code_ldf(fstore(d),fregister_name(freg),0,ireg,""); emit_dpop_free(xreg,d); } void code_dassop(int op,int reg,int d) { if (!(arch_mode&UseFPP)) code_dassop_d(op,reg,d); else code_dassop_f(op,reg,d); } void code_register_dassop(int reg,int op,int d) { // reg op= dpop() int xreg; if (!(arch_mode&UseFPP)) { if (!d) { xreg=emit_pop(0); dtosop(op,reg,xreg); emit_pop_free(xreg); } else { xreg=emit_lpop(); dtosop(op,reg,xreg); emit_lpop_free(xreg); set_double(lreg); } } else { 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); if (!(arch_mode&UseFPP)) { error(-1); } inc_inst(1); printf("\tmvf%c\t%s,#1\n",dsuffix(d),fregister_name(g)); return g; } void code_dpreinc_d(int e1,int e2,int d,int reg) { int xreg; int dir=caddr(e1); if (!d) { if (car(e2)==FREGISTER) { use_float(d,reg); code_save_stacks(); code_float_lib_c("__addsf3",cadr(e2),cadr(e2),dir); if (reg!=cadr(e2)) code_register(cadr(e2),reg); return; } g_expr(e2); if(!is_int_reg(creg)) error(-1); xreg = ireg; emit_push(); code_save_stacks(); code_rindirect(xreg,FREGISTER_OPERAND,0,0,0); code_double_lib_c("__addsf3",DREGISTER_OPERAND,RET_DREGISTER,dir); xreg = emit_pop(0); code_assign_register(xreg,0,RET_DREGISTER); if (use) { if (reg==USE_CREG) set_freg(RET_FREGISTER,0); else code_register(RET_DREGISTER,reg); } emit_pop_free(xreg); } else { if (car(e2)==DREGISTER) { use_float(d,reg); code_save_stacks(); code_double_lib_c("__adddf3",cadr(e2),cadr(e2),dir); if (reg!=cadr(e2)) lmove(reg,cadr(e2)); return; } g_expr(e2); if(!is_int_reg(creg)) error(-1); xreg = ireg; emit_push(); code_save_stacks(); lload(xreg,DREGISTER_OPERAND,0); code_float_lib_c("__adddf3",DREGISTER_OPERAND,RET_DREGISTER,dir); xreg = emit_pop(0); lstore(xreg,RET_DREGISTER); if (use) { if (reg==USE_CREG) set_dreg(RET_DREGISTER,0); else lmove(reg,RET_DREGISTER); } emit_pop_free(xreg); } } void code_dpostinc_d(int e1,int e2,int d,int reg) { int g,xreg; int dir=caddr(e1); if (!d) { if (car(e2)==FREGISTER) { xreg = cadr(e2); code_float_lib_c("__addsf3",xreg,RET_DREGISTER,dir); // xreg は increment する // USE_CREG だと increment する前の値を creg にセット // reg が指定されていれば、それに前の値をセット if (reg==USE_CREG) { use_float(d,reg); if (reg==RET_FREGISTER) { reg = get_dregister(d); } set_freg(reg,0); } g = list3(reg,0,xreg); g = list3(xreg,g,RET_FREGISTER); parallel_rassign(g); return; } g_expr(e2); if(!is_int_reg(creg)) error(-1); xreg = ireg; emit_push(); code_save_stacks(); use_float(0,reg); code_rindirect(xreg,FREGISTER_OPERAND,0,0,0); code_float_lib_c("__addsf3",DREGISTER_OPERAND,RET_DREGISTER,dir); xreg = emit_pop(0); emit_push(); if (use) { use_longlong(reg); code_rindirect(xreg,reg,0,0,0); } reg = emit_lpop(); code_assign_register(xreg,0,reg); emit_pop_free(reg); emit_pop_free(xreg); } else { if (car(e2)==DREGISTER) { xreg = cadr(e2); code_double_lib_c("__adddf3",xreg,RET_DREGISTER,dir); // xreg は increment する // USE_CREG だと increment する前の値を creg にセット // reg が指定されていれば、それに前の値をセット if (reg==USE_CREG) { use_float(d,reg); if (reg==RET_DREGISTER) { reg = get_dregister(d); } set_dreg(reg,0); } g = list3(regv_l(reg),0,regv_l(xreg)); g = list3(regv_h(reg),g,regv_h(xreg)); g = list3(regv_l(xreg),g,regv_l(RET_DREGISTER)); g = list3(regv_h(xreg),g,regv_h(RET_DREGISTER)); parallel_rassign(g); return; } g_expr(e2); if(!is_int_reg(creg)) error(-1); xreg = ireg; emit_push(); code_save_stacks(); use_float(1,reg); lload(xreg,DREGISTER_OPERAND,0); code_double_lib_c("__adddf3",DREGISTER_OPERAND,RET_DREGISTER,dir); xreg = emit_pop(0); emit_lpush(); if (use) { use_longlong(reg); lload(xreg,reg,0); } reg = emit_lpop(); lstore(xreg,reg); emit_lpop_free(reg); emit_pop_free(xreg); } } void code_dpreinc_f(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=fregister_name(g=code_dload_1(d)); if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); if (d) set_dreg(reg,0); else set_freg(reg,0); } frn=fregister_name(reg); inc_inst(1); printf("\t%s%c\t%s, %s, %s\n", dir>0?"adf":"suf",dsuffix(d), crn,crn,grn); if (use && reg!=cadr(e2)) { inc_inst(1); printf("\tmvf%c\t%s, %s\n",dsuffix(d),frn,crn); } } else { g_expr(e2); if (!is_int_reg(creg)) error(-1); reg0 = ireg; if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); if (d) set_dreg(reg,0); else set_freg(reg,0); } grn = fregister_name(g = code_dload_1(d)); frn=fregister_name(reg); code_ldf(fload(d),frn,0,reg0,""); inc_inst(1); printf("\t%s%c\t%s, %s, %s\n", dir>0?"adf":"suf",dsuffix(d), frn,frn,grn); code_ldf(fstore(d),frn,0,reg0,""); } free_register(g); } void code_dpostinc_f(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=fregister_name(g=code_dload_1(d)); if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); set_freg(reg,0); } frn=fregister_name(reg); if (use && reg!=cadr(e2)) { inc_inst(1); printf("\tmvf%c\t%s, %s\n",dsuffix(d),frn,crn); } inc_inst(1); printf("\t%s%c\t%s,%s,%s\n",dir>0?"adf":"suf", dsuffix(d),crn,crn,grn); } else { g_expr(e2); if (!is_int_reg(creg)) error(-1); crn=register_name(reg0=ireg); if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); set_freg(reg,0); } frn=fregister_name(reg); grn = fregister_name(g = code_dload_1(d)); code_ldf(fload(d),frn,0,reg0,""); inc_inst(1); printf("\t%s%c\t%s, %s, %s\n", dir>0?"adf":"suf",dsuffix(d), grn,frn,grn); code_ldf(fstore(d),grn,0,reg0,""); } free_register(g); } void code_dpreinc(int e1,int e2,int d,int reg) { if (!(arch_mode&UseFPP)) code_dpreinc_d(e1,e2,d,reg); else code_dpreinc_f(e1,e2,d,reg); } void code_dpostinc(int e1,int e2,int d,int reg) { if (!(arch_mode&UseFPP)) code_dpostinc_d(e1,e2,d,reg); else code_dpostinc_f(e1,e2,d,reg); } int drexpr(int e1, int e2,int l1, int op,int cond) { int op1=0; char *opn=0; if (!cond) { switch(op) { case FOP+GT: return drexpr(e2,e1,l1,FOP+GE,1); case FOP+GE: return drexpr(e2,e1,l1,FOP+GT,1); case FOP+EQ: op=FOP+NEQ; break; case FOP+NEQ: op=FOP+EQ; break; case DOP+GT: return drexpr(e2,e1,l1,DOP+GE,1); case DOP+GE: return drexpr(e2,e1,l1,DOP+GT,1); case DOP+EQ: op=DOP+NEQ; break; case DOP+NEQ: op=DOP+EQ; break; } } switch(op) { case FOP+GT: op1=FOP+CMP; opn = "bgt"; break; case FOP+GE: op1=FOP+CMPGE; opn = "bge"; break; case FOP+EQ: op1=FOP+CMP; opn = "beq"; break; case FOP+NEQ: op1=FOP+CMP; opn = "bne"; break; case DOP+GT: op1=DOP+CMP; opn = "bgt"; break; case DOP+GE: op1=DOP+CMPGE; opn = "bge"; break; case DOP+EQ: op1=DOP+CMP; opn = "beq"; break; case DOP+NEQ: op1=DOP+CMP; opn = "bne"; break; default: error(-1); } g_expr(list3(op1,e2,e1)); inc_inst(1); printf("\t%s\t.L%d\n",opn,l1); return l1; } int emit_dpop(int d) { int xreg,reg; if (!(arch_mode&UseFPP)) { return emit_lpop(); } xreg=pop_fregister(); if (xreg<= -REG_LVAR_OFFSET) { reg = get_dregister(d); code_drlvar(REG_LVAR_OFFSET+xreg,1,reg); free_lvar(REG_LVAR_OFFSET+xreg); xreg=reg; } return xreg; } void emit_dpop_free(int e1,int d) { free_register(e1); } void emit_dpush(int d) { int new_reg; if (!(arch_mode&UseFPP)) { emit_lpush(); return; } if (!is_float_reg(creg)) error(-1); if (freg_sp>MAX_MAX) error(-1); new_reg = get_dregister(d); /* 絶対に取れる */ freg_stack[freg_sp++] = freg; /* push するかわりにレジスタを使う */ creg = freg = new_reg; } #endif #if LONGLONG_CODE /* 64bit int part */ int lrexpr_bool(int e1, int reg) { return 0; } int lrexpr(int e1, int e2,int l1, int op,int cond) { int reg,regh,regl,e3h,e3l; int e3,l2; g_expr(e1); emit_lpush(); g_expr(e2); e3 = emit_lpop(); if (!is_longlong_reg(creg)) error(-1); reg = lreg; l2 = fwdlabel(); regh = regv_h(reg); regl = regv_l(reg); e3h = regv_h(e3); e3l = regv_l(e3); switch(op) { case LOP+GT: case LOP+GE: pcond(GT, 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); inc_inst(1); printf("\torr\t%s, %s, %s\n", lregister_name_low(reg), lregister_name_low(reg), lregister_name_high(reg)); code_cmp_register(regv_l(reg),label,cond); } void code_cmp_lrgvar(int e1,int creg,int label,int cond) { use_longlong(creg); code_lrgvar(e1,creg); code_cmp_lregister(creg,label,cond); } void code_cmp_lrlvar(int e1,int creg,int label,int cond) { use_longlong(creg); code_lrlvar(e1,creg); code_cmp_lregister(creg,label,cond); } #endif #if LONGLONG_CODE||FLOAT_CODE int emit_lpop() { int xreg,reg; xreg=lreg_stack[--lreg_sp]; if (xreg<= -REG_LVAR_OFFSET) { reg = get_lregister(); code_lrlvar(REG_LVAR_OFFSET+xreg,reg); free_lvar(REG_LVAR_OFFSET+xreg); xreg = reg; } return xreg; } void code_lregister(int e2,int reg) { use_longlong(reg); if (reg!=e2) { lmove(reg,e2); } } void code_lassign(int e2,int creg) { use_longlong(creg); lstore(e2,creg); } void code_lassign_gvar(int e2,int creg) { int r; use_longlong(creg); r = get_ptr_cache(ncaddr(e2)); #if ENDIAN_L==0 code_ldf(cstore(0),lregister_name_low(creg),cadr(e2),r,""); code_ldf(cstore(0),lregister_name_high(creg),cadr(e2)+SIZE_OF_INT,r,""); #else code_ldf(cstore(0),lregister_name_high(creg),cadr(e2),r,""); code_ldf(cstore(0),lregister_name_low(creg),cadr(e2)+SIZE_OF_INT,r,""); #endif } void code_lassign_lvar(int e2,int creg) { char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); lvar_intro(e2); inc_inst(2); #if ENDIAN_L==0 printf("\tstr\t%s, ",crn_l);lvar(e2,""); printf("\tstr\t%s, ",crn_h);lvar(e2+SIZE_OF_INT,""); #else printf("\tstr\t%s, ",crn_h);lvar(e2,""); printf("\tstr\t%s, ",crn_l);lvar(e2+SIZE_OF_INT,""); #endif } void code_lassign_lregister(int e2,int reg) { use_longlong(reg); if (e2!=reg) { lmove(e2,reg); } } void emit_lpop_free(int xreg) { if (xreg>=0) free_register(xreg); } void emit_lpush() { int new_reg; if (!is_longlong_reg(creg)) error(-1); if (lreg_sp>MAX_MAX) error(-1); new_reg = get_lregister(); /* 絶対に取れる(?) */ lreg_stack[lreg_sp++] = creg; /* push するかわりにレジスタを使う */ lreg = creg = new_reg; } void code_lrgvar(int e1,int creg) { int r; char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); r = get_ptr_cache(ncaddr(e1)); #if ENDIAN_L==0 code_ldf("ldr",crn_l,cadr(e1),r,""); code_ldf("ldr",crn_h,cadr(e1)+SIZE_OF_INT,r,""); #else code_ldf("ldr",crn_h,cadr(e1),r,""); code_ldf("ldr",crn_l,cadr(e1)+SIZE_OF_INT,r,""); #endif } void code_lrlvar(int e1,int creg) { char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); inc_inst(2); lvar_intro(e1); printf("\tldr\t%s, ",crn_l); lvar(e1,""); printf("\tldr\t%s, ",crn_h); lvar(e1+SIZE_OF_INT,""); } #endif #if LONGLONG_CODE static long long ll0 = 1LL; static int code_l1(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[1]:j[0]; } static int code_l2(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[0]:j[1]; } void code_lconst(int e1,int creg) { use_longlong(creg); #if ENDIAN_L==0 code_const(code_l1(lcadr(e1)),regv_l(creg)); code_const(code_l2(lcadr(e1)),regv_h(creg)); #else code_const(code_l1(lcadr(e1)),regv_h(creg)); code_const(code_l2(lcadr(e1)),regv_l(creg)); #endif } void code_lneg(int creg) { char *rh,*rl; use_longlong(creg); rl=lregister_name_low(creg); rh=lregister_name_high(creg); inc_inst(2); printf("\trsbs\t%s, %s, #0\n",rl,rl); printf("\trsc\t%s, %s, #0\n",rh,rh); } static void code_longlong_lib(char *lib,int reg,int oreg) { code_save_stacks(); clear_ptr_cache(); set_operands(regv_l(reg),regv_h(reg),regv_l(oreg),regv_h(oreg)); extern_conv(lib); // set_lreg(RET_LREGISTER,0); } #define check_lreg(reg) lmove(reg,RET_LREGISTER) void ltosop(int op,int reg,int oreg) { int dx = -1; int ox = -1; char *orn_h,*crn_h; char *orn_l,*crn_l; // reg = reg op oreg use_longlong(reg); if(oreg==-1) { error(-1); } else if (oreg<= -REG_LVAR_OFFSET) { ox = get_lregister(); if (ox<0) error(-1); use_reg(ox); code_rlvar(oreg+REG_LVAR_OFFSET,ox); oreg = ox; } switch(op) { case LLSHIFT: case LULSHIFT: code_longlong_lib("__ashldi3",reg,oreg); check_lreg(reg); if(ox!=-1) free_register(ox); return; case LRSHIFT: code_longlong_lib("__ashrdi3",reg,oreg); check_lreg(reg); if(ox!=-1) free_register(ox); return; case LURSHIFT: code_longlong_lib("__lshrdi3",reg,oreg); check_lreg(reg); if(ox!=-1) free_register(ox); return; } orn_h = lregister_name_high(oreg); orn_l = lregister_name_low(oreg); crn_h = lregister_name_high(reg); crn_l = lregister_name_low(reg); switch(op) { case LADD: inc_inst(2); printf("\tadds\t%s, %s, %s\n",crn_l,crn_l,orn_l); printf("\tadc\t%s, %s, %s\n",crn_h,crn_h,orn_h); break; case LSUB: inc_inst(2); printf("\tsubs\t%s, %s, %s\n",crn_l,crn_l,orn_l); printf("\tsbc\t%s, %s, %s\n",crn_h,crn_h,orn_h); break; case LCMP: error(-1); break; case LBAND: inc_inst(2); printf("\tand\t%s, %s, %s\n",crn_l,crn_l,orn_l); printf("\tand\t%s, %s, %s\n",crn_h,crn_h,orn_h); break; case LEOR: inc_inst(2); printf("\teor\t%s, %s, %s\n",crn_l,crn_l,orn_l); printf("\teor\t%s, %s, %s\n",crn_h,crn_h,orn_h); break; case LBOR: inc_inst(2); printf("\torr\t%s, %s, %s\n",crn_l,crn_l,orn_l); printf("\torr\t%s, %s, %s\n",crn_h,crn_h,orn_h); break; case LMUL: case LUMUL: code_longlong_lib("__muldi3",reg,oreg); check_lreg(reg); break; case LDIV: code_longlong_lib("__divdi3",reg,oreg); check_lreg(reg); break; case LUDIV: code_longlong_lib("__udivdi3",reg,oreg); check_lreg(reg); break; case LMOD: code_longlong_lib("__moddi3",reg,oreg); check_lreg(reg); break; case LUMOD: code_longlong_lib("__umoddi3",reg,oreg); check_lreg(reg); break; default: error(-1); } if(ox!=-1) free_register(ox); if(dx!=-1) free_register(dx); } int code_lconst_op_p(int op,int e) { long long v; if (car(e)==LCONST) { v = lcadr(e); } else if (car(e)==CONST) { v = cadr(e); } else return 0; switch(op) { case LMUL: case LUMUL: /* case LDIV: */ case LUDIV: return ilog(v); case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: return 0<v&&v<=64; case LADD: case LSUB: case LBOR: case LEOR: case LBAND: return (is_stage1_const(v,0)>0) && (is_stage1_const(v>>32,0)>0); default: return 0; } } void loprtc(int op,int creg,int e) { char *crn_h; char *crn_l; char *grn; int v=0; int vh=0; int greg,dx=-1; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); if (car(e)==LCONST) { v = lcadr(e); vh = lcadr(e)>>32; } else if (car(e)==CONST) { v = cadr(e); vh = (v<0)?-1:0; } switch(op) { case LMUL: case LUMUL: v=ilog(v); case LLSHIFT: case LULSHIFT: if (v==0) return; if (v==32) { code_register(regv_l(creg),regv_h(creg)); code_const(0,regv_l(creg)); return; } else if (v>31) { printf("\tmov\t%s, %s, lsl #%d\n",crn_h,crn_l,v-32); code_const(0,regv_l(creg)); return; } greg = get_register(); grn = register_name(greg); inc_inst(4); printf("\tmov\t%s, %s, lsl #%d\n",crn_h,crn_h,v); printf("\tmov\t%s, %s, lsr #%d\n",grn,crn_l,32-v); printf("\torr\t%s, %s,%s\n",crn_h,crn_h,grn); printf("\tmov\t%s, %s, lsl #%d\n",crn_l,crn_l,v); free_register(greg); return; case LDIV: v=ilog(v); case LRSHIFT: if (v==0) return; if (v==32) { code_register(regv_h(creg),regv_l(creg)); printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l); return; } else if (v>31) { printf("\tmov\t%s, %s, asr #%d\n",crn_l,crn_h,v-32); printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l); return; } greg = get_register(); grn = register_name(greg); inc_inst(4); printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_l,v); printf("\tmov\t%s, %s, lsl #%d\n",grn,crn_h,32-v); printf("\torr\t%s, %s,%s\n",crn_l,crn_l,grn); printf("\tmov\t%s, %s, asr #%d\n",crn_h,crn_h,v); free_register(greg); return; case LUDIV: v=ilog(v); case LURSHIFT: if (v==0) return; if (v==32) { code_register(regv_h(creg),regv_l(creg)); code_const(0,regv_h(creg)); return; } else if (v>31) { printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_h,v-32); code_const(0,regv_h(creg)); return; } greg = get_register(); grn = register_name(greg); inc_inst(4); printf("\tmov\t%s, %s, lsl #%d\n",grn,crn_h,32-v); printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_l,v); printf("\torr\t%s, %s,%s\n",crn_l,grn,crn_l); printf("\tmov\t%s, %s, lsr #%d\n",crn_h,crn_h,v); free_register(greg); return; case LADD: inc_inst(2); printf("\tadds\t%s, %s, #%d\n",crn_l,crn_l,v); printf("\tadc\t%s, %s, #%d\n",crn_h,crn_h,vh); break; case LSUB: inc_inst(2); printf("\tsubs\t%s, %s, #%d\n",crn_l,crn_l,v); printf("\tsbc\t%s, %s, #%d\n",crn_h,crn_h,vh); break; case LBAND: inc_inst(2); printf("\tand\t%s, %s, #%d\n",crn_l,crn_l,v); printf("\tand\t%s, %s, #%d\n",crn_h,crn_h,vh); break; case LEOR: inc_inst(2); printf("\teor\t%s, %s, #%d\n",crn_l,crn_l,v); printf("\teor\t%s, %s, #%d\n",crn_h,crn_h,vh); break; case LBOR: inc_inst(2); printf("\torr\t%s, %s, #%d\n",crn_l,crn_l,v); printf("\torr\t%s, %s, #%d\n",crn_h,crn_h,vh); break; default: error(-1); } if (dx!=-1) free_register(dx); } void code_i2ll(int reg) { char *crn,*crn_h,*crn_l; int reg0; crn = register_name(reg0 = ireg); use_longlong(reg); crn_h = lregister_name_high(lreg); crn_l = lregister_name_low(lreg); inc_inst(2); if (reg0!=regv_l(lreg)) printf("\tmov\t%s, %s\n",crn_l,crn); printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l); } void code_i2ull(int reg) { code_i2ll(reg); } void code_u2ll(int reg) { char *crn,*crn_h,*crn_l; int reg0; crn = register_name(reg0 = ireg); use_longlong(reg); crn_h = lregister_name_high(lreg); crn_l = lregister_name_low(lreg); inc_inst(2); if (reg0!=regv_l(lreg)) printf("\tmov\t%s, %s\n",crn_l,crn); printf("\tmov\t%s, #0\n",crn_h); } void code_u2ull(int creg) { code_u2ll(creg); } void code_ll2i(int reg) { char *crn_l; int reg0; crn_l = lregister_name_low(reg0=lreg); use_int(reg); if (ireg!=regv_l(reg0)) { inc_inst(1); printf("\tmov\t%s, %s\n",register_name(ireg),crn_l); } } void code_ll2u(int creg) { code_ll2i(creg); } void code_ull2i(int creg) { code_ll2i(creg); } void code_ull2u(int creg) { code_ll2i(creg); } #if FLOAT_CODE void code_d2ll(int reg) { // fixdfdi$stub code_assign_input_double_long( list2(LREGISTER,LREGISTER_OPERAND),list2(FREGISTER,freg)) ; extern_conv("__fixdfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) { use_longlong(reg); } } void code_d2ull(int reg) { code_assign_input_double_long( list2(LREGISTER,LREGISTER_OPERAND),list2(FREGISTER,freg)) ; extern_conv("__fixunsdfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) { use_longlong(reg); } } void code_f2ll(int reg) { code_assign_input_float_int(list2(REGISTER,REGISTER_OPERAND),list2(FREGISTER,freg)); extern_conv("__fixsfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) { use_longlong(reg); } } void code_f2ull(int reg) { code_assign_input_float_int(list2(REGISTER,REGISTER_OPERAND),list2(FREGISTER,freg)); extern_conv("__fixunssfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) { use_longlong(reg); } } void code_ll2d(int reg) { set_lreg(LREGISTER_OPERAND,1); extern_conv("__floatdidf"); set_dreg(RET_DREGISTER,0); if (reg!=USE_CREG&®!=RET_FREGISTER) use_float(1,reg); } void code_ll2f(int reg) { set_lreg(LREGISTER_OPERAND,1); extern_conv("__floatdisf"); set_freg(RET_FREGISTER,0); if (reg!=USE_CREG&®!=RET_FREGISTER) use_float(0,reg); } void code_ull2d(int creg) { code_ll2d(creg); } void code_ull2f(int creg) { code_ll2f(creg); } #endif static void ladd(int dreg,int rreg,int v) // rreg = dreg + v { // v should be 8bit const with 2's shift inc_inst(2); if (v>0) { printf("\tadds\t%s, %s, #%d\n", lregister_name_low(rreg),lregister_name_low(dreg), v); printf("\tadc\t%s, %s, #0\n", lregister_name_high(rreg),lregister_name_high(dreg)); } else { printf("\tsubs\t%s, %s, #%d\n", lregister_name_low(rreg),lregister_name_low(dreg), -v); printf("\tsbc\t%s, %s, #0\n", lregister_name_high(rreg),lregister_name_high(dreg)); } } void code_lpreinc(int e1,int e2,int reg) { int dreg=-1,xreg=-1; int dir=caddr(e1); if (car(e2)==LREGISTER) { use_longlong(reg); ladd(cadr(e2),cadr(e2),dir); if (reg!=cadr(e2)) { lmove(reg,cadr(e2)); } return; } g_expr(e2); if(!is_int_reg(creg)) error(-1); emit_push(); if (reg==USE_CREG) { dreg=get_lregister(); if (!dreg) error(-1); set_lreg(dreg,0); // free old lreg==creg } else { dreg = reg; } xreg = emit_pop(0); lload(xreg,dreg,0); ladd(dreg,dreg,dir); code_lassign(xreg,dreg); emit_pop_free(xreg); if (dreg!=-1) free_register(dreg); } void code_lpostinc(int e1,int e2,int reg) { int dreg,nreg,xreg; int dir=caddr(e1); if (car(e2)==LREGISTER) { use_longlong(reg); lmove(reg,cadr(e2)); ladd(cadr(e2),cadr(e2),dir); return; } g_expr(e2); if(!is_int_reg(creg)) error(-1); emit_push(); nreg=get_lregister(); if (!nreg) error(-1); if (reg==USE_CREG) { dreg=get_lregister(); if (!dreg) error(-1); set_lreg(dreg,0); // free old lreg==creg } else { dreg = reg; } xreg = emit_pop(0); lload(xreg,dreg,0); ladd(dreg,nreg,dir); lstore(xreg,nreg); emit_pop_free(xreg); free_register(nreg); } void code_lassop(int op,int reg) { int xreg; int edx,edx0=-1; // (*creg) op = pop() xreg = emit_lpop(0); /* pop e3 value */ if (!is_int_reg(creg)) error(-1); edx = ireg; emit_push(); use_longlong(reg); if (regv_l(lreg)==edx || regv_h(lreg)==edx) { edx0 = get_register(); if(!edx0) error(-1); inc_inst(1); printf("## lassop\n\tmov\t%s, %s\n",register_name(edx0), register_name(edx)); edx = edx0; } lload(edx,reg,0); // free_register(edx); don't do this, it will free pushed register ltosop(op,reg,xreg); // loprtc? emit_lpop_free(xreg); use_reg(reg); edx = emit_pop(0); code_lassign(edx,reg); emit_pop_free(edx); if (edx0!=-1) free_register(edx0); if (reg!=lreg) free_register(reg); } void code_register_lassop(int reg,int op) { // reg op = pop() int xreg=emit_lpop(); ltosop(op,reg,xreg); emit_lpop_free(xreg); } #endif void code_save_stacks() { int i,reg; for(i=0;i<reg_sp;i++) { if ((reg=reg_stack[i])>=0) { code_assign_lvar( (reg_stack[i]=new_lvar(SIZE_OF_INT)),reg,0); reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET; free_register(reg); } } #if FLOAT_CODE for(i=0;i<freg_sp;i++) { if ((reg=freg_stack[i])>=0) { code_dassign_lvar( (freg_stack[i]=new_lvar(SIZE_OF_DOUBLE)),reg,1); freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET; free_register(reg); } } #endif #if LONGLONG_CODE for(i=0;i<lreg_sp;i++) { if ((reg=lreg_stack[i])>=0) { code_lassign_lvar( (lreg_stack[i]=new_lvar(SIZE_OF_LONGLONG)),reg); lreg_stack[i]= lreg_stack[i]-REG_LVAR_OFFSET; free_register(reg); } } #endif } void emit_lib(char *p[]) { while(*p) { printf("%s\n",*p++); } } void code_closing() { global_table(); /* printf("\t.ident \"Micro-C compiled\"\n"); */ } #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: inc_inst(2+(max-min)); code_cmpdimm(max-min,t,dlabel,-1); printf("\tldrls\tpc, [pc, %s, asl #2]\n",trn); break; case 2: inc_inst(4+(max-min)/2); printf("\ttst\t%s, #1\n",trn); printf("\tbne\t.L%d\n",dlabel); code_cmpdimm(max-min,t,dlabel,-1); printf("\tldrls\tpc, [pc, %s, asl #1]\n",trn); break; break; case 4: inc_inst(5+(max-min)/4); printf("\ttst\t%s, #3\n",trn); printf("\tbne\t.L%d\n",dlabel); code_cmpdimm(max-min,t,dlabel,-1); printf("\tldrls\tpc, [pc, %s]\n",trn); break; break; default: error(-1); } printf("\tb\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) { // STRINGS? 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 { if (c=='\n') inc_inst(1); 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),regv_h(reg),SIZE_OF_INT*2,adr,cext_at(0,0)); /* load mmmmmm */ code_ld(cload(0,0),regv_l(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); inc_inst(1); printf("\tadd\t%s,%s,%s\n", register_name(regv_l(reg)), register_name(regv_l(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); inc_inst(4); code_const(~mask,tmp); printf("\torr\t%s, %s, %s\n",trn,crn,trn); /* do conjunction */ printf("\tand\t%s, %s, %s\n",lrn,trn,lrn); /* make or-mask */ code_const(mask,tmp); printf("\tand\t%s, %s, %s\n",trn,crn,trn); /* do disjunction */ printf("\torr\t%s, %s, %s\n",crn,trn,lrn); } extern void code_bit_replace(int adr,int value,int type) { int sign,bitsz,l,align; int bitsize,bitpos; int mask = 0; int tmp = -1,lvalue,size; char *crn,*lrn,*trn; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); if (l==1) { #if LONGLONG_CODE int tmp2; // use_int(adr); lvalue = get_lregister(); tmp2 = get_register(); code_register(adr,tmp2); adr = tmp2; lload(adr,lvalue,0); use_longlong(value); crn = lregister_name_high(value); lrn = lregister_name_high(lvalue); /* shift left */ if (bitpos) loprtc(LLSHIFT,value,list2(CONST,bitpos)); trn = register_name(tmp = get_register()); if (bitpos+bitsize>=32) { /* make and-mask upper */ mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); make_mask_and_or(mask,tmp,trn,crn,lrn); } crn = lregister_name_low(value); lrn = lregister_name_low(lvalue); if (bitpos<32) { /* make and-mask lower */ mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); make_mask_and_or(mask,tmp,trn,crn,lrn); } code_lassign(adr,value); free_register(lvalue); free_register(adr); } else if (l==2) { int i; int tmpvar; // use_int(adr); use_longlong(value); lvalue = get_register(); code_register(adr,lvalue); adr = lvalue; tmpvar=new_lvar(SIZE_OF_LONGLONG); code_lassign_lvar(tmpvar,value); trn = register_name(tmp = get_register()); /* make and-mask upper */ i=bitpos; if (i) oprtc(LSHIFT,regv_l(value),list2(CONST,i)); if (i<0||32<=i) error(-1); crn = lregister_name_low(value); code_ld(cload(0,0),regv_h(value),0,adr,cext_at(0,0)); lrn = lregister_name_high(value); mask = make_mask(0,31-bitpos); make_mask_and_or(mask,tmp,trn,crn,lrn); inc_inst(1); printf("\t%s\t%s, [%s, #0]\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); inc_inst(1); printf("\t%s\t%s, [%s, #4]\n",cstore(0),crn,register_name(adr)); /* make and-mask lower */ code_ld(cload(0,0),regv_l(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); inc_inst(1); printf("\t%s\t%s, [%s, #8]\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) { inc_inst(1); if (is_stage1_const(m,0)>0) { printf("\tand\t%s, %s, #%d\n",crn,crn,m); } else { trn = register_name(tmp=get_register()); code_const((~mask|c),tmp); /* do conjunction */ printf("\tand\t%s, %s, %s\n",crn,trn,crn); } } if (tmp!=-1) { free_register(tmp); tmp=-1; } /* make or-mask */ c = mask&c; if (c!=0) { inc_inst(1); /* do disjunction */ if (is_stage1_const(c,0)>0) { printf("\torr\t%s, %s, #%d\n",crn,crn,c); } else { trn = register_name(tmp=get_register()); code_const(c,tmp); printf("\torr\t%s, %s, %s\n",crn,trn,crn); } } if (tmp!=-1) free_register(tmp); } extern void code_bit_replace_const(int value,int adr,int type) { int sign,bitsz,l,align; int bitsize,bitpos,size; int mask = 0; int c; int lvalue; #if LONGLONG_CODE long long lc; int tmp; #endif char *crn; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); if (l==1) { #if LONGLONG_CODE use_int(adr); lvalue = get_lregister(); lload(adr,lvalue,0); crn = lregister_name_high(lvalue); /* shift left */ lc = lcadr(value); lc <<= bitpos; if (bitpos+bitsize>=32) { /* make and-mask upper */ mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); make_mask_and_or_const(mask,crn,(int)(lc>>32)); } crn = lregister_name_low(lvalue); if (bitpos<32) { /* make and-mask lower */ mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); make_mask_and_or_const(mask,crn,(int)lc); } code_lassign(adr,lvalue); free_register(adr); free_register(lvalue); } else if (l==2) { // three int container char *trn; /* hhhhhh mmmmmmmmmmmm lllllll lllll 00000000000 mmmmmmmmmmmm 0000000 hhhhhhh |-----||-----------||------------||-------||-------| */ use_int(adr); crn = register_name(adr); trn = register_name(tmp = get_register()); /* shift right */ lc = lcadr(value); /* make and-mask upper */ code_ld(cload(0,0),tmp,0,adr,cext_at(0,0)); mask = make_mask(0,31-bitpos); make_mask_and_or_const(mask,trn,(int)(lc<<bitpos)); inc_inst(1); printf("\t%s\t%s, [%s, #0]\n",cstore(0),trn,crn); /* store middle */ code_const((int)(lc>>(32-bitpos)),tmp); inc_inst(1); printf("\t%s\t%s, [%s, #4]\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))); inc_inst(1); printf("\t%s\t%s, [%s, #8]\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) { return code_arg_alignment0(args,n, type0,sz,is_code); } extern int code_lvar_alignment(int args,NMTBL *n, int type0,int sz) { return code_lvar_alignment0(args,n, type0,sz); } /* end */