Mercurial > hg > CbC > old > device
view mc-code-powerpc.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 Power PC (Mac OS X) */ /* ************************************************************************ ** 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" #include "mc-include.c" // #undef __APPLE__ static char *init_src0 = #ifdef __APPLE__ "\ #define __ppc__ 1\n\ #define __BIG_ENDIAN__ 1\n\ #define __STDC__ 1\n\ #define __GNUC__ 1\n\ #define __inline inline\n\ #define __inline__ inline\n\ #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 alloca __builtin_alloca\n\ #define __FLT_MIN__ 1.17549435e-38F\n\ #define __DBL_MIN__ 2.2250738585072014e-308\n\ #define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L\n\ " #else "\ #define __inline inline\n\ #define __extension__\n\ #define __const const\n\ #define __inline__ inline\n\ typedef struct __builtin_va_list { \\\n\ long long_last; \\\n\ long float_first; \\\n\ long float_last; \\\n\ long stack_top; \\\n\ long arg; \\\n\ long top; \\\n\ } __builtin_va_list; \\\n\ \\\n\ #define __builtin_va_start(__ap0,v) \\\n\ { \\\n\ __builtin_va_list *__ap = &__ap0; \\\n\ long __top = __ap->top = (long)&__my_va_list; \\\n\ __ap->long_last = __top +32; \\\n\ __ap->float_first = __ap->long_last; \\\n\ __ap->stack_top = __top+32+64+8; \\\n\ long __adr = (long)(&v) + sizeof(v); \\\n\ if (__adr >= __ap->stack_top) __ap->arg = __ap->float_first = __adr; \\\n\ if (__builtin_types_compatible_p(typeof(v),double)) \\\n\ __ap->float_first = __adr; \\\n\ __ap->arg = __adr; \\\n\ } \\\n\ \n\ #define __builtin_va_arg(__ap0,type) ({ \\\n\ __builtin_va_list *__ap = &__ap0; \\\n\ long __arg; \\\n\ if (__builtin_types_compatible_p(type,double) \\\n\ && __ap->float_first < __ap->stack_top) { \\\n\ __arg = __ap->float_first; \\\n\ __ap->float_first = __ap->float_first+8; \\\n\ if (__ap->float_first==__ap->float_last) \\\n\ __ap->float_first = __ap->stack_top;\\\n\ } else { \\\n\ if (__builtin_types_compatible_p(type,long long)) { \\\n\ if (__ap->arg==__ap->top+4) __ap->arg += 4; \\\n\ __arg = __ap->arg; \\\n\ __ap->arg += 8; \\\n\ if (__ap->arg==__ap->top+16+16) \\\n\ __ap->arg = __ap->stack_top; \\\n\ } else { \\\n\ __arg = __ap->arg; \\\n\ __ap->arg = __ap->arg+sizeof(type); \\\n\ if (__ap->arg==__ap->long_last) \\\n\ __ap->arg = __ap->stack_top; \\\n\ } \\\n\ } \\\n\ *((type *)(__arg)); \\\n\ }) \\\n\ \n" "// #define __builtin_va_arg(ap,type) (*((type *)__builtin_va_next((type),&ap)))\n\ #define alloca __builtin_alloca\n\ #define __DBL_MIN_EXP__ (-1021)\n\ #define __FLT_MIN__ 1.17549435e-38F\n\ #define __CHAR_BIT__ 8\n\ #define __WCHAR_MAX__ 2147483647\n\ #define __DBL_DENORM_MIN__ 4.9406564584124654e-324\n\ #define __FLT_EVAL_METHOD__ 0\n\ #define __DBL_MIN_10_EXP__ (-307)\n\ #define __FINITE_MATH_ONLY__ 0\n\ #define __GNUC_PATCHLEVEL__ 0\n\ #define __SHRT_MAX__ 32767\n\ #define __LDBL_MAX__ 1.79769313486231580793728971405301e+308L\n\ #define __UINTMAX_TYPE__ long long unsigned int\n\ #define __linux 1\n\ #define __CHAR_UNSIGNED__ 1\n\ #define __LDBL_MAX_EXP__ 1024\n\ #define __linux__ 1\n\ #define __SCHAR_MAX__ 127\n\ #define __USER_LABEL_PREFIX__ \n\ #define __STDC_HOSTED__ 1\n\ #define __LDBL_HAS_INFINITY__ 1\n\ #define __DBL_DIG__ 15\n\ #define __FLT_EPSILON__ 1.19209290e-7F\n\ #define _CALL_SYSV 1\n\ #define __LDBL_MIN__ 2.00416836000897277799610805135016e-292L\n\ #define __unix__ 1\n\ #define __DECIMAL_DIG__ 33\n\ #define __gnu_linux__ 1\n\ #define __LDBL_HAS_QUIET_NAN__ 1\n\ #define __GNUC__ 4\n\ #define __DBL_MAX__ 1.7976931348623157e+308\n\ #define __DBL_HAS_INFINITY__ 1\n\ #define __DBL_MAX_EXP__ 1024\n\ #define __LONG_LONG_MAX__ 9223372036854775807LL\n\ #define __PPC__ 1\n\ #define __GXX_ABI_VERSION 1002\n\ #define __FLT_MIN_EXP__ (-125)\n\ #define __DBL_MIN__ 2.2250738585072014e-308\n\ #define __DBL_HAS_QUIET_NAN__ 1\n\ #define __REGISTER_PREFIX__ \n\ #define __NO_INLINE__ 1\n\ #define _ARCH_PPC 1\n\ #define __FLT_MANT_DIG__ 24\n\ #define __VERSION__ \"mc-powerpc\"\n\ #define __BIG_ENDIAN__ 1\n\ #define __powerpc__ 1\n\ #define unix 1\n\ #define __SIZE_TYPE__ unsigned int\n\ #define __ELF__ 1\n\ #define __FLT_RADIX__ 2\n\ #define __LDBL_EPSILON__ 4.94065645841246544176568792868221e-324L\n\ #define __GNUC_RH_RELEASE__ 3\n\ #define __LDBL_DIG__ 31\n\ #define __FLT_HAS_QUIET_NAN__ 1\n\ #define __FLT_MAX_10_EXP__ 38\n\ #define __LONG_MAX__ 2147483647L\n\ #define __FLT_HAS_INFINITY__ 1\n\ #define __unix 1\n\ #define _BIG_ENDIAN 1\n\ #define linux 1\n\ #define __PPC 1\n\ #define __LDBL_MANT_DIG__ 106\n\ #define __WCHAR_TYPE__ long int\n\ #define __FLT_DIG__ 6\n\ #define __powerpc 1\n\ #define __INT_MAX__ 2147483647\n\ #define __LONG_DOUBLE_128__ 1\n\ #define __FLT_MAX_EXP__ 128\n\ #define __DBL_MANT_DIG__ 53\n\ #define __WINT_TYPE__ unsigned int\n\ #define __LDBL_MIN_EXP__ (-968)\n\ #define __LDBL_MAX_10_EXP__ 308\n\ #define __DBL_EPSILON__ 2.2204460492503131e-16\n\ #define PPC 1\n\ #define powerpc 1\n\ #define __INTMAX_MAX__ 9223372036854775807LL\n\ #define __FLT_DENORM_MIN__ 1.40129846e-45F\n\ #define __FLT_MAX__ 3.40282347e+38F\n\ #define __FLT_MIN_10_EXP__ (-37)\n\ #define __INTMAX_TYPE__ long long int\n\ #define __GNUC_MINOR__ 1\n\ #define __DBL_MAX_10_EXP__ 308\n\ #define __LDBL_DENORM_MIN__ 4.94065645841246544176568792868221e-324L\n\ #define __STDC__ 1\n\ #define __PTRDIFF_TYPE__ int\n\ #define __LDBL_MIN_10_EXP__ (-291)\n\ " #endif #ifdef __APPLE__ "#define __APPLE__ 1\n" #endif ; #define TEXT_EMIT_MODE 0 #define DATA_EMIT_MODE 1 #define RODATA_EMIT_MODE 2 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 ascii(char *s,int len); #ifdef __APPLE__ static char lpfx[] = "L_"; static char npfx[] = "_"; #else static char lpfx[] = ".LC"; static char npfx[] = ""; #endif int eval_order = NORMAL; static int creg; static int output_mode = TEXT_EMIT_MODE; int data_alignment = 0; static int code_disp_label; static int code_setup; static int r1_offset_label; static int lvar_offset_label; static int max_func_arg_label; #ifndef __APPLE__ static int arg_offset_label; #endif static int arg_offset_v = 0; static int reg_save; static int freg_save; 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 1 #define ENDIAN_L 1 #define ENDIAN_D 1 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]; /* 実際のレジスタの領域 */ #ifdef __APPLE__ #define REG_sp 1 #define REG_fp 30 #define REG_VAR_BASE 29 #define REG_VAR_MIN 18 #define MIN_TMP_REG 3 #define MAX_TMP_REG 11 #define FREG_VAR_BASE 31 #define FREG_VAR_MIN 20 #define MIN_TMP_FREG 1 #define MAX_TMP_FREG 14 #else #define REG_sp 1 #define REG_fp 31 #define REG_VAR_BASE 29 #define REG_VAR_MIN 18 #define MIN_TMP_REG 3 #define MAX_TMP_REG 11 #define FREG_VAR_BASE 31 #define FREG_VAR_MIN 20 #define MIN_TMP_FREG 1 #define MAX_TMP_FREG 9 #endif int MAX_REGISTER=30; /* PowerPCのレジスタを10個まで使う*/ int MAX_FREGISTER=31; #define REAL_MAX_REGISTER 32 /* PowerPCのレジスタが32ということ*/ #define REAL_MAX_FREGISTER 32 /* PowerPCのレジスタが32ということ*/ #define REAL_MAX_LREGISTER 16 #define FREG_OFFSET REAL_MAX_REGISTER #define LREG_OFFSET (REAL_MAX_REGISTER+REAL_MAX_FREGISTER) #define RET_REGISTER 3 #define RET_FREGISTER (1+FREG_OFFSET) #define RET_LREGISTER_H 3 /* high word */ #define RET_LREGISTER_L 4 /* low word */ #define RET_LREGISTER LREG_OFFSET int MAX_INPUT_REGISTER_VAR = 11-MIN_TMP_REG; int MAX_CODE_INPUT_REGISTER_VAR = 11-MIN_TMP_REG; int MAX_INPUT_DREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG; int MAX_INPUT_FREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG; int MAX_CODE_INPUT_DREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG; int MAX_CODE_INPUT_FREGISTER_VAR = MAX_TMP_FREG-MIN_TMP_FREG; static int powerpc_regs[REAL_MAX_REGISTER+REAL_MAX_FREGISTER+ REAL_MAX_LREGISTER]; static int regv_h0[REAL_MAX_LREGISTER]; static int regv_l0[REAL_MAX_LREGISTER]; #define regv_h(i) regv_h0[(i)-LREG_OFFSET] #define regv_l(i) regv_l0[(i)-LREG_OFFSET] static int *regs = powerpc_regs; #define CREG_REGISTER (MAX_TMP_REG) #define FREG_FREGISTER (MAX_TMP_FREG+FREG_OFFSET) #define LREG_LREGISTER (MAX_TMP_REG+LREG_OFFSET) static int max_reg_var, max_freg_var; #ifdef __APPLE__ static char *reg_name[] = { "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9", "r10","r11","r12","r13","r14","r15","r16","r17","r18","r19", "r20","r21","r22","r23","r24","r25","r26","r27","r28","r29", "r30","r31", "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9", "f10","f11","f12","f13","f14","f15","f16","f17","f18","f19", "f20","f21","f22","f23","f24","f25","f26","f27","f28","f29", "f30","f31" }; #else // PS3 (PowerPC Fedora Core) static char *reg_name[] = { "r0","r1","r2","r3","r4","r5","r6","r7","r8","r9", "r10","r11","r12","r13","r14","r15","r16","r17","r18","r19", "r20","r21","r22","r23","r24","r25","r26","r27","r28","r29", "r30","r31", "0","1","2","3","4","5","6","7","8","9", "10","11","12","13","14","15","16","17","18","19", "20","21","22","23","24","25","26","27","28","29", "30","31" }; #endif #define round4(i) align(i,4) #define round16(i) align(i,16) #define register_name(i) reg_name[i] #define fregister_name(i) reg_name[i] #define lregister_name_low(i) reg_name[regv_l(i)] #define lregister_name_high(i) reg_name[regv_h(i)] #define DEBUG_REG 1 #if DEBUG_REG char *rn(int i) { return register_name(i); } char *fn(int i) { return fregister_name(i); } char *lln(int i) { return lregister_name_low(i); } char *lhn(int i) { return lregister_name_high(i); } int ll(int i) { return regv_l(i); } int lh(int i) { return regv_h(i); } #endif #define is_int_reg(i) (0<=i&&i<REAL_MAX_REGISTER) #define is_float_reg(i) (REAL_MAX_REGISTER<=i&&i<REAL_MAX_FREGISTER+REAL_MAX_REGISTER) #define is_longlong_reg(i) (LREG_OFFSET<=i&&i<LREG_OFFSET+REAL_MAX_LREGISTER) #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]!=REG_VAR) free_register(lreg); lreg = 0; } if (!ireg) ireg = get_register(); // else if (ireg!=i) free_register(i); i = ireg; } if (!regs[i]) regs[i]=USING_REG; creg = i; return i; } #if LONGLONG_CODE #define use_longlong(reg) if (reg==USE_CREG) reg=use_longlong0() static int use_longlong0() { int i = creg; if (!is_longlong_reg(i)) { if (ireg) { if (regs[ireg]!=REG_VAR) 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; } #endif #if FLOAT_CODE #define use_float(d,reg) if (reg==USE_CREG) reg=d?use_double0():use_float0() static int use_float0() { int i = creg; if (!is_float_reg(i)) { if (lreg) { if (regs[lreg]!=REG_VAR) free_register(lreg); lreg = 0; } if (!freg) freg = get_dregister(0); else if (freg!=i) if (regs[i]!=REG_VAR) free_register(i); i = freg; } if (!regs[i]) regs[i]=USING_REG; creg = i; return i; } static int use_double0() { int i = creg; if (!is_float_reg(i)) { if (lreg) { if (regs[lreg]!=REG_VAR) free_register(lreg); lreg = 0; } if (!freg) freg = get_dregister(1); else if (freg!=i) if (regs[i]!=REG_VAR) free_register(i); i = freg; } if (!regs[i]) regs[i]=USING_REG; creg = i; return i; } #endif #if FLOAT_CODE #ifdef __APPLE__ static NMTBL float_zero = {"_float_zero",0,STATIC,FLOAT,0}; static NMTBL float_one = {"_float_one",0,STATIC,FLOAT,0}; #else static NMTBL float_zero = {"__float_zero",0,STATIC,FLOAT,0}; static NMTBL float_one = {"__float_one",0,STATIC,FLOAT,0}; #endif static char * fload(int d); static int code_d1(double d); static int code_d2(double d); #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); static void set_freg(int,int); static void set_lreg(int,int); static void jcond(int l, char cond); static void register_usage(char *s); static int max_func_args; static int my_func_args; #define ARG_LVAR_OFFSET 0x10000000 /* r0 return value etc. r3-r10 input register r22-r29 saved register variable (input register for code segment) r30 stack pointer r31 0 r1 frame pointer f0 return value etc. f1-r8 input register f24-f31 saved register variable function call stack frame (Mac OS X) <-------r1_offset------------------------------> r30 <------------lvar_offset0------> <--lvar_offset--> r1 r+ +------------+---+---------------+----------+--------------+----+ - callee arg xx register save local caller arg xx reg_save disp max_func_args*SIZE_OF_INT lvar>0 lvar<0 lvar>0x1000 0000 function call stack frame (PS3) <---------------r1_offset------------------------------> r30--> <--arg_offset--> xxx<----------lvar_offset--> <----r1 r+ +------+---+------+---------------+----------+--------------+----+ - callee arg reg arg register save local caller arg xx reg_save disp max_func_args*SIZE_OF_INT lvar>0 lvar<0 lvar>0x1000 0000 code segment stack frame * gotoを呼び出した関数のr1 ! r1(goto前のr1) # * r30 <---r1_offset---------> r1 r+ +----------+--+----------+----------------+-----------+----------+----+ cousin arg xx reg save !callee arg !code local caller arg xx r20-r29 lvar>0 lvar<0 lvar>0x1000 000 f20-f31 <-my_func_args--><--disp-----><-max_func_arg-> *SIZE_OF_INT *SIZE_OF_INT */ #ifdef __APPLE__ #define arg_offset 24 #define arg_offset1 24 #define func_disp_offset 68 #define func_disp_offset1 16 #define code_disp_offset0 (-4) #else #define arg_offset (8) #define arg_offset0 (8) #define arg_offset1 (8) #define func_disp_offset (12) #define code_disp_offset0 (-4) #endif int disp_offset = -4; #define CODE_LVAR(l) ((l)+code_disp_offset0) #define CODE_CALLER_ARG(l) ((l)+arg_offset1) #define FUNC_LVAR(l) ((l)+disp_offset) #ifdef __APPLE__ #define CALLEE_ARG(l) ((l)+arg_offset) #else #define CALLEE_ARG(l) ((l)+arg_offset+((l>=arg_offset_v)?arg_offset0:0)) #endif #define CALLER_ARG(l) ((l)+arg_offset1) void code_offset_set() { #if 0 int l; #endif int lvar_offsetv = round16(-disp+max_func_args*SIZE_OF_INT)+func_disp_offset; int r1_offsetv = round16(lvar_offsetv-reg_save); printf(".set %s%d,%d\n",lpfx,lvar_offset_label,r1_offsetv-lvar_offsetv); if (r1_offsetv-lvar_offsetv > 65000) error(-1); // too large function arguments? printf(".set %s%d,%d\n",lpfx,r1_offset_label,r1_offsetv); if (max_func_arg_label) { printf(".set %s%d,%d\n",lpfx,max_func_arg_label, round16(max_func_args*SIZE_OF_INT)+24); max_func_arg_label = 0; } #if 0 printf("## reg_save %d\n",reg_save); printf("## function %s\n",fnptr->nm); l = ARG_LVAR_OFFSET; printf("## offset call0\t%d\n",CALLER_ARG); l = ARG_LVAR_OFFSET+max_func_args*SIZE_OF_INT; printf("## offset calln\t%d %d\n",CALLER_ARG,max_func_args*SIZE_OF_INT); l = disp; printf("## offset lvarn\t%d %d\n",FUNC_LVAR+lvar_offsetv,disp); l = 0; printf("## offset lvar0\t%d\n",FUNC_LVAR+lvar_offsetv); l = -reg_save; printf("## offset regs\t%d\n",FUNC_LVAR+lvar_offsetv); printf("## offset r1off\t%d\n",r1_offsetv); l = 0; printf("## offset carg0\t%d\n",CALLEE_ARG+r1_offsetv); l = my_func_args; printf("## offset cargn\t%d %d\n",CALLEE_ARG+r1_offsetv,my_func_args); #endif } static int large_offset_reg; #ifdef __APPLE__ static void lvar(int l) { char *rn; if (!large_offset_reg) { if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("lo16(%d)(r1)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); } else printf("lo16(%d)(r30)\n",CODE_LVAR(l)); } else if (l<0) { /* local variable */ printf("lo16(%d)(r30)\n",FUNC_LVAR(l)); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("lo16(%d)(r1)\n",CALLER_ARG(l-ARG_LVAR_OFFSET)); } else { /* callee's arguments */ printf("lo16(%d+%s%d)(r30)\n",CALLEE_ARG(l),lpfx,lvar_offset_label); } } else { rn = register_name(large_offset_reg); if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("lo16(%d)(%s)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),rn); } else printf("lo16(%d)(%s)\n",CODE_LVAR(l),rn); } else if (l<0) { /* local variable */ printf("lo16(%d)(%s)\n",FUNC_LVAR(l),rn); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("lo16(%d)(%s)\n",CALLER_ARG(l-ARG_LVAR_OFFSET),rn); } else { /* callee's arguments */ printf("lo16(%d+%s%d)(%s)\n",CALLEE_ARG(l),lpfx,lvar_offset_label,rn); } free_register(large_offset_reg); } } /* if size of local variables / input variables is more then 64k, lo16 does not work. We have to use ha16 also. But we can't know the exact size in one path compile. We may safely use lvar16ha if disp or max_func_args > 32k. Of course this is redundant for smaller offset. But who cares who use very large local variables? */ #define LARGE_OFFSET(l) (l<-32000||l>32000) static void lvar_intro(int l) { char *rn; large_offset_reg=0; if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ if (LARGE_OFFSET(CODE_CALLER_ARG(l-ARG_LVAR_OFFSET))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,r1,ha16(%d)\n",rn, CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); } } else { if (LARGE_OFFSET(CODE_LVAR(l))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,r30,ha16(%d)\n",rn,CODE_LVAR(l)); } } } else if (l<0) { /* local variable */ if (LARGE_OFFSET(FUNC_LVAR(l))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,r30,ha16(%d)\n",rn,FUNC_LVAR(l)); } } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ if (LARGE_OFFSET(CALLER_ARG(l-ARG_LVAR_OFFSET))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,r1,ha16(%d)\n",rn,CALLER_ARG(l-ARG_LVAR_OFFSET)); } } else { /* callee's arguments */ if (LARGE_OFFSET(CALLEE_ARG(l))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,r30,ha16(%d+%s%d)\n", rn,CALLEE_ARG(l),lpfx,lvar_offset_label); } } } #else /* PS3 */ static void lvar(int l) { char *rn; if (!large_offset_reg) { if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("%d@l(1)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); } else printf("%d@l(%d)\n",CODE_LVAR(l),REG_fp); } else if (l<0) { /* local variable */ printf("%d@l(%d)\n",FUNC_LVAR(l),REG_fp); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("%d@l(1)\n",CALLER_ARG(l-ARG_LVAR_OFFSET)); } else { /* callee's arguments */ printf("%d+%s%d@l(%d)\n",CALLEE_ARG(l),lpfx,lvar_offset_label,REG_fp) ; } } else { rn = register_name(large_offset_reg); if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("%d@l(%s)\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),rn); } else printf("%d@l(%s)\n",CODE_LVAR(l),rn); } else if (l<0) { /* local variable */ printf("%d@l(%s)\n",FUNC_LVAR(l),rn); } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ printf("%d@l(%s)\n",CALLER_ARG(l-ARG_LVAR_OFFSET),rn); } else { /* callee's arguments */ printf("%d+%s%d@l(%s)\n",CALLEE_ARG(l),lpfx,lvar_offset_label,rn); } free_register(large_offset_reg); } } /* if size of local variables / input variables is more then 64k, lo16 does not work. We have to use ha16 also. But we can't know the exact size in one path compile. We may safely use lvar16ha if disp or max_func_args > 32k. Of course this is redundant for smaller offset. But who cares who use very large local variables? */ #define LARGE_OFFSET(l) (l<-32000||l>32000) static void lvar_intro(int l) { char *rn; large_offset_reg=0; if (is_code(fnptr)) { if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ if (LARGE_OFFSET(CODE_CALLER_ARG(l-ARG_LVAR_OFFSET))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,1,%d@ha\n",rn, CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); } } else { if (LARGE_OFFSET(CODE_LVAR(l))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,%d,%d@ha\n",rn,REG_fp,CODE_LVAR(l)); } } } else if (l<0) { /* local variable */ if (LARGE_OFFSET(FUNC_LVAR(l))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,%d,%d@ha\n",rn,REG_fp,FUNC_LVAR(l)); } } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ if (LARGE_OFFSET(CALLER_ARG(l-ARG_LVAR_OFFSET))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,1,%d@ha\n",rn,CALLER_ARG(l-ARG_LVAR_OFFSET)); } } else { /* callee's arguments */ if (LARGE_OFFSET(CALLEE_ARG(l))) { rn=register_name(large_offset_reg=get_register()); printf("\taddis %s,%d,%d+%s%d@ha\n", rn,REG_fp,CALLEE_ARG(l),lpfx,lvar_offset_label); } } } #endif void code_lvar(int e2,int reg) { use_int(reg); lvar_intro(e2); printf("\tla %s,",register_name(reg)); lvar(e2); } void code_init(void) { /* called only once */ init_src = init_src0; size_of_int = SIZE_OF_INT; size_of_pointer = SIZE_OF_INT; size_of_short = SIZE_OF_SHORT; size_of_float = SIZE_OF_FLOAT; size_of_double = SIZE_OF_DOUBLE; size_of_longlong = SIZE_OF_LONGLONG; endian = ENDIAN; struct_align = size_of_int; regv_l(RET_LREGISTER) = RET_LREGISTER_L; regv_h(RET_LREGISTER) = RET_LREGISTER_H; } extern void emit_reinit() { /* called for each file */ /* heap is initialized here, setup ptr cache free list */ output_mode = -1; init_ptr_cache(); } void gexpr_code_init(void){ } void code_gexpr(int e){ if ((is_int_reg(creg))&®s[creg]==REG_VAR) creg = ireg = 0; else if (is_float_reg(creg)&®s[creg]==REG_VAR) creg = lreg = 0; else if (is_longlong_reg(creg)&®s[creg]==REG_VAR) creg = lreg = 0; // if (is_int_reg(creg) && creg!=ireg) error(-1); } /* set variable storage type and offset save register contents to our stack for & operator */ 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; arg_offset_v = 0; int offset = 0; function_type(fnptr->ty,&dots); if (dots && (in || !parse_mode)) { type = INT; mode = LDECL; stmode = 0; n = def(lsearch("__my_va_list",0),0); n->dsp = 0; // first argument } if (in) return; while (args) { /* process in reverse order */ n = ncadddr(args); type = n->ty; int sz = size(type); offset = code_arg_alignment(offset,n,type,sz,is_code0); 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++; arg_offset_v += (caddr(args)=SIZE_OF_INT); } } else if (type==FLOAT) { if ((reg = get_input_dregister_var(freg_var,n,is_code0,0))) { n->sc = DREGISTER; n->dsp = cadr(reg); regs[n->dsp]= INPUT_REG; freg_var++; arg_offset_v += (caddr(args)=size(type)); } } else if (type==DOUBLE) { if ((reg = get_input_dregister_var(freg_var,n,is_code0,1))) { n->sc = DREGISTER; n->dsp = cadr(reg); regs[n->dsp]= INPUT_REG; freg_var++; arg_offset_v += (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; arg_offset_v += (caddr(args)=size(type)); } } args = cadr(args); } if (is_function(fnptr)) { #ifndef __APPLE__ if (dots) { arg_offset_v = MAX_INPUT_REGISTER_VAR*SIZE_OF_INT + MAX_INPUT_DREGISTER_VAR*SIZE_OF_DOUBLE; } printf(".set %s%d, %d\n",lpfx, arg_offset_label, arg_offset_v+ arg_offset); #endif code_save_input_registers(dots); } } int get_register(void) { /* 使われていないレジスタを調べる */ int i,j,reg; for(i=MAX_TMP_REG;i>MIN_TMP_REG;i--) { if (regs[i]) continue; /* 使われている */ regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ return i; /* その場所を表す番号を返す */ } /* PTR_CACHE をつぶす */ if ((i=last_ptr_cache())) { clear_ptr_cache_reg(i); regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ return i; /* その場所を表す番号を返す */ } /* search register stack */ for(i=0;i<reg_sp;i++) { if ((reg=reg_stack[i])>=0) { code_assign_lvar( (j=new_lvar(SIZE_OF_INT)),reg,0); reg_stack[i]= j-REG_LVAR_OFFSET; return reg; } } #if LONGLONG_CODE /* search register stack */ for(i=0;i<lreg_sp;i++) { if ((reg=lreg_stack[i])>=0) { code_lassign_lvar( (j=new_lvar(SIZE_OF_LONGLONG)),reg); lreg_stack[i]= j-REG_LVAR_OFFSET; free_register(reg); return get_register(); } } #endif for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) { reg =REG_VAR_BASE-i; if (! regs[reg]) { /* 使われていないなら */ regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */ if (i>max_reg_var) max_reg_var=i; 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; for(i=MAX_TMP_FREG+FREG_OFFSET;i>MIN_TMP_FREG+FREG_OFFSET;i--) { if (regs[i]) continue; /* 使われている */ regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ return i; /* その場所を表す番号を返す */ } /* search register stack */ for(i=0;i<freg_sp;i++) { if ((reg=freg_stack[i])>=0) { code_dassign_lvar( (freg_stack[i]=new_lvar(SIZE_OF_DOUBLE)),reg,1); freg_stack[i]= freg_stack[i]-REG_LVAR_OFFSET; return reg; } } for(i=0;i<FREG_VAR_BASE-REG_VAR_MIN;i++) { reg =FREG_VAR_BASE-i+FREG_OFFSET; if (! regs[reg]) { /* 使われていないなら */ regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */ if (i>max_freg_var) max_freg_var=i; return reg; /* その場所を表す番号を返す */ } } /* 空いている場所がないなら、エラー (いったい誰が使ってるの?) */ error(REG_ERR); return freg; } #if 0 int get_dregister(int d) { int i = get_dregister0(d); printf("## get_dregister %d\n",i); return i; } #endif int pop_fregister(void) { /* レジスタから値を取り出す */ return freg_stack[--freg_sp]; } #endif int get_lregister0() { int i; for(i=LREG_OFFSET+1;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) { if (regs[i]==0) { return i; } } return -1; } static int get_lregister1(int n,int m) { int i; #if 1 for(i=LREG_OFFSET;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) { if (regv_l(i)==n && regv_h(i)==m) { return i; } } #endif return get_lregister0(); } static void cleanup_lregister0() { int i; // we should not have this, but powerpc's function // lost some input register variables. #if 1 for(i=LREG_OFFSET+1;i<REAL_MAX_LREGISTER+LREG_OFFSET;i++) { if (regs[i]) { if(!regv_l(i) && !regv_h(i)) { regs[i]=0; // printf("## cleanup lreg 0 %d\n",i); } else if(!regs[regv_l(i)] && !regs[regv_h(i)]) { free_register(i); // printf("## cleanup lreg 1 %d\n",i); } } } #endif } 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) { if (regs[h]!=REG_VAR) free_register(h); if (regs[i]!=REG_VAR) free_register(i); return -1; } regv_l(i) = l; if (!regs[i]) regs[i]=USING_REG; // printf("## get_lregister %d %s %s\n",i, lregister_name_high(i), lregister_name_low(i)); 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) goto not_found; if (regs[ll]==0) { for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) { if (! regs[REG_VAR_BASE-i]) { /* 使われていないなら */ /* そのレジスタを使うことを宣言し */ regs[REG_VAR_BASE-i]=USING_REG; if (i>max_reg_var) max_reg_var=i; for(j=0;j<REG_VAR_BASE-REG_VAR_MIN;j++) { if (! regs[REG_VAR_BASE-j]) { /* 使われていないなら */ /* そのレジスタを使うことを宣言し */ regs[REG_VAR_BASE-j]=REG_VAR; if (j>max_reg_var) max_reg_var=j; /* その場所を表す番号を返す */ regs[ll]=REG_VAR; 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 && regs[xreg]!=REG_VAR) free_register(xreg); } void free_register(int i) { /* いらなくなったレジスタを開放 */ // printf("## free_register %d\n",i); if (is_longlong_reg(i)) { regs[regv_l(i)]=0; regs[regv_h(i)]=0; } regs[i]=0; } extern void use_ptr_cache(int r) { regs[r]=PTRC_REG; } int get_input_dregister_var(int i,NMTBL *n,int is_code,int d) { if (is_code) { if(!(i<FREG_VAR_BASE-FREG_VAR_MIN)) return 0; i = FREG_VAR_BASE-i+FREG_OFFSET; } else { if (i<0||i>=MAX_INPUT_DREGISTER_VAR) return 0; i = i+MIN_TMP_FREG+FREG_OFFSET; } return list3n(DREGISTER,i,n); } int get_input_lregister_var(int i,NMTBL *n,int is_code) { int ll; if (i!=-1) { if (is_code) { if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0; i = REG_VAR_BASE-i; } else { if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0; #ifndef __APPLE__ if (i%2==1) i++; #endif i = i+MIN_TMP_REG; } ll = get_lregister1(i,i+1); #if ENDIAN_L==0 regv_l(ll)=i; regv_h(ll)=i+1; #else regv_h(ll)=i; regv_l(ll)=i+1; #endif } else { error(-1); ll=LREG_OFFSET+2; } return list3n(LREGISTER,ll,n); } int get_input_register_var(int i,NMTBL *n,int is_code) { if (is_code) { if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0; i = REG_VAR_BASE-i; } else { if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0; i = i+MIN_TMP_REG; } return list3n(REGISTER,i,n); } /* double register case? */ int get_input_register_var_1(int i,NMTBL *n,int is_code) { if (is_code) { if(!(i<REG_VAR_BASE-REG_VAR_MIN)) return 0; i = REG_VAR_BASE-i; } else { if (i<0||i>=MAX_INPUT_REGISTER_VAR+1) return 0; i = i+MIN_TMP_REG; } return list3n(REGISTER,i,n); } int free_register_count(int d) { int i,count,fcount; fcount = count = 0; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) count++; } for(i=0;i<MAX_FREGISTER;i++) { if (! regs[i+FREG_OFFSET]) fcount++; } printf("## free reg %d freg %d\n",count,fcount); return d?fcount:count; } #if 0 static int register_full(void) { int i; for(i=0;i<MAX_REGISTER;i++) { if (! regs[i]) { return 0; } } return 1; } #endif void free_all_register(void) { int i; // printf("## free_all register\n"); #if LONGLONG_CODE for(i=0;i<REAL_MAX_LREGISTER;i++) { regs[i+LREG_OFFSET]=0; regv_l(i+LREG_OFFSET) = 0; regv_h(i+LREG_OFFSET) = 0; } lreg = 0; // set_lreg(LREG_LREGISTER,0); #endif for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; } for(i=0;i<MAX_FREGISTER;i++) { regs[i+FREG_OFFSET]=0; } #if FLOAT_CODE 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 DREGISTER: case FREGISTER: break; case REGISTER: if(cadr(s)==cadr(t)) return 1; break; case LREGISTER: if(cadr(s)==regv_l(cadr(t))) return 1; if(cadr(s)==regv_h(cadr(t))) return 1; break; } break; case DREGISTER: case FREGISTER: switch(car(t)) { case REGISTER: case LREGISTER: break; case DREGISTER: case FREGISTER: if(cadr(s)==cadr(t)) return 1; break; } break; case LREGISTER: switch(car(t)) { case DREGISTER: 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: 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; } // int lreg_count; void register_usage(char *s) { #if 1 int i,j; #endif #define USAGE_MAX 4 if (!lsrc) return; printf("## %d: %s:",lineno,s); if (ireg) printf(" creg=%s",register_name(ireg)); if (freg) printf(" freg=%s",fregister_name(freg)); if (lreg) printf(" lreg=%s,%s",lregister_name_high(lreg), lregister_name_low(lreg)); #if 1 for(j=0,i=0;i<MAX_REGISTER;i++) if (regs[i]) j++; if (j>USAGE_MAX) { printf("\n## regs(%d):",j); for(i=0;i<MAX_REGISTER;i++) { printf("%d",regs[i]); } } if (reg_sp>0) { printf(" stack "); for(i=reg_sp;i>0;i--) { if(reg_stack[i-1]>=0) { printf(" %s",register_name(reg_stack[i-1])); } else printf(",%d",reg_stack[i-1]); } } for(j=0,i=0;i<MAX_FREGISTER;i++) if (regs[i+FREG_OFFSET]) j++; if (j>USAGE_MAX) { printf("\n## freg(%d):",j); 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++; // lreg_count = j; if (j>USAGE_MAX) { printf("\n## lreg(%d):",j); for(i=0;i<REAL_MAX_LREGISTER;i++) { printf("%d",regs[i+LREG_OFFSET]); } #if 0 for(i=0;i<REAL_MAX_LREGISTER;i++) { if (regs[i+LREG_OFFSET] && regv_l(i+LREG_OFFSET)) printf(" %s-%s", lregister_name_high(i+LREG_OFFSET),lregister_name_low(i+LREG_OFFSET)); else if (regv_l(i+LREG_OFFSET)) printf(" *%s-%s", lregister_name_high(i+LREG_OFFSET),lregister_name_low(i+LREG_OFFSET)); } #endif } 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(0); gexpr_code_init(); register_usage("gexpr_init"); } void emit_init(void) { /* called before each declaration */ free_all_register(); max_reg_var=-1; max_freg_var=-1; reg_sp = 0; freg_sp = 0; } int get_register_var(NMTBL *n) { int i; for(i=0;i<REG_VAR_BASE-REG_VAR_MIN;i++) { if (! regs[REG_VAR_BASE-i]) { /* 使われていないなら */ /* そのレジスタを使うことを宣言し */ regs[REG_VAR_BASE-i]=REG_VAR; if (i>max_reg_var) max_reg_var=i; /* その場所を表す番号を返す */ return list3n(REGISTER,REG_VAR_BASE-i,n); } } return list3n(LVAR,new_lvar(SIZE_OF_INT),0); } int get_dregister_var(NMTBL *n,int d) { int i; for(i=0;i<FREG_VAR_BASE-FREG_VAR_MIN;i++) { if (! regs[FREG_VAR_BASE-i+FREG_OFFSET]) { /* 使われていないなら */ regs[FREG_VAR_BASE-i+FREG_OFFSET]=REG_VAR; /*そのレジスタを使うことを宣言し*/ if (i>max_freg_var) max_freg_var=i; /* その場所を表す番号を返す */ return list3n(DREGISTER, FREG_VAR_BASE-i+FREG_OFFSET,n); } } return list3n(LVAR,new_lvar(SIZE_OF_DOUBLE),0); } int emit_push() { int new_reg,old=creg; if (!is_int_reg(creg)) error(-1); if (reg_sp>MAX_MAX) error(-1); new_reg = get_register(); /* 絶対に取れる */ if (new_reg==creg) error(-1); // 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; } #ifdef __APPLE__ static int code_base; #endif extern void code_ptr_cache_def(int r,NMTBL *nptr) { char *rrn = register_name(r); #ifdef __APPLE__ if (nptr->sc==STATIC && !(is_code(nptr)||is_function(nptr))) { printf("\taddis %s,r31,ha16(_%s-L_%d)\n", rrn,nptr->nm,code_base); printf("\tla %s,lo16(_%s-L_%d)(%s)\n", rrn,nptr->nm,code_base,rrn); } else { printf("\taddis %s,r31,ha16(L_%s$non_lazy_ptr-L_%d)\n", rrn,nptr->nm,code_base); printf("\tlwz %s,lo16(L_%s$non_lazy_ptr-L_%d)(%s)\n", rrn,nptr->nm,code_base,rrn); } #else printf("\tlis %s,%s@ha\n", rrn,nptr->nm); printf("\tla %s,%s@l(%s)\n", rrn,nptr->nm,rrn); #endif } static char *cload(int sz) { return sz==1?"lbz":sz==SIZE_OF_SHORT?"lhz":"lwz"; } static char *cstore(int sz) { return sz==1?"stb":sz==SIZE_OF_SHORT?"sth":"stw"; } static void cext(int sign,int sz,int reg) { char *crn = register_name(reg); if (sign) { if (sz==1) printf("\textsb %s,%s\n",crn,crn); else if (sz==SIZE_OF_SHORT) printf("\textsh %s,%s\n",crn,crn); } else { if (sz==1) printf("\trlwinm %s,%s,0,0xff\n",crn,crn); else if (sz==SIZE_OF_SHORT) printf("\trlwinm %s,%s,0,0xffff\n",crn,crn); } } void code_label(int labelno) { clear_ptr_cache(); printf("%s%d:\n",lpfx,labelno); } static void code_add(int reg,int offset,int r) { char *crn = register_name(reg); char *rrn = register_name(r); if (offset==0) { if(r!=reg) printf("\tmr %s,%s\n",crn,rrn); } else if (LARGE_OFFSET(offset)) { #ifdef __APPLE__ printf("\tla %s,lo16(%d)(%s)\n",crn,offset,rrn); printf("\taddis %s,%s,ha16(%d)\n",crn,crn,offset); #else printf("\tla %s,%d@l(%s)\n",crn,offset,rrn); printf("\taddis %s,%s,%d@ha\n",crn,crn,offset); #endif } else printf("\taddi %s,%s,%d\n",crn,rrn,offset); } static void code_ld(char *ld,int reg,int offset,int r) { char *crn = register_name(reg); char *rrn = register_name(r); if (LARGE_OFFSET(offset)) { #ifdef __APPLE__ printf("\taddis %s,%s,ha16(%d)\n",crn,rrn,offset); printf("\t%s %s,lo16(%d)(%s)\n",ld,crn,offset,crn); #else printf("\taddis %s,%s,%d@ha\n",crn,rrn,offset); printf("\t%s %s,%d@l(%s)\n",ld,crn,offset,crn); #endif } else printf("\t%s %s,%d(%s)\n",ld,crn,offset,rrn); } static void code_ldf(char *ld,char *crn,int offset,int r) { char *rrn = register_name(r); int reg; char *lrn; if (offset<-32768||32767<offset) { lrn = register_name(reg = get_register()); #ifdef __APPLE__ printf("\taddis %s,%s,ha16(%d)\n",lrn,rrn,offset); printf("\t%s %s,lo16(%d)(%s)\n",ld,crn,offset,lrn); #else printf("\taddis %s,%s,%d@ha\n",lrn,rrn,offset); printf("\t%s %s,%d@l(%s)\n",ld,crn,offset,lrn); #endif free_register(reg); } else printf("\t%s %s,%d(%s)\n",ld,crn,offset,rrn); } 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("lwz",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),reg,cadr(e1),get_ptr_cache(ncaddr(e1))); cext(sign,sz,reg); } void code_register(int e2,int reg) { use_int(reg); if (reg!=e2) printf("\tmr %s,%s\n",register_name(reg),register_name(e2)); } extern void code_i2c(int reg) { use_int(reg); cext(1,1,reg); } extern void code_i2s(int reg) { use_int(reg); cext(1,SIZE_OF_SHORT,reg); } extern void code_u2uc(int reg) { use_int(reg); cext(0,1,reg); } extern void code_u2us(int reg) { use_int(reg); cext(0,SIZE_OF_SHORT,reg); } void code_rlvar(int e2,int reg) { use_int(reg); lvar_intro(e2); printf("\tlwz %s,",register_name(reg)); lvar(e2); } void code_crlvar(int e2,int reg,int sign,int sz) { use_int(reg); lvar_intro(e2); printf("\t%s %s,",cload(sz),register_name(reg)); lvar(e2); cext(sign,sz,reg); } void code_fname(NMTBL *n,int reg) { int r; use_int(reg); r = get_ptr_cache(n); if(r!=reg) printf("\tmr %s,%s\n",register_name(reg),register_name(r)); return; } void code_label_value(int label,int reg) { char *crn; use_int(reg); crn = register_name(reg); #ifdef __APPLE__ printf("\taddis %s,r31,ha16(L_%d-L_%d)\n",crn,label,code_base); printf("\tla %s,lo16(L_%d-L_%d)(%s)\n",crn,label,code_base,crn); #else printf("\tlis %s,.LC%d@ha\n",crn,label); printf("\tla %s,.LC%d@l(%s)\n",crn,label,crn); #endif return; } void code_const(int e2,int reg) { char *crn; use_int(reg); crn = register_name(reg); // printf("## 0x%08x\n",e2); #ifdef __APPLE__ if (-32768<e2&&e2<32768) printf("\tli %s,%d\n",crn,e2); else if ((e2&0xffff)==0) printf("\tlis %s,ha16(%d)\n",crn,e2); else { printf("\tlis %s,ha16(%d)\n",crn,e2); printf("\taddi %s,%s,lo16(%d)\n",crn,crn,e2); } #else if (-32768<e2&&e2<32768) printf("\tli %s,%d\n",crn,e2); else if ((e2&0xffff)==0) printf("\tlis %s,%d@ha\n",crn,e2); else { printf("\tlis %s,%d@ha\n",crn,e2); printf("\taddi %s,%s,%d@l\n",crn,crn,e2); } #endif } void code_neg(int creg) { use_int(creg); printf("\tneg %s,%s\n", register_name(creg), register_name(creg)); } void code_not(int creg) { use_int(creg); printf("\tnor %s,%s,%s\n", register_name(creg), register_name(creg),register_name(creg)); } void code_lnot(int creg) { use_int(creg); #ifdef __APPLE__ printf("\tsubfic r0,%s,0\n", register_name(creg)); printf("\tadde %s,r0,%s\n", register_name(creg),register_name(creg)); #else printf("\tsubfic 0,%s,0\n", register_name(creg)); printf("\tadde %s,0,%s\n", register_name(creg),register_name(creg)); #endif } void code_preinc(int e1,int e2,int dir,int sign,int sz,int reg) { char *xrn,*drn; if (car(e2)==REGISTER) { use_int(reg); printf("\taddi %s,%s,%d\n", register_name(cadr(e2)),register_name(cadr(e2)), dir); if (use && cadr(e2)!=reg) printf("\tmr %s,%s\n",register_name(reg),register_name(cadr(e2))); return; } g_expr(e2); if (!is_int_reg(creg)) error(-1); xrn = register_name(creg); if (reg==USE_CREG) { reg=get_register(); if (!reg) error(-1); drn = register_name(reg); set_ireg(reg,0); } else { drn = register_name(reg); } printf("\t%s %s,0(%s)\n",cload(sz),drn,xrn); if (use) cext(sign,sz,reg); printf("\taddi %s,%s,%d\n",drn,drn,dir); printf("\t%s %s,0(%s)\n",cstore(sz),drn,xrn); } void code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) { char *xrn,*crn,*nrn; int nreg; if (car(e2)==REGISTER) { use_int(reg); if (use) printf("\tmr %s,%s\n",register_name(reg),register_name(cadr(e2))); printf("\taddi %s,%s,%d\n", register_name(cadr(e2)),register_name(cadr(e2)),dir); return; } g_expr(e2); if (!is_int_reg(creg)) error(-1); crn = register_name(creg); nreg=get_register(); if (!nreg) error(-1); nrn = register_name(nreg); if (reg==USE_CREG) { reg=get_register(); if (!reg) error(-1); xrn = register_name(reg); set_ireg(reg,0); } else { xrn = register_name(reg); } printf("\t%s %s,0(%s)\n",cload(sz),xrn,crn); if (use) cext(sign,sz,reg); printf("\taddi %s,%s,%d\n",nrn,xrn,dir); printf("\t%s %s,0(%s)\n",cstore(sz),nrn,crn); free_register(nreg); } void code_return(int creg) { use_int(creg); code_label_value(retcont,creg); } #define R1SAVE 0 void code_environment(int creg) { /* save frame pointer */ use_int(creg); #if R1SAVE printf("\tlwz %s,0(%s)\n",register_name(creg),register_name(1)); #else printf("\tmr %s,%s\n",register_name(creg),register_name(REG_fp)); // int l = 0; // printf("\tla %s,",register_name(creg)); // printf("lo16(%d+L_%d)(r30)\n",FUNC_LVAR,lvar_offset_label); #endif } static int rexpr_bool(int e1,int reg); #if FLOAT_CODE static int drexpr_bool(int e1,int reg); #endif #if LONGLONG_CODE static int lrexpr_bool(int e1,int reg) { return 0; } #endif void code_bool(int e1,int reg) { char *xrn; int e2,e3; if (rexpr_bool(e1,reg)) return; #if FLOAT_CODE else if (drexpr_bool(e1,reg)) return; #endif #if LONGLONG_CODE else if (lrexpr_bool(e1,reg)) return; #endif b_expr(e1,1,e2=fwdlabel(),1); /* including > < ... */ if (use) { use_int(reg); xrn = register_name(reg); printf("\tli %s,0\n",xrn); jmp(e3=fwdlabel()); fwddef(e2); printf("\tli %s,1\n",xrn); fwddef(e3); } else { fwddef(e2); } } #define code_gt(cond) (cond?"gt":"le") #define code_ugt(cond) (cond?"gt":"le") #define code_ge(cond) (cond?"ge":"lt") #define code_uge(cond) (cond?"ge":"lt") #define code_eq(cond) (cond?"eq":"ne") static int cmpflag = 7; static void inc_cmpflag() { // gcc use cmpflag 4 and 7, and gcc4 believes flag 4 is preserved. do { cmpflag = (cmpflag+1)%8; } while (cmpflag!=4 && cmpflag!=7); } #ifdef __APPLE__ static char *crname_[] = { "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7" }; #else static char *crname_[] = { "0", "1", "2", "3", "4", "5", "6", "7" }; #endif #define crname(d) (crname_[d]) void code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) { use_int(reg); code_ld(cload(sz),reg,cadr(e1),get_ptr_cache(ncaddr(e1))); cext(0,sz,reg); inc_cmpflag(); printf("\tcmpwi %s,%s,0\n",crname(cmpflag),register_name(reg)); jcond(label,cond); } void code_cmp_crlvar(int e2,int reg, int sz,int label,int cond) { char *crn; use_int(reg); crn = register_name(reg); lvar_intro(e2); printf("\t%s %s,",cload(sz),crn); lvar(e2); cext(0,sz,reg); code_cmp_register(reg,label,cond); } void code_cmp_rgvar(int e1,int reg,int label,int cond) { use_int(reg); code_ld("lwz",reg,cadr(e1),get_ptr_cache(ncaddr(e1))); code_cmp_register(reg,label,cond); } void code_cmp_rlvar(int e2,int reg,int label,int cond) { char *crn; use_int(reg); crn = register_name(reg); lvar_intro(e2); printf("\tlwz %s,",crn); lvar(e2); code_cmp_register(reg,label,cond); } void code_cmp_register(int e2,int label,int cond) { use_int(e2); inc_cmpflag(); printf("\tcmpwi %s,%s,0\n",crname(cmpflag),register_name(e2)); jcond(label,cond); } void code_string(int e1,int creg) { int lb; NMTBL *n = ncaddr(e1); if ((lb=attr_value(n,LABEL))) { // already defined return code_label_value(lb,creg) ; } use_int(creg); lb = emit_string_label(); ascii(n->nm,n->dsp); if (output_mode==TEXT_EMIT_MODE) { printf(".text\n"); } else { text_mode(0); } code_label_value(lb,creg); 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)); } if (output_mode==TEXT_EMIT_MODE) { printf(".text\n"); } else { text_mode(0); } code_label_value(l,reg); } #define MAX_COPY_LEN 20 // #define MAX_COPY_LEN 10 void emit_copy(int from,int to,int length,int offset,int value,int det) { char *frn; char *trn; char *drn; char *memmove = "memmove"; int l; int dreg = get_register(); if (!dreg) error(-1); drn = register_name(dreg); use_int(from); use_int(to); frn = register_name(from); trn = register_name(to); /* length <0 means upward direction copy */ switch (length) { case 0: break; case 1: case -1: printf("\tlbz %s,%d(%s)\n",drn,offset,frn); printf("\tstb %s,%d(%s)\n",drn,offset,trn); break; case 2: case -2: printf("\tlhz %s,%d(%s)\n",drn,offset,frn); printf("\tsth %s,%d(%s)\n",drn,offset,trn); break; case 4: case -4: printf("\tlwz %s,%d(%s)\n",drn,offset,frn); printf("\tstw %s,%d(%s)\n",drn,offset,trn); break; default: if (length <0) { if (length >= -MAX_COPY_LEN) { free_register(dreg); dreg = 0; for(;length<=-4;length+=4,offset-=4) emit_copy(from,to,-4,offset-4,0,det); for(;length<=-2;length+=2,offset-=2) emit_copy(from,to,-2,offset-2,0,det); if(length<0) emit_copy(from,to,length,offset-1,0,det); break; } } else if (length <=MAX_COPY_LEN) { free_register(dreg); dreg = 0; for(;length>=4;length-=4,offset+=4) emit_copy(from,to,4,offset,0,det); for(;length>=2;length-=2,offset+=2) emit_copy(from,to,2,offset,0,det); if(length>0) emit_copy(from,to,length,offset,0,det); break; } clear_ptr_cache(); code_save_stacks(); l = list3(3,0,to); l = list3(4,l,from); parallel_rassign(l); #ifdef __APPLE__ printf("\tli r5,%d\n",length>0?length:-length); /* offset should be ignored */ /* overrap must be allowed */ printf("\tbl L_%s$stub\n",memmove); #else printf("\tli 5,%d\n",length>0?length:-length); /* offset should be ignored */ /* overrap must be allowed */ printf("\tbl %s\n",memmove); #endif 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(to); // set_ireg(to,1); } } if (dreg) free_register(dreg); } int push_struct(int e4,int t,int arg) { int length,count; int dreg,sreg; char *drn,*crn,*srn; g_expr(e4); if (!is_int_reg(creg)) error(-1); length=size(t); if(length%SIZE_OF_INT) { length += SIZE_OF_INT - (length%SIZE_OF_INT); } dreg = get_register(); if (!dreg) error(-1); drn = register_name(dreg); crn = register_name(creg); if (length<MAX_COPY_LEN) { sreg = get_register(); if (!sreg) error(-1); srn = register_name(sreg); code_lvar(cadr(arg),dreg); for(count=0;count<length;count+=SIZE_OF_INT) { printf("\tlwz %s,%d(%s)\n",srn,count,crn); printf("\tstw %s,%d(%s)\n",srn,count,drn); } free_register(sreg); free_register(dreg); return length/SIZE_OF_INT; } else { code_lvar(cadr(arg),dreg); /* downward direction copy */ emit_copy(creg,dreg,length,0,0,1); } free_register(dreg); return length/SIZE_OF_INT; } static void set_ireg(int reg,int mode) { if (!is_int_reg(reg)) error(-1); if (reg!=creg) { clear_ptr_cache_reg(reg); if (ireg && reg!=ireg ) { clear_ptr_cache_reg(ireg); if (regs[ireg]!=REG_VAR) free_register(ireg); if (mode) { printf("\tmr %s,%s\n",register_name(reg),register_name(ireg)); } } if (regs[creg]!=REG_VAR) { clear_ptr_cache_reg(creg); free_register(creg); } if (creg==lreg) lreg = 0; regs[reg]=USING_REG; } creg = ireg = reg; } static void set_freg(int reg,int mode) { if (!is_float_reg(reg)) error(-1); if (reg!=creg) { if (freg && reg!=freg) { free_register(freg); if (mode) { printf("\tfmr %s,%s\n",fregister_name(reg),fregister_name(freg)); } } // if (creg!=ireg) free_register(creg); regs[reg]=USING_REG; } creg = freg = reg; } static void set_lreg(int reg,int mode) { if (reg==RET_LREGISTER) { regv_l(reg) = RET_LREGISTER_L; regv_h(reg) = RET_LREGISTER_H; } if (!is_longlong_reg(reg)) error(-1); if (reg!=creg) { if (lreg) { if (reg!=lreg) { if (mode) { printf("\tmr %s,%s\n", lregister_name_low(reg),lregister_name_low(lreg)); printf("\tmr %s,%s\n", lregister_name_high(reg),lregister_name_high(lreg)); } free_register(lreg); } if (lreg==creg) creg=0; } if (creg) free_register(creg); regs[reg]=USING_REG; clear_ptr_cache_reg(regv_l(reg)); regs[regv_l(reg)]=USING_REG; clear_ptr_cache_reg(regv_h(reg)); regs[regv_h(reg)]=USING_REG; creg = lreg = reg; } } static void set_lreg_operand(int reg,int mode) { // save_stack,clear_ptr_cache is assumed if (!is_longlong_reg(reg)) { error(-1); return; } if (mode) { if (regv_l(reg)!=3) printf("\tmr %s,%s\n", register_name(3),lregister_name_high(reg)); if (regv_l(reg)!=4) printf("\tmr %s,%s\n", register_name(4),lregister_name_low(reg)); } } static void set_lreg_operand1(int reg,int mode) { // save_stack,clear_ptr_cache is assumed if (!is_longlong_reg(reg)) { error(-1); return; } if (mode) { if (regv_l(reg)!=5) printf("\tmr %s,%s\n", register_name(5),lregister_name_high(reg)); if (regv_l(reg)!=6) printf("\tmr %s,%s\n", register_name(6),lregister_name_low(reg)); } } static void use_reg(int arg) { // printf("## use reg %d\n",arg); if (arg<0||arg> REAL_MAX_REGISTER+REAL_MAX_FREGISTER+ REAL_MAX_LREGISTER) 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; } } /* store input argument into stack we need this always because of one path compiler */ static void code_save_input_registers(int dots) { int args; NMTBL *n; int reg; int tag; // int lvar; int t; /* fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); */ int reg_offset = 0; int offset = 0; int reg_var = 0; if (!parse_mode && dots) { int stype = type; int smode = mode; type = INT; mode = LDECL; stmode = 0; // lsearch defines local name NMTBL *n = def(lsearch("__my_va_list",0),0); n->dsp = offset; type = stype; mode = smode; } for(args = fnptr->dsp;args;args = cadr(args)) { n = ncadddr(args); tag = n->sc; reg = n->dsp; if (!n||n==&null_nptr) error(REG_ERR); if (tag==REGISTER) { n->dsp = offset; offset+=SIZE_OF_INT; t = INT; reg += reg_offset; /* for duplicated floating point argument */ reg_var++; } else if (tag==DREGISTER) { n->dsp = offset; t = n->ty; #ifdef __APPLE__ if(t==FLOAT) { offset+=SIZE_OF_FLOAT; reg_offset+=1; } else if(t==DOUBLE) { offset+=SIZE_OF_DOUBLE; reg_offset+=2; } else error(-1); reg_var += 2; #else if(t==FLOAT) { offset+=SIZE_OF_FLOAT; } else if(t==DOUBLE) { offset+=SIZE_OF_DOUBLE; } else error(-1); #endif } else if (tag==LREGISTER) { n->dsp = offset; t = n->ty; offset+=SIZE_OF_LONGLONG; reg_offset+=2; reg_var += 2; } else { // n->dsp = offset; this is no allowed becase of arg reorder offset += size(n->ty); continue; } n->sc = LVAR; g_expr_u(assign_expr0( list3n(LVAR,n->dsp,0),list3n(tag,reg,n),n->ty,t)); if (tag==REGISTER||tag==DREGISTER||tag==FREGISTER||tag==LREGISTER) { free_register(reg); } } if (dots) { while ((reg = get_input_register_var(reg_var,0,0))) { g_expr_u(assign_expr0( list3n(LVAR,offset,0),reg,INT,INT)); offset+=SIZE_OF_INT; reg_var++; } #ifndef __APPLE__ int skip = fwdlabel(); int freg_var = 0; printf("\tbne 1,%s%d\n",lpfx,skip); while ((reg = get_input_dregister_var(freg_var,0,0,1))) { g_expr_u(assign_expr0( list3n(LVAR,offset,0),reg,DOUBLE,DOUBLE)); offset+=SIZE_OF_DOUBLE; freg_var++; } fwddef(skip); #endif } my_func_args = offset; } int not_simple_p(int e3) { switch (e3) { case FUNCTION: case CONV: case LCALL: case STASS: case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: case LDIV: case LUDIV: case LMOD: case LUMOD: case LASSOP: case ALLOCA: case INLINE: return 1; } return 0; } static int simple_arg(int e3) { return !contains_p(e3,not_simple_p); } #define caller_arg_offset_v(arg) (ARG_LVAR_OFFSET+(arg)*SIZE_OF_INT) /* use input register as current register なんで、こんなに複雑なんだ? むしろ、INPUT_REG みたいな mark をいれたら? */ 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) { // free_regsiter(lreg) でいいんじゃないの? if (regv_l(lreg)==reg) { regs[lreg]=0; if (regv_h(lreg)>reg&®s[regv_h(lreg)]==USING_REG) { 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&®s[regv_l(lreg)]==USING_REG) { 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),mode); use_input_reg(regv_l(reg),mode); } else if (is_float_reg(reg)) { if (freg&® == freg) { if (creg==freg) creg = ireg; freg = 0; } } if (mode) use_reg(reg); } static int compute_complex_arg(int e3,int reg_arg_list,int arg) { int t=caddr(e3); int e4 = car(e3); reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==REGISTER||car(arg)==DREGISTER|| car(arg)==FREGISTER||car(arg)==LREGISTER) use_input_reg(cadr(arg),1); g_expr_u(assign_expr0(arg,e4,t,t)); car(e3) = arg; return reg_arg_list; } #ifdef __APPLE__ 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=type_value(caddr(e3)); if (t>=0&&(car(t)==BIT_FIELD)) { t = type_value(cadr(t)); } if(scalar(t)) { nargs ++ ; reg_arg++; } else if (t==LONGLONG||t==ULONGLONG) { nargs ++ ; reg_arg++; nargs ++ ; reg_arg++; } else if (t==FLOAT) { if (*preg_arg<MAX_INPUT_REGISTER_VAR) { reg_arg += 1; } freg_arg++; nargs += size(t)/SIZE_OF_INT; } else if (t==DOUBLE) { if (*preg_arg<MAX_INPUT_REGISTER_VAR) { reg_arg += 2; } nargs += size(t)/SIZE_OF_INT; freg_arg++; } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { nargs += round4(size(t))/SIZE_OF_INT; } else { error(TYERR); nargs ++ ; } *pnargs += nargs; *preg_arg += reg_arg; *pfreg_arg += freg_arg; } #else 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=type_value(caddr(e3)); if (t>=0&&(car(t)==BIT_FIELD)) { t = type_value(cadr(t)); } if(scalar(t)) { reg_arg++; if (*preg_arg>=MAX_INPUT_REGISTER_VAR) nargs ++ ; } else if (t==LONGLONG||t==ULONGLONG) { if (*preg_arg%2==1) reg_arg++; // alignment if (*pnargs%2==1) nargs++; // alignment reg_arg++; reg_arg++; if (*preg_arg+1>=MAX_INPUT_REGISTER_VAR) nargs += 2; } else if (t==FLOAT) { freg_arg++; if (*pfreg_arg>=MAX_INPUT_DREGISTER_VAR) nargs += size(t)/SIZE_OF_INT; } else if (t==DOUBLE) { freg_arg++; if (*pfreg_arg>=MAX_INPUT_DREGISTER_VAR) nargs += round4(size(t))/SIZE_OF_INT; } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { nargs += round4(size(t))/SIZE_OF_INT; } else { error(TYERR); nargs ++ ; } *pnargs += nargs; *preg_arg += reg_arg; *pfreg_arg += freg_arg; } #endif #define AS_SAVE 1 #define AS_ARG 0 /* set storage type of caller's arguments register or stack this muse corprate with code_arg_register(); if AS_SAVE is set, register variable (or temporary local variable) is used. */ static int get_input_arg(int t,int mode,int nargs,int reg_arg,int freg_arg) { t = type_value(t); if (t>=0&&(car(t)==BIT_FIELD)) { t = type_value(cadr(t)); } if(scalar(t)) { if (mode==AS_SAVE) { return get_register_var(0); } else if (reg_arg>=MAX_INPUT_REGISTER_VAR) { return list3n(LVAR,caller_arg_offset_v(nargs),0); } else { int e = get_input_register_var(reg_arg,0,0); clear_ptr_cache_reg(cadr(e)); return e; } } 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 { int e = get_input_lregister_var(reg_arg,0,0); clear_ptr_cache_reg(regv_l(cadr(e))); clear_ptr_cache_reg(regv_h(cadr(e))); return e; } } 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 (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,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); } } int function(int e1) { int e2,e3,e4,e5,nargs,t,r0; 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; char *jrn; int complex_; int pnargs=0,preg_arg=0,pfreg_arg=0; int stargs; special_lvar = -1; ret_type = function_type(cadddr(e1),&dots); if (caddr(cadddr(e1))==0) dots=1; arg_assign = 0; e2 = cadr(e1); if (car(e2) == FNAME) { fn=ncaddr(e2); } else { if (car(e2)==INDIRECT) e2=cadr(e2); // (*func)(i) case jmp = get_register_var(0); if (car(jmp)!=REGISTER) error(-1); reg_arg_list = list2(jmp,reg_arg_list); if (!simple_arg(e2)) { g_expr_u(assign_expr0(jmp,e2,INT,INT)); } else arg_assign = list2(assign_expr0(jmp,e2,INT,INT),arg_assign); } /* first we execute complex argument to avoid interaction with input variables */ stargs = 0; complex_ = 0; nargs = reg_arg = freg_arg = 0; for (e3 = e1 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) { t=caddr(e3); if ((e5= !simple_arg(car(e3)))) { if (complex_) { arg = get_input_arg(caddr(complex_),AS_SAVE, pnargs,preg_arg,pfreg_arg); reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); } pnargs=nargs;preg_arg=reg_arg;pfreg_arg=freg_arg; complex_ = e3; } if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { // The struct should be pushed after complex arguments. if (e5) { // compute address only, complex_ is me now. Clear it. complex_ = 0; e4 = car(e3); if (car(e4)==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 } } 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); } } 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)); if (t==LONGLONG||t==ULONGLONG) { if (reg_arg+1==MAX_INPUT_REGISTER_VAR) { // half register, half memory case arg_assign = list2( assign_expr0(r0=get_input_register_var(reg_arg,0,0), arg,INT,INT), arg_assign); use_input_reg(cadr(r0),1); } } car(e3)=0; // done } nargs = reg_arg = freg_arg = 0; for (e3 = e1; e3; increment_function_arg(e3,&nargs,®_arg,&freg_arg), e3 = cadr(e3)) { if (!(e4=car(e3))) continue; t=type_value(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) { set_ireg(cadr(arg),0); g_expr_u(assign_expr0(arg,e4,t,t)); use_input_reg(cadr(arg),1); } else g_expr_u(assign_expr0(arg,e4,t,t)); } else if (t==LONGLONG||t==ULONGLONG) { if (reg_arg+1==MAX_INPUT_REGISTER_VAR) { // half register, half memory case // put whole long long anyway arg_assign = list2( assign_expr0(r0=get_input_register_var(reg_arg,0,0), arg,INT,INT), arg_assign); use_input_reg(cadr(r0),1); reg_arg_list = list2(r0,reg_arg_list); } else { 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||t==FLOAT) { #ifdef __APPLE__ if (reg_arg<MAX_INPUT_REGISTER_VAR) { /* sigh... printf requires floating value in integer registers */ if (dots) { int r1; if (car(e4)==DRLVAR) { special_lvar = cadr(e4); e5 = list3n(LVAR,special_lvar,0); } else { special_lvar = new_lvar(SIZE_OF_DOUBLE); g_expr(assign_expr0( (e5=list3n(LVAR,special_lvar,0)),e4,DOUBLE,t)); reg_arg_list = list2(e5,reg_arg_list); e4 = list2(DREGISTER,freg); /* freg should not change until XXX */ } r0=get_input_register_var(reg_arg,0,0); r1 = reg_arg+1+MIN_TMP_REG; if (regs[r1]==PTRC_REG) clear_ptr_cache_reg(list2(REGISTER,r1)); /* else if (regs[r1]) error(-1); */ r1=get_input_register_var_1(reg_arg+1,0,0); use_input_reg(cadr(r0),1); /* protect from input register free */ use_input_reg(cadr(r1),1); /* protect from input register free */ reg_arg_list = list2(r0,reg_arg_list); reg_arg_list = list2(r1,reg_arg_list); arg_assign = list2( assign_expr0(r0,e5,INT,INT), arg_assign); arg_assign = list2( assign_expr0(r1, list3n(LVAR,special_lvar+SIZE_OF_INT,0), INT,INT), arg_assign); } } if (dots && (freg_arg*8+reg_arg*4)>=32 && freg_arg<MAX_INPUT_DREGISTER_VAR) { /* it requires integer register and floating register and stack value. */ arg_assign = list2( assign_expr0(list3n(LVAR,caller_arg_offset_v(nargs),0), get_input_dregister_var(freg_arg,0,0,1),t,t), arg_assign); } #endif reg_arg_list = list2(arg,reg_arg_list); if (car(arg)==DREGISTER) { set_freg(cadr(arg),0); g_expr_u(assign_expr0(arg,e4,t,t)); use_input_reg(cadr(arg),1); } else g_expr_u(assign_expr0(arg,e4,t,t)); } // 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(); #ifndef __APPLE__ if (dots) { if (freg_arg) { // variadic function has floating value in register printf("\tcreqv 6,6,6\n"); } else { // printf("\tcrxor 6,6,6\n"); // for value in stack } } #endif if (car(e2) == FNAME) { #ifdef __APPLE__ printf("\tbl\tL_%s$stub\n",fn->nm); #else printf("\tbl\t%s\n",fn->nm); #endif } else { jrn = register_name(cadr(jmp)); printf("\tmtctr %s\n",jrn); printf("\tbctrl\n"); } free_register_var(reg_arg_list); if (ret_type==DOUBLE||ret_type==FLOAT) { set_freg(RET_FREGISTER,0); } else if (ret_type==ULONGLONG||ret_type==LONGLONG) { set_lreg(RET_LREGISTER,0); use_reg(RET_LREGISTER); } else if (ret_type==VOID) { } else { set_ireg(RET_REGISTER,0); } cleanup_lregister0(); return ret_type; } void code_alloca(int e1,int reg) { char *crn,*grn; int g; if (!is_const(e1)) { g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); use_int(reg); } else { use_int(reg); code_const(round16(cadr(e1)),reg); } use_int(reg); g = get_register(); crn = register_name(reg); grn = register_name(g); // printf("\trlwinm r0,%s,0,0,27\n",crn); #ifdef R1SAVE printf("\tlwz %s,0(%s)\n",grn,register_name(1)); printf("\tneg %s,%s\n",crn,crn); printf("\tstwux %s,%s,%s\n",grn,register_name(1),crn); #else printf("\tlwz %s,0(%s)\n",grn,register_name(1)); printf("\tneg %s,%s\n",crn,crn); printf("\tstwux %s,%s,%s\n",grn,register_name(1),crn); #endif // printf("\tstw %s,0(r1)\n",grn); if (!max_func_arg_label) max_func_arg_label = fwdlabel(); #ifdef __APPLE__ printf("\taddis r1,r1,ha16(L_%d)\n",max_func_arg_label); printf("\taddi %s,r1,lo16(L_%d)\n",crn,max_func_arg_label); #else printf("\taddis 1,1,.LC%d@ha\n",max_func_arg_label); printf("\taddi %s,1,.LC%d@l\n",crn,max_func_arg_label); #endif free_register(g); } void code_frame_pointer(int e3) { use_int(e3); #if R1SAVE printf("\tmr %s,%s\n",register_name(1),register_name(e3)); #else printf("\tmr %s,%s\n",register_name(REG_fp),register_name(e3)); #endif } int code_frame_pointer_register() { return list2(REGISTER,REG_fp); } void code_fix_frame_pointer(int disp_offset) { #if 0 printf("\tla r30,"); printf("lo16(%d)(r30)\n",FUNC_LVAR(0)-CODE_LVAR(0)); #endif } void code_jmp(char *s) { max_reg_var = REG_VAR_BASE-REG_VAR_MIN; max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN; #ifdef __APPLE__ printf("\tb L_%s$stub\n",s); #else printf("\tb %s\n",s); #endif control=0; } void code_indirect_jmp(int e2) { max_reg_var = REG_VAR_BASE-REG_VAR_MIN; max_freg_var = FREG_VAR_BASE-FREG_VAR_MIN; use_int(e2); printf("\tmtctr %s\n",register_name(e2)); printf("\tbctr\n"); control=0; } static void code_add_op(char *op, char *crn, int offset, char *rrn) { #ifdef __APPLE__ if (LARGE_OFFSET(offset)) { printf("\taddis %s,%s,ha16(%d)\n",crn,crn,offset); } printf("\t%s %s,lo16(%d)(%s)\n",op,crn,offset,rrn); #else if (LARGE_OFFSET(offset)) { printf("\taddis %s,%s,%d@ha\n",crn,crn,offset); } printf("\t%s %s,%d@l(%s)\n",op,crn,offset,rrn); #endif } void code_rindirect(int e1, int reg,int offset, int sign,int sz) { char *crn,*rrn; g_expr(e1); if (!is_int_reg(creg)) error(-1); crn=register_name(creg); use_int(reg); rrn=register_name(reg); code_add_op(cload(sz),rrn,offset,crn); cext(sign,sz,reg); } #if FLOAT_CODE int code_drindirect(int e1, int reg,int offset, int d) { char *crn; g_expr(e1); if (!is_int_reg(creg)) error(-1); crn=register_name(creg); use_float(d,reg); code_add_op(fload(d),fregister_name(reg),offset,crn); return d?DOUBLE:FLOAT; } #endif #if LONGLONG_CODE static void lload(int creg,int reg,int offset) { char *crn = register_name(creg); #ifdef __APPLE__ if (LARGE_OFFSET(offset)) { printf("\taddis %s,%s,ha16(%d)\n",crn,crn,offset); } #if ENDIAN_L==0 if (creg!=regv_l(reg)) { printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset,crn); printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn); } else { printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn); printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset,crn); } #else if (creg!=regv_h(reg)) { printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset,crn); printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn); } else { printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn); printf("\tlwz %s,lo16(%d)(%s)\n",lregister_name_high(reg),offset,crn); } #endif #else if (LARGE_OFFSET(offset)) { printf("\taddis %s,%s,%d@ha\n",crn,crn,offset); } #if ENDIAN_L==0 if (creg!=regv_l(reg)) { printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset,crn); printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn); } else { printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset+SIZE_OF_INT,crn); printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset,crn); } #else if (creg!=regv_h(reg)) { printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset,crn); printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn); } else { printf("\tlwz %s,%d@l(%s)\n",lregister_name_low(reg),offset+SIZE_OF_INT,crn); printf("\tlwz %s,%d@l(%s)\n",lregister_name_high(reg),offset,crn); } #endif #endif } int code_lrindirect(int e1, int reg, int offset, int us) { char *crn; int creg0; g_expr(e1); if (!is_int_reg(creg)) error(-1); crn=register_name(creg0=creg); use_longlong(reg); lload(creg0,reg,offset); return us?ULONGLONG:LONGLONG; } #endif void code_assign_gvar(int e2,int creg,int byte) { use_int(creg); code_ldf(cstore(byte),register_name(creg),cadr(e2), get_ptr_cache(ncaddr(e2))); } void code_assign_lvar(int e2,int creg,int byte) { char *crn; use_int(creg); crn=register_name(creg); lvar_intro(e2); printf("\t%s %s,",cstore(byte),crn); lvar(e2); } void code_assign_register(int e2,int byte,int creg) { use_int(creg); if (e2!=creg) printf("\tmr %s,%s\n",register_name(e2),register_name(creg)); } void code_assign(int e2,int byte,int creg) { char *drn; char *crn; use_int(e2); drn=register_name(e2); use_int(creg); crn=register_name(creg); printf("\t%s %s,0(%s)\n",cstore(byte),crn,drn); } void code_register_assop(int e2,int reg, int op,int byte) { // reg <= reg(e2) op=reg use_int(reg); tosop(op,e2,reg); } void code_assop(int op,int creg, int byte,int sign) { int xreg; // (*pop()) op = creg // creg should be ecx use_int(creg); xreg = emit_pop(0); /* pop e3 value */ emit_push(); ld_indexx(byte,0,creg,ireg,sign); tosop(op,ireg,xreg); emit_pop_free(xreg); xreg = emit_pop(0); /* pop e3 value */ printf("\t%s %s,0(%s)\n",cstore(byte), register_name(ireg),register_name(xreg)); emit_pop_free(xreg); } int tosop_operand_safe_p(int op) { return 1; } void tosop(int op,int creg,int oreg) { int dx = -1; int ox = -1; char *orn,*crn,*drn; // 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("slw",creg,oreg); if(ox!=-1) free_register(ox); return; case RSHIFT: shift("sraw",creg,oreg); if(ox!=-1) free_register(ox); return; case URSHIFT: shift("srw",creg,oreg); if(ox!=-1) free_register(ox); return; } orn = register_name(oreg); crn = register_name(creg); switch(op) { case ADD: printf("\tadd %s,%s,%s\n",crn,crn,orn); break; case SUB: printf("\tsub %s,%s,%s\n",crn,crn,orn); break; case CMP: inc_cmpflag(); printf("\tcmpw %s,%s,%s\n",crname(cmpflag),crn,orn); break; case UCMP: inc_cmpflag(); printf("\tcmplw %s,%s,%s\n",crname(cmpflag),crn,orn); break; case BAND: printf("\tand %s,%s,%s\n",crn,crn,orn); break; case EOR: printf("\txor %s,%s,%s\n",crn,crn,orn); break; case BOR: printf("\tor %s,%s,%s\n",crn,crn,orn); break; case MUL: printf("\tmullw %s,%s,%s\n",crn,crn,orn); break; case UMUL: printf("\tmullw %s,%s,%s\n",crn,crn,orn); break; case DIV: printf("\tdivw %s,%s,%s\n",crn,crn,orn); break; case UDIV: printf("\tdivwu %s,%s,%s\n",crn,crn,orn); break; case MOD: dx=get_register(); drn = register_name(dx); printf("\tdivw %s,%s,%s\n",drn,crn,orn); printf("\tmullw %s,%s,%s\n",drn,drn,orn); printf("\tsubf %s,%s,%s\n",crn,drn,crn); break; case UMOD: dx=get_register(); drn = register_name(dx); printf("\tdivwu %s,%s,%s\n",drn,crn,orn); printf("\tmullw %s,%s,%s\n",drn,drn,orn); printf("\tsubf %s,%s,%s\n",crn,drn,crn); break; default: error(-1); } if(dx!=-1) free_register(dx); if(ox!=-1) free_register(ox); } int code_const_op_p(int op,int v) { if (car(v)!=CONST) return 0; if (op==DIV||op==UDIV) return ilog(v); if (op==BAND||op==MOD||op==UMOD) return 0; v = cadr(v); return (-32766<v&&v<32767); } void oprtc(int op,int creg, int v) { char *crn; int l; use_int(creg); crn = register_name(creg); v = cadr(v); switch(op) { case LSHIFT: case ULSHIFT: printf("\tslwi %s,%s,%d\n",crn,crn,v); return; case DIV: v = ilog(v); case RSHIFT: printf("\tsrawi %s,%s,%d\n",crn,crn,v); return; case UDIV: v = ilog(v); case URSHIFT: printf("\tsrwi %s,%s,%d\n",crn,crn,v); return; case ADD: #ifdef __APPLE__ printf("\taddi %s,%s,lo16(%d)\n",crn,crn,v); #else printf("\taddi %s,%s,%d@l\n",crn,crn,v); #endif break; case SUB: #ifdef __APPLE__ printf("\taddi %s,%s,lo16(-%d)\n",crn,crn,v); #else printf("\taddi %s,%s,-%d@l\n",crn,crn,v); #endif break; case CMP: inc_cmpflag(); #ifdef __APPLE__ printf("\tcmpwi %s,%s,lo16(%d)\n",crname(cmpflag),crn,v); #else printf("\tcmpwi %s,%s,%d@l\n",crname(cmpflag),crn,v); #endif break; case UCMP: inc_cmpflag(); #ifdef __APPLE__ printf("\tcmplwi %s,%s,lo16(%d)\n",crname(cmpflag),crn,v); #else printf("\tcmplwi %s,%s,%d@l\n",crname(cmpflag),crn,v); #endif break; case EOR: #ifdef __APPLE__ printf("\txori %s,%s,lo16(%d)\n",crn,crn,v); #else printf("\txori %s,%s,%d@l\n",crn,crn,v); #endif break; case BOR: #ifdef __APPLE__ printf("\tori %s,%s,lo16(%d)\n",crn,crn,v); #else printf("\tori %s,%s,%d@l\n",crn,crn,v); #endif break; case MUL: case UMUL: if ((l=ilog(v))) { printf("\tslwi %s,%s,%d\n",crn,crn,l); } else #ifdef __APPLE__ printf("\tmulli %s,%s,lo16(%d)\n",crn,crn,v); #else printf("\tmulli %s,%s,%d@l\n",crn,crn,v); #endif break; default: error(-1); } } void shift(char *op, int creg, int reg) { char *crn; char *rrn = register_name(reg); use_int(creg); crn = register_name(creg); printf("\t%s %s,%s,%s\n",op,crn,crn,rrn); } void ld_indexx(int byte, int n, int xreg,int creg, int sign) { char *crn; use_int(creg); crn = register_name(creg); printf("\t%s %s,%d(%s)\n",cload(byte),register_name(creg),n, register_name(xreg)); cext(sign,byte,creg); } int code_csvalue() { return glist2(REGISTER,creg); } void code_cmpdimm(int e, int csreg,int label,int cond) { int reg,regsv; /* used in dosiwtch() */ inc_cmpflag(); if (-32767<e&&e<32767) { printf("\tcmpwi %s,%s,%d\n",crname(cmpflag),register_name(csreg),e); jcond(label,cond); } else { regsv = regs[csreg]; regs[csreg]=USING_REG; reg = get_register(); regs[csreg]= regsv; code_const(e,reg); printf("\tcmpw %s,%s,%s\n",crname(cmpflag),register_name(csreg),register_name(reg)); jcond(label,cond); free_register(reg); } } void code_opening(char *filename) { printf("\t.file \"%s\"\n",filename); /* printf("\t.version\t\"01.01\"\n"); */ printf("cbc_compiled.:\n"); // printf(".text\n"); #ifndef __APPLE__ printf( " .set r0,0\n" " .set r1,1\n" " .set r2,2\n" " .set r3,3\n" " .set r4,4\n" " .set r5,5\n" " .set r6,6\n" " .set r7,7\n" " .set r8,8\n" " .set r9,9\n" " .set r10,10\n" " .set r11,11\n" " .set r12,12\n" " .set r13,13\n" " .set r14,14\n" " .set r15,15\n" " .set r16,16\n" " .set r17,17\n" " .set r18,18\n" " .set r19,19\n" " .set r20,20\n" " .set r21,21\n" " .set r22,22\n" " .set r23,23\n" " .set r24,24\n" " .set r25,25\n" " .set r26,26\n" " .set r27,27\n" " .set r28,28\n" " .set r29,29\n" " .set r30,30\n" " .set r31,31\n" ); #endif } #define CRBITSIZ 4 static int rexpr_bool(int e1,int reg) { int t,flag=-1,eq=-1,neg=-1; char *rn; switch(car(e1)) { case GT: t=INT; flag = 2; break; case UGT: t=0; flag = 2; break; case GE: t=INT; flag = 2; eq=3; break; case UGE: t=0; flag = 2; eq=3; break; case LT: t=INT; flag = 1; break; case ULT: t=0; flag = 1; break; case LE: t=INT; flag = 1; eq=3; break; case ULE: t=0; flag = 1; eq=3; break; case EQ: t=INT; flag = 3; break; case NEQ: t=INT; flag = 3; neg=3; break; default: return 0; } g_expr(list3((t==INT?CMP:UCMP),cadr(e1),caddr(e1))); use_int(reg); rn = register_name(reg); t = CRBITSIZ*cmpflag; if (eq>0) { printf("\tcror %d,%d,%d\n",t+flag-1,t+eq-1,t+flag-1); } if (neg>0) { neg = t+neg-1, printf("\tcrnor %d,%d,%d\n",neg,neg,neg); } printf("\tmfcr %s\n",rn); printf("\trlwinm %s,%s,%d,1\n",rn,rn,t+flag); return 1; } int rexpr(int e1, int l1, int cond,int t) { char *s=0; switch(car(e1)+BNOT*(!cond)) { case GT: s=code_gt(1); break; case UGT: s=code_ugt(1); break; case GE: s=code_ge(1); break; case UGE: s=code_uge(1); break; case LT: s=code_ge(!1); break; case ULT: s=code_uge(!1);break; case LE: s=code_gt(!1); break; case ULE: s=code_ugt(!1);break; case EQ: s=code_eq(1); break; case NEQ: s=code_eq(!1); break; case GT+BNOT: s=code_gt(0); break; case UGT+BNOT: s=code_ugt(0); break; case GE+BNOT: s=code_ge(0); break; case UGE+BNOT: s=code_uge(0); break; case LT+BNOT: s=code_ge(!0); break; case ULT+BNOT: s=code_uge(!0);break; case LE+BNOT: s=code_gt(!0); break; case ULE+BNOT: s=code_ugt(!0);break; case EQ+BNOT: s=code_eq(0); break; case NEQ+BNOT: s=code_eq(!0); break; default: error(-1); } g_expr(list3((t==INT?CMP:UCMP),cadr(e1),caddr(e1))); printf("\tb%s %s,%s%d\n",s,crname(cmpflag),lpfx,l1); return l1; } static void jcond(int l, char cond) { if (cond==LT) { printf("\tb%s %s,%s%d\n",code_ge(0),crname(cmpflag),lpfx,l); } else if (cond==1||cond==0) { printf("\tb%s %s,%s%d\n",cond?"ne":"eq",crname(cmpflag),lpfx,l); } else error(-1); } void jmp(int l) { printf("\tb\t%s%d\n",lpfx,l); } extern void code_comment(char *s) { printf("## %s",s); } void code_enter(char *name) { #ifdef __APPLE__ if (output_mode!=TEXT_EMIT_MODE) text_mode(0); else printf("\t.align 2\n"); if (stmode!=STATIC) printf(".globl _%s\n",name); #ifdef DOT_SIZE printf("\t.type\t%s,@function\n",name); #endif printf("_%s:\n",name); code_disp_label=fwdlabel(); #if 0 printf("\tla r1,lo16(L_%d)(r30)\n",code_disp_label); #else printf("\tla r1,lo16(L_%d)(r30)\n",code_disp_label); printf("\taddis r1,r1,ha16(L_%d)\n",code_disp_label); #endif printf("\tbcl 20,31,L_%d\n",code_base = fwdlabel()); fwddef(code_base); printf("\tmflr r31\n"); max_func_args = 0; clear_ptr_cache(); #else if (output_mode!=TEXT_EMIT_MODE) text_mode(0); else printf("\t.align 2\n"); if (stmode!=STATIC) printf(".globl %s\n",name); #ifdef DOT_SIZE printf("\t.type\t%s,@function\n",name); #endif printf("%s:\n",name); code_disp_label=fwdlabel(); #if 0 printf("\tla r1,lo16(L_%d)(r30)\n",code_disp_label); #else printf("\tla 1,%s%d@l(31)\n",lpfx,code_disp_label); printf("\taddis 1,1,%s%d@ha\n",lpfx,code_disp_label); #endif max_func_args = 0; clear_ptr_cache(); #endif } 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) { int r1_offsetv; disp&= -SIZE_OF_INT; r1_offsetv = -disp+max_func_args*SIZE_OF_INT -code_disp_offset0 +8+32+48; #ifdef __APPLE__ printf(".set L_%d,%d\n",code_disp_label,-r1_offsetv); if (max_func_arg_label) { printf(".set L_%d,%d\n",max_func_arg_label,max_func_args*SIZE_OF_INT+24); max_func_arg_label = 0; } #else printf(".set .LC%d,%d\n",code_disp_label,-r1_offsetv); if (max_func_arg_label) { printf(".set .LC%d,%d\n",max_func_arg_label,max_func_args*SIZE_OF_INT+24); max_func_arg_label = 0; } #endif local_table(); // free_all_register(); } void enter(char *name) { #ifdef __APPLE__ if (output_mode!=TEXT_EMIT_MODE) text_mode(0); else printf("\t.align 2\n"); if (stmode!=STATIC) printf(".globl %s%s\n",npfx,name); /* printf("\t.type\t%s,@function\n",name); */ printf("%s%s:\n",npfx,name); code_setup=fwdlabel(); printf("\tmflr r0\n"); printf("\tbl L_%d\n",code_setup); code_base=fwdlabel(); fwddef(code_base); r1_offset_label = fwdlabel(); lvar_offset_label = fwdlabel(); #if 0 printf("\taddi r30,r1,lo16(-L_%d)\n",lvar_offset_label); printf("\tstwu r1,lo16(-L_%d)(r1)\n",r1_offset_label); // printf("\tmr r30,r1\n"); #else printf("\taddi r30,r1,lo16(-L_%d)\n",lvar_offset_label); printf("\tlis r31,ha16(-L_%d)\n",r1_offset_label); printf("\taddi r31,r31,lo16(-L_%d)\n",r1_offset_label); printf("\tstwux r1,r1,r31\n"); #endif printf("\tmflr r31\n"); #else if (output_mode!=TEXT_EMIT_MODE) text_mode(0); else printf("\t.align 2\n"); if (stmode!=STATIC) printf(".globl %s%s\n",npfx,name); /* printf("\t.type\t%s,@function\n",name); */ printf("%s:\n",name); control = 1; code_setup=fwdlabel(); arg_offset_label = fwdlabel(); printf("\tmflr 0\n"); printf("\tstwu %d,-%s%d@l(%d)\n",1,lpfx,arg_offset_label,1); printf("\tbl .LC%d\n",code_setup); r1_offset_label = fwdlabel(); lvar_offset_label = fwdlabel(); printf("\tmr %d,1\n",REG_fp); printf("\taddi %d,1,-%s%d@l\n",REG_fp,lpfx,lvar_offset_label); printf("\tlis %d,-%s%d@ha\n",30,lpfx,r1_offset_label); printf("\taddi %d,%d,-%s%d@l\n",30,30,lpfx,r1_offset_label); printf("\tstwux 1,1,%d\n",30); #endif max_func_args = 0; clear_ptr_cache(); } void enter1() { text_mode(0); // set_lreg(LREG_LREGISTER,0); set_ireg(CREG_REGISTER,0); set_freg(FREG_FREGISTER,0); } int reg_save_offset() { return -( (REAL_MAX_REGISTER-(REG_VAR_BASE-max_reg_var))*SIZE_OF_INT+ (REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*SIZE_OF_DOUBLE ); } void code_label_call(int l) { #ifdef __APPLE__ printf("\tbl\tL_%d\n",l); #else printf("\tbl\t.LC%d\n",l); #endif } void code_ret() { printf("\tblr\n"); } #ifndef __APPLE__ static int saveFP_used=0; static char *saveFP_lib[] = { ".saveFP: stfd 14,-144(1)", " stfd 15,-136(1)", " stfd 16,-128(1)", " stfd 17,-120(1)", " stfd 18,-112(1)", " stfd 19,-104(1)", " stfd 20,-96(1)", " stfd 21,-88(1)", " stfd 22,-80(1)", " stfd 23,-72(1)", " stfd 24,-64(1)", " stfd 25,-56(1)", " stfd 26,-48(1)", " stfd 27,-40(1)", " stfd 28,-32(1)", " stfd 29,-24(1)", " stfd 31,-16(1)", " stfd 30,-8(1)", " stw 0,4(1)", " blr", ".restFP: ", " lfd 14,-144(1)", " lfd 15,-136(1)", " lfd 16,-128(1)", " lfd 17,-120(1)", " lfd 18,-112(1)", " lfd 19,-104(1)", " lfd 20,-96(1)", " lfd 21,-88(1)", " lfd 22,-80(1)", " lfd 23,-72(1)", " lfd 24,-64(1)", " lfd 25,-56(1)", " lfd 26,-48(1)", " lfd 27,-40(1)", " lfd 28,-32(1)", " lfd 29,-24(1)", " lwz 0,4(1)", " lfd 31,-16(1)", " lwz 1,0(1)", " mtlr 0", " blr", 0 }; #endif static void make_return_continuation() { #if R1SAVE retcont1 = fwdlabel(); #endif fwddef(retcont); if (cadr(fnptr->ty)==FLOAT||cadr(fnptr->ty)==DOUBLE) { printf("\tfmr %s,%s\n",fregister_name(1),fregister_name(31)); printf("\tmr %s,%s\n",register_name(30),register_name(28)); } else if (cadr(fnptr->ty)>0&&( car(cadr(fnptr->ty))==STRUCT || car(cadr(fnptr->ty))==UNION)) { int sz = size(cadr(fnptr->ty)); #ifdef __APPLE__ printf("\tli r7,%d\n",sz); printf("\tsubl r6,r7,r30\n"); printf("\tlwz r3,lo16(%d)(r30)\n",(my_func_args-1)*SIZE_OF_INT); // emit_copy(6,3,sz,0,1,1); #else printf("\tli 7,%d\n",sz); printf("\tsubl 6,7,%d\n",REG_fp); printf("\tlwz 3,%d@l(%d)\n",(my_func_args-1)*SIZE_OF_INT,REG_fp); // emit_copy(6,3,sz,0,1,1); #endif printf("\tmr %s,%s\n",register_name(30),register_name(28)); } else if (cadr(fnptr->ty)!=VOID) { printf("\tmr %s,%s\n",register_name(3),register_name(29)); printf("\tmr %s,%s\n",register_name(30),register_name(28)); } #if R1SAVE jmp(retcont1); #else #endif } void leave(int control, char *name) { #if R1SAVE int retcont1=0; #else #endif if (max_freg_var>=0 && max_freg_var<=3) max_freg_var=3; reg_save = reg_save_offset(); if (control) { code_set_return_register(1); } if (retcont) { if (control) jmp(retlabel); make_return_continuation(); } fwddef(retlabel); #if R1SAVE printf("\tlwz %s,0(%s)\n",register_name(1),register_name(1)); if (retcont) { fwddef(retcont1); } #else #ifdef __APPLE__ printf("\taddi r1,r30,lo16(L_%d)\n",lvar_offset_label); #else printf("\taddi 1,%d,%s%d@l\n",REG_fp,lpfx,lvar_offset_label); #endif #endif if (max_freg_var>=0) { #ifdef __APPLE__ printf("\tlmw r%d,%d(%s)\n", REG_VAR_BASE-max_reg_var,reg_save,register_name(1)); freg_save = 72-(REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*4; printf("\tb restFP+%d ; restore f%d-f31\n", freg_save, FREG_VAR_BASE-max_freg_var); #else printf("\tlmw %d,%d(%s)\n", REG_VAR_BASE-max_reg_var,reg_save,register_name(1)); freg_save = 72-(REAL_MAX_FREGISTER-(FREG_VAR_BASE-max_freg_var))*4; printf("\tb .restFP+%d # restore f%d-f31\n", freg_save, FREG_VAR_BASE-max_freg_var); #endif } else { #ifdef __APPLE__ printf("\tlwz r0,8(r1)\n"); printf("\tmtlr r0\n"); printf("\tlmw r%d,%d(r1)\n", REG_VAR_BASE-max_reg_var,reg_save); #else printf("\tlmw %d,%d(1)\n", REG_VAR_BASE-max_reg_var,reg_save); printf("\tlwz %s,4(1)\n",register_name(0)); printf("\tlwz 1,0(1)\n"); printf("\tmtlr %s\n",register_name(0)); #endif code_ret(); } disp &= -SIZE_OF_INT; fwddef(code_setup); #ifdef __APPLE__ printf("\tstmw %s,%d(%s)\n", register_name(REG_VAR_BASE-max_reg_var),reg_save,register_name(1)); printf("\tstw %s,8(%s)\n",register_name(0),register_name(1)); #else printf("\tstmw %s,%d(%s)\n", register_name(REG_VAR_BASE-max_reg_var),reg_save,register_name(1)); printf("\tstw %s,4(%s)\n",register_name(0),register_name(1)); #endif if (max_freg_var>=0) { #ifdef __APPLE__ printf("\tb saveFP+%d ; save f%d-f31\n", freg_save, FREG_VAR_BASE-max_freg_var); #else saveFP_used = 1; printf("\tb .saveFP+%d # save f%d-f31\n", freg_save, FREG_VAR_BASE-max_freg_var); #endif } else { printf("\tblr\n"); } code_offset_set(); local_table(); labelno++; // free_all_register(); } int code_set_return_register(int mode) { if (cadr(fnptr->ty)==DOUBLE||cadr(fnptr->ty)==FLOAT) { set_freg(RET_FREGISTER,mode); return freg; } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) { set_lreg(RET_LREGISTER,mode); return lreg; } else if (cadr(fnptr->ty)==VOID) { return 0; } else { set_ireg(RET_REGISTER,mode); return ireg; } } int code_get_fixed_creg(int reg,int type) { return creg; } void code_set_fixed_creg(int reg,int mode,int type) { if (type==FLOAT||type==DOUBLE) { set_freg(reg,mode); } else if (type==LONGLONG||type==ULONGLONG) { set_lreg(reg,mode); // use_reg(reg); } else { set_ireg(reg,mode); } } void gen_gdecl(char *n, int gpc) { /* if (stmode!=STATIC) printf(".globl _%s\n",n); */ } extern void ascii(char *s,int len) { cstring_mode(); 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\t.align 2\n",34); } extern int emit_string_label() { int lb; lb=fwdlabel(); cstring_mode(); printf("%s%d:\n",lpfx,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 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; } } 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); if (n && n->sc!=STATIC) printf("\t.globl\t%s%s\n",npfx,n->nm); printf("%s%s:\n",npfx,n->nm); } extern void emit_space(int sp) { data_mode(0); printf("\t.space\t%d\n",sp); } extern void emit_char(int d) { data_mode(0); printf("\t.byte %d\n",d); } extern void emit_short(int d) { data_mode(0); printf("\t.short %d\n",d); } extern void emit_int(int d) { data_mode(0); printf("\t.long %d\n",d); } extern void emit_longlong(int e) { #if LONGLONG_CODE long long d = lcadr(e); data_mode(0); #if ENDIAN_L==0 printf("\t.long\t0x%x,0x%x\n",code_l1(d),code_l2(d)); #else printf("\t.long\t0x%x,0x%x\n",code_l2(d),code_l1(d)); #endif #endif } extern void emit_double(int e) { #if FLOAT_CODE double d = dcadr(e); data_mode(0); #if ENDIAN_D==0 printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d)); #else printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d)); #endif #endif } extern void emit_float(int e) { #if FLOAT_CODE float f = dcadr(e); data_mode(0); printf("\t.long\t0x%x\n",*(int *)&f); #endif } extern void emit_address(char *s,int offset) { data_mode(0); if (offset) printf("\t.long %s%s+%d\n",npfx,s,offset); else printf("\t.long %s%s\n",npfx,s); } extern void emit_label(int labelno) { data_mode(0); printf("\t.long %s%d\n",lpfx,labelno); } extern void emit_data_closing(NMTBL *n) { #ifdef DOT_SIZE int lb; #endif if (mode==GDECL) { #ifdef DOT_SIZE #ifdef __APPLE__ data_mode(0); lb=fwdlabel(); printf("%s%d:\n",lpfx,lb); printf("\t.size\t%s,%s%d-%%ss\n",n->nm,lb,lpfx,npfx,n->nm); #else data_mode(0); lb=fwdlabel(); printf(".LC%d:\n",lb); printf("\t.size\t%s,%s%d-%s%s\n",n->nm,lb,lpfx,npfx,n->nm); #endif #endif } } #ifdef __APPLE__ void global_table(void) { NMTBL *n; int init; char *extrn; init=0; global_list = reversen(global_list); text_mode(0); for(n = global_list;n!=&null_nptr;n = n->next) { if ((n->sc == GVAR) && n->dsp != -1) { /* n->dsp = -1 means initialized global */ if (init==0) { // data_mode(0); text_mode(0); printf("\t.align 3\n"); init=1; } int align; if ((align=attr_value(n,ALIGNED))) { int a = ilog(caddr(align)); printf(".comm %s%s,%d,%d\n",npfx,n->nm,size(n->ty),a); } else if (size(n->ty)>1) { printf(".comm %s%s,%d,2\n",npfx,n->nm,size(n->ty)); } else printf(".comm %s%s,%d\n",npfx,n->nm,size(n->ty)); } 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) { text_mode(0); printf("\t.align 8\n"); // data_mode(0); init=1; } printf(".lcomm %s%s,%d\n",npfx,n->nm,size(n->ty)); } } for(n = global_list;n!=&null_nptr;n = n->next) { if (is_code(n)||is_function(n)) { extrn = n->nm; if (n->sc==EXTRN1) { data_mode(0); printf(".picsymbol_stub\n"); printf("L_%s$stub:\n",extrn); printf("\t.indirect_symbol _%s\n",extrn); printf("\tmflr r0\n"); printf("\tbcl 20,31,L0$_%s\n",extrn); printf("L0$_%s:\n",extrn); printf("\tmflr r11\n"); printf("\taddis r11,r11,ha16(L_%s$lazy_ptr-L0$_%s)\n",extrn,extrn); printf("\tmtlr r0\n"); printf("\tlwz r12,lo16(L_%s$lazy_ptr-L0$_%s)(r11)\n",extrn,extrn); printf("\tmtctr r12\n"); printf("\taddi r11,r11,lo16(L_%s$lazy_ptr-L0$_%s)\n",extrn,extrn); printf("\tbctr\n"); printf(".data\n"); printf(".lazy_symbol_pointer\n"); printf("L_%s$lazy_ptr:\n",extrn); printf("\t.indirect_symbol _%s\n",extrn); printf("\t.long dyld_stub_binding_helper\n"); } else if (n->sc==STATIC) { text_mode(0); printf("\t.set L_%s$stub,_%s\n",extrn,extrn); data_mode(0); printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",extrn,extrn); } } } init=0; for(n = global_list;n!=&null_nptr;n = n->next) { if (n->sc == GVAR) { if (init==0) { printf(".data\n"); init=1; } printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",n->nm,n->nm); } } init = 0; for(n = global_list;n!=&null_nptr;n = n->next) { if ((is_code(n)||is_function(n))&& !has_attr(n,FNAME)) // not used as value continue; if (n->sc==EXTRN1) { if(init==0) { printf(".data\n"); printf(".non_lazy_symbol_pointer\n"); init=1; } printf("L_%s$non_lazy_ptr:\n",n->nm); printf("\t.indirect_symbol _%s\n",n->nm); printf("\t.long\t0\n"); } } } #else static void comm(NMTBL *n) { int align = 1; if ((align=attr_value(n,ALIGNED))) { align = ilog(caddr(align)); } else { if (size(n->ty)>4) align = 2; else if (size(n->ty)>4) align = 0; switch(n->ty) { case DOUBLE: case LONGLONG: case ULONGLONG: align = 8; break; case INT: case UNSIGNED: case FLOAT: align = 4; break; case SHORT: case USHORT: align = 2; break; } } printf("\t.comm %s,%d,%d\n",n->nm,size(n->ty),align); } void global_table(void) { NMTBL *n; int init; init=0; global_list = reversen(global_list); 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); } } } #endif #ifdef __APPLE__ void local_table(void) { NMTBL *n; int init; init=0; /* static local variables */ for(n = local_static_list;n!=&null_nptr;n = n->next) { if (n->sc == STATIC) { if (init==0) { data_mode(0); init=1; } if (n->dsp != -1) /* initialized static */ printf(".lcomm _%s,%d\n",n->nm,size(n->ty)); printf("L_%s$non_lazy_ptr:\n\t.long\t_%s\n",n->nm,n->nm); } } } #else void local_table(void) { NMTBL *n; int init; init=0; /* static local variables */ for(n = local_static_list;n!=&null_nptr;n = n->next) { if (n->sc == STATIC) { if (init==0) { data_mode(0); init=1; } if (n->dsp != -1) /* initialized static */ printf(".lcomm %s,%d\n",n->nm,size(n->ty)); } } } #endif void cstring_mode(int align) { if (output_mode!=RODATA_EMIT_MODE) { #ifdef __APPLE__ printf(".cstring\n\t.align 2\n"); #else printf("\t.section\t.rodata\n\t.align 2\n"); #endif output_mode = RODATA_EMIT_MODE; } } void text_mode(int align) { if (output_mode!=TEXT_EMIT_MODE) { printf(".text\n"); printf("\t.align 2\n"); 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); */ } #if FLOAT_CODE /* floating point */ static int float_one_lib_used=0; static char *float_one_lib[] = { ".data", /* ".literal8", */ " .align 3", "__float_one:", " .long 1065353216", ".text", /* ".set L__float_one$non_lazy_ptr,__float_one", */ 0 }; static int float_zero_lib_used=0; static char *float_zero_lib[] = { ".data", /* ".literal8", */ " .align 3", "__float_zero:", " .long 0", ".text", /* ".set L__float_zero$non_lazy_ptr,__float_zero", */ 0 }; char * fstore(int d) { return (d?"stfd":"stfs"); } char * fload(int d) { return d?"lfd":"lfs"; } void code_cmp_dregister(int e2,int d,int label,int cond) { char *frn,*rrn,*grn; int greg,r; grn = fregister_name(greg = get_dregister(d)); use_float(d,e2); frn = register_name(e2); float_zero_lib_used=1; r = get_ptr_cache(&float_zero); rrn = register_name(r); printf("\tlfs %s,0(%s)\n",grn,rrn); inc_cmpflag(); printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),grn,frn); free_register(greg); jcond(label,cond); return; } void code_dregister(int e2,int freg,int d) { use_float(d,freg); if (freg!=e2) { if (is_int_reg(e2)) error(-1); printf("\tfmr %s,%s\n",fregister_name(freg),fregister_name(e2)); } } void code_dassign_gvar(int e2,int freg,int d) { use_float(d,freg); code_ldf(fstore(d),fregister_name(freg),cadr(e2), get_ptr_cache(ncaddr(e2))); } void code_dassign_lvar(int e2,int freg,int d) { use_float(d,freg); lvar_intro(e2); printf("\t%s %s,",fstore(d),fregister_name(freg)); lvar(e2); } void code_dassign(int e2,int freg,int d) { use_float(d,freg); printf("\t%s %s,0(%s)\n",fstore(d),fregister_name(freg),register_name(e2)); } void code_dassign_dregister(int e2,int d,int freg) { use_float(d,freg); if (e2!=freg) { printf("\tfmr %s,%s\n",fregister_name(e2),fregister_name(freg)); } } static double d0 = 1.0; int code_d1(double d) { int *i = (int *)&d0; int *j = (int *)&d; return (i[1] == 0x3ff00000)?j[0]:j[1]; } int code_d2(double d) { int *i = (int *)&d0; int *j = (int *)&d; return (i[1] == 0x3ff00000)?j[1]:j[0]; } int code_f(double d) { float f = d; int *j = (int *)&f; return *j; } static void emit_dconst0(ValuePtr value, int lb, void *arg) { long d = (long) arg; printf(" \t.data\n\t.align 3\n"); printf("%s%d:\n",lpfx,lb); if (d) { #if ENDIAN_D==0 printf("\t.long\t0x%x,0x%x\n",code_d1(value->d),code_d2(value->d)); #else printf("\t.long\t0x%x,0x%x\n",code_d2(value->d),code_d1(value->d)); #endif } else { printf("\t.long\t0x%x\n",code_f(value->f)); } if (output_mode==TEXT_EMIT_MODE) { printf(".text\n"); } else { text_mode(0); } } /* load double / float const we should keep what constant we have create */ void code_dconst(int e2,int freg,int d) { int sz; Value value; value.d = dcadr(e2); int r; char *rrn,*frn; use_float(d,freg); frn = fregister_name(freg); if (value.d==0.0) { float_zero_lib_used=1; r = get_ptr_cache(&float_zero); rrn = register_name(r); printf("\tlfs %s,0(%s)\n",frn,rrn); return; } if (value.d==1.0) { float_one_lib_used=1; r = get_ptr_cache(&float_one); rrn = register_name(r); printf("\tlfs %s,0(%s)\n",frn,rrn); return; } if (d) { sz = sizeof(double); } else { sz = sizeof(float); value.f = (float) value.d; } long d_mode = d; int lb = get_data_label(&value,sz,emit_dconst0, (void*) d_mode); rrn = register_name((r=get_register())); // use_reg(r); // to clear ptr cache code_label_value(lb,r); if (d) { printf("\tlfd %s,0(%s)\n",frn,rrn); } else { printf("\tlfs %s,0(%s)\n",frn,rrn); } free_register(r); } void code_builtin_fabsf(int e) { char *frn; g_expr0(e); use_float(0,freg); frn = fregister_name(freg); printf("\tfabs %s,%s\n",frn,frn); } void code_builtin_fabs(int e) { char *frn; g_expr0(e); use_float(1,freg); frn = fregister_name(freg); printf("\tfabs %s,%s\n",frn,frn); } static void code_inf(int d) { int lb; int r; char *rrn,*frn; int freg = USE_CREG; use_float(d,freg); frn = fregister_name(freg); rrn = register_name((r=get_register())); use_reg(r); // to clear ptr cache printf(" \t.data\n\t.align 3\n"); lb=fwdlabel(); printf("L_%d:\n",lb); if (d) { #if ENDIAN_D==0 printf("\t.long\t0x%x,0x%x\n",0,0x7ff00000); #else printf("\t.long\t0x%x,0x%x\n",0x7ff00000,0); #endif } else { printf("\t.long\t0x%x\n",0x7f800000); } if (output_mode==TEXT_EMIT_MODE) { printf(".text\n"); } else { text_mode(0); } code_label_value(lb,r); if (d) { printf("\tlfd %s,0(%s)\n",frn,rrn); } else { printf("\tlfs %s,0(%s)\n",frn,rrn); } free_register(r); } void code_builtin_inff() { code_inf(0); } void code_builtin_inf() { code_inf(1); } void code_dneg(int freg,int d) { char *frn; use_float(d,freg); frn = fregister_name(freg); printf("\tfneg %s,%s\n",frn,frn); } void code_d2i() { char *frn; char *crn; int e2 = new_lvar(SIZE_OF_DOUBLE); use_double0(); frn = fregister_name(freg); use_int0(); crn = register_name(creg); free_lvar(e2); printf("\tfctiwz %s,%s\n",frn,frn); lvar_intro(e2); printf("\tstfd %s,",frn); lvar(e2); lvar_intro(e2+SIZE_OF_DOUBLE-SIZE_OF_INT); printf("\tlwz %s,",crn); lvar(e2+SIZE_OF_DOUBLE-SIZE_OF_INT); } static int i2d_lib_used=0; #ifdef __APPLE__ static char *i2d_lib[] = { ".data", /* ".literal8", */ " .align 3", "__i2dLC0:", " .long 1127219200", " .long -2147483648", ".text", " .align 2", "i2d_:", " mflr r0", " bcl 20,31,__i2dL1$pb", "__i2dL1$pb:", " mflr r10", " mtlr r0", " xoris r3,r3,0x8000", " stw r3,-28(r1)", " lis r0,0x4330", " stw r0,-32(r1)", " lfd f0,-32(r1)", " addis r9,r10,ha16(__i2dLC0-__i2dL1$pb)", " lfd f1,lo16(__i2dLC0-__i2dL1$pb)(r9)", " fsub f1,f0,f1", " blr", 0 }; #else static char *i2d_lib[] = { ".data", /* ".literal8", */ " .align 3", "__i2dLC0:", " .long 1127219200", " .long -2147483648", ".text", " .align 2", "i2d_:", " xoris 3,3,0x8000", " stw 3,-28(1)", " lis 0,0x4330", " stw 0,-32(1)", " lfd 0,-32(1)", " lis 9,__i2dLC0@ha", " lfd 1,__i2dLC0@l(9)", " fsub 1,0,1", " blr", 0 }; #endif void code_i2d() { i2d_lib_used = 1; clear_ptr_cache(); code_save_stacks(); set_ireg(RET_REGISTER,1); printf("\tbl i2d_\n"); set_freg(RET_FREGISTER,0); } static int d2u_lib_used=0; #ifdef __APPLE__ static char *d2u_lib[] = { /* ".literal8", */ " .align 3", "__d2uLC0:", " .long 1105199104", " .long 0", ".text", " .align 2", "d2u_:", " mflr r0", " bcl 20,31,__d2uL1$pb", "__d2uL1$pb:", " mflr r10", " mtlr r0", " addis r9,r10,ha16(__d2uLC0-__d2uL1$pb)", " lfd f0,lo16(__d2uLC0-__d2uL1$pb)(r9)", " fcmpu cr0,f1,f0", " cror 2,1,2", " beq- cr0,__d2uL2", " fctiwz f0,f1", " stfd f0,-32(r1)", " lwz r3,-28(r1)", " blr", "__d2uL2:", " addis r9,r10,ha16(__d2uLC0-__d2uL1$pb)", " lfd f0,lo16(__d2uLC0-__d2uL1$pb)(r9)", " fsub f0,f1,f0", " fctiwz f0,f0", " stfd f0,-24(r1)", " lwz r3,-20(r1)", " xoris r3,r3,0x8000", " blr", 0 }; #else static char *d2u_lib[] = { /* ".literal8", */ " .align 3", "__d2uLC0:", " .long 1105199104", " .long 0", ".text", " .align 2", "d2u_:", " lis 9,__d2uLC0@ha", " lfd 0,__d2uLC0@l(9)", " fcmpu 0,1,0", " cror 2,1,2", " beq- 0,__d2uL2", " fctiwz 0,1", " stfd 0,-32(1)", " lwz 3,-28(1)", " blr", "__d2uL2:", " lis 9,__d2uLC0@ha", " lfd 0,__d2uLC0@l(9)", " fsub 0,1,0", " fctiwz 0,0", " stfd 0,-24(1)", " lwz 3,-20(1)", " xoris 3,3,0x8000", " blr", 0 }; #endif void code_d2u() { code_save_stacks(); clear_ptr_cache(); d2u_lib_used=1; set_freg(RET_FREGISTER,1); printf("\tbl d2u_\n"); set_ireg(RET_REGISTER,0); } static int u2d_lib_used=0; #ifdef __APPLE__ static char *u2d_lib[] = { ".data", /* ".literal8", */ " .align 3", "__u2dLC1:", " .long 1127219200", " .long 0", ".text", " .align 2", "u2d_:", " mflr r0", " bcl 20,31,__u2dL2$pb", "__u2dL2$pb:", " mflr r10", " mtlr r0", " stw r3,-28(r1)", " lis r0,0x4330", " stw r0,-32(r1)", " lfd f0,-32(r1)", " addis r9,r10,ha16(__u2dLC1-__u2dL2$pb)", " lfd f1,lo16(__u2dLC1-__u2dL2$pb)(r9)", " fsub f1,f0,f1", " blr", 0 }; #else static char *u2d_lib[] = { ".data", /* ".literal8", */ " .align 3", "__u2dLC1:", " .long 1127219200", " .long 0", ".text", " .align 2", ".u2d_:", " stw 3,-28(1)", " lis 0,0x4330", " stw 0,-32(1)", " lfd 0,-32(1)", " lis 9,__u2dLC1@ha", " lfd 1,__u2dLC1@l(9)", " fsub 1,0,1", " blr", 0 }; #endif void code_u2d() { code_save_stacks(); clear_ptr_cache(); u2d_lib_used = 1; set_ireg(RET_REGISTER,1); #ifdef __APPLE__ printf("\tbl u2d_\n"); #else printf("\tbl .u2d_\n"); #endif set_freg(RET_FREGISTER,0); } void code_d2f() { } void code_f2d() { } void code_f2i() { code_d2i(); } void code_f2u() { code_d2u(); } void code_i2f() { code_i2d(); } void code_u2f() { code_u2d(); } void code_drgvar(int e2,int d,int freg) { 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) { use_float(d,freg); lvar_intro(e2); printf("\t%s %s,",fload(d),fregister_name(freg)); lvar(e2); } void code_cmp_drgvar(int e2,int reg,int d,int label,int cond) { char *frn; int g=get_dregister(d); char *grn=fregister_name(g); use_float(d,reg); frn=fregister_name(reg); code_ldf(fload(1),grn,cadr(e2), get_ptr_cache(ncaddr(e2))); inc_cmpflag(); printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn); free_register(g); jcond(label,cond); } void code_cmp_drlvar(int e2,int reg,int d,int label,int cond) { char *frn; int g=get_dregister(d); char *grn=fregister_name(g); use_float(d,reg); frn=fregister_name(reg); lvar_intro(e2); printf("\t%s %s,",fload(1),grn); lvar(e2); inc_cmpflag(); printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn); free_register(g); jcond(label,cond); } void dtosop(int op,int reg,int oreg) { char *opn=""; char *frn; char *grn; int ox = -1; use_float(1,reg); if(oreg==-1) { error(-1); } else if (oreg<= -REG_LVAR_OFFSET) { ox = get_dregister(1); if (ox<0) error(-1); use_reg(ox); code_drlvar(oreg+REG_LVAR_OFFSET,1,ox); oreg = ox; } grn=fregister_name(oreg); frn=fregister_name(reg); switch(op) { case FADD: case DADD: opn="fadd"; break; case FSUB: case DSUB: opn="fsub"; break; case FDIV: case DDIV: opn="fdiv"; break; case FMUL: case DMUL: opn="fmul"; break; case FCMP: case DCMP: inc_cmpflag(); printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn); if (ox!=-1) free_register(ox); return; case FCMPGE: case DCMPGE: inc_cmpflag(); printf("\tfcmpu %s,%s,%s\n",crname(cmpflag),frn,grn); if (ox!=-1) free_register(ox); return; default: error(-1); return; } printf("\t%s %s,%s,%s\n",opn,frn,frn,grn); if (ox!=-1) free_register(ox); } void code_dassop(int op,int reg,int d) { /* we have lvalue in creg, applied floating value is in freg */ // (*creg) op = pop() int xreg=emit_dpop(d); char *crn; char *frn; crn=register_name(ireg); use_float(d,reg); frn =fregister_name(reg); printf("\t%s %s,0(%s)\n",fload(d),frn,crn); dtosop(op,reg,xreg); printf("\t%s %s,0(%s)\n",fstore(d),frn,crn); emit_dpop_free(xreg,d); } void code_register_dassop(int reg,int op,int d) { // reg op= dpop() int xreg=emit_dpop(d); dtosop(op,reg,xreg); emit_dpop_free(xreg,d); } static int code_dload_1(int d) { int r,g; char *drn,*grn; // load 1 float_one_lib_used=1; r = get_ptr_cache(&float_one); drn=register_name(r); grn=fregister_name(g=get_dregister(d)); printf("\tlfs %s,0(%s)\n",grn,drn); return g; } void code_dpreinc(int e1,int e2,int d,int reg) { char *frn,*crn,*grn; int g; 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); printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",crn,crn,grn); if (use && reg!=cadr(e2)) printf("\tfmr %s,%s\n",frn,crn); } else { g_expr(e2); if (!is_int_reg(creg)) error(-1); crn=register_name(ireg); if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); set_freg(reg,0); } frn=fregister_name(reg); grn = fregister_name(g = code_dload_1(d)); printf("\t%s %s,0(%s)\n",fload(d),frn,crn); printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",frn,frn,grn); printf("\t%s %s,0(%s)\n",fstore(d),frn,crn); } free_register(g); } void code_dpostinc(int e1,int e2,int d,int reg) { char *frn,*crn,*grn; int g; 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)) printf("\tfmr %s,%s\n",frn,crn); printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",crn,crn,grn); } else { g_expr(e2); if (!is_int_reg(creg)) error(-1); crn=register_name(ireg); if (reg==USE_CREG) { reg=get_dregister(d); if (!reg) error(-1); set_freg(reg,0); } frn=fregister_name(reg); grn = fregister_name(g = code_dload_1(d)); printf("\t%s %s,0(%s)\n",fload(d),frn,crn); printf("\t%s %s,%s,%s\n",(caddr(e1)>0)?"fadd":"fsub",grn,frn,grn); printf("\t%s %s,0(%s)\n",fstore(d),grn,crn); } free_register(g); } static int drexpr_bool(int e1,int reg) { int flag=-1,eq=-1,neg=-1,t; char *rn; switch(car(e1)) { case DOP+GT: case FOP+GT: flag = 2; break; case DOP+GE: case FOP+GE: flag = 2; eq=3; break; case DOP+LT: case FOP+LT: flag = 1; break; case DOP+LE: case FOP+LE: flag = 1; eq=3; break; case DOP+EQ: case FOP+EQ: flag = 3; break; case DOP+NEQ: case FOP+NEQ: flag = 3; neg=3; break; default: return 0; } g_expr(list3(DCMP,cadr(e1),caddr(e1))); use_int(reg); rn = register_name(reg); t = CRBITSIZ*cmpflag; if (eq>0) { printf("\tcror %d,%d,%d\n",t+flag-1,t+eq-1,t+flag-1); } if (neg>0) { neg = t+neg-1, printf("\tcrnor %d,%d,%d\n",neg,neg,neg); } printf("\tmfcr %s\n",rn); printf("\trlwinm %s,%s,%d,1\n",rn,rn,t+flag); return 1; } int drexpr(int e1, int e2,int l1, int op,int cond) { 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; } } g_expr(list3(DCMP, e1,e2)); switch(op) { case DOP+GT: case FOP+GT: printf("\tbgt\t%s,%s%d\n",crname(cmpflag),lpfx,l1); break; case DOP+GE: case FOP+GE: printf("\tbge\t%s,%s%d\n",crname(cmpflag),lpfx,l1); break; case DOP+EQ: case FOP+EQ: printf("\tbeq\t%s,%s%d\n",crname(cmpflag),lpfx,l1); break; case DOP+NEQ: case FOP+NEQ: printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,l1); break; } return l1; } int emit_dpop(int d) { int xreg,reg; xreg=pop_fregister(); if (xreg<= -REG_LVAR_OFFSET) { reg = get_dregister(d); code_drlvar(REG_LVAR_OFFSET+xreg,1,reg); free_lvar(REG_LVAR_OFFSET+xreg); xreg=reg; } return xreg; } void emit_dpop_free(int e1,int d) { if (e1>=0 && e1!=creg && regs[e1]!=REG_VAR) free_register(e1); } void emit_dpush(int d) { int new_reg; if (!is_float_reg(creg)) error(-1); if (freg_sp>MAX_MAX) error(-1); new_reg = get_dregister(1); /* 絶対に取れる */ freg_stack[freg_sp++] = freg; /* push するかわりにレジスタを使う */ creg = freg = new_reg; } #endif #if LONGLONG_CODE /* 64bit int part */ static void lmove(int to,int from) // to <= from { int tmp; if (regv_h(to)==regv_l(from)&&(regv_l(to)==regv_h(from))) { tmp = get_register(); printf("\tmr %s,%s\n",register_name(tmp),lregister_name_low(from)); printf("\tmr %s,%s\n",lregister_name_high(to),lregister_name_high(from)); printf("\tmr %s,%s\n",lregister_name_low(to),register_name(tmp)); free_register(tmp); } else if (regv_h(to)==regv_l(from)) { printf("\tmr %s,%s\n",lregister_name_low(to),lregister_name_low(from)); printf("\tmr %s,%s\n",lregister_name_high(to),lregister_name_high(from)); } else { printf("\tmr %s,%s\n",lregister_name_high(to),lregister_name_high(from)); printf("\tmr %s,%s\n",lregister_name_low(to),lregister_name_low(from)); } } static void pcond(char *s,int cmpflag,int l1) { printf("\tb%s %s,%s%d\n",s,crname(cmpflag),lpfx,l1); } static int lcmp(int op,int cond) { if (op==LOP+UGT||op==LOP+UGE) { return UCMP; } else if (op==LOP+LE||op==LOP+GE) { return CMP; } else { return CMP; } } int lrexpr(int e1, int e2,int l1, int op,int cond) { int reg; int e3; int l2; int op1,cr0,cr1; g_expr(e1); emit_lpush(); g_expr(e2); e3 = emit_lpop(); if (!is_longlong_reg(creg)) error(-1); reg = lreg; op1 = lcmp(op,cond); tosop(op1,regv_h(e3),regv_h(reg)); cr0 = cmpflag; tosop(op1,regv_l(e3),regv_l(reg)); cr1 = cmpflag; l2 = fwdlabel(); // cond==0 jump on false condtion ( if(x) => rexpr(.. cond=0 ...) ) switch(op+(!cond)*BNOT) { case LOP+GT: case LOP+GE: pcond(code_gt(1),cr0,1?l1:l2); pcond(code_eq(0),cr0,1?l2:l1); break; case LOP+UGT: case LOP+UGE: pcond(code_ugt(1),cr0,1?l1:l2); pcond(code_eq(0), cr0,1?l2:l1); break; case LOP+EQ: pcond(code_eq(0),cr0,(1?l2:l1)); pcond(code_eq(cond),cr1,l1); break; case LOP+NEQ: pcond(code_eq(0),cr0,(1?l1:l2)); pcond(code_eq(!1),cr1,l1); break; case LOP+GT+BNOT: case LOP+GE+BNOT: pcond(code_gt(1),cr0,0?l1:l2); pcond(code_eq(0),cr0,0?l2:l1); break; case LOP+UGT+BNOT: case LOP+UGE+BNOT: pcond(code_ugt(1),cr0,0?l1:l2); pcond(code_eq(0), cr0,0?l2:l1); break; case LOP+EQ+BNOT: pcond(code_eq(0),cr0,(0?l2:l1)); pcond(code_eq(0),cr1,l1); break; case LOP+NEQ+BNOT: pcond(code_eq(0),cr0,(0?l1:l2)); pcond(code_eq(!0),cr1,l1); break; default: error(-1); } switch(op+BNOT*(!cond)) { case LOP+GT: pcond(code_gt(1), cr1,l1); break; case LOP+GE: pcond(code_ge(1), cr1,l1); break; case LOP+UGT: pcond(code_ugt(1), cr1,l1); break; case LOP+UGE: pcond(code_uge(1), cr1,l1); break; case LOP+GT+BNOT: pcond(code_gt(0), cr1,l1); break; case LOP+GE+BNOT: pcond(code_ge(0), cr1,l1); break; case LOP+UGT+BNOT: pcond(code_ugt(0), cr1,l1); break; case LOP+UGE+BNOT: pcond(code_uge(0), cr1,l1); break; } fwddef(l2); emit_lpop_free(e3); return l1; } int emit_lpop() { int xreg,reg; xreg=lreg_stack[--lreg_sp]; if (xreg<= -REG_LVAR_OFFSET) { reg = get_lregister(); code_lrlvar(REG_LVAR_OFFSET+xreg,reg); free_lvar(REG_LVAR_OFFSET+xreg); xreg = reg; } return xreg; } void code_lregister(int e2,int reg) { use_longlong(reg); if (reg!=e2) { lmove(reg,e2); } } void code_cmp_lregister(int reg,int label,int cond) { use_longlong(reg); printf("\tor %s,%s,%s\n", lregister_name_low(reg), lregister_name_low(reg), lregister_name_high(reg)); inc_cmpflag(); printf("\tcmpwi %s,%s,0\n",crname(cmpflag),lregister_name_low(reg)); jcond(label,cond); } void code_cmp_lrgvar(int e1,int creg,int label,int cond) { use_longlong(creg); code_lrgvar(e1,creg); code_cmp_lregister(creg,label,cond); } void code_cmp_lrlvar(int e1,int creg,int label,int cond) { use_longlong(creg); code_lrlvar(e1,creg); code_cmp_lregister(creg,label,cond); } void code_lassign(int e2,int creg) { char *drn = register_name(e2); char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); #if ENDIAN_L==0 printf("\tstw %s,0(%s)\n",crn_l,drn); printf("\tstw %s,%d(%s)\n",crn_h,SIZE_OF_INT,drn); #else printf("\tstw %s,0(%s)\n",crn_h,drn); printf("\tstw %s,%d(%s)\n",crn_l,SIZE_OF_INT,drn); #endif } void code_lassign_gvar(int e2,int creg) { int r; use_longlong(creg); r = get_ptr_cache(ncaddr(e2)); #if ENDIAN_L==0 code_ldf(cstore(0),lregister_name_low(creg),cadr(e2),r); code_ldf(cstore(0),lregister_name_high(creg),cadr(e2)+SIZE_OF_INT,r); #else code_ldf(cstore(0),lregister_name_high(creg),cadr(e2),r); code_ldf(cstore(0),lregister_name_low(creg),cadr(e2)+SIZE_OF_INT,r); #endif } void code_lassign_lvar(int e2,int creg) { char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); lvar_intro(e2); #if ENDIAN_L==0 printf("\tstw %s,",crn_l);lvar(e2); printf("\tstw %s,",crn_h);lvar(e2+SIZE_OF_INT); #else printf("\tstw %s,",crn_h);lvar(e2); printf("\tstw %s,",crn_l);lvar(e2+SIZE_OF_INT); #endif } void code_lassign_lregister(int e2,int reg) { use_longlong(reg); if (e2!=reg) { lmove(e2,reg); } } static long long ll0 = 1LL; static int code_l1(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[1]:j[0]; } static int code_l2(long long d) { int *i = (int *)&ll0; int *j = (int *)&d; return (i[1] == 1)?j[0]:j[1]; } void code_lconst(int e1,int creg) { use_longlong(creg); #if ENDIAN_L==0 code_const(code_l1(lcadr(e1)),regv_h(creg)); code_const(code_l2(lcadr(e1)),regv_l(creg)); #else code_const(code_l1(lcadr(e1)),regv_l(creg)); code_const(code_l2(lcadr(e1)),regv_h(creg)); #endif } void code_lneg(int creg) { use_longlong(creg); printf("\tsubfic %s,%s,0\n", lregister_name_low(creg),lregister_name_low(creg)); printf("\tsubfze %s,%s\n", lregister_name_high(creg),lregister_name_high(creg)); } 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(cload(0),crn_l,cadr(e1),r); code_ldf(cload(0),crn_h,cadr(e1)+SIZE_OF_INT,r); #else code_ldf(cload(0),crn_h,cadr(e1),r); code_ldf(cload(0),crn_l,cadr(e1)+SIZE_OF_INT,r); #endif } void code_lrlvar(int e1,int creg) { char *crn_h; char *crn_l; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); lvar_intro(e1); #if ENDIAN_L==0 printf("\tlwz %s,",crn_l); lvar(e1); printf("\tlwz %s,",crn_h); lvar(e1+SIZE_OF_INT); #else printf("\tlwz %s,",crn_h); lvar(e1); printf("\tlwz %s,",crn_l); lvar(e1+SIZE_OF_INT); #endif } #if 0 static int lumod_lib_used=0; static char *lumod_lib[] = { }; static int lmod_lib_used=0; static char *lmod_lib[] = { }; static int ludiv_lib_used=0; static char *ludiv_lib[] = { }; static int ldiv_lib_used=0; static char *ldiv_lib[] = { }; #endif static int lsrd_lib_used=0; static char *lsrd_lib[] = { #ifdef __APPLE__ ".text", " .align 2", ".lsrd__:", " mr. r5,r5", " beqlr", " subfic r2,r5,32", " stw r3,-32(r1)", " stw r4,-28(r1)", " cmpwi cr7,r2,0", " bgt+ cr7,L__lsrd1", " neg r0,r2", " lwz r2,-32(r1)", " li r9,0", " srw r2,r2,r0", " stw r9,-48(r1)", " b L__lsrd2", "L__lsrd1: lwz r0,-32(r1)", " slw r9,r0,r2", " lwz r2,-28(r1)", " srw r0,r0,r5", " srw r2,r2,r5", " stw r0,-48(r1)", " or r2,r2,r9", "L__lsrd2: stw r2,-44(r1)", " lwz r3,-48(r1)", " lwz r4,-44(r1)", " blr", #else ".text", " .align 2", ".lsrd__:", " mr. 5,5", " beqlr", " subfic 8,5,32", " stw 3,-32(1)", " stw 4,-28(1)", " cmpwi 7,8,0", " bgt+ 7,.L__lsrd1", " neg 0,2", " lwz 8,-32(1)", " li 9,0", " srw 8,8,0", " stw 9,-48(1)", " b .L__lsrd2", ".L__lsrd1: lwz 0,-32(1)", " slw 9,0,8", " lwz 8,-28(1)", " srw 0,0,5", " srw 8,8,5", " stw 0,-48(1)", " or 8,8,9", ".L__lsrd2: stw 8,-44(1)", " lwz 3,-48(1)", " lwz 4,-44(1)", " blr", #endif 0 }; static int asld_lib_used=0; static char *asld_lib[] = { #ifdef __APPLE__ ".text", " .align 2", ".asld__:", " mr. r5,r5", " beqlr", " subfic r2,r5,32", " stw r3,-32(r1)", " stw r4,-28(r1)", " cmpwi cr7,r2,0", " bgt+ cr7,L__asld1", " neg r0,r2", " lwz r2,-28(r1)", " li r9,0", " slw r2,r2,r0", " stw r9,-44(r1)", " b L__asld2", "L__asld1: lwz r0,-28(r1)", " srw r9,r0,r2", " lwz r2,-32(r1)", " slw r0,r0,r5", " slw r2,r2,r5", " stw r0,-44(r1)", " or r2,r2,r9", "L__asld2: stw r2,-48(r1)", " lwz r3,-48(r1)", " lwz r4,-44(r1)", " blr", #else ".text", " .align 2", ".asld__:", " mr. 5,5", " beqlr", " subfic 8,5,32", " stw 3,-32(1)", " stw 4,-28(1)", " cmpwi 7,8,0", " bgt+ 7,.L__asld1", " neg 0,8", " lwz 8,-28(1)", " li 9,0", " slw 8,8,0", " stw 9,-44(1)", " b .L__asld2", ".L__asld1: lwz 0,-28(1)", " srw 9,0,8", " lwz 8,-32(1)", " slw 0,0,5", " slw 8,8,5", " stw 0,-44(1)", " or 8,8,9", ".L__asld2: stw 8,-48(1)", " lwz 3,-48(1)", " lwz 4,-44(1)", " blr", #endif 0 }; static int asrd_lib_used=0; static char *asrd_lib[] = { #ifdef __APPLE__ ".text", " .align 2", ".asrd__:", " mr. r5,r5", " beqlr", " subfic r2,r5,32", " stw r3,-32(r1)", " stw r4,-28(r1)", " cmpwi cr7,r2,0", " bgt+ cr7,L__asrd1", " lwz r0,-32(r1)", " neg r2,r2", " sraw r2,r0,r2", " srawi r0,r0,31", " b L__asrd2", "L__asrd1: lwz r0,-32(r1)", " slw r9,r0,r2", " lwz r2,-28(r1)", " sraw r0,r0,r5", " srw r2,r2,r5", " or r2,r2,r9", "L__asrd2: stw r0,-48(r1)", " stw r2,-44(r1)", " lwz r3,-48(r1)", " lwz r4,-44(r1)", " blr", #else ".text", " .align 2", ".asrd__:", " mr. 5,5", " beqlr", " subfic 8,5,32", " stw 3,-32(1)", " stw 4,-28(1)", " cmpwi 7,8,0", " bgt+ 7,.L__asrd1", " lwz 0,-32(1)", " neg 8,8", " sraw 8,0,8", " srawi 0,0,31", " b .L__asrd2", ".L__asrd1: lwz 0,-32(1)", " slw 9,0,8", " lwz 8,-28(1)", " sraw 0,0,5", " srw 8,8,5", " or 8,8,9", ".L__asrd2: stw 0,-48(1)", " stw 8,-44(1)", " lwz 3,-48(1)", " lwz 4,-44(1)", " blr", #endif 0 }; #endif static void extern_conv(char *conv) { code_save_stacks(); clear_ptr_cache(); extern_define(conv,0,FUNCTION,1); #ifdef __APPLE__ printf("\tbl L_%s$stub\n",conv); #else printf("\tbl %s\n",conv); #endif } #if FLOAT_CODE #if 0 static int d2ll_lib_used=0; static char *d2ll_lib[] = { }; static int d2ull_lib_used=0; static char *d2ull_lib[] = { }; static int f2ll_lib_used=0; static char *f2ll_lib[] = { }; static int f2ull_lib_used=0; static char *f2ull_lib[] = { }; static int ll2d_lib_used=0; static char *ll2d_lib[] = { }; static int ll2f_lib_used=0; static char *ll2f_lib[] = { }; #endif #endif static void code_asld_lib(int reg,int oreg) { code_save_stacks(); clear_ptr_cache(); asld_lib_used = 1; set_lreg_operand(reg,1); set_lreg(RET_LREGISTER,0); if (regv_l(oreg)!=5) { printf("\tmr %s,%s\n", register_name(5), lregister_name_low(oreg)); } printf("\tbl .asld__\n"); } static void code_asrd_lib(int reg,int oreg) // ___ashrdi3$stub { code_save_stacks(); clear_ptr_cache(); asrd_lib_used = 1; set_lreg_operand(reg,1); set_lreg(RET_LREGISTER,0); if (regv_l(oreg)!=5) { printf("\tmr %s,%s\n", register_name(5), lregister_name_low(oreg)); } printf("\tbl .asrd__\n"); } static void code_lsrd_lib(int reg,int oreg) // ___lshrdi3$stub { code_save_stacks(); clear_ptr_cache(); lsrd_lib_used = 1; set_lreg_operand(reg,1); set_lreg(RET_LREGISTER,0); if (regv_l(oreg)!=5) { printf("\tmr %s,%s\n", register_name(5), lregister_name_low(oreg)); } printf("\tbl .lsrd__\n"); } static void code_ldiv_lib(int reg,int oreg) // ___divdi3$stub { code_save_stacks(); clear_ptr_cache(); set_lreg_operand(reg,1); set_lreg(RET_LREGISTER,0); set_lreg_operand1(oreg,1); extern_conv("__divdi3"); } static void code_ludiv_lib(int reg,int oreg) // ___udivdi3$stub { code_save_stacks(); clear_ptr_cache(); set_lreg_operand(reg,1); set_lreg(RET_LREGISTER,0); set_lreg_operand1(oreg,1); extern_conv("__udivdi3"); } static void code_lmod_lib(int reg,int oreg) // ___moddi3$stub { code_save_stacks(); clear_ptr_cache(); set_lreg_operand(reg,1); set_lreg(RET_LREGISTER,0); set_lreg_operand1(oreg,1); extern_conv("__moddi3"); } static void code_lumod_lib(int reg,int oreg) // ___umoddi3$stub { code_save_stacks(); clear_ptr_cache(); set_lreg(RET_LREGISTER,0); set_lreg_operand(reg,1); set_lreg_operand1(oreg,1); extern_conv("__umoddi3"); } #define check_lreg(reg) if (reg!=lreg) { lmove(reg,lreg); /* reg<=lreg */ } // reg = reg op oreg void ltosop(int op,int reg,int oreg) { int dx = -1; int ox = -1; int creg_mode = (reg==USE_CREG); char *orn_h,*crn_h,*drn_h; char *orn_l,*crn_l,*drn_l; // creg = creg 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_lrlvar(oreg+REG_LVAR_OFFSET,ox); oreg = ox; } switch(op) { case LLSHIFT: case LULSHIFT: code_asld_lib(reg,oreg); // ___ashldi3$stub check_lreg(reg); if(ox!=-1) free_register(ox); return; case LRSHIFT: code_asrd_lib(reg,oreg); // ___ashrdi3$stub check_lreg(reg); if(ox!=-1) free_register(ox); return; case LURSHIFT: code_lsrd_lib(reg,oreg); // ___lshrdi3$stub check_lreg(reg); if(ox!=-1) free_register(ox); return; } orn_h = lregister_name_high(oreg); orn_l = lregister_name_low(oreg); crn_h = lregister_name_high(reg); crn_l = lregister_name_low(reg); switch(op) { case LADD: printf("\taddc %s,%s,%s\n",crn_l,crn_l,orn_l); printf("\tadde %s,%s,%s\n",crn_h,crn_h,orn_h); break; case LSUB: printf("\tsubfc %s,%s,%s\n",crn_l,orn_l,crn_l); printf("\tsubfe %s,%s,%s\n",crn_h,orn_h,crn_h); break; case LCMP: error(-1); break; case LBAND: printf("\tand %s,%s,%s\n",crn_l,crn_l,orn_l); printf("\tand %s,%s,%s\n",crn_h,crn_h,orn_h); break; case LEOR: printf("\txor %s,%s,%s\n",crn_l,crn_l,orn_l); printf("\txor %s,%s,%s\n",crn_h,crn_h,orn_h); break; case LBOR: printf("\tor %s,%s,%s\n",crn_l,crn_l,orn_l); printf("\tor %s,%s,%s\n",crn_h,crn_h,orn_h); break; case LMUL: case LUMUL: // code_save_stacks(); // clear_ptr_cache(); dx=get_lregister(); if (dx<0) error(-1); use_reg(dx); drn_l = lregister_name_low(dx); drn_h = lregister_name_high(dx); /* drn_l = l32( crn_l * orn_l); drn_h = h32( crn_l * orn_l); crn_h = l32( crn_h * orn_l); drn_h = drn_h + crn_h; crn_l = l32( crn_l * orn_h); crn_h = drn_h + crn_l; crn_l = drn_l; */ printf("\tmulhwu %s,%s,%s\n",drn_h,crn_l,orn_l); printf("\tmullw %s,%s,%s\n", drn_l,crn_l,orn_l); printf("\tmullw %s,%s,%s\n", crn_h,crn_h,orn_l); printf("\tadd %s,%s,%s\n", drn_h,drn_h,crn_h); printf("\tmullw %s,%s,%s\n", crn_l,orn_h,crn_l); printf("\tadd %s,%s,%s\n", crn_h,drn_h,crn_l); printf("\tmr %s,%s\n", crn_l,drn_l); break; case LDIV: code_ldiv_lib(reg,oreg); // ___divdi3$stub if (!creg_mode) check_lreg(reg); break; case LUDIV: code_ludiv_lib(reg,oreg); // ___udivdi3$stub if (!creg_mode) check_lreg(reg); break; case LMOD: code_lmod_lib(reg,oreg); // ___moddi3$stub if (!creg_mode) check_lreg(reg); break; case LUMOD: code_lumod_lib(reg,oreg); // ___umoddi3$stub if (!creg_mode) check_lreg(reg); break; default: error(-1); } if(ox!=-1) free_register(ox); if(dx!=-1) free_register(dx); } int code_lconst_op_p(int op,int e) { int v; if (car(e)==LCONST) { if (!(-32766<lcadr(e)&&lcadr(e)<32767)) return 0; v = lcadr(e); } else if (car(e)==CONST) { if (!(-32766<cadr(e)&&cadr(e)<32767)) return 0; v = cadr(e); } else return 0; switch(op) { case LMUL: case LUMUL: case LUDIV: // case LDIV: return ilog(v); case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: return (0<=v&&v<=64); case LADD: case LSUB: return 1; case LBOR: return (v>0); default: return 0; } } void loprtc(int op,int creg,int e) { char *crn_h; char *crn_l; char *grn; int v=0; int greg; use_longlong(creg); crn_h = lregister_name_high(creg); crn_l = lregister_name_low(creg); if (car(e)==LCONST) v = lcadr(e); else if (car(e)==CONST) v = cadr(e); switch(op) { case 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("\tslwi %s,%s,%d\n",crn_h,crn_l,v-32); code_const(0,regv_l(creg)); return; } greg = get_register(); grn = register_name(greg); use_reg(greg); printf("\tsrwi %s,%s,%d\n",grn,crn_l,32-v); printf("\tslwi %s,%s,%d\n",crn_h,crn_h,v); printf("\tor %s,%s,%s\n",crn_h,grn,crn_h); printf("\tslwi %s,%s,%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("\tsrawi %s,%s,31\n",crn_h,crn_l); return; } else if (v>31) { printf("\tsrawi %s,%s,%d\n",crn_l,crn_h,v-32); printf("\tsrawi %s,%s,31\n",crn_h,crn_l); return; } greg = get_register(); use_reg(greg); grn = register_name(greg); printf("\tsrwi %s,%s,%d\n",grn,crn_l,v); printf("\tinsrwi %s,%s,%d,0\n",grn,crn_h,v); printf("\tsrawi %s,%s,%d\n",crn_h,crn_h,v); printf("\tmr %s,%s\n",crn_l,grn); 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("\tsrwi %s,%s,%d\n",crn_l,crn_h,v-32); code_const(0,regv_h(creg)); return; } greg = get_register(); use_reg(greg); grn = register_name(greg); printf("\tslwi %s,%s,%d\n",grn,crn_h,32-v); printf("\tsrwi %s,%s,%d\n",crn_l,crn_l,v); printf("\tor %s,%s,%s\n",crn_l,grn,crn_l); printf("\tsrwi %s,%s,%d\n",crn_h,crn_h,v); free_register(greg); return; case LSUB: v = -v; case LADD: printf("\taddic %s,%s,%d\n",crn_l,crn_l,v); if (v<0) printf("\taddme %s,%s\n",crn_h,crn_h); else printf("\taddze %s,%s\n",crn_h,crn_h); break; case LBOR: #ifdef __APPLE__ printf("\tori %s,%s,lo16(%d)\n",crn_l,crn_l,v); #else printf("\tori %s,%s,%d@l\n",crn_l,crn_l,v); #endif break; default: error(-1); } } void emit_lpop_free(int xreg) { if (xreg>=0 && xreg!=creg && regs[xreg]!=REG_VAR) free_register(xreg); } void emit_lpush() { int new_reg; if (!is_longlong_reg(creg)) error(-1); if (lreg_sp>MAX_MAX) error(-1); new_reg = get_lregister(); /* 絶対に取れる(?) */ lreg_stack[lreg_sp++] = creg; /* push するかわりにレジスタを使う */ lreg = creg = new_reg; } void code_i2ll(int reg) { char *crn,*crn_h,*crn_l; int reg0; crn = register_name(reg0 = ireg); use_longlong(reg); crn_h = lregister_name_high(lreg); crn_l = lregister_name_low(lreg); if (reg0!=regv_l(lreg)) printf("\tmr %s,%s\n",crn_l,crn); printf("\tsrawi %s,%s,31\n",crn_h,crn_l); } void code_i2ull(int reg) { code_i2ll(reg); } void code_u2ll(int reg) { char *crn,*crn_h,*crn_l; int reg0; crn = register_name(reg0 = ireg); use_longlong(reg); crn_h = lregister_name_high(lreg); crn_l = lregister_name_low(lreg); if (reg0!=regv_l(lreg)) printf("\tmr %s,%s\n",crn_l,crn); printf("\tli %s,0\n",crn_h); } void code_u2ull(int creg) { code_u2ll(creg); } void code_ll2i(int reg) { char *crn_l; int reg0; crn_l = lregister_name_low(reg0=lreg); use_int(reg); if (ireg!=regv_l(reg0)) printf("\tmr %s,%s\n",register_name(ireg),crn_l); } void code_ll2u(int creg) { code_ll2i(creg); } void code_ull2i(int creg) { code_ll2i(creg); } void code_ull2u(int creg) { code_ll2i(creg); } #if FLOAT_CODE void code_d2ll(int reg) { // fixdfdi$stub set_freg(RET_FREGISTER,1); extern_conv("__fixdfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) use_longlong(reg); } void code_d2ull(int reg) { set_freg(RET_FREGISTER,1); extern_conv("__fixunsdfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) use_longlong(reg); } void code_f2ll(int reg) { set_freg(RET_FREGISTER,1); extern_conv("__fixdfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) use_longlong(reg); } void code_f2ull(int reg) { set_freg(RET_FREGISTER,1); extern_conv("__fixsfdi"); set_lreg(RET_LREGISTER,0); if (reg!=USE_CREG&®!=RET_LREGISTER) use_longlong(reg); } void code_ll2d(int reg) { set_lreg(RET_LREGISTER,1); extern_conv("__floatdidf"); set_freg(RET_FREGISTER,0); if (reg!=USE_CREG&®!=RET_FREGISTER) use_float(1,reg); } void code_ll2f(int reg) { set_lreg(RET_LREGISTER,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); } static void ladd(int creg,int reg,int dir) // creg=reg+dir { printf("\taddic %s,%s,%d\n", lregister_name_low(creg),lregister_name_low(reg), dir); printf("\tadd%s %s,%s\n", dir>0?"ze":"me", lregister_name_high(creg),lregister_name_high(reg)); } void code_lpreinc(int e1,int e2,int reg) { int dreg,xreg; 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); } void code_lpostinc(int e1,int e2,int reg) { int dreg,nreg,xreg; int dir=caddr(e1); if (car(e2)==LREGISTER) { use_longlong(reg); if (use && reg!=cadr(e2)) 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(nreg,dreg,dir); code_lassign(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) { // this can't happen edx0 = get_register(); if(!edx0) error(-1); printf("## lassop\n\tmr %s,%s\n",register_name(edx0),register_name(edx)); edx = edx0; } lload(edx0=edx,reg,0); ltosop(op,reg,xreg); use_reg(reg); edx = emit_pop(0); code_lassign(edx,reg); if (edx0!=-1) free_register(edx0); emit_pop_free(edx); emit_lpop_free(xreg); } 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 } static void emit_lib(char *p[]) { while(*p) { printf("%s\n",*p++); } } void code_closing() { #if FLOAT_CODE if (d2u_lib_used) emit_lib(d2u_lib); if (u2d_lib_used) emit_lib(u2d_lib); if (float_one_lib_used) emit_lib(float_one_lib); if (float_zero_lib_used) emit_lib(float_zero_lib); if (i2d_lib_used) emit_lib(i2d_lib); d2u_lib_used = u2d_lib_used= float_one_lib_used= float_zero_lib_used = i2d_lib_used = 0; #endif #if LONGLONG_CODE if (asld_lib_used) emit_lib(asld_lib); if (lsrd_lib_used) emit_lib(lsrd_lib); if (asrd_lib_used) emit_lib(asrd_lib); asld_lib_used = lsrd_lib_used = asrd_lib_used = 0; #if 0 if (lumod_lib_used) emit_lib(lumod_lib); if (lmod_lib_used) emit_lib(lmod_lib); if (ludiv_lib_used) emit_lib(ludiv_lib); if (ldiv_lib_used) emit_lib(ldiv_lib); #endif #if FLOAT_CODE #if 0 if (dl2ll_lib_used) emit_lib(dl2ll_lib); if (d2ull_lib_used) emit_lib(d2ull_lib); if (f2ll_lib_used) emit_lib(f2ll_lib); if (f2ull_lib_used) emit_lib(f2ull_lib); if (ll2d_lib_used) emit_lib(ll2d_lib); if (ll2f_lib_used) emit_lib(ll2f_lib); #endif #endif #endif #ifndef __APPLE__ if (saveFP_used) emit_lib(saveFP_lib); #endif global_table(); /* printf("\t.ident \"Micro-C compiled\"\n"); */ } #if CASE_CODE int code_table_jump_p(int delta) { return 1; } void code_table_jump(int l,int csvalue,int delta,int max,int min,int dlabel) { int t,s,u=-1; char *crn = register_name(csvalue); // can be t,s,u char *trn = register_name(t=get_register()); char *srn = register_name(s=get_register()); char *urn; inc_cmpflag(); if (min>32767||min<-32765) { if (t==csvalue) { code_const(min,s); printf("\tsub\t%s,%s,%s\n",trn,crn,srn); } else { code_const(min,t); printf("\tsub\t%s,%s,%s\n",trn,crn,trn); } } else { #ifdef __APPLE__ printf("\taddi\t%s,%s,lo16(%d)\n",trn,crn,-min); #else printf("\taddi\t%s,%s,%d@l\n",trn,crn,-min); #endif } printf("\tcmplwi %s,%s,%d\n",crname(cmpflag),trn,max-min); printf("\tbgt-\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel); inc_cmpflag(); switch(delta) { case 1: printf("\tslwi %s,%s,2\n",trn,trn); break; case 2: printf("\tli %s,1\n",srn); printf("\tand %s,%s,%s\n",srn,srn,trn); printf("\tcmplwi %s,%s,0\n",crname(cmpflag),srn); printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel); printf("\tslwi %s,%s,1\n",trn,trn); break; case 4: printf("\tli %s,3\n",srn); printf("\tand %s,%s,%s\n",srn,srn,trn); printf("\tcmplwi %s,%s,0\n",crname(cmpflag),srn); printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel); break; default: urn = register_name(u=get_register()); printf("\tli %s,%d\n",srn,delta); printf("\tdivwu %s,%s,%s\n",urn,trn,srn); printf("\tmullw %s,%s,%s\n",srn,urn,srn); printf("\tsubf %s,%s,%s\n",srn,trn,srn); printf("\tcmplwi %s,%s,0\n",crname(cmpflag),srn); printf("\tbne\t%s,%s%d\n",crname(cmpflag),lpfx,dlabel); printf("\tslwi %s,%s,2\n",trn,urn); } #ifdef __APPLE__ printf("\taddis %s,r31,ha16(L_%d-L_%d)\n", srn,l,code_base); printf("\tla %s,lo16(L_%d-L_%d)(%s)\n", srn,l,code_base,srn); printf("\tadd %s,%s,%s\n",trn,srn,trn); printf("\tlwz r0,0(%s)\n",trn); printf("\tadd r0,r0,%s\n",srn); printf("\tmtctr r0\n"); printf("\tbctr\n"); #else printf("\tlis %s,%s%d@ha\n",srn,lpfx,l); printf("\tla %s,%s%d@l(%s)\n",srn,lpfx,l,srn); printf("\tadd %s,%s,%s\n",trn,srn,trn); printf("\tlwz 0,0(%s)\n",trn); printf("\tadd 0,0,%s\n",srn); printf("\tmtctr 0\n"); printf("\tbctr\n"); #endif free_register(s); free_register(t); if (u!=-1) free_register(u); } void code_table_open(int l) { printf("\t.p2align 2\n"); fwddef(l); } void code_table_value(int label,int table_top) { printf("\t.long %s%d-%s%d\n",lpfx,label,lpfx,table_top); } 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("%s%d:\n",lpfx,cadr(rstr)); } else { error(-1); } } /* prepare asm operands char *constraints sgtring int oeprand 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 */ extern 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); retry: switch((c=*p)) { case '?': case '!': case '+': case '%': case '#': case '*': case '=': // output register p++; goto retry; case '&': // earlyclobber p++; clobber = 1; goto retry; case 'b': // address base register (what?) case '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); break; case 'm': repl = list3(list2(0,0),repl,clobber); break; case 'i': if (car(e1)==GVAR) { e1=list3n(FNAME,0,ncaddr(e1)); } else if (car(e1)==FNAME) { e1=list3n(FNAME,0,ncaddr(e1)); } else if (car(e1)==STRING) { val = emit_string_label(); ascii(ncaddr(e1)->nm,ncaddr(e1)->dsp); e1=list2(LABEL,val); } else if (car(e1)==CONST) { } else error(-1); repl = list3(e1,repl,clobber); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': 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); break; default: printf("### unknown asm constraint %c\n",c); } 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(0); c = *asm_str; if (c!='\t'&&c!=' ') printf("\t"); for(i=0;repl && i<MAX_ASM_REG;i++) { reg[i] = car(repl); repl = cadr(repl); } p = asm_str; while((c = *p++)) { if (c=='%') { c = *p++; if (!c) { break; } else if (c=='%') { printf("%%"); continue; } else if (!digit(c)) { printf("%%%c",c); continue; } val = 0; do { val = val*10 + c-'0'; } while (digit(c=*p++)) ; p--; if (val>MAX_ASM_REG) error(-1); // too large register rstr = reg[val]; emit_asm_operand(rstr); } else { printf("%c",c); } } printf("\n"); } #endif #if BIT_FIELD_CODE /* bit field alignment calcuration */ static void set_bitsz(int type,int *pbitpos,int *pbitsize, int *psign,int *pbitsz,int *palign,int *pl) { int sign=0,bitsz=0; int align=4,l=0; *pbitpos = cadr(caddr(type)); *pbitsize = caddr(caddr(type)); switch(cadr(type)) { /* value type */ case INT: sign=1; bitsz=32; align=4;break; case UNSIGNED: bitsz=32; align=4;break; case CHAR: sign=1; bitsz= 8; align=1;break; case UCHAR: bitsz= 8; align=1;break; case SHORT: sign=1; bitsz=16; align=2;break; case USHORT: sign=1; bitsz=16; align=2;break; #ifdef __APPLE__ case LONGLONG: sign=1; bitsz=64; align=4;l=1; break; case ULONGLONG: bitsz=64; align=4;l=1; break; #else case LONGLONG: sign=1; bitsz=64; align=8;l=1; break; case ULONGLONG: bitsz=64; align=8;l=1; break; #endif default: error(-1); } *psign = sign; *pbitsz = bitsz; *palign = align; *pl = l; } /* bit field alignment calcuration this is architecture depenedent */ extern int code_bit_field_disp(int type,int *poffset,int *bfd,int *sz) { int sign,bitsz,align; int i; int bitpos = *bfd; int bitpos0; int bitsize; int offset = *poffset; int l; set_bitsz(type,&bitpos0,&bitsize,&sign,&bitsz,&align,&l); if (bitsize>bitsz) { error(BTERR); bitsize = bitsz; } /* bfd means previous bit field bit offset */ if (bitpos) { /* previous field is bit field and spaces may remain */ /* calc previsous offset */ i= offset-(bitpos+7)/8; for(l = bitpos;l>0;l -= 8,i++) { if ((i & (align-1))==0 && l+bitsize <= bitsz) { /* alignment is correct and space remains */ *poffset=offset=i; i = l+bitsize; *bfd = (i==bitsz)?0:i; *sz = (i+7)/8; // printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",l,bitsize,bitsz,*poffset); return l; } } } /* first bit-field */ if ((i=(offset & (align-1)))) { *poffset = (offset += (align-i)); } bitpos = 0; *bfd = (bitsize==bitsz)?0:bitsize; *sz = (bitsize+7)/8; // printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",bitpos,bitsize,bitsz,*poffset); return bitpos; } /* bit field value */ extern void code_bit_field(int type,int adr, int reg) { int sign,bitsz,l,align; int bitsize,bitpos; int i,size; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); /* this implementation returns -1 for int i:1; */ if (l==1) { #if LONGLONG_CODE // use_int(adr); use_longlong(reg); lload(adr,reg,0); /* shift left */ if (bitpos) loprtc(LLSHIFT,reg,list2(CONST,bitpos)); /* shift right */ if ((i=bitsz-bitsize)) loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i)); #endif } else { // use_int(adr); use_int(reg); #ifdef __APPLE__ printf("\t%s %s,lo16(%d)(%s)\n",cload(size), register_name(reg),0,register_name(adr)); #else printf("\t%s %s,%d@l(%s)\n",cload(size), register_name(reg),0,register_name(adr)); #endif cext(sign,size,reg); /* shift left */ if ((i=bitpos+(32-bitsz))) oprtc(LSHIFT,reg,list2(CONST,i)); /* shift right */ if ((i=bitsz-bitsize+(32-bitsz))) oprtc(sign?RSHIFT:URSHIFT,reg,list2(CONST,i)); } } /* bit field replacement */ static void make_mask_and_or(int mask,int tmp,char *trn,char *crn,char *lrn) { // printf("## mask 0x%08x ~0x%08x\n",mask,~mask); code_const(~mask,tmp); printf("\tor %s,%s,%s\n",trn,crn,trn); /* do conjunction */ printf("\tand %s,%s,%s\n",lrn,trn,lrn); /* make or-mask */ code_const(mask,tmp); printf("\tand %s,%s,%s\n",trn,crn,trn); /* do disjunction */ printf("\tor %s,%s,%s\n",crn,trn,lrn); } extern void code_bit_replace(int adr,int value,int type) { int sign,bitsz,l,align; int bitsize,bitpos; int mask = 0; int tmp = -1; int i; int lvalue; char *crn,*lrn,*trn; int 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); if (l) { #if LONGLONG_CODE // use_int(adr); lvalue = get_lregister(); lload(adr,lvalue,0); use_longlong(value); crn = lregister_name_low(value); lrn = lregister_name_low(lvalue); /* shift left */ if ((i=bitsz-bitsize-bitpos)) loprtc(LLSHIFT,value,list2(CONST,i)); trn = register_name(tmp = get_register()); if (bitpos+bitsize>=32) { /* make and-mask lower */ mask = make_mask(bitpos>=32?bitpos-32:0,bitpos+bitsize-32-1); make_mask_and_or(mask,tmp,trn,crn,lrn); } crn = lregister_name_high(value); lrn = lregister_name_high(lvalue); if (bitpos<32) { /* make and-mask upper */ mask = make_mask(bitpos,bitpos+bitsize>=32?31:bitpos+bitsize-1); make_mask_and_or(mask,tmp,trn,crn,lrn); } code_lassign(adr,value); free_register(lvalue); // free_register(adr); #endif } else { // use_int(adr); use_int(value); lvalue = get_register(); #ifdef __APPLE__ printf("\t%s %s,lo16(%d)(%s)\n",cload(size), register_name(lvalue),0,register_name(adr)); #else printf("\t%s %s,%d@l(%s)\n",cload(size), register_name(lvalue),0,register_name(adr)); #endif cext(sign,size,lvalue); crn = register_name(value); lrn = register_name(lvalue); /* shift left */ if ((i=bitsz-bitsize-bitpos)) oprtc(LSHIFT,value,list2(CONST,i)); trn = register_name(tmp = get_register()); /* make and-mask */ mask = make_mask(bitpos+(32-bitsz),bitpos+bitsize-1+(32-bitsz)); make_mask_and_or(mask,tmp,trn,crn,lrn); free_register(lvalue); code_assign(adr,size,value); } if (tmp!=-1) free_register(tmp); if (use) { code_bit_field(type,adr,USE_CREG); } } static void make_mask_and_or_const(int mask,char *crn,int c) { char *trn; int tmp = -1; // printf("## mask 0x%08x ~0x%08x\n",mask,~mask); if ((~mask|c)!=-1) { trn = register_name(tmp=get_register()); code_const((~mask|c),tmp); /* do conjunction */ printf("\tand %s,%s,%s\n",crn,trn,crn); } /* make or-mask */ c = mask&c; if (c!=0) { /* do disjunction */ if (!((mask&c)&0xffff0000)) { #ifdef __APPLE__ printf("\tori %s,%s,lo16(%d)\n",crn,crn,c); #else printf("\tori %s,%s,%d@l\n",crn,crn,c); #endif } else { trn = register_name(tmp=get_register()); code_const(c,tmp); printf("\tor %s,%s,%s\n",crn,trn,crn); } } if (tmp!=-1) free_register(tmp); } extern void code_bit_replace_const(int value,int adr,int type) { int sign,bitsz,l,align; int bitsize,bitpos,size; int mask = 0; int i; int c; int lvalue; #if LONGLONG_CODE long long lc; #endif char *crn; set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); size = bitsz/8; // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); if (l) { #if LONGLONG_CODE use_int(adr); lvalue = get_lregister(); lload(adr,lvalue,0); crn = lregister_name_low(lvalue); /* shift left */ lc = lcadr(value); if ((i=bitsz-bitsize-bitpos)) lc <<= i; if (bitpos+bitsize>=32) { /* make and-mask lower */ mask = make_mask(bitpos>=32?bitpos-32:0,bitpos+bitsize-32-1); make_mask_and_or_const(mask,crn,(int)lc); } crn = lregister_name_high(lvalue); if (bitpos<32) { /* make and-mask upper */ mask = make_mask(bitpos,bitpos+bitsize>=32?31:bitpos+bitsize-1); make_mask_and_or_const(mask,crn,(int)(lc>>32)); } code_lassign(adr,lvalue); free_register(lvalue); #endif } else { use_int(adr); lvalue = get_register(); #ifdef __APPLE__ printf("\t%s %s,lo16(%d)(%s)\n",cload(size), register_name(lvalue),0,register_name(adr)); #else printf("\t%s %s,%d@l(%s)\n",cload(size), register_name(lvalue),0,register_name(adr)); #endif cext(sign,size,lvalue); crn = register_name(lvalue); /* shift left */ c = cadr(value); if ((i=bitsz-bitsize-bitpos)) c <<= i; /* make and-mask */ mask = make_mask(bitpos+(32-bitsz),bitpos+bitsize-1+(32-bitsz)); 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 */