/* * ARMv4 code generator for TCC * * Copyright (c) 2003 Daniel Glöckner * Copyright (c) 2012 Thomas Preud'homme * * Based on i386-gen.c by Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef TARGET_DEFS_ONLY #if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP)#error "Currently TinyCC only supports float computation with VFP instructions"#endif /* number of available registers */#ifdef TCC_ARM_VFP#define NB_REGS 13#else#define NB_REGS 9#endif #ifndef CONFIG_TCC_CPUVER# define CONFIG_TCC_CPUVER 5#endif /* a register can belong to several classes. The classes must be sorted from more general to more precise (see gv2() code which does assumptions on it). */#define RC_INT 0x0001 /* generic integer register */#define RC_FLOAT 0x0002 /* generic float register */#define RC_R0 0x0004#define RC_R1 0x0008#define RC_R2 0x0010#define RC_R3 0x0020#define RC_R12 0x0040#define RC_F0 0x0080#define RC_F1 0x0100#define RC_F2 0x0200#define RC_F3 0x0400#ifdef TCC_ARM_VFP#define RC_F4 0x0800#define RC_F5 0x1000#define RC_F6 0x2000#define RC_F7 0x4000#endif#define RC_IRET RC_R0 /* function return: integer register */#define RC_IRE2 RC_R1 /* function return: second integer register */#define RC_FRET RC_F0 /* function return: float register */ /* pretty names for the registers */enum { TREG_R0 = 0, TREG_R1, TREG_R2, TREG_R3, TREG_R12, TREG_F0, TREG_F1, TREG_F2, TREG_F3,#ifdef TCC_ARM_VFP TREG_F4, TREG_F5, TREG_F6, TREG_F7,#endif TREG_SP = 13, TREG_LR,}; #ifdef TCC_ARM_VFP#define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0)#endif /* return registers for function */#define REG_IRET TREG_R0 /* single word int return register */#define REG_IRE2 TREG_R1 /* second word return register (for long long) */#define REG_FRET TREG_F0 /* float return register */ #ifdef TCC_ARM_EABI#define TOK___divdi3 TOK___aeabi_ldivmod#define TOK___moddi3 TOK___aeabi_ldivmod#define TOK___udivdi3 TOK___aeabi_uldivmod#define TOK___umoddi3 TOK___aeabi_uldivmod#endif /* defined if function parameters must be evaluated in reverse order */#define INVERT_FUNC_PARAMS /* defined if structures are passed as pointers. Otherwise structures are directly pushed on stack. *//* #define FUNC_STRUCT_PARAM_AS_PTR */ /* pointer size, in bytes */#define PTR_SIZE 4 /* long double size and alignment, in bytes */#ifdef TCC_ARM_VFP#define LDOUBLE_SIZE 8#endif #ifndef LDOUBLE_SIZE#define LDOUBLE_SIZE 8#endif #ifdef TCC_ARM_EABI#define LDOUBLE_ALIGN 8#else#define LDOUBLE_ALIGN 4#endif #if LDOUBLE_SIZE == 8# define TCC_USING_DOUBLE_FOR_LDOUBLE 1#endif /* maximum alignment (for aligned attribute support) */#define MAX_ALIGN 8 #define CHAR_IS_UNSIGNED #define ARM_SOFTFP_FLOAT 0#define ARM_HARD_FLOAT 1 /******************************************************/#else /* ! TARGET_DEFS_ONLY *//******************************************************/#define USING_GLOBALS#include "tcc.h" ST_DATA const char * const target_machine_defs = "__arm__\0" "__arm\0" "arm\0" "__arm_elf__\0" "__arm_elf\0" "arm_elf\0" "__ARM_ARCH_4__\0" "__ARMEL__\0" "__APCS_32__\0"#if defined TCC_ARM_EABI "__ARM_EABI__\0"#endif ; ST_DATA const int reg_classes[NB_REGS] = { /* r0 */ RC_INT | RC_R0, /* r1 */ RC_INT | RC_R1, /* r2 */ RC_INT | RC_R2, /* r3 */ RC_INT | RC_R3, /* r12 */ RC_INT | RC_R12, /* f0 */ RC_FLOAT | RC_F0, /* f1 */ RC_FLOAT | RC_F1, /* f2 */ RC_FLOAT | RC_F2, /* f3 */ RC_FLOAT | RC_F3,#ifdef TCC_ARM_VFP /* d4/s8 */ RC_FLOAT | RC_F4,/* d5/s10 */ RC_FLOAT | RC_F5,/* d6/s12 */ RC_FLOAT | RC_F6,/* d7/s14 */ RC_FLOAT | RC_F7,#endif}; static int float_abi;static int func_sub_sp_offset, last_itod_magic;static int leaffunc; #if defined(CONFIG_TCC_BCHECK)static addr_t func_bound_offset;static unsigned long func_bound_ind;ST_DATA int func_bound_add_epilog;#endif #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP)static CType float_type, double_type, func_float_type, func_double_type;ST_FUNC void arm_init(struct TCCState *s){ float_type.t = VT_FLOAT; double_type.t = VT_DOUBLE; func_float_type.t = VT_FUNC; func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD); func_double_type.t = VT_FUNC; func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD); float_abi = s->float_abi;#ifndef TCC_ARM_HARDFLOAT// XXX: Works on OpenBSD// # warning "soft float ABI currently not supported: default to softfp"#endif}#else#define func_float_type func_old_type#define func_double_type func_old_type#define func_ldouble_type func_old_typeST_FUNC void arm_init(struct TCCState *s){#if 0#if !defined (TCC_ARM_VFP) tcc_warning("Support for FPA is deprecated and will be removed in next" " release");#endif#if !defined (TCC_ARM_EABI) tcc_warning("Support for OABI is deprecated and will be removed in next" " release");#endif#endif}#endif #define CHECK_R(r) ((r) >= TREG_R0 && (r) <= TREG_LR) static int two2mask(int a,int b) { if (!CHECK_R(a) || !CHECK_R(b)) tcc_error("compiler error! registers %i,%i is not valid",a,b); return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT);} static int regmask(int r) { if (!CHECK_R(r)) tcc_error("compiler error! register %i is not valid",r); return reg_classes[r]&~(RC_INT|RC_FLOAT);} /******************************************************/ void o(uint32_t i){ /* this is a good place to start adding big-endian support*/ int ind1; if (nocode_wanted) return; ind1 = ind + 4; if (!cur_text_section) tcc_error("compiler error! This happens f.ex. if the compiler\n" "can't evaluate constant expressions outside of a function."); if (ind1 > cur_text_section->data_allocated) section_realloc(cur_text_section, ind1); cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i;} static uint32_t stuff_const(uint32_t op, uint32_t c){ int try_neg=0; uint32_t nc = 0, negop = 0; switch(op&0x1F00000) { case 0x800000: //add case 0x400000: //sub try_neg=1; negop=op^0xC00000; nc=-c; break; case 0x1A00000: //mov case 0x1E00000: //mvn try_neg=1; negop=op^0x400000; nc=~c; break; case 0x200000: //xor if(c==~0) return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000; break; case 0x0: //and if(c==~0) return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000; case 0x1C00000: //bic try_neg=1; negop=op^0x1C00000; nc=~c; break; case 0x1800000: //orr if(c==~0) return (op&0xFFF0FFFF)|0x1E00000; break; } do { uint32_t m; int i; if(c<256) /* catch undefined <<32 */ return op|c; for(i=2;i<32;i+=2) { m=(0xffu>>i)|(0xffu<<(32-i)); if(!(c&~m)) return op|(i<<7)|(c<<i)|(c>>(32-i)); } op=negop; c=nc; } while(try_neg--); return 0;} //only add,subvoid stuff_const_harder(uint32_t op, uint32_t v) { uint32_t x; x=stuff_const(op,v); if(x) o(x); else { uint32_t a[16], nv, no, o2, n2; int i,j,k; a[0]=0xff; o2=(op&0xfff0ffff)|((op&0xf000)<<4);; for(i=1;i<16;i++) a[i]=(a[i-1]>>2)|(a[i-1]<<30); for(i=0;i<12;i++) for(j=i<4?i+12:15;j>=i+4;j--) if((v&(a[i]|a[j]))==v) { o(stuff_const(op,v&a[i])); o(stuff_const(o2,v&a[j])); return; } no=op^0xC00000; n2=o2^0xC00000; nv=-v; for(i=0;i<12;i++) for(j=i<4?i+12:15;j>=i+4;j--) if((nv&(a[i]|a[j]))==nv) { o(stuff_const(no,nv&a[i])); o(stuff_const(n2,nv&a[j])); return; } for(i=0;i<8;i++) for(j=i+4;j<12;j++) for(k=i<4?i+12:15;k>=j+4;k--) if((v&(a[i]|a[j]|a[k]))==v) { o(stuff_const(op,v&a[i])); o(stuff_const(o2,v&a[j])); o(stuff_const(o2,v&a[k])); return; } no=op^0xC00000; nv=-v; for(i=0;i<8;i++) for(j=i+4;j<12;j++) for(k=i<4?i+12:15;k>=j+4;k--) if((nv&(a[i]|a[j]|a[k]))==nv) { o(stuff_const(no,nv&a[i])); o(stuff_const(n2,nv&a[j])); o(stuff_const(n2,nv&a[k])); return; } o(stuff_const(op,v&a[0])); o(stuff_const(o2,v&a[4])); o(stuff_const(o2,v&a[8])); o(stuff_const(o2,v&a[12])); }} uint32_t encbranch(int pos, int addr, int fail){ addr-=pos+8; addr/=4; if(addr>=0x1000000 || addr<-0x1000000) { if(fail) tcc_error("FIXME: function bigger than 32MB"); return 0; } return 0x0A000000|(addr&0xffffff);} int decbranch(int pos){ int x; x=*(uint32_t *)(cur_text_section->data + pos); x&=0x00ffffff; if(x&0x800000) x-=0x1000000; return x*4+pos+8;} /* output a symbol and patch all calls to it */void gsym_addr(int t, int a){ uint32_t *x; int lt; while(t) { x=(uint32_t *)(cur_text_section->data + t); t=decbranch(lt=t); if(a==lt+4) *x=0xE1A00000; // nop else { *x &= 0xff000000; *x |= encbranch(lt,a,1); } }} #ifdef TCC_ARM_VFPstatic uint32_t vfpr(int r){ if(r<TREG_F0 || r>TREG_F7) tcc_error("compiler error! register %i is no vfp register",r); return r - TREG_F0;}#elsestatic uint32_t fpr(int r){ if(r<TREG_F0 || r>TREG_F3) tcc_error("compiler error! register %i is no fpa register",r); return r - TREG_F0;}#endif static uint32_t intr(int r){ if(r == TREG_R12) return 12; if(r >= TREG_R0 && r <= TREG_R3) return r - TREG_R0; if (!(r >= TREG_SP && r <= TREG_LR)) tcc_error("compiler error! register %i is no int register",r); return r + (13 - TREG_SP);} static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift){ if(*off>maxoff || *off&((1<<shift)-1)) { uint32_t x, y; x=0xE280E000; if(*sgn) x=0xE240E000; x|=(*base)<<16; *base=14; // lr y=stuff_const(x,*off&~maxoff); if(y) { o(y); *off&=maxoff; return; } y=stuff_const(x,(*off+maxoff)&~maxoff); if(y) { o(y); *sgn=!*sgn; *off=((*off+maxoff)&~maxoff)-*off; return; } stuff_const_harder(x,*off&~maxoff); *off&=maxoff; }} static uint32_t mapcc(int cc){ switch(cc) { case TOK_ULT: return 0x30000000; /* CC/LO */ case TOK_UGE: return 0x20000000; /* CS/HS */ case TOK_EQ: return 0x00000000; /* EQ */ case TOK_NE: return 0x10000000; /* NE */ case TOK_ULE: return 0x90000000; /* LS */ case TOK_UGT: return 0x80000000; /* HI */ case TOK_Nset: return 0x40000000; /* MI */ case TOK_Nclear: return 0x50000000; /* PL */ case TOK_LT: return 0xB0000000; /* LT */ case TOK_GE: return 0xA0000000; /* GE */ case TOK_LE: return 0xD0000000; /* LE */ case TOK_GT: return 0xC0000000; /* GT */ } tcc_error("unexpected condition code"); return 0xE0000000; /* AL */} static int negcc(int cc){ switch(cc) {Lines 1–500 of 2375. Load more
/* * ARMv4 code generator for TCC * * Copyright (c) 2003 Daniel Glöckner * Copyright (c) 2012 Thomas Preud'homme * * Based on i386-gen.c by Fabrice Bellard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef TARGET_DEFS_ONLY #if defined(TCC_ARM_EABI) && !defined(TCC_ARM_VFP) #error "Currently TinyCC only supports float computation with VFP instructions" #endif /* number of available registers */ #ifdef TCC_ARM_VFP #define NB_REGS 13 #else #define NB_REGS 9 #endif #ifndef CONFIG_TCC_CPUVER # define CONFIG_TCC_CPUVER 5 #endif /* a register can belong to several classes. The classes must be sorted from more general to more precise (see gv2() code which does assumptions on it). */ #define RC_INT 0x0001 /* generic integer register */ #define RC_FLOAT 0x0002 /* generic float register */ #define RC_R0 0x0004 #define RC_R1 0x0008 #define RC_R2 0x0010 #define RC_R3 0x0020 #define RC_R12 0x0040 #define RC_F0 0x0080 #define RC_F1 0x0100 #define RC_F2 0x0200 #define RC_F3 0x0400 #ifdef TCC_ARM_VFP #define RC_F4 0x0800 #define RC_F5 0x1000 #define RC_F6 0x2000 #define RC_F7 0x4000 #endif #define RC_IRET RC_R0 /* function return: integer register */ #define RC_IRE2 RC_R1 /* function return: second integer register */ #define RC_FRET RC_F0 /* function return: float register */ /* pretty names for the registers */ enum { TREG_R0 = 0, TREG_R1, TREG_R2, TREG_R3, TREG_R12, TREG_F0, TREG_F1, TREG_F2, TREG_F3, #ifdef TCC_ARM_VFP TREG_F4, TREG_F5, TREG_F6, TREG_F7, #endif TREG_SP = 13, TREG_LR, }; #ifdef TCC_ARM_VFP #define T2CPR(t) (((t) & VT_BTYPE) != VT_FLOAT ? 0x100 : 0) #endif /* return registers for function */ #define REG_IRET TREG_R0 /* single word int return register */ #define REG_IRE2 TREG_R1 /* second word return register (for long long) */ #define REG_FRET TREG_F0 /* float return register */ #ifdef TCC_ARM_EABI #define TOK___divdi3 TOK___aeabi_ldivmod #define TOK___moddi3 TOK___aeabi_ldivmod #define TOK___udivdi3 TOK___aeabi_uldivmod #define TOK___umoddi3 TOK___aeabi_uldivmod #endif /* defined if function parameters must be evaluated in reverse order */ #define INVERT_FUNC_PARAMS /* defined if structures are passed as pointers. Otherwise structures are directly pushed on stack. */ /* #define FUNC_STRUCT_PARAM_AS_PTR */ /* pointer size, in bytes */ #define PTR_SIZE 4 /* long double size and alignment, in bytes */ #ifdef TCC_ARM_VFP #define LDOUBLE_SIZE 8 #endif #ifndef LDOUBLE_SIZE #define LDOUBLE_SIZE 8 #endif #ifdef TCC_ARM_EABI #define LDOUBLE_ALIGN 8 #else #define LDOUBLE_ALIGN 4 #endif #if LDOUBLE_SIZE == 8 # define TCC_USING_DOUBLE_FOR_LDOUBLE 1 #endif /* maximum alignment (for aligned attribute support) */ #define MAX_ALIGN 8 #define CHAR_IS_UNSIGNED #define ARM_SOFTFP_FLOAT 0 #define ARM_HARD_FLOAT 1 /******************************************************/ #else /* ! TARGET_DEFS_ONLY */ /******************************************************/ #define USING_GLOBALS #include "tcc.h" ST_DATA const char * const target_machine_defs = "__arm__\0" "__arm\0" "arm\0" "__arm_elf__\0" "__arm_elf\0" "arm_elf\0" "__ARM_ARCH_4__\0" "__ARMEL__\0" "__APCS_32__\0" #if defined TCC_ARM_EABI "__ARM_EABI__\0" #endif ; ST_DATA const int reg_classes[NB_REGS] = { /* r0 */ RC_INT | RC_R0, /* r1 */ RC_INT | RC_R1, /* r2 */ RC_INT | RC_R2, /* r3 */ RC_INT | RC_R3, /* r12 */ RC_INT | RC_R12, /* f0 */ RC_FLOAT | RC_F0, /* f1 */ RC_FLOAT | RC_F1, /* f2 */ RC_FLOAT | RC_F2, /* f3 */ RC_FLOAT | RC_F3, #ifdef TCC_ARM_VFP /* d4/s8 */ RC_FLOAT | RC_F4, /* d5/s10 */ RC_FLOAT | RC_F5, /* d6/s12 */ RC_FLOAT | RC_F6, /* d7/s14 */ RC_FLOAT | RC_F7, #endif }; static int float_abi; static int func_sub_sp_offset, last_itod_magic; static int leaffunc; #if defined(CONFIG_TCC_BCHECK) static addr_t func_bound_offset; static unsigned long func_bound_ind; ST_DATA int func_bound_add_epilog; #endif #if defined(TCC_ARM_EABI) && defined(TCC_ARM_VFP) static CType float_type, double_type, func_float_type, func_double_type; ST_FUNC void arm_init(struct TCCState *s) { float_type.t = VT_FLOAT; double_type.t = VT_DOUBLE; func_float_type.t = VT_FUNC; func_float_type.ref = sym_push(SYM_FIELD, &float_type, FUNC_CDECL, FUNC_OLD); func_double_type.t = VT_FUNC; func_double_type.ref = sym_push(SYM_FIELD, &double_type, FUNC_CDECL, FUNC_OLD); float_abi = s->float_abi; #ifndef TCC_ARM_HARDFLOAT // XXX: Works on OpenBSD // # warning "soft float ABI currently not supported: default to softfp" #endif } #else #define func_float_type func_old_type #define func_double_type func_old_type #define func_ldouble_type func_old_type ST_FUNC void arm_init(struct TCCState *s) { #if 0 #if !defined (TCC_ARM_VFP) tcc_warning("Support for FPA is deprecated and will be removed in next" " release"); #endif #if !defined (TCC_ARM_EABI) tcc_warning("Support for OABI is deprecated and will be removed in next" " release"); #endif #endif } #endif #define CHECK_R(r) ((r) >= TREG_R0 && (r) <= TREG_LR) static int two2mask(int a,int b) { if (!CHECK_R(a) || !CHECK_R(b)) tcc_error("compiler error! registers %i,%i is not valid",a,b); return (reg_classes[a]|reg_classes[b])&~(RC_INT|RC_FLOAT); } static int regmask(int r) { if (!CHECK_R(r)) tcc_error("compiler error! register %i is not valid",r); return reg_classes[r]&~(RC_INT|RC_FLOAT); } /******************************************************/ void o(uint32_t i) { /* this is a good place to start adding big-endian support*/ int ind1; if (nocode_wanted) return; ind1 = ind + 4; if (!cur_text_section) tcc_error("compiler error! This happens f.ex. if the compiler\n" "can't evaluate constant expressions outside of a function."); if (ind1 > cur_text_section->data_allocated) section_realloc(cur_text_section, ind1); cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i&255; i>>=8; cur_text_section->data[ind++] = i; } static uint32_t stuff_const(uint32_t op, uint32_t c) { int try_neg=0; uint32_t nc = 0, negop = 0; switch(op&0x1F00000) { case 0x800000: //add case 0x400000: //sub try_neg=1; negop=op^0xC00000; nc=-c; break; case 0x1A00000: //mov case 0x1E00000: //mvn try_neg=1; negop=op^0x400000; nc=~c; break; case 0x200000: //xor if(c==~0) return (op&0xF010F000)|((op>>16)&0xF)|0x1E00000; break; case 0x0: //and if(c==~0) return (op&0xF010F000)|((op>>16)&0xF)|0x1A00000; case 0x1C00000: //bic try_neg=1; negop=op^0x1C00000; nc=~c; break; case 0x1800000: //orr if(c==~0) return (op&0xFFF0FFFF)|0x1E00000; break; } do { uint32_t m; int i; if(c<256) /* catch undefined <<32 */ return op|c; for(i=2;i<32;i+=2) { m=(0xffu>>i)|(0xffu<<(32-i)); if(!(c&~m)) return op|(i<<7)|(c<<i)|(c>>(32-i)); } op=negop; c=nc; } while(try_neg--); return 0; } //only add,sub void stuff_const_harder(uint32_t op, uint32_t v) { uint32_t x; x=stuff_const(op,v); if(x) o(x); else { uint32_t a[16], nv, no, o2, n2; int i,j,k; a[0]=0xff; o2=(op&0xfff0ffff)|((op&0xf000)<<4);; for(i=1;i<16;i++) a[i]=(a[i-1]>>2)|(a[i-1]<<30); for(i=0;i<12;i++) for(j=i<4?i+12:15;j>=i+4;j--) if((v&(a[i]|a[j]))==v) { o(stuff_const(op,v&a[i])); o(stuff_const(o2,v&a[j])); return; } no=op^0xC00000; n2=o2^0xC00000; nv=-v; for(i=0;i<12;i++) for(j=i<4?i+12:15;j>=i+4;j--) if((nv&(a[i]|a[j]))==nv) { o(stuff_const(no,nv&a[i])); o(stuff_const(n2,nv&a[j])); return; } for(i=0;i<8;i++) for(j=i+4;j<12;j++) for(k=i<4?i+12:15;k>=j+4;k--) if((v&(a[i]|a[j]|a[k]))==v) { o(stuff_const(op,v&a[i])); o(stuff_const(o2,v&a[j])); o(stuff_const(o2,v&a[k])); return; } no=op^0xC00000; nv=-v; for(i=0;i<8;i++) for(j=i+4;j<12;j++) for(k=i<4?i+12:15;k>=j+4;k--) if((nv&(a[i]|a[j]|a[k]))==nv) { o(stuff_const(no,nv&a[i])); o(stuff_const(n2,nv&a[j])); o(stuff_const(n2,nv&a[k])); return; } o(stuff_const(op,v&a[0])); o(stuff_const(o2,v&a[4])); o(stuff_const(o2,v&a[8])); o(stuff_const(o2,v&a[12])); } } uint32_t encbranch(int pos, int addr, int fail) { addr-=pos+8; addr/=4; if(addr>=0x1000000 || addr<-0x1000000) { if(fail) tcc_error("FIXME: function bigger than 32MB"); return 0; } return 0x0A000000|(addr&0xffffff); } int decbranch(int pos) { int x; x=*(uint32_t *)(cur_text_section->data + pos); x&=0x00ffffff; if(x&0x800000) x-=0x1000000; return x*4+pos+8; } /* output a symbol and patch all calls to it */ void gsym_addr(int t, int a) { uint32_t *x; int lt; while(t) { x=(uint32_t *)(cur_text_section->data + t); t=decbranch(lt=t); if(a==lt+4) *x=0xE1A00000; // nop else { *x &= 0xff000000; *x |= encbranch(lt,a,1); } } } #ifdef TCC_ARM_VFP static uint32_t vfpr(int r) { if(r<TREG_F0 || r>TREG_F7) tcc_error("compiler error! register %i is no vfp register",r); return r - TREG_F0; } #else static uint32_t fpr(int r) { if(r<TREG_F0 || r>TREG_F3) tcc_error("compiler error! register %i is no fpa register",r); return r - TREG_F0; } #endif static uint32_t intr(int r) { if(r == TREG_R12) return 12; if(r >= TREG_R0 && r <= TREG_R3) return r - TREG_R0; if (!(r >= TREG_SP && r <= TREG_LR)) tcc_error("compiler error! register %i is no int register",r); return r + (13 - TREG_SP); } static void calcaddr(uint32_t *base, int *off, int *sgn, int maxoff, unsigned shift) { if(*off>maxoff || *off&((1<<shift)-1)) { uint32_t x, y; x=0xE280E000; if(*sgn) x=0xE240E000; x|=(*base)<<16; *base=14; // lr y=stuff_const(x,*off&~maxoff); if(y) { o(y); *off&=maxoff; return; } y=stuff_const(x,(*off+maxoff)&~maxoff); if(y) { o(y); *sgn=!*sgn; *off=((*off+maxoff)&~maxoff)-*off; return; } stuff_const_harder(x,*off&~maxoff); *off&=maxoff; } } static uint32_t mapcc(int cc) { switch(cc) { case TOK_ULT: return 0x30000000; /* CC/LO */ case TOK_UGE: return 0x20000000; /* CS/HS */ case TOK_EQ: return 0x00000000; /* EQ */ case TOK_NE: return 0x10000000; /* NE */ case TOK_ULE: return 0x90000000; /* LS */ case TOK_UGT: return 0x80000000; /* HI */ case TOK_Nset: return 0x40000000; /* MI */ case TOK_Nclear: return 0x50000000; /* PL */ case TOK_LT: return 0xB0000000; /* LT */ case TOK_GE: return 0xA0000000; /* GE */ case TOK_LE: return 0xD0000000; /* LE */ case TOK_GT: return 0xC0000000; /* GT */ } tcc_error("unexpected condition code"); return 0xE0000000; /* AL */ } static int negcc(int cc) { switch(cc) {