diff options
author | Thomas Preud'homme <robotux@celest.fr> | 2016-12-17 11:04:34 +0000 |
---|---|---|
committer | Thomas Preud'homme <robotux@celest.fr> | 2016-12-17 11:04:34 +0000 |
commit | 3f2e65a51523fbb98a44b71c29ae3a3fcc13854b (patch) | |
tree | 6e401550a4eddcc55a9db4b685e6a4968550a661 /i386-gen.c | |
parent | 83bd60f5184818823d7be84af0930236d0d892f7 (diff) |
New upstream version 0.9.27~git20161217.cd9514ab
Diffstat (limited to 'i386-gen.c')
-rw-r--r-- | i386-gen.c | 130 |
1 files changed, 85 insertions, 45 deletions
@@ -21,7 +21,7 @@ #ifdef TARGET_DEFS_ONLY /* number of available registers */ -#define NB_REGS 4 +#define NB_REGS 5 #define NB_ASM_REGS 8 /* a register can belong to several classes. The classes must be @@ -33,6 +33,8 @@ #define RC_ST0 0x0008 #define RC_ECX 0x0010 #define RC_EDX 0x0020 +#define RC_EBX 0x0040 + #define RC_IRET RC_EAX /* function return: integer register */ #define RC_LRET RC_EDX /* function return: second integer register */ #define RC_FRET RC_ST0 /* function return: float register */ @@ -42,6 +44,7 @@ enum { TREG_EAX = 0, TREG_ECX, TREG_EDX, + TREG_EBX, TREG_ST0, TREG_ESP = 4 }; @@ -71,28 +74,18 @@ enum { #define psym oad /******************************************************/ -/* ELF defines */ - -#define EM_TCC_TARGET EM_386 - -/* relocation type for 32 bit data relocation */ -#define R_DATA_32 R_386_32 -#define R_DATA_PTR R_386_32 -#define R_JMP_SLOT R_386_JMP_SLOT -#define R_COPY R_386_COPY - -#define ELF_START_ADDR 0x08048000 -#define ELF_PAGE_SIZE 0x1000 - -/******************************************************/ #else /* ! TARGET_DEFS_ONLY */ /******************************************************/ #include "tcc.h" +/* define to 1/0 to [not] have EBX as 4th register */ +#define USE_EBX 1 + ST_DATA const int reg_classes[NB_REGS] = { /* eax */ RC_INT | RC_EAX, /* ecx */ RC_INT | RC_ECX, /* edx */ RC_INT | RC_EDX, + /* ebx */ (RC_INT | RC_EBX) * USE_EBX, /* st0 */ RC_FLOAT | RC_ST0, }; @@ -100,6 +93,7 @@ static unsigned long func_sub_sp_offset; static int func_ret_sub; #ifdef CONFIG_TCC_BCHECK static addr_t func_bound_offset; +static unsigned long func_bound_ind; #endif /* XXX: make it faster ? */ @@ -171,14 +165,14 @@ ST_FUNC int oad(int c, int s) } /* output constant with relocation if 'r & VT_SYM' is true */ -ST_FUNC void gen_addr32(int r, Sym *sym, int c) +ST_FUNC void gen_addr32(int r, Sym *sym, long c) { if (r & VT_SYM) greloc(cur_text_section, sym, ind, R_386_32); gen_le32(c); } -ST_FUNC void gen_addrpc32(int r, Sym *sym, int c) +ST_FUNC void gen_addrpc32(int r, Sym *sym, long c) { if (r & VT_SYM) greloc(cur_text_section, sym, ind, R_386_PC32); @@ -223,6 +217,8 @@ ST_FUNC void load(int r, SValue *sv) ft = sv->type.t; fc = sv->c.i; + ft &= ~(VT_VOLATILE | VT_CONSTANT); + v = fr & VT_VALMASK; if (fr & VT_LVAL) { if (v == VT_LLOCAL) { @@ -298,6 +294,7 @@ ST_FUNC void store(int r, SValue *v) ft = v->type.t; fc = v->c.i; fr = v->r & VT_VALMASK; + ft &= ~(VT_VOLATILE | VT_CONSTANT); bt = ft & VT_BTYPE; /* XXX: incorrect if float reg to reg */ if (bt == VT_FLOAT) { @@ -351,6 +348,7 @@ static void gcall_or_jmp(int is_jmp) { int r; if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) { + int rt; /* constant case */ if (vtop->r & VT_SYM) { /* relocation case */ @@ -362,6 +360,30 @@ static void gcall_or_jmp(int is_jmp) ind + 1, R_386_PC32, 0); } oad(0xe8 + is_jmp, vtop->c.i - 4); /* call/jmp im */ + /* extend the return value to the whole register if necessary + visual studio and gcc do not always set the whole eax register + when assigning the return value of a function */ + rt = vtop->type.ref->type.t; + switch (rt & VT_BTYPE) { + case VT_BYTE: + if (rt & VT_UNSIGNED) { + o(0xc0b60f); /* movzx %al, %eax */ + } + else { + o(0xc0be0f); /* movsx %al, %eax */ + } + break; + case VT_SHORT: + if (rt & VT_UNSIGNED) { + o(0xc0b70f); /* movzx %ax, %eax */ + } + else { + o(0xc0bf0f); /* movsx %ax, %eax */ + } + break; + default: + break; + } } else { /* otherwise, indirect call */ r = gv(RC_INT); @@ -490,9 +512,9 @@ ST_FUNC void gfunc_call(int nb_args) } #ifdef TCC_TARGET_PE -#define FUNC_PROLOG_SIZE 10 +#define FUNC_PROLOG_SIZE (10 + USE_EBX) #else -#define FUNC_PROLOG_SIZE 9 +#define FUNC_PROLOG_SIZE (9 + USE_EBX) #endif /* generate function prolog of type 't' */ @@ -576,9 +598,10 @@ ST_FUNC void gfunc_prolog(CType *func_type) #ifdef CONFIG_TCC_BCHECK /* leave some room for bound checking code */ if (tcc_state->do_bounds_check) { + func_bound_offset = lbounds_section->data_offset; + func_bound_ind = ind; oad(0xb8, 0); /* lbound section pointer */ oad(0xb8, 0); /* call to function */ - func_bound_offset = lbounds_section->data_offset; } #endif } @@ -594,30 +617,31 @@ ST_FUNC void gfunc_epilog(void) addr_t saved_ind; addr_t *bounds_ptr; Sym *sym_data; + /* add end of table info */ bounds_ptr = section_ptr_add(lbounds_section, sizeof(addr_t)); *bounds_ptr = 0; + /* generate bound local allocation */ saved_ind = ind; - ind = func_sub_sp_offset; + ind = func_bound_ind; sym_data = get_sym_ref(&char_pointer_type, lbounds_section, func_bound_offset, lbounds_section->data_offset); greloc(cur_text_section, sym_data, ind + 1, R_386_32); oad(0xb8, 0); /* mov %eax, xxx */ gen_static_call(TOK___bound_local_new); - ind = saved_ind; + /* generate bound check local freeing */ o(0x5250); /* save returned value, if any */ - greloc(cur_text_section, sym_data, - ind + 1, R_386_32); + greloc(cur_text_section, sym_data, ind + 1, R_386_32); oad(0xb8, 0); /* mov %eax, xxx */ gen_static_call(TOK___bound_local_delete); - o(0x585a); /* restore returned value, if any */ } #endif + o(0x5b * USE_EBX); /* pop ebx */ o(0xc9); /* leave */ if (func_ret_sub == 0) { o(0xc3); /* ret */ @@ -641,10 +665,11 @@ ST_FUNC void gfunc_epilog(void) o(0xe58955); /* push %ebp, mov %esp, %ebp */ o(0xec81); /* sub esp, stacksize */ gen_le32(v); -#if FUNC_PROLOG_SIZE == 10 +#ifdef TCC_TARGET_PE o(0x90); /* adjust to FUNC_PROLOG_SIZE */ #endif } + o(0x53 * USE_EBX); /* push ebx */ ind = saved_ind; } @@ -667,6 +692,32 @@ ST_FUNC void gjmp_addr(int a) } } +ST_FUNC void gtst_addr(int inv, int a) +{ + int v = vtop->r & VT_VALMASK; + if (v == VT_CMP) { + inv ^= (vtop--)->c.i; + a -= ind + 2; + if (a == (char)a) { + g(inv - 32); + g(a); + } else { + g(0x0f); + oad(inv - 16, a - 4); + } + } else if ((v & ~1) == VT_JMP) { + if ((v & 1) != inv) { + gjmp_addr(a); + gsym(vtop->c.i); + } else { + gsym(vtop->c.i); + o(0x05eb); + gjmp_addr(a); + } + vtop--; + } +} + /* generate a test. set 'inv' to invert test. Stack entry is popped */ ST_FUNC int gtst(int inv, int t) { @@ -713,9 +764,9 @@ ST_FUNC void gen_opi(int op) c = vtop->c.i; if (c == (char)c) { /* generate inc and dec for smaller code */ - if (c==1 && opc==0) { + if (c==1 && opc==0 && op != TOK_ADDC1) { o (0x40 | r); // inc - } else if (c==1 && opc==5) { + } else if (c==1 && opc==5 && op != TOK_SUBC1) { o (0x48 | r); // dec } else { o(0x83); @@ -807,6 +858,8 @@ ST_FUNC void gen_opi(int op) fr = vtop[0].r; vtop--; save_reg(TREG_EDX); + /* save EAX too if used otherwise */ + save_reg_upstack(TREG_EAX, 1); if (op == TOK_UMULL) { o(0xf7); /* mul fr */ o(0xe0 + fr); @@ -982,8 +1035,7 @@ ST_FUNC void gen_cvt_itof(int t) /* convert fp to int 't' type */ ST_FUNC void gen_cvt_ftoi(int t) { - #ifndef COMMIT_4ad186c5ef61_IS_FIXED - /* a good version but it takes a more time to execute */ +#if 1 gv(RC_FLOAT); save_reg(TREG_EAX); save_reg(TREG_EDX); @@ -991,19 +1043,7 @@ ST_FUNC void gen_cvt_ftoi(int t) vtop->r = TREG_EAX; /* mark reg as used */ if (t == VT_LLONG) vtop->r2 = TREG_EDX; - #else - /* a new version with a bug: t2a = 44100312 */ - /* - #include<stdio.h> - int main() { - int t1 = 176401255; - float f = 0.25f; - int t2a = (int)(t1 * f); // must be 44100313 - int t2b = (int)(t1 * (float)0.25f); - printf("t2a=%d t2b=%d \n",t2a,t2b); - return 0; - } - */ +#else int bt = vtop->type.t & VT_BTYPE; if (bt == VT_FLOAT) vpush_global_sym(&func_old_type, TOK___fixsfdi); @@ -1016,7 +1056,7 @@ ST_FUNC void gen_cvt_ftoi(int t) vpushi(0); vtop->r = REG_IRET; vtop->r2 = REG_LRET; - #endif +#endif } /* convert from one floating point type to another */ @@ -1058,7 +1098,7 @@ ST_FUNC void gen_bounded_ptr_add(void) ST_FUNC void gen_bounded_ptr_deref(void) { addr_t func; - addr_t size, align; + int size, align; Elf32_Rel *rel; Sym *sym; |